summaryrefslogtreecommitdiff
path: root/Include
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@redhat.com>2019-04-11 22:30:31 +0200
committerGitHub <noreply@github.com>2019-04-11 22:30:31 +0200
commit9e23f0a27cb8bf6e4ea1d2aef36a91502282bbc9 (patch)
tree388f7d0875c63ac435b5a40d8abf4cb65e6b1915 /Include
parentac31da8f3710f9f9b8dbb4c36b2108fb1e5b4a48 (diff)
downloadcpython-git-9e23f0a27cb8bf6e4ea1d2aef36a91502282bbc9.tar.gz
[3.7] bpo-36389: _PyObject_IsFreed() now also detects uninitialized memory (GH-12770) (GH-12788)
* 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(). (cherry picked from commit 2b00db68554422ec37faba2a80179a0172df6349) * bpo-36389: Change PyMem_SetupDebugHooks() constants (GH-12782) Modify CLEANBYTE, DEADDYTE and FORBIDDENBYTE constants: use 0xCD, 0xDD and 0xFD, rather than 0xCB, 0xBB and 0xFB, to use the same byte patterns than Windows CRT debug malloc() and free(). (cherry picked from commit 4c409beb4c360a73d054f37807d3daad58d1b567)
Diffstat (limited to 'Include')
-rw-r--r--Include/internal/mem.h24
-rw-r--r--Include/pymem.h2
2 files changed, 24 insertions, 2 deletions
diff --git a/Include/internal/mem.h b/Include/internal/mem.h
index a731e30e6a..5896e4a050 100644
--- a/Include/internal/mem.h
+++ b/Include/internal/mem.h
@@ -145,6 +145,30 @@ PyAPI_FUNC(void) _PyGC_Initialize(struct _gc_runtime_state *);
#define _PyGC_generation0 _PyRuntime.gc.generation0
+/* 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 (0xCD) and newly freed memory
+ with DEADBYTE (0xDD). Detect also "untouchable bytes" marked
+ with FORBIDDENBYTE (0xFD). */
+static inline int _PyMem_IsPtrFreed(void *ptr)
+{
+ uintptr_t value = (uintptr_t)ptr;
+#if SIZEOF_VOID_P == 8
+ return (value == (uintptr_t)0xCDCDCDCDCDCDCDCD
+ || value == (uintptr_t)0xDDDDDDDDDDDDDDDD
+ || value == (uintptr_t)0xFDFDFDFDFDFDFDFD);
+#elif SIZEOF_VOID_P == 4
+ return (value == (uintptr_t)0xCDCDCDCD
+ || value == (uintptr_t)0xDDDDDDDD
+ || value == (uintptr_t)0xFDFDFDFD);
+#else
+# error "unknown pointer size"
+#endif
+}
+
#ifdef __cplusplus
}
#endif
diff --git a/Include/pymem.h b/Include/pymem.h
index ef6e0bb5e2..458a6489c7 100644
--- a/Include/pymem.h
+++ b/Include/pymem.h
@@ -55,8 +55,6 @@ PyAPI_FUNC(int) PyTraceMalloc_Untrack(
PyAPI_FUNC(PyObject*) _PyTraceMalloc_GetTraceback(
unsigned int domain,
uintptr_t ptr);
-
-PyAPI_FUNC(int) _PyMem_IsFreed(void *ptr, size_t size);
#endif /* !defined(Py_LIMITED_API) */