strtod_l.c contains a conditional which is never going to pass because it requires both base == 16 and base != 16. if ((c < L_('0') || c > L_('9')) && (base == 16 && (c < (CHAR_TYPE) TOLOWER (L_('a')) || c > (CHAR_TYPE) TOLOWER (L_('f')))) #ifdef USE_WIDE_CHAR && c != (wint_t) decimal #else && ({ for (cnt = 0; decimal[cnt] != '\0'; ++cnt) if (decimal[cnt] != cp[cnt]) break; decimal[cnt] != '\0'; }) #endif && (base == 16 && (cp == start_of_digits || (CHAR_TYPE) TOLOWER (c) != L_('p'))) && (base != 16 && (CHAR_TYPE) TOLOWER (c) != L_('e'))) I believe the fix is to change "base == 16 &&" to "base != 16 ||" in both places, "base != 16 &&" to "base == 16 ||", "c < (CHAR_TYPE) TOLOWER (L_('a'))" to "(CHAR_TYPE) TOLOWER (c) < L_('a')" and likewise for 'f'. The following test shows that this causes an actual bug. #include <stdlib.h> int main(void) { const char *s = "0x"; char *ep; double r = strtod(s, &ep); if (r != 0) abort(); if (ep != s + 1) abort(); exit(0); }
Fixed in cvs.
Subject: Bug 3664 CVSROOT: /cvs/glibc Module name: libc Branch: glibc-2_5-branch Changes by: jakub@sourceware.org 2007-01-12 18:07:19 Modified files: . : ChangeLog stdlib : Makefile strtod_l.c Added files: stdlib : tst-atof1.c tst-atof2.c tst-strtod2.c tst-strtod3.c Log message: * stdlib/Makefile (tst-strtod3-ENV): Define. * stdlib/strtod_l.c (____STRTOF_INTERNAL): Parse thousand separators also if no non-zero digits found. * stdlib/Makefile (tests): Add tst-strtod3. [BZ #3664] * stdlib/strtod_l.c (____STRTOF_INTERNAL): Fix test to recognize empty parsed strings. * stdlib/Makefile (tests): Add tst-strtod2. * stdlib/tst-strtod2.c: New file. [BZ #3673] * stdlib/strtod_l.c (____STRTOF_INTERNAL): Fix exp_limit computation. * stdlib/Makefile (tests): Add tst-atof2. * stdlib/tst-atof2.c: New file. [BZ #3674] * stdlib/strtod_l.c (____STRTOF_INTERNAL): Adjust exponent value correctly if removing trailing zero of hex-float. * stdlib/Makefile (tests): Add tst-atof1. * stdlib/tst-atof1.c: New file. Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/libc/ChangeLog.diff?cvsroot=glibc&only_with_tag=glibc-2_5-branch&r1=1.10362.2.28&r2=1.10362.2.29 http://sourceware.org/cgi-bin/cvsweb.cgi/libc/stdlib/tst-atof1.c.diff?cvsroot=glibc&only_with_tag=glibc-2_5-branch&r1=NONE&r2=1.1.4.1 http://sourceware.org/cgi-bin/cvsweb.cgi/libc/stdlib/tst-atof2.c.diff?cvsroot=glibc&only_with_tag=glibc-2_5-branch&r1=NONE&r2=1.1.4.1 http://sourceware.org/cgi-bin/cvsweb.cgi/libc/stdlib/tst-strtod2.c.diff?cvsroot=glibc&only_with_tag=glibc-2_5-branch&r1=NONE&r2=1.3.2.1 http://sourceware.org/cgi-bin/cvsweb.cgi/libc/stdlib/tst-strtod3.c.diff?cvsroot=glibc&only_with_tag=glibc-2_5-branch&r1=NONE&r2=1.1.4.1 http://sourceware.org/cgi-bin/cvsweb.cgi/libc/stdlib/Makefile.diff?cvsroot=glibc&only_with_tag=glibc-2_5-branch&r1=1.109.2.2&r2=1.109.2.3 http://sourceware.org/cgi-bin/cvsweb.cgi/libc/stdlib/strtod_l.c.diff?cvsroot=glibc&only_with_tag=glibc-2_5-branch&r1=1.14&r2=1.14.2.1