[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
yet another snprintf bug
From: |
Bruno Haible |
Subject: |
yet another snprintf bug |
Date: |
Sun, 29 Apr 2007 17:46:42 +0200 |
User-agent: |
KMail/1.5.4 |
[v]snprintf (buf, 0, format, ...) is expected to write nothing into 'buf'
according to C99 and POSIX. On Tru64, this nevertheless writes one NUL byte.
And on HP-UX 11.00...11.23, with vsnprintf, this even overwrites as much of
'buf' as it can... This works around it.
2007-04-29 Bruno Haible <address@hidden>
* m4/printf.m4 (gl_VSNPRINTF_ZEROSIZE_C99): New macro.
* m4/snprintf-posix.m4 (gl_FUNC_SNPRINTF_POSIX): Invoke
gl_VSNPRINTF_ZEROSIZE_C99. Test gl_cv_func_vsnprintf_zerosize_c99.
* m4/vsnprintf-posix.m4 (gl_FUNC_VSNPRINTF_POSIX): Likewise.
* modules/snprintf-posix-tests (Files): Add tests/test-snprintf.c.
(configure.ac): Define CHECK_SNPRINTF_POSIX.
(TESTS, check_PROGRAMS): Add test-snprintf.
* modules/vsnprintf-posix-tests (Files): Add tests/test-vsnprintf.c.
(configure.ac): Define CHECK_VSNPRINTF_POSIX.
(TESTS, check_PROGRAMS): Add test-vsnprintf.
* tests/test-snprintf.c (main) [!CHECK_SNPRINTF_POSIX]: Disable
assertions that fail on HP-UX, OSF/1, or IRIX.
* tests/test-vsnprintf.c (main) [!CHECK_VSNPRINTF_POSIX]: Likewise.
*** m4/printf.m4 12 Apr 2007 23:13:32 -0000 1.20
--- m4/printf.m4 29 Apr 2007 15:34:08 -0000
***************
*** 1,4 ****
! # printf.m4 serial 6
dnl Copyright (C) 2003, 2007 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
--- 1,4 ----
! # printf.m4 serial 7
dnl Copyright (C) 2003, 2007 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
***************
*** 361,366 ****
--- 361,376 ----
dnl Test whether the return value of the snprintf function is the number
dnl of bytes (excluding the terminating NUL) that would have been produced
dnl if the buffer had been large enough. (ISO C99, POSIX:2001)
+ dnl For example, this test program fails on IRIX 6.5:
+ dnl ---------------------------------------------------------------------
+ dnl #include <stdio.h>
+ dnl int main()
+ dnl {
+ dnl static char buf[8];
+ dnl int retval = snprintf (buf, 3, "%d", 12345);
+ dnl return retval >= 0 && retval < 3;
+ dnl }
+ dnl ---------------------------------------------------------------------
dnl Result is gl_cv_func_snprintf_retval_c99.
AC_DEFUN([gl_SNPRINTF_RETVAL_C99],
***************
*** 475,480 ****
--- 485,588 ----
])
])
+ dnl Test whether the vsnprintf function, when passed a zero size, produces no
+ dnl output. (ISO C99, POSIX:2001)
+ dnl For example, snprintf nevertheless writes a NUL byte in this case
+ dnl on OSF/1 5.1:
+ dnl ---------------------------------------------------------------------
+ dnl #include <stdio.h>
+ dnl int main()
+ dnl {
+ dnl static char buf[8] = "DEADBEEF";
+ dnl snprintf (buf, 0, "%d", 12345);
+ dnl return buf[0] != 'D';
+ dnl }
+ dnl ---------------------------------------------------------------------
+ dnl And vsnprintf writes any output without bounds in this case, behaving like
+ dnl vsprintf, on HP-UX 11 and OSF/1 5.1:
+ dnl ---------------------------------------------------------------------
+ dnl #include <stdarg.h>
+ dnl #include <stdio.h>
+ dnl static int my_snprintf (char *buf, int size, const char *format, ...)
+ dnl {
+ dnl va_list args;
+ dnl int ret;
+ dnl va_start (args, format);
+ dnl ret = vsnprintf (buf, size, format, args);
+ dnl va_end (args);
+ dnl return ret;
+ dnl }
+ dnl int main()
+ dnl {
+ dnl static char buf[8] = "DEADBEEF";
+ dnl my_snprintf (buf, 0, "%d", 12345);
+ dnl return buf[0] != 'D';
+ dnl }
+ dnl ---------------------------------------------------------------------
+ dnl Result is gl_cv_func_vsnprintf_zerosize_c99.
+
+ AC_DEFUN([gl_VSNPRINTF_ZEROSIZE_C99],
+ [
+ AC_REQUIRE([AC_PROG_CC])
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+ AC_CACHE_CHECK([whether vsnprintf respects a zero size as in C99],
+ [gl_cv_func_vsnprintf_zerosize_c99],
+ [
+ AC_TRY_RUN([
+ #include <stdarg.h>
+ #include <stdio.h>
+ static int my_snprintf (char *buf, int size, const char *format, ...)
+ {
+ va_list args;
+ int ret;
+ va_start (args, format);
+ ret = vsnprintf (buf, size, format, args);
+ va_end (args);
+ return ret;
+ }
+ int main()
+ {
+ static char buf[8] = "DEADBEEF";
+ my_snprintf (buf, 0, "%d", 12345);
+ return buf[0] != 'D';
+ }],
+ [gl_cv_func_vsnprintf_zerosize_c99=yes],
+ [gl_cv_func_vsnprintf_zerosize_c99=no],
+ [
+ changequote(,)dnl
+ case "$host_os" in
+ # Guess yes on glibc systems.
+ *-gnu*) gl_cv_func_vsnprintf_zerosize_c99="guessing
yes";;
+ # Guess yes on FreeBSD >= 5.
+ freebsd[1-4]*) gl_cv_func_vsnprintf_zerosize_c99="guessing
no";;
+ freebsd* | kfreebsd*) gl_cv_func_vsnprintf_zerosize_c99="guessing
yes";;
+ # Guess yes on MacOS X >= 10.3.
+ darwin[1-6].*) gl_cv_func_vsnprintf_zerosize_c99="guessing
no";;
+ darwin*) gl_cv_func_vsnprintf_zerosize_c99="guessing
yes";;
+ # Guess yes on Solaris >= 2.6.
+ solaris2.[0-5]*) gl_cv_func_vsnprintf_zerosize_c99="guessing
no";;
+ solaris*) gl_cv_func_vsnprintf_zerosize_c99="guessing
yes";;
+ # Guess yes on AIX >= 4.
+ aix[1-3]*) gl_cv_func_vsnprintf_zerosize_c99="guessing
no";;
+ aix*) gl_cv_func_vsnprintf_zerosize_c99="guessing
yes";;
+ # Guess yes on IRIX >= 6.5.
+ irix6.5) gl_cv_func_vsnprintf_zerosize_c99="guessing
yes";;
+ # Guess yes on NetBSD >= 3.
+ netbsd[1-2]* | netbsdelf[1-2]* | netbsdaout[1-2]* | netbsdcoff[1-2]*)
+ gl_cv_func_vsnprintf_zerosize_c99="guessing
no";;
+ netbsd*) gl_cv_func_vsnprintf_zerosize_c99="guessing
yes";;
+ # Guess yes on BeOS.
+ beos*) gl_cv_func_vsnprintf_zerosize_c99="guessing
yes";;
+ # Guess yes on mingw.
+ mingw* | pw*) gl_cv_func_vsnprintf_zerosize_c99="guessing
yes";;
+ # If we don't know, assume the worst.
+ *) gl_cv_func_vsnprintf_zerosize_c99="guessing
no";;
+ esac
+ changequote([,])dnl
+ ])
+ ])
+ ])
+
dnl The results of these tests on various platforms are:
dnl
dnl 1 = gl_PRINTF_SIZES_C99
***************
*** 486,491 ****
--- 594,600 ----
dnl 7 = gl_SNPRINTF_TRUNCATION_C99
dnl 8 = gl_SNPRINTF_RETVAL_C99
dnl 9 = gl_SNPRINTF_DIRECTIVE_N
+ dnl 10 = gl_VSNPRINTF_ZEROSIZE_C99
dnl
dnl 1 = checking whether printf supports size specifiers as in C99...
dnl 2 = checking whether printf supports the 'a' and 'A' directives...
***************
*** 496,523 ****
dnl 7 = checking whether snprintf truncates the result as in C99...
dnl 8 = checking whether snprintf returns a byte count as in C99...
dnl 9 = checking whether snprintf fully supports the 'n' directive...
dnl
dnl . = yes, # = no.
dnl
! dnl 1 2 3 4 5 6 7 8 9
! dnl glibc 2.5 . . . . . . . . .
! dnl glibc 2.3.6 . # . . . . . . .
! dnl FreeBSD 5.4, 6.1 . ? . . . . . . .
! dnl MacOS X 10.3.9 . # . . . . . . .
! dnl OpenBSD 3.9, 4.0 . # ? . . . . . ?
! dnl Cygwin 2007 . # # . . . . . .
! dnl Cygwin 2006 # # # . . . . . .
! dnl Solaris 10 . # . . . . . . .
! dnl Solaris 2.6 ... 9 # # # . . . . . .
! dnl Solaris 2.5.1 # # # . . # # # #
! dnl AIX 5.2 . # . . . . . . .
! dnl AIX 4.3.2, 5.1 # # # . . . . . .
! dnl HP-UX 11.31 . # . . . . . # #
! dnl HP-UX 10.20, 11.00, 11.11, 11.23 # # # . . . . # #
! dnl IRIX 6.5 # # # . . . . # .
! dnl OSF/1 5.1 # # # . . . . # .
! dnl OSF/1 4.0d # # # . . # # # #
! dnl NetBSD 4.0 . ? ? . . . . . ?
! dnl NetBSD 3.0 . # # . # . . . .
! dnl BeOS # # # . # . . . .
! dnl mingw # # # . # . # # #
--- 605,633 ----
dnl 7 = checking whether snprintf truncates the result as in C99...
dnl 8 = checking whether snprintf returns a byte count as in C99...
dnl 9 = checking whether snprintf fully supports the 'n' directive...
+ dnl 10 = checking whether vsnprintf respects a zero size as in C99...
dnl
dnl . = yes, # = no.
dnl
! dnl 1 2 3 4 5 6 7 8 9 10
! dnl glibc 2.5 . . . . . . . . . .
! dnl glibc 2.3.6 . # . . . . . . . .
! dnl FreeBSD 5.4, 6.1 . ? . . . . . . . .
! dnl MacOS X 10.3.9 . # . . . . . . . .
! dnl OpenBSD 3.9, 4.0 . # ? . . . . . ? ?
! dnl Cygwin 2007 . # # . . . . . . ?
! dnl Cygwin 2006 # # # . . . . . . ?
! dnl Solaris 10 . # . . . . . . . .
! dnl Solaris 2.6 ... 9 # # # . . . . . . .
! dnl Solaris 2.5.1 # # # . . # # # # #
! dnl AIX 5.2 . # . . . . . . . .
! dnl AIX 4.3.2, 5.1 # # # . . . . . . .
! dnl HP-UX 11.31 . # . . . . . # # .
! dnl HP-UX 10.20, 11.00, 11.11, 11.23 # # # . . . . # # #
! dnl IRIX 6.5 # # # . . . . # . .
! dnl OSF/1 5.1 # # # . . . . # . #
! dnl OSF/1 4.0d # # # . . # # # # #
! dnl NetBSD 4.0 . ? ? . . . . . ? ?
! dnl NetBSD 3.0 . # # . # . . . . .
! dnl BeOS # # # . # . . . . .
! dnl mingw # # # . # . # # # .
*** m4/snprintf-posix.m4 11 Apr 2007 23:46:07 -0000 1.4
--- m4/snprintf-posix.m4 29 Apr 2007 15:34:08 -0000
***************
*** 1,4 ****
! # snprintf-posix.m4 serial 3
dnl Copyright (C) 2007 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
--- 1,4 ----
! # snprintf-posix.m4 serial 4
dnl Copyright (C) 2007 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
***************
*** 18,23 ****
--- 18,24 ----
gl_SNPRINTF_TRUNCATION_C99
gl_SNPRINTF_RETVAL_C99
gl_SNPRINTF_DIRECTIVE_N
+ gl_VSNPRINTF_ZEROSIZE_C99
case "$gl_cv_func_printf_sizes_c99" in
*yes)
case "$gl_cv_func_printf_directive_a" in
***************
*** 34,42 ****
*yes)
case "$gl_cv_func_snprintf_directive_n" in
*yes)
! # snprintf exists and is already POSIX
! # compliant.
! gl_cv_func_snprintf_posix=yes
;;
esac
;;
--- 35,47 ----
*yes)
case "$gl_cv_func_snprintf_directive_n" in
*yes)
! case "$gl_cv_func_vsnprintf_zerosize_c99"
in
! *yes)
! # snprintf exists and is already POSIX
! # compliant.
! gl_cv_func_snprintf_posix=yes
! ;;
! esac
;;
esac
;;
*** m4/vsnprintf-posix.m4 11 Apr 2007 23:46:07 -0000 1.4
--- m4/vsnprintf-posix.m4 29 Apr 2007 15:34:08 -0000
***************
*** 1,4 ****
! # vsnprintf-posix.m4 serial 3
dnl Copyright (C) 2007 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
--- 1,4 ----
! # vsnprintf-posix.m4 serial 4
dnl Copyright (C) 2007 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
***************
*** 19,24 ****
--- 19,25 ----
gl_SNPRINTF_TRUNCATION_C99
gl_SNPRINTF_RETVAL_C99
gl_SNPRINTF_DIRECTIVE_N
+ gl_VSNPRINTF_ZEROSIZE_C99
case "$gl_cv_func_printf_sizes_c99" in
*yes)
case "$gl_cv_func_printf_directive_a" in
***************
*** 35,43 ****
*yes)
case "$gl_cv_func_snprintf_directive_n" in
*yes)
! # vsnprintf exists and is already POSIX
! # compliant.
! gl_cv_func_vsnprintf_posix=yes
;;
esac
;;
--- 36,48 ----
*yes)
case "$gl_cv_func_snprintf_directive_n" in
*yes)
! case "$gl_cv_func_vsnprintf_zerosize_c99"
in
! *yes)
! # vsnprintf exists and is already
POSIX
! # compliant.
! gl_cv_func_vsnprintf_posix=yes
! ;;
! esac
;;
esac
;;
*** modules/snprintf-posix-tests 6 Apr 2007 14:36:56 -0000 1.3
--- modules/snprintf-posix-tests 29 Apr 2007 15:34:08 -0000
***************
*** 1,14 ****
Files:
tests/test-snprintf-posix.c
tests/test-snprintf-posix.h
Depends-on:
stdint
configure.ac:
Makefile.am:
! TESTS += test-snprintf-posix
! check_PROGRAMS += test-snprintf-posix
EXTRA_DIST += test-snprintf-posix.h
--- 1,17 ----
Files:
tests/test-snprintf-posix.c
tests/test-snprintf-posix.h
+ tests/test-snprintf.c
Depends-on:
stdint
configure.ac:
+ AC_DEFINE([CHECK_SNPRINTF_POSIX], 1,
+ [Define to 1 for strict checking in test-snprintf.c.])
Makefile.am:
! TESTS += test-snprintf-posix test-snprintf
! check_PROGRAMS += test-snprintf-posix test-snprintf
EXTRA_DIST += test-snprintf-posix.h
*** modules/vsnprintf-posix-tests 6 Apr 2007 14:36:56 -0000 1.3
--- modules/vsnprintf-posix-tests 29 Apr 2007 15:34:08 -0000
***************
*** 1,14 ****
Files:
tests/test-vsnprintf-posix.c
tests/test-snprintf-posix.h
Depends-on:
stdint
configure.ac:
Makefile.am:
! TESTS += test-vsnprintf-posix
! check_PROGRAMS += test-vsnprintf-posix
EXTRA_DIST += test-snprintf-posix.h
--- 1,17 ----
Files:
tests/test-vsnprintf-posix.c
tests/test-snprintf-posix.h
+ tests/test-vsnprintf.c
Depends-on:
stdint
configure.ac:
+ AC_DEFINE([CHECK_VSNPRINTF_POSIX], 1,
+ [Define to 1 for strict checking in test-vsnprintf.c.])
Makefile.am:
! TESTS += test-vsnprintf-posix test-vsnprintf
! check_PROGRAMS += test-vsnprintf-posix test-vsnprintf
EXTRA_DIST += test-snprintf-posix.h
*** tests/test-snprintf.c 29 Apr 2007 09:15:13 -0000 1.2
--- tests/test-snprintf.c 29 Apr 2007 15:34:08 -0000
***************
*** 50,62 ****
retval = snprintf (buf, size, "%d", 12345);
if (size < 6)
{
ASSERT (retval < 0 || retval >= size);
if (size > 0)
{
ASSERT (memcmp (buf, "12345", size - 1) == 0);
ASSERT (buf[size - 1] == '\0' || buf[size - 1] == '0' + size);
}
! ASSERT (memcmp (buf + size, "DEADBEEF" + size, 8 - size) == 0);
}
else
{
--- 50,67 ----
retval = snprintf (buf, size, "%d", 12345);
if (size < 6)
{
+ #if CHECK_SNPRINTF_POSIX
ASSERT (retval < 0 || retval >= size);
+ #endif
if (size > 0)
{
ASSERT (memcmp (buf, "12345", size - 1) == 0);
ASSERT (buf[size - 1] == '\0' || buf[size - 1] == '0' + size);
}
! #if !CHECK_SNPRINTF_POSIX
! if (size > 0)
! #endif
! ASSERT (memcmp (buf + size, "DEADBEEF" + size, 8 - size) == 0);
}
else
{
*** tests/test-vsnprintf.c 29 Apr 2007 09:15:13 -0000 1.2
--- tests/test-vsnprintf.c 29 Apr 2007 15:34:08 -0000
***************
*** 63,75 ****
retval = my_snprintf (buf, size, "%d", 12345);
if (size < 6)
{
ASSERT (retval < 0 || retval >= size);
if (size > 0)
{
ASSERT (memcmp (buf, "12345", size - 1) == 0);
ASSERT (buf[size - 1] == '\0' || buf[size - 1] == '0' + size);
}
! ASSERT (memcmp (buf + size, "DEADBEEF" + size, 8 - size) == 0);
}
else
{
--- 63,80 ----
retval = my_snprintf (buf, size, "%d", 12345);
if (size < 6)
{
+ #if CHECK_VSNPRINTF_POSIX
ASSERT (retval < 0 || retval >= size);
+ #endif
if (size > 0)
{
ASSERT (memcmp (buf, "12345", size - 1) == 0);
ASSERT (buf[size - 1] == '\0' || buf[size - 1] == '0' + size);
}
! #if !CHECK_VSNPRINTF_POSIX
! if (size > 0)
! #endif
! ASSERT (memcmp (buf + size, "DEADBEEF" + size, 8 - size) == 0);
}
else
{
- yet another snprintf bug,
Bruno Haible <=