xref: /third_party/python/Python/mysnprintf.c (revision 7db96d56)
1#include "Python.h"
2
3/* snprintf() and vsnprintf() wrappers.
4
5   If the platform has vsnprintf, we use it, else we
6   emulate it in a half-hearted way.  Even if the platform has it, we wrap
7   it because platforms differ in what vsnprintf does in case the buffer
8   is too small:  C99 behavior is to return the number of characters that
9   would have been written had the buffer not been too small, and to set
10   the last byte of the buffer to \0.  At least MS _vsnprintf returns a
11   negative value instead, and fills the entire buffer with non-\0 data.
12   Unlike C99, our wrappers do not support passing a null buffer.
13
14   The wrappers ensure that str[size-1] is always \0 upon return.
15
16   PyOS_snprintf and PyOS_vsnprintf never write more than size bytes
17   (including the trailing '\0') into str.
18
19   Return value (rv):
20
21    When 0 <= rv < size, the output conversion was unexceptional, and
22    rv characters were written to str (excluding a trailing \0 byte at
23    str[rv]).
24
25    When rv >= size, output conversion was truncated, and a buffer of
26    size rv+1 would have been needed to avoid truncation.  str[size-1]
27    is \0 in this case.
28
29    When rv < 0, "something bad happened".  str[size-1] is \0 in this
30    case too, but the rest of str is unreliable.  It could be that
31    an error in format codes was detected by libc, or on platforms
32    with a non-C99 vsnprintf simply that the buffer wasn't big enough
33    to avoid truncation, or on platforms without any vsnprintf that
34    PyMem_Malloc couldn't obtain space for a temp buffer.
35
36   CAUTION:  Unlike C99, str != NULL and size > 0 are required.
37   Also, size must be smaller than INT_MAX.
38*/
39
40int
41PyOS_snprintf(char *str, size_t size, const  char  *format, ...)
42{
43    int rc;
44    va_list va;
45
46    va_start(va, format);
47    rc = PyOS_vsnprintf(str, size, format, va);
48    va_end(va);
49    return rc;
50}
51
52int
53PyOS_vsnprintf(char *str, size_t size, const char  *format, va_list va)
54{
55    assert(str != NULL);
56    assert(size > 0);
57    assert(size <= (INT_MAX - 1));
58    assert(format != NULL);
59
60    int len;  /* # bytes written, excluding \0 */
61    /* We take a size_t as input but return an int.  Sanity check
62     * our input so that it won't cause an overflow in the
63     * vsnprintf return value.  */
64    if (size > INT_MAX - 1) {
65        len = -666;
66        goto Done;
67    }
68
69#if defined(_MSC_VER)
70    len = _vsnprintf(str, size, format, va);
71#else
72    len = vsnprintf(str, size, format, va);
73#endif
74
75Done:
76    if (size > 0) {
77        str[size-1] = '\0';
78    }
79    return len;
80}
81