I came across the following intriguing interview question:
test 1: printf("test %s\n", NULL); printf("test %s\n", NULL); prints: test (null) test (null) test 2: printf("%s\n", NULL); printf("%s\n", NULL); prints Segmentation fault (core dumped)
Though this may work OK on some computers, it fails with a segmentation failure on mine. What is the most plausible explanation for this behavior? The code above is written in C.
My gcc information is as follows:
deep@deep:~$ gcc --version gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Asked by Deepanjan Mazumdar
First things first: printf is expecting a valid (i.e. non-NULL) pointer for its %s argument so passing it a NULL is officially undefined. It may print “(null)” or it may delete all files on your hard drive–either is correct behavior as far as ANSI is concerned (at least, that’s what Harbison and Steele tells me.)
That being said, this is really strange behavior. What happens, it turns out, is that when you execute a simple printf like this:
Gcc is (hum) clever enough to decompose this into a put call. This is the initial printf:
printf("test %s\n", NULL);
is sophisticated enough that gcc will produce a genuine printf call instead.
(Notice that when you compile, gcc issues warnings about your erroneous printf parameter.) That’s because it acquired the ability to parse *printf format strings a long time ago.)
By compiling with the -save-temps option and then inspecting the resulting.s file, you can observe this for yourself.
When I put the first example together, I got:
movl $.LC0, %eax movl $0, %esi movq %rax, %rdi movl $0, %eax call printf ; <-- Actually calls printf!
(I contributed the comments.)
However, the second one yielded the following code:
movl $0, %edi ; Stores NULL in the puts argument list call puts ; Calls puts
The strange thing is that it doesn’t print the newline after it. It’s as if it’s worked out that this will create a segfault and thus doesn’t bother. (Which it does—it alerted me when I was putting it together.)
Answered by Chris Reuter
The reason for this is that you’re invoking undefined behavior in the C language, and anything can happen.
To explain why this is happening, contemporary gcc optimizes printf(” % sn”, x) to puts(x), because puts does not contain the foolish code to print (null) when it finds a null pointer, although conventional printf implementations do. Because gcc can’t (in general) optimize non-trivial format strings like this, printf is used when the format string contains additional content.
Answered by R.. GitHub STOP HELPING ICE
The following is taken from Section 7.1.4 (of C99 or C11):
The behavior is explicitly unknown because the printf() specification specifies nothing about what occurs when you feed it a null reference for the percent s specifier. (It’s worth noting that supplying a null reference to the percent p specifier does not result in undefined behavior.)
Here’s the fprintf() family behavior’s ‘chapter and verse’ (C2011 — it’s a different section number in C1999):
The s conversion specifier’s requirements rule out the idea of a null pointer being valid since a null pointer does not point to the first member of an array of the suitable type. The void pointer does not have to point to anything in particular according to the p conversion specifier specification, hence NULL is allowed.
When a null pointer is supplied, several implementations print a string like (null), which is a dangerous kindness to rely on. The beauty of undefined behavior is that it is permissible, but not essential, to respond in this way. A crash is also allowed but not needed (which is unfortunate because people get bitten if they work on a forgiving system and then port to a less forgiving one).
Answered by Jonathan Leffler
Attempting to print the NULL pointer, which does not point to any address, results in undefined behavior. Undefined meaning it’s up to your compiler or C library to decide what to do when it tries to print NULL.
Answered by Yunchi
Post is based on https://stackoverflow.com/questions/11589342/what-is-the-behavior-of-printing-null-with-printfs-s-specifier