Tearing apart printf() (2018)
maizure.org
maizure.org
1. printf may malloc so don't use it in an out of memory situation. Though I think this problem is vanishingly unlikely these days.
2. printf of floats used to require linking to the math library on some platforms (-lm)
3. I am pathetically grateful for nice diagnostics you get when you use the wrong % formatter in more recent C compilers. This used to be a rich source of errors and non-portability.
I feel like you've just saved my future self from a terrible bug in the future. Thanks
It is exceedingly rare for malloc() to give you a recovery chance on failure. Folks are so used to the Linux model of overcommit+OOM killer that almost nobody's code can gracefully deal with memory exhaustion.
Alternatively: don’t call printf from your interposed malloc, bad things will happen ;)
The Linux kernel style suffix extensions (cf. https://www.kernel.org/doc/Documentation/printk-formats.txt) are much better on the latter front.
You can avoid this by doing something like:
setvbuf(stdout, NULL, _IONBF, 0);https://sourceware.org/git/?p=glibc.git;a=blob;f=stdio-commo...
I'd like to point out that FreeBSD's printf only does this if:
1. you use a lot of arguments (i.e. a compile-time decision, and quite rare)
2. use wchar_t support (also a compile-time decision and quite rare)
3. the output is to something that buffers/mallocs (i.e. stdio)
4. locale support does it for some reason (I simply haven't checked this)
Which makes it great to use in e.g. crash handlers. It's actually Async-Signal-Safe if you cut out the stdio bits. And it's available under BSD license... and actually a nice read (more on that in a separate post.)
000000000040f9c0 <__libc_write>:
40f9c0: 83 3d c5 bb 2a 00 00 cmpl $0x0,0x2abbc5(%rip) # 6bb58c <__libc_multiple_threads>
40f9c7: 75 14 jne 40f9dd <__write_nocancel+0x14>
000000000040f9c9 <__write_nocancel>:
40f9c9: b8 01 00 00 00 mov $0x1,%eax
40f9ce: 0f 05 syscall
This is because they are set when the write function is called. The System V AMD64 ABI specifies that rdi, rsi and rdx are used for the 1st, 2nd and 3rd arguments of a function, perfectly matching the Linux system call ABI. The 5th and 6th also match: r8 and r9, respectively. However, the 4th argument doesn't match: system calls use r10 while System V uses rcx. I wish I knew why.He has much more serious problems nowadays...
https://github.com/lattera/freebsd/blob/master/lib/libc/stdi...
For FRRouting, we decided we want to use Linux kernel style extensions (like "%pI4"), so to get this in a portable way we imported FreeBSD's printf into our code. Since printf() isn't exactly "hot" code getting changed a lot, we considered the maintenance / duplication cost acceptable.
You can see the result here:
https://github.com/FRRouting/frr/tree/master/lib/printf
http://docs.frrouting.org/projects/dev-guide/en/latest/loggi...
stdio support is completely gone in our copy, WCHAR_SUPPORT is disabled at compile time, locale support is stubbed out/hardcoded to C locale. None of these matter to us. As a result, we can use this printf even in the SEGV handler. (That's only a bonus though, the main reason was extensibility on the format specifiers.)