Skip to content

Commit a3caf1b

Browse files
committed
handle overflows for 'K' and 'u' formats in do_mkvalue
1 parent 6a9bfee commit a3caf1b

File tree

3 files changed

+52
-24
lines changed

3 files changed

+52
-24
lines changed

Doc/c-api/arg.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,7 @@ Building values
626626
``z#`` (:class:`str` or ``None``) [const char \*, :c:type:`Py_ssize_t`]
627627
Same as ``s#``.
628628
629+
.. _capi-py-buildvalue-format-u:
629630
``u`` (:class:`str`) [const wchar_t \*]
630631
Convert a null-terminated :c:type:`wchar_t` buffer of Unicode (UTF-16 or UCS-4)
631632
data to a Python Unicode object. If the Unicode buffer pointer is ``NULL``,
@@ -669,6 +670,7 @@ Building values
669670
``L`` (:class:`int`) [long long]
670671
Convert a C :c:expr:`long long` to a Python integer object.
671672
673+
.. _capi-py-buildvalue-format-K:
672674
``K`` (:class:`int`) [unsigned long long]
673675
Convert a C :c:expr:`unsigned long long` to a Python integer object.
674676
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix overflows when handling :ref:`K <capi-py-buildvalue-format-K>` and
2+
:ref:`u <capi-py-buildvalue-format-u>` formats in :c:func:`Py_BuildValue`.
3+
Patch by Bénédikt Tran.

Python/modsupport.c

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,30 @@ do_mktuple(const char **p_format, va_list *p_va, char endchar, Py_ssize_t n)
268268
return v;
269269
}
270270

271+
static Py_ssize_t
272+
safe_strlen(const char *u)
273+
{
274+
size_t m = strlen(u);
275+
if (m > PY_SSIZE_T_MAX) {
276+
PyErr_SetString(PyExc_OverflowError,
277+
"string too long for Python string");
278+
return -1;
279+
}
280+
return (Py_ssize_t)m;
281+
}
282+
283+
static Py_ssize_t
284+
safe_wcslen(const wchar_t *u)
285+
{
286+
size_t m = wcslen(u);
287+
if (m > PY_SSIZE_T_MAX) {
288+
PyErr_SetString(PyExc_OverflowError,
289+
"string too long for Python string");
290+
return -1;
291+
}
292+
return (Py_ssize_t)m;
293+
}
294+
271295
static PyObject *
272296
do_mkvalue(const char **p_format, va_list *p_va)
273297
{
@@ -318,32 +342,41 @@ do_mkvalue(const char **p_format, va_list *p_va)
318342
}
319343

320344
case 'L':
321-
return PyLong_FromLongLong((long long)va_arg(*p_va, long long));
345+
{
346+
long long v = va_arg(*p_va, long long);
347+
return PyLong_FromLongLong(v);
348+
}
322349

323350
case 'K':
324-
return PyLong_FromUnsignedLongLong((long long)va_arg(*p_va, unsigned long long));
351+
{
352+
unsigned long long v = va_arg(*p_va, unsigned long long);
353+
return PyLong_FromUnsignedLongLong(v);
354+
}
325355

326356
case 'u':
327357
{
328358
PyObject *v;
329-
const wchar_t *u = va_arg(*p_va, wchar_t*);
330-
Py_ssize_t n;
359+
const wchar_t *u = va_arg(*p_va, const wchar_t *);
360+
Py_ssize_t n = -1;
331361
if (**p_format == '#') {
332362
++*p_format;
333363
n = va_arg(*p_va, Py_ssize_t);
334364
}
335-
else
336-
n = -1;
337365
if (u == NULL) {
338366
v = Py_NewRef(Py_None);
339367
}
340368
else {
341-
if (n < 0)
342-
n = wcslen(u);
369+
if (n < 0) {
370+
n = safe_wcslen(u);
371+
if (n < 0) {
372+
return NULL;
373+
}
374+
}
343375
v = PyUnicode_FromWideChar(u, n);
344376
}
345377
return v;
346378
}
379+
347380
case 'f':
348381
case 'd':
349382
return PyFloat_FromDouble(
@@ -376,25 +409,20 @@ do_mkvalue(const char **p_format, va_list *p_va)
376409
{
377410
PyObject *v;
378411
const char *str = va_arg(*p_va, const char *);
379-
Py_ssize_t n;
412+
Py_ssize_t n = -1;
380413
if (**p_format == '#') {
381414
++*p_format;
382415
n = va_arg(*p_va, Py_ssize_t);
383416
}
384-
else
385-
n = -1;
386417
if (str == NULL) {
387418
v = Py_NewRef(Py_None);
388419
}
389420
else {
390421
if (n < 0) {
391-
size_t m = strlen(str);
392-
if (m > PY_SSIZE_T_MAX) {
393-
PyErr_SetString(PyExc_OverflowError,
394-
"string too long for Python string");
422+
n = safe_strlen(str);
423+
if (n < 0) {
395424
return NULL;
396425
}
397-
n = (Py_ssize_t)m;
398426
}
399427
v = PyUnicode_FromStringAndSize(str, n);
400428
}
@@ -405,25 +433,20 @@ do_mkvalue(const char **p_format, va_list *p_va)
405433
{
406434
PyObject *v;
407435
const char *str = va_arg(*p_va, const char *);
408-
Py_ssize_t n;
436+
Py_ssize_t n = -1;
409437
if (**p_format == '#') {
410438
++*p_format;
411439
n = va_arg(*p_va, Py_ssize_t);
412440
}
413-
else
414-
n = -1;
415441
if (str == NULL) {
416442
v = Py_NewRef(Py_None);
417443
}
418444
else {
419445
if (n < 0) {
420-
size_t m = strlen(str);
421-
if (m > PY_SSIZE_T_MAX) {
422-
PyErr_SetString(PyExc_OverflowError,
423-
"string too long for Python bytes");
446+
n = safe_strlen(str);
447+
if (n < 0) {
424448
return NULL;
425449
}
426-
n = (Py_ssize_t)m;
427450
}
428451
v = PyBytes_FromStringAndSize(str, n);
429452
}

0 commit comments

Comments
 (0)