diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 6f92ca08dd537b..d2c1cf8408898e 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -392,9 +392,9 @@ _ctypes_alloc_format_string_with_shape(int ndim, const Py_ssize_t *shape, strcat(new_prefix, "("); for (k = 0; k < ndim; ++k) { if (k < ndim-1) { - sprintf(buf, "%zd,", shape[k]); + PyOS_snprintf(buf, sizeof(buf), "%zd,", shape[k]); } else { - sprintf(buf, "%zd)", shape[k]); + PyOS_snprintf(buf, sizeof(buf), "%zd)", shape[k]); } strcat(new_prefix, buf); } @@ -2632,7 +2632,8 @@ unique_key(CDataObject *target, Py_ssize_t index) size_t bytes_left; Py_BUILD_ASSERT(sizeof(string) - 1 > sizeof(Py_ssize_t) * 2); - cp += sprintf(cp, "%x", Py_SAFE_DOWNCAST(index, Py_ssize_t, int)); + cp += PyOS_snprintf(cp, sizeof(string), "%x", + Py_SAFE_DOWNCAST(index, Py_ssize_t, int)); while (target->b_base) { bytes_left = sizeof(string) - (cp - string) - 1; /* Hex format needs 2 characters per byte */ @@ -2641,7 +2642,8 @@ unique_key(CDataObject *target, Py_ssize_t index) "ctypes object structure too deep"); return NULL; } - cp += sprintf(cp, ":%x", Py_SAFE_DOWNCAST(target->b_index, Py_ssize_t, int)); + cp += PyOS_snprintf(cp, bytes_left, ":%x", + Py_SAFE_DOWNCAST(target->b_index, Py_ssize_t, int)); target = target->b_base; } return PyUnicode_FromStringAndSize(string, cp-string); @@ -3353,11 +3355,12 @@ static PPROC FindAddress(void *handle, const char *name, PyObject *type) funcname -> _funcname@ where n is 0, 4, 8, 12, ..., 128 */ - mangled_name = alloca(strlen(name) + 1 + 1 + 1 + 3); /* \0 _ @ %d */ + int toalloc = strlen(name) + 1 + 1 + 1 + 3; /* \0 _ @ %d */ + mangled_name = alloca(toalloc); if (!mangled_name) return NULL; for (i = 0; i < 32; ++i) { - sprintf(mangled_name, "_%s@%d", name, i*4); + PyOS_snprintf(mangled_name, toalloc, "_%s@%d", name, i*4); Py_BEGIN_ALLOW_THREADS address = (PPROC)GetProcAddress(handle, mangled_name); Py_END_ALLOW_THREADS @@ -4844,10 +4847,10 @@ PyCArrayType_from_ctype(PyObject *itemtype, Py_ssize_t length) return NULL; } #ifdef MS_WIN64 - sprintf(name, "%.200s_Array_%Id", + PyOS_snprintf(name, sizeof(name), "%.200s_Array_%Id", ((PyTypeObject *)itemtype)->tp_name, length); #else - sprintf(name, "%.200s_Array_%ld", + PyOS_snprintf(name, sizeof(name), "%.200s_Array_%ld", ((PyTypeObject *)itemtype)->tp_name, (long)length); #endif diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c index 83a52757d60979..cdcfe74473567f 100644 --- a/Modules/_ctypes/stgdict.c +++ b/Modules/_ctypes/stgdict.c @@ -612,7 +612,7 @@ PyCStructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct PyErr_NoMemory(); return -1; } - sprintf(buf, "%s:%s:", fieldfmt, fieldname); + PyOS_snprintf(buf, len + 2 + 1, "%s:%s:", fieldfmt, fieldname); ptr = stgdict->format; if (dict->shape != NULL) { diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c index f317dc14e15bf1..f3b5fe1c8f77d2 100644 --- a/Modules/_datetimemodule.c +++ b/Modules/_datetimemodule.c @@ -1559,11 +1559,13 @@ make_freplacement(PyObject *object) { char freplacement[64]; if (PyTime_Check(object)) - sprintf(freplacement, "%06d", TIME_GET_MICROSECOND(object)); + PyOS_snprintf(freplacement, sizeof(freplacement), + "%06d", TIME_GET_MICROSECOND(object)); else if (PyDateTime_Check(object)) - sprintf(freplacement, "%06d", DATE_GET_MICROSECOND(object)); + PyOS_snprintf(freplacement, sizeof(freplacement), + "%06d", DATE_GET_MICROSECOND(object)); else - sprintf(freplacement, "%06d", 0); + PyOS_snprintf(freplacement, sizeof(freplacement), "%06d", 0); return PyBytes_FromStringAndSize(freplacement, strlen(freplacement)); } diff --git a/Modules/_pickle.c b/Modules/_pickle.c index 360c7910f67187..8296676a3c09d2 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -2140,7 +2140,7 @@ save_long(PicklerObject *self, PyObject *obj) } } else { - sprintf(pdata, "%c%ld\n", INT, val); + PyOS_snprintf(pdata, sizeof(pdata), "%c%ld\n", INT, val); len = strlen(pdata); } if (_Pickler_Write(self, pdata, len) < 0) diff --git a/Modules/_ssl.c b/Modules/_ssl.c index c9e2f24d66cc00..bf49fcc04aef01 100644 --- a/Modules/_ssl.c +++ b/Modules/_ssl.c @@ -1332,8 +1332,9 @@ _get_peer_alt_names (_sslmodulestate *state, X509 *certificate) { } else if (name->d.ip->length == 16) { /* PyUnicode_FromFormat() does not support %X */ unsigned char *p = name->d.ip->data; - len = sprintf( + len = PyOS_snprintf( buf, + sizeof(buf), "%X:%X:%X:%X:%X:%X:%X:%X", p[0] << 8 | p[1], p[2] << 8 | p[3], diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index c1892f6fa0a4b8..3fe5b3faf7d57a 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -1036,7 +1036,8 @@ test_capsule(PyObject *self, PyObject *Py_UNUSED(ignored)) #undef FAIL #define FAIL(x) \ { \ - sprintf(buffer, "%s module: \"%s\" attribute: \"%s\"", \ + PyOS_snprintf(buffer, sizeof(buffer), \ + "%s module: \"%s\" attribute: \"%s\"", \ x, known->module, known->attribute); \ error = buffer; \ goto exit; \ diff --git a/Modules/getnameinfo.c b/Modules/getnameinfo.c index 335021f79bafea..3e26d556191fbe 100644 --- a/Modules/getnameinfo.c +++ b/Modules/getnameinfo.c @@ -139,7 +139,7 @@ getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) if (serv == NULL || servlen == 0) { /* what we should do? */ } else if (flags & NI_NUMERICSERV) { - sprintf(numserv, "%d", ntohs(port)); + PyOS_snprintf(numserv, sizeof(numserv), "%d", ntohs(port)); if (strlen(numserv) > servlen) return ENI_MEMORY; strcpy(serv, numserv); diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c index f11d4b1a6e0591..2022c8416235a8 100644 --- a/Modules/socketmodule.c +++ b/Modules/socketmodule.c @@ -1349,11 +1349,11 @@ makebdaddr(bdaddr_t *bdaddr) octets[i] = ((*bdaddr) >> (8 * i)) & 0xFF; } - sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + PyOS_snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X", octets[5], octets[4], octets[3], octets[2], octets[1], octets[0]); #else - sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X", + PyOS_snprintf(buf, sizeof(buf), "%02X:%02X:%02X:%02X:%02X:%02X", bdaddr->b[5], bdaddr->b[4], bdaddr->b[3], bdaddr->b[2], bdaddr->b[1], bdaddr->b[0]); #endif diff --git a/Modules/unicodedata.c b/Modules/unicodedata.c index c108f14871f946..0c86385e0facb6 100644 --- a/Modules/unicodedata.c +++ b/Modules/unicodedata.c @@ -1108,7 +1108,7 @@ _getucname(PyObject *self, if (buflen < 28) /* Worst case: CJK UNIFIED IDEOGRAPH-20000 */ return 0; - sprintf(buffer, "CJK UNIFIED IDEOGRAPH-%X", code); + PyOS_snprintf(buffer, buflen, "CJK UNIFIED IDEOGRAPH-%X", code); return 1; } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 2d8dab6f378006..33483179ac6c11 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -270,13 +270,15 @@ PyBytes_FromFormatV(const char *format, va_list vargs) case 'd': if (longflag) { - sprintf(buffer, "%ld", va_arg(vargs, long)); + PyOS_snprintf(buffer, sizeof(buffer), + "%ld", va_arg(vargs, long)); } else if (size_tflag) { - sprintf(buffer, "%zd", va_arg(vargs, Py_ssize_t)); + PyOS_snprintf(buffer, sizeof(buffer), + "%zd", va_arg(vargs, Py_ssize_t)); } else { - sprintf(buffer, "%d", va_arg(vargs, int)); + PyOS_snprintf(buffer, sizeof(buffer), "%d", va_arg(vargs, int)); } assert(strlen(buffer) < sizeof(buffer)); WRITE_BYTES(buffer); @@ -284,26 +286,29 @@ PyBytes_FromFormatV(const char *format, va_list vargs) case 'u': if (longflag) { - sprintf(buffer, "%lu", va_arg(vargs, unsigned long)); + PyOS_snprintf(buffer, sizeof(buffer), + "%lu", va_arg(vargs, unsigned long)); } else if (size_tflag) { - sprintf(buffer, "%zu", va_arg(vargs, size_t)); + PyOS_snprintf(buffer, sizeof(buffer), + "%zu", va_arg(vargs, size_t)); } else { - sprintf(buffer, "%u", va_arg(vargs, unsigned int)); + PyOS_snprintf(buffer, sizeof(buffer), + "%u", va_arg(vargs, unsigned int)); } assert(strlen(buffer) < sizeof(buffer)); WRITE_BYTES(buffer); break; case 'i': - sprintf(buffer, "%i", va_arg(vargs, int)); + PyOS_snprintf(buffer, sizeof(buffer), "%i", va_arg(vargs, int)); assert(strlen(buffer) < sizeof(buffer)); WRITE_BYTES(buffer); break; case 'x': - sprintf(buffer, "%x", va_arg(vargs, int)); + PyOS_snprintf(buffer, sizeof(buffer), "%x", va_arg(vargs, int)); assert(strlen(buffer) < sizeof(buffer)); WRITE_BYTES(buffer); break; @@ -329,7 +334,7 @@ PyBytes_FromFormatV(const char *format, va_list vargs) } case 'p': - sprintf(buffer, "%p", va_arg(vargs, void*)); + PyOS_snprintf(buffer, sizeof(buffer), "%p", va_arg(vargs, void*)); assert(strlen(buffer) < sizeof(buffer)); /* %p is ill-defined: ensure leading 0x. */ if (buffer[1] == 'X') diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 9194eba0eae15c..b4d194fd5dc01e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -4771,8 +4771,9 @@ type_traverse(PyTypeObject *type, visitproc visit, void *arg) for heaptypes. */ if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) { char msg[200]; - sprintf(msg, "type_traverse() called on non-heap type '%.100s'", - type->tp_name); + PyOS_snprintf(msg, sizeof(msg), + "type_traverse() called on non-heap type '%.100s'", + type->tp_name); _PyObject_ASSERT_FAILED_MSG((PyObject *)type, msg); } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index fd056e38f3f86b..4b994ba170f249 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -705,13 +705,45 @@ backslashreplace(_PyBytesWriter *writer, char *str, return str; } +static Py_ssize_t +get_xmlcharref_length(Py_UCS4 ch) +{ + Py_ssize_t incr; + + /* `2 + 1` part is `&#` + `;` */ + if (ch < 10) { + incr = 2 + 1 + 1; + } + else if (ch < 100) { + incr = 2 + 2 + 1; + } + else if (ch < 1000) { + incr = 2 + 3 + 1; + } + else if (ch < 10000) { + incr = 2 + 4 + 1; + } + else if (ch < 100000) { + incr = 2 + 5 + 1; + } + else if (ch < 1000000) { + incr = 2 + 6 + 1; + } + else { + assert(ch <= MAX_UNICODE); + incr = 2 + 7 + 1; + } + + return incr; +} + /* Implementation of the "xmlcharrefreplace" error handler for 8-bit encodings: ASCII, Latin1, UTF-8, etc. */ static char* xmlcharrefreplace(_PyBytesWriter *writer, char *str, PyObject *unicode, Py_ssize_t collstart, Py_ssize_t collend) { - Py_ssize_t size, i; + Py_ssize_t size, incr, i; Py_UCS4 ch; int kind; const void *data; @@ -722,25 +754,9 @@ xmlcharrefreplace(_PyBytesWriter *writer, char *str, size = 0; /* determine replacement size */ for (i = collstart; i < collend; ++i) { - Py_ssize_t incr; - ch = PyUnicode_READ(kind, data, i); - if (ch < 10) - incr = 2+1+1; - else if (ch < 100) - incr = 2+2+1; - else if (ch < 1000) - incr = 2+3+1; - else if (ch < 10000) - incr = 2+4+1; - else if (ch < 100000) - incr = 2+5+1; - else if (ch < 1000000) - incr = 2+6+1; - else { - assert(ch <= MAX_UNICODE); - incr = 2+7+1; - } + incr = get_xmlcharref_length(ch); + if (size > PY_SSIZE_T_MAX - incr) { PyErr_SetString(PyExc_OverflowError, "encoded result is too long for a Python string"); @@ -755,7 +771,9 @@ xmlcharrefreplace(_PyBytesWriter *writer, char *str, /* generate replacement */ for (i = collstart; i < collend; ++i) { - size = sprintf(str, "&#%d;", PyUnicode_READ(kind, data, i)); + ch = PyUnicode_READ(kind, data, i); + incr = get_xmlcharref_length(ch); + size = PyOS_snprintf(str, incr + 1, "&#%d;", ch); if (size < 0) { return NULL; } @@ -2465,33 +2483,42 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, if (*f == 'u') { if (longflag) { - len = sprintf(buffer, "%lu", va_arg(*vargs, unsigned long)); + len = PyOS_snprintf(buffer, sizeof(buffer), + "%lu", va_arg(*vargs, unsigned long)); } else if (longlongflag) { - len = sprintf(buffer, "%llu", va_arg(*vargs, unsigned long long)); + len = PyOS_snprintf(buffer, sizeof(buffer), + "%llu", va_arg(*vargs, unsigned long long)); } else if (size_tflag) { - len = sprintf(buffer, "%zu", va_arg(*vargs, size_t)); + len = PyOS_snprintf(buffer, sizeof(buffer), + "%zu", va_arg(*vargs, size_t)); } else { - len = sprintf(buffer, "%u", va_arg(*vargs, unsigned int)); + len = PyOS_snprintf(buffer, sizeof(buffer), + "%u", va_arg(*vargs, unsigned int)); } } else if (*f == 'x') { - len = sprintf(buffer, "%x", va_arg(*vargs, int)); + len = PyOS_snprintf(buffer, sizeof(buffer), + "%x", va_arg(*vargs, int)); } else { if (longflag) { - len = sprintf(buffer, "%li", va_arg(*vargs, long)); + len = PyOS_snprintf(buffer, sizeof(buffer), + "%li", va_arg(*vargs, long)); } else if (longlongflag) { - len = sprintf(buffer, "%lli", va_arg(*vargs, long long)); + len = PyOS_snprintf(buffer, sizeof(buffer), + "%lli", va_arg(*vargs, long long)); } else if (size_tflag) { - len = sprintf(buffer, "%zi", va_arg(*vargs, Py_ssize_t)); + len = PyOS_snprintf(buffer, sizeof(buffer), + "%zi", va_arg(*vargs, Py_ssize_t)); } else { - len = sprintf(buffer, "%i", va_arg(*vargs, int)); + len = PyOS_snprintf(buffer, sizeof(buffer), + "%i", va_arg(*vargs, int)); } } assert(len >= 0); @@ -2540,7 +2567,8 @@ unicode_fromformat_arg(_PyUnicodeWriter *writer, { char number[MAX_LONG_LONG_CHARS]; - len = sprintf(number, "%p", va_arg(*vargs, void*)); + len = PyOS_snprintf(number, sizeof(number), + "%p", va_arg(*vargs, void*)); assert(len >= 0); /* %p is ill-defined: ensure leading 0x. */ @@ -8114,7 +8142,8 @@ charmap_encoding_error( for (collpos = collstartpos; collpos < collendpos; ++collpos) { char buffer[2+29+1+1]; char *cp; - sprintf(buffer, "&#%d;", (int)PyUnicode_READ_CHAR(unicode, collpos)); + PyOS_snprintf(buffer, sizeof(buffer), + "&#%d;", (int)PyUnicode_READ_CHAR(unicode, collpos)); for (cp = buffer; *cp; ++cp) { x = charmapencode_output(*cp, mapping, res, respos); if (x==enc_EXCEPTION) diff --git a/Parser/string_parser.c b/Parser/string_parser.c index d4ce33850f7c58..8c73c824747925 100644 --- a/Parser/string_parser.c +++ b/Parser/string_parser.c @@ -118,7 +118,7 @@ decode_unicode_with_escapes(Parser *parser, const char *s, size_t len, Token *t) w_len = PyUnicode_GET_LENGTH(w); for (i = 0; i < w_len; i++) { Py_UCS4 chr = PyUnicode_READ(kind, data, i); - sprintf(p, "\\U%08x", chr); + PyOS_snprintf(p, 10 + 1, "\\U%08x", chr); p += 10; } /* Should be impossible to overflow */ diff --git a/Programs/_freeze_module.c b/Programs/_freeze_module.c index e55f1d56745c4d..bf9d732664bc92 100644 --- a/Programs/_freeze_module.c +++ b/Programs/_freeze_module.c @@ -123,7 +123,7 @@ static PyObject * compile_and_marshal(const char *name, const char *text) { char *filename = (char *) malloc(strlen(name) + 10); - sprintf(filename, "", name); + PyOS_snprintf(filename, strlen(name) + 10, "", name); PyObject *code = Py_CompileStringExFlags(text, filename, Py_file_input, NULL, 0); free(filename); diff --git a/Python/pystrtod.c b/Python/pystrtod.c index d77b846f0403f0..3fd8d3c8336bae 100644 --- a/Python/pystrtod.c +++ b/Python/pystrtod.c @@ -1239,7 +1239,8 @@ format_float_short(double d, char format_code, /* Now that we've done zero padding, add an exponent if needed. */ if (use_exp) { *p++ = float_strings[OFS_E][0]; - exp_len = sprintf(p, "%+.02d", exp); + /* See `bufsize` comments for the size argument. */ + exp_len = PyOS_snprintf(p, 5, "%+.02d", exp); p += exp_len; } exit: diff --git a/Python/specialize.c b/Python/specialize.c index 33a3c4561c7ca2..4b47d356371049 100644 --- a/Python/specialize.c +++ b/Python/specialize.c @@ -234,7 +234,7 @@ _Py_PrintSpecializationStats(int to_file) hex_name[40] = '\0'; char buf[64]; assert(strlen(dirname) + 40 + strlen(".txt") < 64); - sprintf(buf, "%s%s.txt", dirname, hex_name); + PyOS_snprintf(buf, sizeof(buf), "%s%s.txt", dirname, hex_name); FILE *fout = fopen(buf, "w"); if (fout) { out = fout;