bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: vasnprintf.c %n blocked under MSVS8


From: Bruno Haible
Subject: Re: vasnprintf.c %n blocked under MSVS8
Date: Fri, 8 Feb 2008 02:32:55 +0100
User-agent: KMail/1.5.4

Hi Simon,

> Hi!  I received a patch for vasnprintf with rationale:

From whom, please? I would like to acknowledge the original reporter.

> >   - fixes vasnprintf for MSVC8 or higher that has also %n blocked

I understand that it depends on the MSVCRT.DLL, that is, it will also
happen with mingw.

But essentially, the patch is right. I verified that it does not cause
testsuite failures, and added some comments mentioning why this change is
right. Patch appended below.

My earlier statement that nothing needs to be done in gnulib
  <http://lists.gnu.org/archive/html/bug-gnulib/2007-06/msg00066.html>
was wrong; I had not understood that %n makes a program crash on Vista
or that mingw has snprintf().

> Looking at this, I'm not sure I understand the intention.  Why isn't a
> configure test used to determine whether %n works in snprintf or not (if
> that is indeed what is relevant), rather than version-based checks?

Ad-hoc tests are used here for two reasons:
  1) autoconf tests are ok when the user wants to run the built executables
     on the build machine only. But on Woe32 and Linux systems, users often
     want to run the executables also on newer versions of the OS. And here
     it's the newer versions of the OS which introduce the bug. (Whereas
     usually, with autoconf, you test for a bug that exists in old versions
     only.) So, if we build binaries on Windows XP, we need to take into
     account the bug that Windows Vista has introduced.
  2) Here the logic of autoconf tests would be far more complicated than
     the ad-hoc #if tests.

Looking at the matrix in m4/printf.m4, there are 4 types of systems on which
gl_SNPRINTF_DIRECTIVE_N fails, and they are treated differently:
  - glibc with FORTIFY. Here we exploit the fact that
    gl_SNPRINTF_TRUNCATION_C99 and gl_SNPRINTF_RETVAL_C99 succeed.
  - mingw. Here we exploit the fact that
    gl_SNPRINTF_TRUNCATION_C99 and gl_SNPRINTF_RETVAL_C99 "nearly" succeed:
    snprintf does not overwrite more memory than allowed, and its return
    value allows to know when the buffer was not large enough. (There are
    also snprintf implementations which overwrite memory, and others where
    the return value does not indicate an insufficient buffer size.)
  - HP-UX. Here we exploit the fact that
    gl_SNPRINTF_TRUNCATION_C99 succeeds and gl_SNPRINTF_RETVAL_C99 "nearly"
    succeeds.
  - Solaris 2.5.1 and OSF/1 4.0. Here the system has no snprintf() at all,
    hence vasnprintf() computes an upper bound on the needed memory size and
    uses sprintf.

Adding autoconf tests for this case would IMO increase the complexity even
more, rather than reducing it.


2008-02-07  Bruno Haible  <address@hidden>

        * lib/vasnprintf.c (VASNPRINTF): Don't use %n on native Woe32 systems.
        Avoids a crash on Windows Vista.
        Reported by Simon Josefsson <address@hidden>.

*** lib/vasnprintf.c.orig       2008-02-08 01:57:43.000000000 +0100
--- lib/vasnprintf.c    2008-02-08 01:55:39.000000000 +0100
***************
*** 4010,4016 ****
  #endif
                  *fbp = dp->conversion;
  #if USE_SNPRINTF
! # if !(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3))
                fbp[1] = '%';
                fbp[2] = 'n';
                fbp[3] = '\0';
--- 4010,4016 ----
  #endif
                  *fbp = dp->conversion;
  #if USE_SNPRINTF
! # if !(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) || ((defined 
_WIN32 || defined __WIN32__) && ! defined __CYGWIN__))
                fbp[1] = '%';
                fbp[2] = 'n';
                fbp[3] = '\0';
***************
*** 4023,4028 ****
--- 4023,4043 ----
                   in format strings in writable memory may crash the program
                   (if compiled with _FORTIFY_SOURCE=2), so we should avoid it
                   in this situation.  */
+               /* On native Win32 systems (such as mingw), we can avoid using
+                  %n because:
+                    - Although the gl_SNPRINTF_TRUNCATION_C99 test fails,
+                      snprintf does not write more than the specified number
+                      of bytes. (snprintf (buf, 3, "%d %d", 4567, 89) writes
+                      '4', '5', '6' into buf, not '4', '5', '\0'.)
+                    - Although the gl_SNPRINTF_RETVAL_C99 test fails, snprintf
+                      allows us to recognize the case of an insufficient
+                      buffer size: it returns -1 in this case.
+                  On native Win32 systems (such as mingw) where the OS is
+                  Windows Vista, the use of %n in format strings by default
+                  crashes the program. See
+                    <http://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
+                    
<http://msdn2.microsoft.com/en-us/library/ms175782(VS.80).aspx>
+                  So we should avoid %n in this situation.  */
                fbp[1] = '\0';
  # endif
  #else





reply via email to

[Prev in Thread] Current Thread [Next in Thread]