Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions Doc/c-api/conversion.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,8 @@ not.

The wrappers ensure that *str*[*size*-1] is always ``'\0'`` upon return. They
never write more than *size* bytes (including the trailing ``'\0'``) into str.
Both functions require that ``str != NULL``, ``size > 0`` and ``format !=
NULL``.

If the platform doesn't have :c:func:`vsnprintf` and the buffer size needed to
avoid truncation exceeds *size* by more than 512 bytes, Python aborts with a
:c:func:`Py_FatalError`.
Both functions require that ``str != NULL``, ``size > 0``, ``format != NULL``
and ``size < INT_MAX``.

The return value (*rv*) for these functions should be interpreted as follows:

Expand All @@ -48,8 +44,8 @@ The return value (*rv*) for these functions should be interpreted as follows:
this case too, but the rest of *str* is undefined. The exact cause of the error
depends on the underlying platform.

The following functions provide locale-independent string to number conversions.

The following functions provide locale-independent string to number conversions.

.. c:function:: double PyOS_string_to_double(const char *s, char **endptr, PyObject *overflow_exception)

Expand Down
4 changes: 4 additions & 0 deletions Doc/whatsnew/3.10.rst
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ that may require changes to your code.
Build Changes
=============

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


C API Changes
=============
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
The C99 functions :c:func:`snprintf` and :c:func:`vsnprintf` are now required
to build Python.
42 changes: 5 additions & 37 deletions Python/mysnprintf.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,6 @@
PyOS_snprintf and PyOS_vsnprintf never write more than size bytes
(including the trailing '\0') into str.

If the platform doesn't have vsnprintf, and the buffer size needed to
avoid truncation exceeds size by more than 512, Python aborts with a
Py_FatalError.

Return value (rv):

When 0 <= rv < size, the output conversion was unexceptional, and
Expand All @@ -37,6 +33,7 @@
PyMem_Malloc couldn't obtain space for a temp buffer.

CAUTION: Unlike C99, str != NULL and size > 0 are required.
Also, size must be smaller than INT_MAX.
*/

int
Expand All @@ -56,56 +53,27 @@ PyOS_vsnprintf(char *str, size_t size, const char *format, va_list va)
{
assert(str != NULL);
assert(size > 0);
assert(size <= (INT_MAX - 1));
assert(format != NULL);

int len; /* # bytes written, excluding \0 */
#if defined(_MSC_VER) || defined(HAVE_SNPRINTF)
# define _PyOS_vsnprintf_EXTRA_SPACE 1
#else
# define _PyOS_vsnprintf_EXTRA_SPACE 512
char *buffer;
#endif
/* 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. */
if (size > INT_MAX - _PyOS_vsnprintf_EXTRA_SPACE) {
* vsnprintf return value. */
if (size > INT_MAX - 1) {
len = -666;
goto Done;
}

#if defined(_MSC_VER)
len = _vsnprintf(str, size, format, va);
#elif defined(HAVE_SNPRINTF)
len = vsnprintf(str, size, format, va);
#else
/* Emulate vsnprintf(). */
buffer = PyMem_MALLOC(size + _PyOS_vsnprintf_EXTRA_SPACE);
if (buffer == NULL) {
len = -666;
goto Done;
}

len = vsprintf(buffer, format, va);
if (len < 0) {
/* ignore the error */;
}
else if ((size_t)len >= size + _PyOS_vsnprintf_EXTRA_SPACE) {
_Py_FatalErrorFunc(__func__, "Buffer overflow");
}
else {
const size_t to_copy = (size_t)len < size ?
(size_t)len : size - 1;
assert(to_copy < size);
memcpy(str, buffer, to_copy);
str[to_copy] = '\0';
}
PyMem_FREE(buffer);
len = vsnprintf(str, size, format, va);
#endif

Done:
if (size > 0) {
str[size-1] = '\0';
}
return len;
#undef _PyOS_vsnprintf_EXTRA_SPACE
}