diff options
author | Victor Stinner <vstinner@redhat.com> | 2019-04-11 09:33:27 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-11 09:33:27 (GMT) |
commit | 2b00db68554422ec37faba2a80179a0172df6349 (patch) | |
tree | 164b39074b3563200714215ea8273c59f173feb5 /Modules | |
parent | 57b1a2862a99677f09614e9e456d36aae9ddd87c (diff) | |
download | cpython-2b00db68554422ec37faba2a80179a0172df6349.zip cpython-2b00db68554422ec37faba2a80179a0172df6349.tar.gz cpython-2b00db68554422ec37faba2a80179a0172df6349.tar.bz2 |
bpo-36389: _PyObject_IsFreed() now also detects uninitialized memory (GH-12770)
Replace _PyMem_IsFreed() function with _PyMem_IsPtrFreed() inline
function. The function is now way more efficient, it became a simple
comparison on integers, rather than a short loop. It detects also
uninitialized bytes and "forbidden bytes" filled by debug hooks
on memory allocators.
Add unit tests on _PyObject_IsFreed().
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_testcapimodule.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index c515efe..1180b4b 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -4237,6 +4237,59 @@ test_pymem_getallocatorsname(PyObject *self, PyObject *args) static PyObject* +pyobject_is_freed(PyObject *self, PyObject *op) +{ + int res = _PyObject_IsFreed(op); + return PyBool_FromLong(res); +} + + +static PyObject* +pyobject_uninitialized(PyObject *self, PyObject *args) +{ + PyObject *op = (PyObject *)PyObject_Malloc(sizeof(PyObject)); + if (op == NULL) { + return NULL; + } + /* Initialize reference count to avoid early crash in ceval or GC */ + Py_REFCNT(op) = 1; + /* object fields like ob_type are uninitialized! */ + return op; +} + + +static PyObject* +pyobject_forbidden_bytes(PyObject *self, PyObject *args) +{ + /* Allocate an incomplete PyObject structure: truncate 'ob_type' field */ + PyObject *op = (PyObject *)PyObject_Malloc(offsetof(PyObject, ob_type)); + if (op == NULL) { + return NULL; + } + /* Initialize reference count to avoid early crash in ceval or GC */ + Py_REFCNT(op) = 1; + /* ob_type field is after the memory block: part of "forbidden bytes" + when using debug hooks on memory allocatrs! */ + return op; +} + + +static PyObject* +pyobject_freed(PyObject *self, PyObject *args) +{ + PyObject *op = _PyObject_CallNoArg((PyObject *)&PyBaseObject_Type); + if (op == NULL) { + return NULL; + } + Py_TYPE(op)->tp_dealloc(op); + /* Reset reference count to avoid early crash in ceval or GC */ + Py_REFCNT(op) = 1; + /* object memory is freed! */ + return op; +} + + +static PyObject* pyobject_malloc_without_gil(PyObject *self, PyObject *args) { char *buffer; @@ -4907,6 +4960,10 @@ static PyMethodDef TestMethods[] = { {"pymem_api_misuse", pymem_api_misuse, METH_NOARGS}, {"pymem_malloc_without_gil", pymem_malloc_without_gil, METH_NOARGS}, {"pymem_getallocatorsname", test_pymem_getallocatorsname, METH_NOARGS}, + {"pyobject_is_freed", (PyCFunction)(void(*)(void))pyobject_is_freed, METH_O}, + {"pyobject_uninitialized", pyobject_uninitialized, METH_NOARGS}, + {"pyobject_forbidden_bytes", pyobject_forbidden_bytes, METH_NOARGS}, + {"pyobject_freed", pyobject_freed, METH_NOARGS}, {"pyobject_malloc_without_gil", pyobject_malloc_without_gil, METH_NOARGS}, {"tracemalloc_track", tracemalloc_track, METH_VARARGS}, {"tracemalloc_untrack", tracemalloc_untrack, METH_VARARGS}, |