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().
diff --git a/Doc/c-api/conversion.rst b/Doc/c-api/conversion.rst
index b310fcb..efbaa52 100644
--- a/Doc/c-api/conversion.rst
+++ b/Doc/c-api/conversion.rst
@@ -27,12 +27,8 @@
 
 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:
 
@@ -48,8 +44,8 @@
   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)
 
diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst
index 629909b..9878f7f 100644
--- a/Doc/whatsnew/3.10.rst
+++ b/Doc/whatsnew/3.10.rst
@@ -123,6 +123,10 @@
 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
 =============
diff --git a/Misc/NEWS.d/next/Build/2020-06-15-22-14-25.bpo-36020.wbiv0P.rst b/Misc/NEWS.d/next/Build/2020-06-15-22-14-25.bpo-36020.wbiv0P.rst
new file mode 100644
index 0000000..de50dff
--- /dev/null
+++ b/Misc/NEWS.d/next/Build/2020-06-15-22-14-25.bpo-36020.wbiv0P.rst
@@ -0,0 +1,2 @@
+The C99 functions :c:func:`snprintf` and :c:func:`vsnprintf` are now required
+to build Python.
diff --git a/Python/mysnprintf.c b/Python/mysnprintf.c
index 458ca14..cd69198 100644
--- a/Python/mysnprintf.c
+++ b/Python/mysnprintf.c
@@ -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
@@ -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
@@ -56,50 +53,22 @@
 {
     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:
@@ -107,5 +76,4 @@
         str[size-1] = '\0';
     }
     return len;
-#undef _PyOS_vsnprintf_EXTRA_SPACE
 }