Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7ab92d5

Browse files
authored
bpo-36020: Require vsnprintf() to build Python (GH-20899)
The C99 functions snprintf() and vsnprintf() are now required to build Python. PyOS_snprintf() and PyOS_vsnprintf() no longer call Py_FatalError(). Previously, they called Py_FatalError() on a buffer overflow on platforms which don't provide vsnprintf().
1 parent e822e37 commit 7ab92d5

4 files changed

Lines changed: 14 additions & 44 deletions

File tree

Doc/c-api/conversion.rst

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,8 @@ not.
2727
2828
The wrappers ensure that *str*[*size*-1] is always ``'\0'`` upon return. They
2929
never write more than *size* bytes (including the trailing ``'\0'``) into str.
30-
Both functions require that ``str != NULL``, ``size > 0`` and ``format !=
31-
NULL``.
32-
33-
If the platform doesn't have :c:func:`vsnprintf` and the buffer size needed to
34-
avoid truncation exceeds *size* by more than 512 bytes, Python aborts with a
35-
:c:func:`Py_FatalError`.
30+
Both functions require that ``str != NULL``, ``size > 0``, ``format != NULL``
31+
and ``size < INT_MAX``.
3632
3733
The return value (*rv*) for these functions should be interpreted as follows:
3834
@@ -48,8 +44,8 @@ The return value (*rv*) for these functions should be interpreted as follows:
4844
this case too, but the rest of *str* is undefined. The exact cause of the error
4945
depends on the underlying platform.
5046
51-
The following functions provide locale-independent string to number conversions.
5247
48+
The following functions provide locale-independent string to number conversions.
5349
5450
.. c:function:: double PyOS_string_to_double(const char *s, char **endptr, PyObject *overflow_exception)
5551

Doc/whatsnew/3.10.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,10 @@ that may require changes to your code.
123123
Build Changes
124124
=============
125125

126+
* The C99 functions :c:func:`snprintf` and :c:func:`vsnprintf` are now required
127+
to build Python.
128+
(Contributed by Victor Stinner in :issue:`36020`.)
129+
126130

127131
C API Changes
128132
=============
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
The C99 functions :c:func:`snprintf` and :c:func:`vsnprintf` are now required
2+
to build Python.

Python/mysnprintf.c

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@
1515
PyOS_snprintf and PyOS_vsnprintf never write more than size bytes
1616
(including the trailing '\0') into str.
1717
18-
If the platform doesn't have vsnprintf, and the buffer size needed to
19-
avoid truncation exceeds size by more than 512, Python aborts with a
20-
Py_FatalError.
21-
2218
Return value (rv):
2319
2420
When 0 <= rv < size, the output conversion was unexceptional, and
@@ -37,6 +33,7 @@
3733
PyMem_Malloc couldn't obtain space for a temp buffer.
3834
3935
CAUTION: Unlike C99, str != NULL and size > 0 are required.
36+
Also, size must be smaller than INT_MAX.
4037
*/
4138

4239
int
@@ -56,56 +53,27 @@ PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va)
5653
{
5754
assert(str != NULL);
5855
assert(size > 0);
56+
assert(size <= (INT_MAX - 1));
5957
assert(format != NULL);
6058

6159
int len; /* # bytes written, excluding \0 */
62-
#if defined(_MSC_VER) || defined(HAVE_SNPRINTF)
63-
# define _PyOS_vsnprintf_EXTRA_SPACE 1
64-
#else
65-
# define _PyOS_vsnprintf_EXTRA_SPACE 512
66-
char *buffer;
67-
#endif
6860
/* We take a size_t as input but return an int. Sanity check
6961
* our input so that it won't cause an overflow in the
70-
* vsnprintf return value or the buffer malloc size. */
71-
if (size > INT_MAX - _PyOS_vsnprintf_EXTRA_SPACE) {
62+
* vsnprintf return value. */
63+
if (size > INT_MAX - 1) {
7264
len = -666;
7365
goto Done;
7466
}
7567

7668
#if defined(_MSC_VER)
7769
len = _vsnprintf(str, size, format, va);
78-
#elif defined(HAVE_SNPRINTF)
79-
len = vsnprintf(str, size, format, va);
8070
#else
81-
/* Emulate vsnprintf(). */
82-
buffer = PyMem_MALLOC(size + _PyOS_vsnprintf_EXTRA_SPACE);
83-
if (buffer == NULL) {
84-
len = -666;
85-
goto Done;
86-
}
87-
88-
len = vsprintf(buffer, format, va);
89-
if (len < 0) {
90-
/* ignore the error */;
91-
}
92-
else if ((size_t)len >= size + _PyOS_vsnprintf_EXTRA_SPACE) {
93-
_Py_FatalErrorFunc(__func__, "Buffer overflow");
94-
}
95-
else {
96-
const size_t to_copy = (size_t)len < size ?
97-
(size_t)len : size - 1;
98-
assert(to_copy < size);
99-
memcpy(str, buffer, to_copy);
100-
str[to_copy] = '\0';
101-
}
102-
PyMem_FREE(buffer);
71+
len = vsnprintf(str, size, format, va);
10372
#endif
10473

10574
Done:
10675
if (size > 0) {
10776
str[size-1] = '\0';
10877
}
10978
return len;
110-
#undef _PyOS_vsnprintf_EXTRA_SPACE
11179
}

0 commit comments

Comments
 (0)