diff options
author | Victor Stinner <vstinner@redhat.com> | 2019-04-11 11:33:27 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-11 11:33:27 +0200 |
commit | 2b00db68554422ec37faba2a80179a0172df6349 (patch) | |
tree | 164b39074b3563200714215ea8273c59f173feb5 /Objects | |
parent | bpo-36597: fix random doctest failure (GH-12776) (diff) | |
download | cpython-2b00db68554422ec37faba2a80179a0172df6349.tar.gz cpython-2b00db68554422ec37faba2a80179a0172df6349.tar.bz2 cpython-2b00db68554422ec37faba2a80179a0172df6349.zip |
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 'Objects')
-rw-r--r-- | Objects/object.c | 15 | ||||
-rw-r--r-- | Objects/obmalloc.c | 18 |
2 files changed, 8 insertions, 25 deletions
diff --git a/Objects/object.c b/Objects/object.c index bd44acacb61..c9aa479abdc 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -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; } diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c index 1c2a32050f9..e919fad595b 100644 --- a/Objects/obmalloc.c +++ b/Objects/obmalloc.c @@ -1914,7 +1914,7 @@ _Py_GetAllocatedBlocks(void) /* Special bytes broadcast into debug memory blocks at appropriate times. * Strings of these are unlikely to be valid addresses, floats, ints or - * 7-bit ASCII. + * 7-bit ASCII. If modified, _PyMem_IsPtrFreed() should be updated as well. */ #undef CLEANBYTE #undef DEADBYTE @@ -2059,22 +2059,6 @@ _PyMem_DebugRawCalloc(void *ctx, size_t nelem, size_t elsize) } -/* Heuristic checking if the memory has been freed. Rely on the debug hooks on - Python memory allocators which fills the memory with DEADBYTE (0xDB) when - memory is deallocated. */ -int -_PyMem_IsFreed(void *ptr, size_t size) -{ - unsigned char *bytes = ptr; - for (size_t i=0; i < size; i++) { - if (bytes[i] != DEADBYTE) { - return 0; - } - } - return 1; -} - - /* The debug free first checks the 2*SST bytes on each end for sanity (in particular, that the FORBIDDENBYTEs with the api ID are still intact). Then fills the original bytes with DEADBYTE. |