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