Skip to content

Commit b498c7f

Browse files
bpo-36020: Remove snprintf macro in pyerrors.h (GH-20889)
On Windows, GH-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(). (cherry picked from commit e822e37) Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent 9a0624a commit b498c7f

File tree

6 files changed

+26
-31
lines changed

6 files changed

+26
-31
lines changed

Include/pyerrors.h

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
extern "C" {
55
#endif
66

7+
#include <stdarg.h> // va_list
8+
79
/* Error handling definitions */
810

911
PyAPI_FUNC(void) PyErr_SetNone(PyObject *);
@@ -307,21 +309,6 @@ PyAPI_FUNC(int) PyUnicodeTranslateError_SetReason(
307309
const char *reason /* UTF-8 encoded string */
308310
);
309311

310-
/* These APIs aren't really part of the error implementation, but
311-
often needed to format error messages; the native C lib APIs are
312-
not available on all platforms, which is why we provide emulations
313-
for those platforms in Python/mysnprintf.c,
314-
WARNING: The return value of snprintf varies across platforms; do
315-
not rely on any particular behavior; eventually the C99 defn may
316-
be reliable.
317-
*/
318-
#if defined(MS_WIN32) && !defined(HAVE_SNPRINTF)
319-
# define HAVE_SNPRINTF
320-
# define snprintf _snprintf
321-
# define vsnprintf _vsnprintf
322-
#endif
323-
324-
#include <stdarg.h>
325312
PyAPI_FUNC(int) PyOS_snprintf(char *str, size_t size, const char *format, ...)
326313
Py_GCC_ATTRIBUTE((format(printf, 3, 4)));
327314
PyAPI_FUNC(int) PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
On Windows, ``#include "pyerrors.h"`` no longer defines ``snprintf`` and
2+
``vsnprintf`` macros.

Modules/_ctypes/callbacks.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ PrintError(const char *msg, ...)
8484
va_list marker;
8585

8686
va_start(marker, msg);
87-
vsnprintf(buf, sizeof(buf), msg, marker);
87+
PyOS_vsnprintf(buf, sizeof(buf), msg, marker);
8888
va_end(marker);
8989
if (f != NULL && f != Py_None)
9090
PyFile_WriteString(buf, f);

Modules/socketmodule.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -473,13 +473,12 @@ remove_unusable_flags(PyObject *m)
473473
#endif
474474

475475
#ifdef MS_WIN32
476-
#undef EAFNOSUPPORT
477-
#define EAFNOSUPPORT WSAEAFNOSUPPORT
478-
#define snprintf _snprintf
476+
# undef EAFNOSUPPORT
477+
# define EAFNOSUPPORT WSAEAFNOSUPPORT
479478
#endif
480479

481480
#ifndef SOCKETCLOSE
482-
#define SOCKETCLOSE close
481+
# define SOCKETCLOSE close
483482
#endif
484483

485484
#if (defined(HAVE_BLUETOOTH_H) || defined(HAVE_BLUETOOTH_BLUETOOTH_H)) && !defined(__NetBSD__) && !defined(__DragonFly__)

Parser/tokenizer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1133,7 +1133,7 @@ verify_identifier(struct tok_state *tok)
11331133
Py_DECREF(s);
11341134
// PyUnicode_FromFormatV() does not support %X
11351135
char hex[9];
1136-
snprintf(hex, sizeof(hex), "%04X", ch);
1136+
(void)PyOS_snprintf(hex, sizeof(hex), "%04X", ch);
11371137
if (Py_UNICODE_ISPRINTABLE(ch)) {
11381138
syntaxerror(tok, "invalid character '%c' (U+%s)", ch, hex);
11391139
}

Python/mysnprintf.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include "Python.h"
22

3-
/* snprintf() wrappers. If the platform has vsnprintf, we use it, else we
3+
/* snprintf() and vsnprintf() wrappers.
4+
5+
If the platform has vsnprintf, we use it, else we
46
emulate it in a half-hearted way. Even if the platform has it, we wrap
57
it because platforms differ in what vsnprintf does in case the buffer
68
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, ...)
5254
int
5355
PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va)
5456
{
57+
assert(str != NULL);
58+
assert(size > 0);
59+
assert(format != NULL);
60+
5561
int len; /* # bytes written, excluding \0 */
56-
#ifdef HAVE_SNPRINTF
57-
#define _PyOS_vsnprintf_EXTRA_SPACE 1
62+
#if defined(_MSC_VER) || defined(HAVE_SNPRINTF)
63+
# define _PyOS_vsnprintf_EXTRA_SPACE 1
5864
#else
59-
#define _PyOS_vsnprintf_EXTRA_SPACE 512
65+
# define _PyOS_vsnprintf_EXTRA_SPACE 512
6066
char *buffer;
6167
#endif
62-
assert(str != NULL);
63-
assert(size > 0);
64-
assert(format != NULL);
6568
/* We take a size_t as input but return an int. Sanity check
6669
* our input so that it won't cause an overflow in the
6770
* 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)
7073
goto Done;
7174
}
7275

73-
#ifdef HAVE_SNPRINTF
76+
#if defined(_MSC_VER)
77+
len = _vsnprintf(str, size, format, va);
78+
#elif defined(HAVE_SNPRINTF)
7479
len = vsnprintf(str, size, format, va);
7580
#else
76-
/* Emulate it. */
81+
/* Emulate vsnprintf(). */
7782
buffer = PyMem_MALLOC(size + _PyOS_vsnprintf_EXTRA_SPACE);
7883
if (buffer == NULL) {
7984
len = -666;
@@ -96,9 +101,11 @@ PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va)
96101
}
97102
PyMem_FREE(buffer);
98103
#endif
104+
99105
Done:
100-
if (size > 0)
106+
if (size > 0) {
101107
str[size-1] = '\0';
108+
}
102109
return len;
103110
#undef _PyOS_vsnprintf_EXTRA_SPACE
104111
}

0 commit comments

Comments
 (0)