7

As I was writing a unit test, I stumbled upon some odd behavior from glibc, regarding "%p" and the NULL pointer.

If I have a line such as printf("NULL pointer is %p\n", NULL);, then I see NULL pointer is (nil) printed to the screen, as I expected.

If I instead use the wide-character version: wprintf(L"NULL pointer is %p\n", NULL);, then it prints out NULL pointer is (, and stops at the opening parenthesis. If I print a non-NULL pointer, it prints that pointer, both normal and wide-character versions. Is this a known bug of glibc, or am I just missing something?

NB: I realize that the C standard says that pointers with %p are converted in an implementation-defined manner; it just seems unusual to just print ( for a NULL pointer.

Drew McGowen
  • 11,471
  • 1
  • 31
  • 57
  • 1
    looks like a bug ..... – David Heffernan Jul 28 '14 at 18:52
  • 2
    The result strings do not match what one would expect from the format strings: in the format strings, there are single quote marks (`'`) around the `%p`, but they do not appear in the result strings. Is this a typo in the question? – James McNellis Jul 28 '14 at 18:52
  • Instead of `NULL`, have you tried `L'\0'`? – Fiddling Bits Jul 28 '14 at 19:03
  • 1
    @FiddlingBits `%p` expects a pointer, whereas `L'\0'` is an integer constant. Regardless, it still gives the same result. – Drew McGowen Jul 28 '14 at 19:05
  • [This can't be right either](http://coliru.stacked-crooked.com/a/ffa19139dad72878)... – rubenvb Jul 28 '14 at 19:22
  • @rubenvb that's because you can't mix `printf` and `wprintf` on the same stream - once a stream is oriented as either wide character or not, it can't be changed – Drew McGowen Jul 28 '14 at 19:24
  • @Drew First time I noticed this. Then again, I never mixed wide and non-wide output. [Nice answer on the matter](http://stackoverflow.com/a/8682010/256138) (including comments). – rubenvb Jul 28 '14 at 19:41

2 Answers2

8

This is definitely a bug: https://sourceware.org/git/gitweb.cgi?p=glibc.git;a=blob;f=stdio-common/vfprintf.c;hb=c15cf13a8a672bd27bf3d94b995c52872eed537d#l932

 934             /* Write "(nil)" for a nil pointer.  */                           \
 935             string = (CHAR_T *) L_("(nil)");                                  \
 936             /* Make sure the full string "(nil)" is printed.  */              \
 937             if (prec < 5)                                                     \
 938               prec = 5;                                                       \
 939             is_long = 0;        /* This is no wide-char string.  */           \
 940             goto LABEL (print_string);                                        \

The L_("(nil)") expands to L"(nil)" for wprintf, but a couple of lines later is_long is set to 0 (i.e. false). As a result string is interpreted as a narrow-character string, so printing it will stop at its first zero byte i.e. after the (.

Reported bug link: https://sourceware.org/bugzilla/show_bug.cgi?id=16890 - this is fixed in version 2.20 of glibc.

Interestingly, this bug appears to have existed for almost 15 years before it was found and fixed - within 2 days of its reporting!

ecatmur
  • 152,476
  • 27
  • 293
  • 366
1

Confirmed on Ubuntu 14.04 LTS; GNU C Library (Ubuntu EGLIBC 2.19-0ubuntu6).

It seems to be a reported bug in at least Debian glibc; the bug has been fixed on 1 May 2014, and should be available in Glibc 2.20. Just wait for upstream updates.