[Python-checkins] bpo-36020: Remove snprintf macro in pyerrors.h (GH-20889)

Victor Stinner webhook-mailer at python.org
Mon Jun 15 15:59:55 EDT 2020


https://github.com/python/cpython/commit/e822e37946f27c09953bb5733acf3b07c2db690f
commit: e822e37946f27c09953bb5733acf3b07c2db690f
branch: master
author: Victor Stinner <vstinner at python.org>
committer: GitHub <noreply at github.com>
date: 2020-06-15T21:59:47+02:00
summary:

bpo-36020: Remove snprintf macro in pyerrors.h (GH-20889)

On Windows, #include "pyerrors.h" no longer defines "snprintf" and
"vsnprintf" macros.

PyOS_snprintf() and PyOS_vsnprintf() should be used to get portable
behavior.

Replace snprintf() calls with PyOS_snprintf() and replace vsnprintf()
calls with PyOS_vsnprintf().

files:
A Misc/NEWS.d/next/C API/2020-06-15-16-46-01.bpo-36020.djI6jw.rst
M Include/pyerrors.h
M Modules/_ctypes/callbacks.c
M Modules/socketmodule.c
M Parser/tokenizer.c
M Python/mysnprintf.c

diff --git a/Include/pyerrors.h b/Include/pyerrors.h
index 399bb7c3a6fac..979a26ba68a03 100644
--- a/Include/pyerrors.h
+++ b/Include/pyerrors.h
@@ -4,6 +4,8 @@
 extern "C" {
 #endif
 
+#include <stdarg.h>               // va_list
+
 /* Error handling definitions */
 
 PyAPI_FUNC(void) PyErr_SetNone(PyObject *);
@@ -307,21 +309,6 @@ PyAPI_FUNC(int) PyUnicodeTranslateError_SetReason(
     const char *reason          /* UTF-8 encoded string */
     );
 
-/* These APIs aren't really part of the error implementation, but
-   often needed to format error messages; the native C lib APIs are
-   not available on all platforms, which is why we provide emulations
-   for those platforms in Python/mysnprintf.c,
-   WARNING:  The return value of snprintf varies across platforms; do
-   not rely on any particular behavior; eventually the C99 defn may
-   be reliable.
-*/
-#if defined(MS_WIN32) && !defined(HAVE_SNPRINTF)
-# define HAVE_SNPRINTF
-# define snprintf _snprintf
-# define vsnprintf _vsnprintf
-#endif
-
-#include <stdarg.h>
 PyAPI_FUNC(int) PyOS_snprintf(char *str, size_t size, const char  *format, ...)
                         Py_GCC_ATTRIBUTE((format(printf, 3, 4)));
 PyAPI_FUNC(int) PyOS_vsnprintf(char *str, size_t size, const char  *format, va_list va)
diff --git a/Misc/NEWS.d/next/C API/2020-06-15-16-46-01.bpo-36020.djI6jw.rst b/Misc/NEWS.d/next/C API/2020-06-15-16-46-01.bpo-36020.djI6jw.rst
new file mode 100644
index 0000000000000..1f91dce4608d3
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2020-06-15-16-46-01.bpo-36020.djI6jw.rst	
@@ -0,0 +1,2 @@
+On Windows, ``#include "pyerrors.h"`` no longer defines ``snprintf`` and
+``vsnprintf`` macros.
diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c
index 29e8fac8c9496..2abfa67cdc06b 100644
--- a/Modules/_ctypes/callbacks.c
+++ b/Modules/_ctypes/callbacks.c
@@ -84,7 +84,7 @@ PrintError(const char *msg, ...)
     va_list marker;
 
     va_start(marker, msg);
-    vsnprintf(buf, sizeof(buf), msg, marker);
+    PyOS_vsnprintf(buf, sizeof(buf), msg, marker);
     va_end(marker);
     if (f != NULL && f != Py_None)
         PyFile_WriteString(buf, f);
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index f60a27ebe408c..db0eeaafeec27 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -436,13 +436,12 @@ remove_unusable_flags(PyObject *m)
 #endif
 
 #ifdef MS_WIN32
-#undef EAFNOSUPPORT
-#define EAFNOSUPPORT WSAEAFNOSUPPORT
-#define snprintf _snprintf
+#  undef EAFNOSUPPORT
+#  define EAFNOSUPPORT WSAEAFNOSUPPORT
 #endif
 
 #ifndef SOCKETCLOSE
-#define SOCKETCLOSE close
+#  define SOCKETCLOSE close
 #endif
 
 #if (defined(HAVE_BLUETOOTH_H) || defined(HAVE_BLUETOOTH_BLUETOOTH_H)) && !defined(__NetBSD__) && !defined(__DragonFly__)
diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c
index d461e4e24e721..f3c1d9b20ade1 100644
--- a/Parser/tokenizer.c
+++ b/Parser/tokenizer.c
@@ -1133,7 +1133,7 @@ verify_identifier(struct tok_state *tok)
         Py_DECREF(s);
         // PyUnicode_FromFormatV() does not support %X
         char hex[9];
-        snprintf(hex, sizeof(hex), "%04X", ch);
+        (void)PyOS_snprintf(hex, sizeof(hex), "%04X", ch);
         if (Py_UNICODE_ISPRINTABLE(ch)) {
             syntaxerror(tok, "invalid character '%c' (U+%s)", ch, hex);
         }
diff --git a/Python/mysnprintf.c b/Python/mysnprintf.c
index 945a81abb01c2..458ca14d5c611 100644
--- a/Python/mysnprintf.c
+++ b/Python/mysnprintf.c
@@ -1,6 +1,8 @@
 #include "Python.h"
 
-/* snprintf() wrappers.  If the platform has vsnprintf, we use it, else we
+/* snprintf() and vsnprintf() wrappers.
+
+   If the platform has vsnprintf, we use it, else we
    emulate it in a half-hearted way.  Even if the platform has it, we wrap
    it because platforms differ in what vsnprintf does in case the buffer
    is too small:  C99 behavior is to return the number of characters that
@@ -52,16 +54,17 @@ PyOS_snprintf(char *str, size_t size, const  char  *format, ...)
 int
 PyOS_vsnprintf(char *str, size_t size, const char  *format, va_list va)
 {
+    assert(str != NULL);
+    assert(size > 0);
+    assert(format != NULL);
+
     int len;  /* # bytes written, excluding \0 */
-#ifdef HAVE_SNPRINTF
-#define _PyOS_vsnprintf_EXTRA_SPACE 1
+#if defined(_MSC_VER) || defined(HAVE_SNPRINTF)
+#  define _PyOS_vsnprintf_EXTRA_SPACE 1
 #else
-#define _PyOS_vsnprintf_EXTRA_SPACE 512
+#  define _PyOS_vsnprintf_EXTRA_SPACE 512
     char *buffer;
 #endif
-    assert(str != NULL);
-    assert(size > 0);
-    assert(format != NULL);
     /* We take a size_t as input but return an int.  Sanity check
      * our input so that it won't cause an overflow in the
      * vsnprintf return value or the buffer malloc size.  */
@@ -70,10 +73,12 @@ PyOS_vsnprintf(char *str, size_t size, const char  *format, va_list va)
         goto Done;
     }
 
-#ifdef HAVE_SNPRINTF
+#if defined(_MSC_VER)
+    len = _vsnprintf(str, size, format, va);
+#elif defined(HAVE_SNPRINTF)
     len = vsnprintf(str, size, format, va);
 #else
-    /* Emulate it. */
+    /* Emulate vsnprintf(). */
     buffer = PyMem_MALLOC(size + _PyOS_vsnprintf_EXTRA_SPACE);
     if (buffer == NULL) {
         len = -666;
@@ -96,9 +101,11 @@ PyOS_vsnprintf(char *str, size_t size, const char  *format, va_list va)
     }
     PyMem_FREE(buffer);
 #endif
+
 Done:
-    if (size > 0)
+    if (size > 0) {
         str[size-1] = '\0';
+    }
     return len;
 #undef _PyOS_vsnprintf_EXTRA_SPACE
 }



More information about the Python-checkins mailing list