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

@ -155,6 +155,31 @@ PyAPI_FUNC(int) _PyMem_SetDefaultAllocator(
PyMemAllocatorDomain domain,
PyMemAllocatorEx *old_alloc);
/* Heuristic checking if a pointer value is newly allocated
(uninitialized) or newly freed. The pointer is not dereferenced, only the
pointer value is checked.
The heuristic relies on the debug hooks on Python memory allocators which
fills newly allocated memory with CLEANBYTE (0xCB) and newly freed memory
with DEADBYTE (0xDB). Detect also "untouchable bytes" marked
with FORBIDDENBYTE (0xFB). */
static inline int _PyMem_IsPtrFreed(void *ptr)
{
uintptr_t value = (uintptr_t)ptr;
#if SIZEOF_VOID_P == 8
return (value == (uintptr_t)0xCBCBCBCBCBCBCBCB
|| value == (uintptr_t)0xDBDBDBDBDBDBDBDB
|| value == (uintptr_t)0xFBFBFBFBFBFBFBFB
);
#elif SIZEOF_VOID_P == 4
return (value == (uintptr_t)0xCBCBCBCB
|| value == (uintptr_t)0xDBDBDBDB
|| value == (uintptr_t)0xFBFBFBFB);
#else
# error "unknown pointer size"
#endif
}
#ifdef __cplusplus
}
#endif