Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Doc/c-api/arg.rst
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,8 @@ Building values
``z#`` (:class:`str` or ``None``) [const char \*, :c:type:`Py_ssize_t`]
Same as ``s#``.

.. _capi-py-buildvalue-format-u:

``u`` (:class:`str`) [const wchar_t \*]
Convert a null-terminated :c:type:`wchar_t` buffer of Unicode (UTF-16 or UCS-4)
data to a Python Unicode object. If the Unicode buffer pointer is ``NULL``,
Expand Down Expand Up @@ -669,6 +671,8 @@ Building values
``L`` (:class:`int`) [long long]
Convert a C :c:expr:`long long` to a Python integer object.

.. _capi-py-buildvalue-format-K:

``K`` (:class:`int`) [unsigned long long]
Convert a C :c:expr:`unsigned long long` to a Python integer object.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix overflows when handling :ref:`K <capi-py-buildvalue-format-K>` and
:ref:`u <capi-py-buildvalue-format-u>` formats in :c:func:`Py_BuildValue`.
Patch by Bénédikt Tran.
71 changes: 47 additions & 24 deletions Python/modsupport.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,30 @@ do_mktuple(const char **p_format, va_list *p_va, char endchar, Py_ssize_t n)
return v;
}

static Py_ssize_t
safe_strlen(const char *u)
{
size_t m = strlen(u);
if (m > PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError,
"string too long for Python string");
return -1;
}
return (Py_ssize_t)m;
}

static Py_ssize_t
safe_wcslen(const wchar_t *u)
{
size_t m = wcslen(u);
if (m > PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError,
"string too long for Python string");
return -1;
}
return (Py_ssize_t)m;
}

static PyObject *
do_mkvalue(const char **p_format, va_list *p_va)
{
Expand Down Expand Up @@ -318,32 +342,41 @@ do_mkvalue(const char **p_format, va_list *p_va)
}

case 'L':
return PyLong_FromLongLong((long long)va_arg(*p_va, long long));
{
long long v = va_arg(*p_va, long long);
return PyLong_FromLongLong(v);
}

case 'K':
return PyLong_FromUnsignedLongLong((long long)va_arg(*p_va, unsigned long long));
{
unsigned long long v = va_arg(*p_va, unsigned long long);
return PyLong_FromUnsignedLongLong(v);
}

case 'u':
{
PyObject *v;
const wchar_t *u = va_arg(*p_va, wchar_t*);
Py_ssize_t n;
const wchar_t *u = va_arg(*p_va, const wchar_t *);
Py_ssize_t n = -1;
if (**p_format == '#') {
++*p_format;
n = va_arg(*p_va, Py_ssize_t);
}
else
n = -1;
if (u == NULL) {
v = Py_NewRef(Py_None);
}
else {
if (n < 0)
n = wcslen(u);
if (n < 0) {
n = safe_wcslen(u);
if (n < 0) {
return NULL;
}
}
v = PyUnicode_FromWideChar(u, n);
}
return v;
}

case 'f':
case 'd':
return PyFloat_FromDouble(
Expand Down Expand Up @@ -376,25 +409,20 @@ do_mkvalue(const char **p_format, va_list *p_va)
{
PyObject *v;
const char *str = va_arg(*p_va, const char *);
Py_ssize_t n;
Py_ssize_t n = -1;
if (**p_format == '#') {
++*p_format;
n = va_arg(*p_va, Py_ssize_t);
}
else
n = -1;
if (str == NULL) {
v = Py_NewRef(Py_None);
}
else {
if (n < 0) {
size_t m = strlen(str);
if (m > PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError,
"string too long for Python string");
n = safe_strlen(str);
if (n < 0) {
return NULL;
}
n = (Py_ssize_t)m;
}
v = PyUnicode_FromStringAndSize(str, n);
}
Expand All @@ -405,25 +433,20 @@ do_mkvalue(const char **p_format, va_list *p_va)
{
PyObject *v;
const char *str = va_arg(*p_va, const char *);
Py_ssize_t n;
Py_ssize_t n = -1;
if (**p_format == '#') {
++*p_format;
n = va_arg(*p_va, Py_ssize_t);
}
else
n = -1;
if (str == NULL) {
v = Py_NewRef(Py_None);
}
else {
if (n < 0) {
size_t m = strlen(str);
if (m > PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError,
"string too long for Python bytes");
n = safe_strlen(str);
if (n < 0) {
return NULL;
}
n = (Py_ssize_t)m;
}
v = PyBytes_FromStringAndSize(str, n);
}
Expand Down
Loading