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:
Victor Stinner 2019-04-11 11:33:27 +02:00 committed by GitHub
parent 57b1a2862a
commit 2b00db6855
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 113 additions and 27 deletions

View file

@ -425,18 +425,17 @@ _Py_BreakPoint(void)
int
_PyObject_IsFreed(PyObject *op)
{
uintptr_t ptr = (uintptr_t)op;
if (_PyMem_IsFreed(&ptr, sizeof(ptr))) {
if (_PyMem_IsPtrFreed(op) || _PyMem_IsPtrFreed(op->ob_type)) {
return 1;
}
int freed = _PyMem_IsFreed(&op->ob_type, sizeof(op->ob_type));
/* ignore op->ob_ref: the value can have be modified
/* ignore op->ob_ref: its value can have be modified
by Py_INCREF() and Py_DECREF(). */
#ifdef Py_TRACE_REFS
freed &= _PyMem_IsFreed(&op->_ob_next, sizeof(op->_ob_next));
freed &= _PyMem_IsFreed(&op->_ob_prev, sizeof(op->_ob_prev));
if (_PyMem_IsPtrFreed(op->_ob_next) || _PyMem_IsPtrFreed(op->_ob_prev)) {
return 1;
}
#endif
return freed;
return 0;
}
@ -453,7 +452,7 @@ _PyObject_Dump(PyObject* op)
if (_PyObject_IsFreed(op)) {
/* It seems like the object memory has been freed:
don't access it to prevent a segmentation fault. */
fprintf(stderr, "<freed object>\n");
fprintf(stderr, "<Freed object>\n");
return;
}