Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
2 changes: 0 additions & 2 deletions Include/objimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,6 @@ PyAPI_FUNC(PyVarObject *) _PyObject_GC_Resize(PyVarObject *, Py_ssize_t);
#define PyObject_GC_Resize(type, op, n) \
( (type *) _PyObject_GC_Resize(_PyVarObject_CAST(op), (n)) )



PyAPI_FUNC(PyObject *) _PyObject_GC_New(PyTypeObject *);
PyAPI_FUNC(PyVarObject *) _PyObject_GC_NewVar(PyTypeObject *, Py_ssize_t);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:c:func:`PyObject_GC_NewVar` and :c:func:`PyObject_GC_Resize` now check for
integer overflow when computing the object size. Patch by Victor Stinner.
13 changes: 0 additions & 13 deletions Objects/tupleobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,6 @@ tuple_alloc(Py_ssize_t size)
return op;
}
}
/* Check for overflow */
if ((size_t)size > ((size_t)PY_SSIZE_T_MAX - (sizeof(PyTupleObject) -
sizeof(PyObject *))) / sizeof(PyObject *)) {
return (PyTupleObject *)PyErr_NoMemory();
}
PyTupleObject *result = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size);
if (result != NULL) {
_PyTuple_RESET_HASH_CACHE(result);
Expand Down Expand Up @@ -1079,14 +1074,6 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
*pv = PyTuple_New(newsize);
return *pv == NULL ? -1 : 0;
}
/* Check for overflow */
if ((size_t)newsize > ((size_t)PY_SSIZE_T_MAX - (sizeof(PyTupleObject) -
sizeof(PyObject *))) / sizeof(PyObject *)) {
*pv = NULL;
Py_DECREF(v);
PyErr_NoMemory();
return -1;
}

if (_PyObject_GC_IS_TRACKED(v)) {
_PyObject_GC_UNTRACK(v);
Expand Down
53 changes: 45 additions & 8 deletions Python/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2102,18 +2102,46 @@ _PyObject_GC_New(PyTypeObject *tp)
return op;
}

// Similar to _PyObject_VAR_SIZE(), but check for integer overflow.
// Set *result and return 0 on success, return -1 on integer overflow.
//
// The result can be greater than PY_SSIZE_T_MAX. The caller is responsible
// for checking result maximum.
static inline int
_PyObject_GC_VAR_SIZE(PyTypeObject *type, Py_ssize_t nitems_signed,
size_t *result)
{
assert(type->tp_itemsize >= 1);
assert(nitems_signed >= 0);

const size_t basicsize = _Py_STATIC_CAST(size_t, type->tp_basicsize);
const size_t nitems = _Py_STATIC_CAST(size_t, nitems_signed);
const size_t itemsize = _Py_STATIC_CAST(size_t, type->tp_itemsize);
if (nitems > ((size_t)PY_SSIZE_T_MAX - basicsize) / itemsize) {
return -1;
}

size_t size = basicsize + nitems * itemsize;
size = _Py_SIZE_ROUND_UP(size, SIZEOF_VOID_P);
*result = size;
return 0;
}

PyVarObject *
_PyObject_GC_NewVar(PyTypeObject *tp, Py_ssize_t nitems)
{
PyVarObject *op;

if (nitems < 0) {
PyErr_BadInternalCall();
return NULL;
}

size_t size;
if (_PyObject_GC_VAR_SIZE(tp, nitems, &size) < 0) {
return (PyVarObject *)PyErr_NoMemory();
}

size_t presize = _PyType_PreHeaderSize(tp);
size_t size = _PyObject_VAR_SIZE(tp, nitems);
op = (PyVarObject *)gc_alloc(tp, size, presize);
PyVarObject *op = (PyVarObject *)gc_alloc(tp, size, presize);
if (op == NULL) {
return NULL;
}
Expand All @@ -2138,14 +2166,23 @@ PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *tp, size_t extra_size)
PyVarObject *
_PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems)
{
const size_t basicsize = _PyObject_VAR_SIZE(Py_TYPE(op), nitems);
const size_t presize = _PyType_PreHeaderSize(Py_TYPE(op));
_PyObject_ASSERT((PyObject *)op, !_PyObject_GC_IS_TRACKED(op));
if (basicsize > (size_t)PY_SSIZE_T_MAX - presize) {
assert(nitems >= 0);

PyTypeObject *type = Py_TYPE(op);
size_t size;
if (_PyObject_GC_VAR_SIZE(type, nitems, &size) < 0) {
return (PyVarObject *)PyErr_NoMemory();
}

const size_t presize = _PyType_PreHeaderSize(type);
if (size > (size_t)PY_SSIZE_T_MAX - presize) {
return (PyVarObject *)PyErr_NoMemory();
}
size += presize;

char *mem = (char *)op - presize;
mem = (char *)_PyObject_ReallocWithType(Py_TYPE(op), mem, presize + basicsize);
mem = (char *)_PyObject_ReallocWithType(type, mem, size);
if (mem == NULL) {
return (PyVarObject *)PyErr_NoMemory();
}
Expand Down
53 changes: 45 additions & 8 deletions Python/gc_free_threading.c
Original file line number Diff line number Diff line change
Expand Up @@ -2811,18 +2811,46 @@ _PyObject_GC_New(PyTypeObject *tp)
return op;
}

// Similar to _PyObject_VAR_SIZE(), but check for integer overflow.
// Set *result and return 0 on success, return -1 on integer overflow.
//
// The result can be greater than PY_SSIZE_T_MAX. The caller is responsible
// for checking result maximum.
static inline int
_PyObject_GC_VAR_SIZE(PyTypeObject *type, Py_ssize_t nitems_signed,
size_t *result)
{
assert(type->tp_itemsize >= 1);
assert(nitems_signed >= 0);

const size_t basicsize = _Py_STATIC_CAST(size_t, type->tp_basicsize);
const size_t nitems = _Py_STATIC_CAST(size_t, nitems_signed);
const size_t itemsize = _Py_STATIC_CAST(size_t, type->tp_itemsize);
if (nitems > ((size_t)PY_SSIZE_T_MAX - basicsize) / itemsize) {
return -1;
}

size_t size = basicsize + nitems * itemsize;
size = _Py_SIZE_ROUND_UP(size, SIZEOF_VOID_P);
*result = size;
return 0;
}

PyVarObject *
_PyObject_GC_NewVar(PyTypeObject *tp, Py_ssize_t nitems)
{
PyVarObject *op;

if (nitems < 0) {
PyErr_BadInternalCall();
return NULL;
}

size_t size;
if (_PyObject_GC_VAR_SIZE(tp, nitems, &size) < 0) {
return (PyVarObject *)PyErr_NoMemory();
}

size_t presize = _PyType_PreHeaderSize(tp);
size_t size = _PyObject_VAR_SIZE(tp, nitems);
op = (PyVarObject *)gc_alloc(tp, size, presize);
PyVarObject *op = (PyVarObject *)gc_alloc(tp, size, presize);
if (op == NULL) {
return NULL;
}
Expand All @@ -2847,14 +2875,23 @@ PyUnstable_Object_GC_NewWithExtraData(PyTypeObject *tp, size_t extra_size)
PyVarObject *
_PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems)
{
const size_t basicsize = _PyObject_VAR_SIZE(Py_TYPE(op), nitems);
const size_t presize = _PyType_PreHeaderSize(((PyObject *)op)->ob_type);
_PyObject_ASSERT((PyObject *)op, !_PyObject_GC_IS_TRACKED(op));
if (basicsize > (size_t)PY_SSIZE_T_MAX - presize) {
assert(nitems >= 0);

PyTypeObject *type = Py_TYPE(op);
size_t size;
if (_PyObject_GC_VAR_SIZE(type, nitems, &size) < 0) {
return (PyVarObject *)PyErr_NoMemory();
}

const size_t presize = _PyType_PreHeaderSize(type);
if (size > (size_t)PY_SSIZE_T_MAX - presize) {
return (PyVarObject *)PyErr_NoMemory();
}
size += presize;

char *mem = (char *)op - presize;
mem = (char *)_PyObject_ReallocWithType(Py_TYPE(op), mem, presize + basicsize);
mem = (char *)_PyObject_ReallocWithType(type, mem, size);
if (mem == NULL) {
return (PyVarObject *)PyErr_NoMemory();
}
Expand Down
Loading