gcc feature breaks glibc feature

most gnome hackers are probably accustomed to the fact that they can pass a null pointer as a value to glibc’s “%s” conversion character and get the string “(null)” output instead of a crash.

take for example, this program:

#include <stdio.h>

int
main (void)
{
  printf ("%s", NULL);

  return 0;
}

this will output “(null)”. nice. i like this glibc feature.

of course, this program fails to put a newline. let’s make the obvious fix:

#include <stdio.h>

int
main (void)
{
  printf ("%s\n", NULL);

  return 0;
}

this program segfaults.

why is this?

let’s look at the assembly code generated for the second program:

...
...
main:
        ....
        ....
        call puts
        ....

it turns out that if gcc sees “printf (“%s\n”, string);” then it assumes that this is exactly equivalent to “puts (string);” and emits the puts code instead. this is without any optimisation enabled. of course, compiling with -ffreestanding causes it to not make this assumption.

of course, puts will crash if you give it a null pointer.

i guess the assumption is probably valid by strict reading of the relevant specifications (printfing a null string is probably said to be “undefined”) but clearly this feature of gcc is in conflict with the “(null)” feature of glibc.