mirror of
https://github.com/python/cpython.git
synced 2025-11-25 12:44:13 +00:00
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().
This commit is contained in:
parent
57b1a2862a
commit
2b00db6855
6 changed files with 113 additions and 27 deletions
|
|
@ -4236,6 +4236,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)
|
||||
{
|
||||
|
|
@ -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},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue