Skip to content

gh-101703: use PyOS_snprintf instead of sprintf #101729

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 17 commits into from
Closed
19 changes: 11 additions & 8 deletions Modules/_ctypes/_ctypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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 */
Expand All @@ -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);
Expand Down Expand Up @@ -3353,11 +3355,12 @@ static PPROC FindAddress(void *handle, const char *name, PyObject *type)
funcname -> _funcname@<n>
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
Expand Down Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion Modules/_ctypes/stgdict.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
8 changes: 5 additions & 3 deletions Modules/_datetimemodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
Expand Down
2 changes: 1 addition & 1 deletion Modules/_pickle.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
3 changes: 2 additions & 1 deletion Modules/_testcapimodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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; \
Expand Down
2 changes: 1 addition & 1 deletion Modules/getnameinfo.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions Modules/socketmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Modules/unicodedata.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
23 changes: 14 additions & 9 deletions Objects/bytesobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -270,40 +270,45 @@ 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);
break;

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;
Expand All @@ -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')
Expand Down
5 changes: 3 additions & 2 deletions Objects/typeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
91 changes: 60 additions & 31 deletions Objects/unicodeobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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");
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion Parser/string_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion Programs/_freeze_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ static PyObject *
compile_and_marshal(const char *name, const char *text)
{
char *filename = (char *) malloc(strlen(name) + 10);
sprintf(filename, "<frozen %s>", name);
PyOS_snprintf(filename, strlen(name) + 10, "<frozen %s>", name);
PyObject *code = Py_CompileStringExFlags(text, filename,
Py_file_input, NULL, 0);
free(filename);
Expand Down
Loading