Coverage Report

Created: 2025-07-04 06:49

/src/cpython/Python/mysnprintf.c
Line
Count
Source (jump to first uncovered line)
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
40
int
41
PyOS_snprintf(char *str, size_t size, const  char  *format, ...)
42
111
{
43
111
    int rc;
44
111
    va_list va;
45
46
111
    va_start(va, format);
47
111
    rc = PyOS_vsnprintf(str, size, format, va);
48
111
    va_end(va);
49
111
    return rc;
50
111
}
51
52
int
53
PyOS_vsnprintf(char *str, size_t size, const char  *format, va_list va)
54
111
{
55
111
    assert(str != NULL);
56
111
    assert(size > 0);
57
111
    assert(size <= (INT_MAX - 1));
58
111
    assert(format != NULL);
59
60
111
    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
111
    if (size > INT_MAX - 1) {
65
0
        len = -666;
66
0
        goto Done;
67
0
    }
68
69
#if defined(_MSC_VER)
70
    len = _vsnprintf(str, size, format, va);
71
#else
72
111
    len = vsnprintf(str, size, format, va);
73
111
#endif
74
75
111
Done:
76
111
    if (size > 0) {
77
111
        str[size-1] = '\0';
78
111
    }
79
111
    return len;
80
111
}