You_Shall_Not_Use_Printf: How to make sure no printf() is used

Every embedded system developer should know by now, that using printf() is not a good thing for smaller systems. Printf() and the like are not only problematic from a code and data size perspective, they are infamous for vulnerability attacks too.

In this article I’ll show you multiple ways how to ban printf() or anything similar you want to avoid.

Search

The first obvious way is to search for ‘printf’ in your code base:

The search for printf()

Obviously, this might get a lot of hits. The above search is not case sensitive, so it shows all kind of similar usage of printf() you might look into.

Linker Map File

There might be many calls to printf() in the application, but not all of them actually are used.

For that case, check the linker .map file: if the address/size of the object is non-zero, it is definitely used:

printf() usage in linker file

Image Info

Another way to find out usage of a symbol is using the ‘Image Info’, e.g. in the NXP MCUXpresso IDE:

Image Info

Retarget (none) library

For embedded applications, the standard I/O which is used by printf() can be re-target, e.g. to a UART or using semihosting, which is usually implemented with a library variant. Use such a library and check if you still can link:

As described in Which Embedded GCC Standard Library? newlib, newlib-nano, …, using a ‘none’ library will not map the low level functions. As long as your application does not re-target them to something like a UART, then this is an easy way to catch printf() usage indirectly.

Assert and printf()

Using asserts in the code is a good way to catch runtime errors. Some SDKs are using printf() in asserts which is questionable in my view. To test it if the asserts are the source of remaining printf()‘s, you can set the NDEBUG macro:

NDEBUG instead of DEBUG

Redefining linker symbols

To catch hidden usage of printf() or any other undesired function, a working approach is to redefined the symbols in the linking phase.

GNU linker –defsym command

With the GNU linker –defsym command I can redirect usage of a symbol to a custom one, for example

--defsym=printf="you_shall_not_use_printf"

That way, the linker will throw an error, because that symbol cannot be found. And if you define an empty function with that name, you can set a breakpoint and find out who might call it anyway.

Summary

Using printf() and the likes can be very problematic for embedded applications: it can use lots of code, data and stack space, plus can cause a security threat.

I do not have and use printf() in production code, and if I have to use variable argument list printing,then I use the better alternatives like XFormat. But it still might be used or linked in with libraries, including the C/C++ standard library one.

I have presented a few ways how to prevent using it, or finding out who is using it. I’m using the --defsym way in different ways successfully to catch, isolate and remove usage of undesired standard library functions.

Happy linking 🙂

Links

Advertisement

25 thoughts on “You_Shall_Not_Use_Printf: How to make sure no printf() is used

  1. The double dash in –defsym seems to have been converted to a single dash or emdash or similar in some of the text. E.g.:

    “GNU linker –defsym command
    With the GNU linker –defsym command I can redirect usage of a symbol to a custom one, for example”

    Liked by 1 person

  2. It’s best to avoid printf() altogether when developing embedded or small hardware systems. Replace the urge to throw down “hello world” breadcrumbs instead with the toggling of lights or other signals using unoccupied GPIO lines. You can even blink once for good, twice for bad, thrice for X, etc.

    If one really needs formatted output, separate the “Swiss Army” knife style of printf() into lots of little single-mode functions — aptly named — and let the logic of program design dictate which format and function to use when, rather than relying upon a function’s runtime decision. A bit of redundancy saves a world of grief.

    Liked by 1 person

  3. Erich,

    I would add that the primary reason printf is so resource wasteful is because it is one of the few functions in C with a variable-length argument list, which is not that critical to embedded systems. The reason people use it (and scanf) is to convert numbers to/from binary representation from/to a human-readable form. To that end I developed my own set of conversion functions years ago, totally obviating the need for printf.

    Like

    • Hi Gary,
      the variable length thing is not much contributing to the overhead. What contributes is all the different formatting possibilities (floating point, alignment, hex, size, lengths, …) which need to be there even if not actually used. The other part is that it uses down the layers hooks to write out the data, possibly including dealing with file I/O.
      And yes, we have built up such conversion functions and utility routines to cover the needs in our applications, and they are available in a ‘McuUtility’ module.

      Like

  4. If you are using GCC then you can use
    #pragma GCC poison printf sprintf …
    Note this only poisons identifiers used after the pragma, see the GCC docs.

    Like

    • sprintf shares the same overhead as printf for the formatting string. It is just better in the sense that it stores things into a buffer than writing things to a standard I/O channel which might cause reentrancy issues.
      and most important: use snprintf, not sprintf.

      Like

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.