Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ad52437

Browse files
committed
Fail if PyMem_Malloc() is called without holding the GIL
Issue #26563: Debug hooks on Python memory allocators now raise a fatal error if functions of the PyMem_Malloc() family are called without holding the GIL.
1 parent 013024e commit ad52437

4 files changed

Lines changed: 43 additions & 11 deletions

File tree

Lib/test/test_capi.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -602,15 +602,24 @@ def test_api_misuse(self):
602602
regex = regex.format(ptr=self.PTR_REGEX)
603603
self.assertRegex(out, regex)
604604

605-
def test_pyobject_malloc_without_gil(self):
606-
# Calling PyObject_Malloc() without holding the GIL must raise an
607-
# error in debug mode.
608-
code = 'import _testcapi; _testcapi.pyobject_malloc_without_gil()'
605+
def check_malloc_without_gil(self, code):
609606
out = self.check(code)
610607
expected = ('Fatal Python error: Python memory allocator called '
611608
'without holding the GIL')
612609
self.assertIn(expected, out)
613610

611+
def test_pymem_malloc_without_gil(self):
612+
# Debug hooks must raise an error if PyMem_Malloc() is called
613+
# without holding the GIL
614+
code = 'import _testcapi; _testcapi.pymem_malloc_without_gil()'
615+
self.check_malloc_without_gil(code)
616+
617+
def test_pyobject_malloc_without_gil(self):
618+
# Debug hooks must raise an error if PyObject_Malloc() is called
619+
# without holding the GIL
620+
code = 'import _testcapi; _testcapi.pyobject_malloc_without_gil()'
621+
self.check_malloc_without_gil(code)
622+
614623

615624
class PyMemMallocDebugTests(PyMemDebugTests):
616625
PYTHONMALLOC = 'malloc_debug'

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ Release date: tba
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #26563: Debug hooks on Python memory allocators now raise a fatal
14+
error if functions of the :c:func:`PyMem_Malloc` family are called without
15+
holding the GIL.
16+
1317
- Issue #26564: On error, the debug hooks on Python memory allocators now use
1418
the :mod:`tracemalloc` module to get the traceback where a memory block was
1519
allocated.

Modules/_testcapimodule.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3643,11 +3643,29 @@ pymem_api_misuse(PyObject *self, PyObject *args)
36433643
Py_RETURN_NONE;
36443644
}
36453645

3646+
static PyObject*
3647+
pymem_malloc_without_gil(PyObject *self, PyObject *args)
3648+
{
3649+
char *buffer;
3650+
3651+
/* Deliberate bug to test debug hooks on Python memory allocators:
3652+
call PyMem_Malloc() without holding the GIL */
3653+
Py_BEGIN_ALLOW_THREADS
3654+
buffer = PyMem_Malloc(10);
3655+
Py_END_ALLOW_THREADS
3656+
3657+
PyMem_Free(buffer);
3658+
3659+
Py_RETURN_NONE;
3660+
}
3661+
36463662
static PyObject*
36473663
pyobject_malloc_without_gil(PyObject *self, PyObject *args)
36483664
{
36493665
char *buffer;
36503666

3667+
/* Deliberate bug to test debug hooks on Python memory allocators:
3668+
call PyObject_Malloc() without holding the GIL */
36513669
Py_BEGIN_ALLOW_THREADS
36523670
buffer = PyObject_Malloc(10);
36533671
Py_END_ALLOW_THREADS
@@ -3841,6 +3859,7 @@ static PyMethodDef TestMethods[] = {
38413859
{"get_recursion_depth", get_recursion_depth, METH_NOARGS},
38423860
{"pymem_buffer_overflow", pymem_buffer_overflow, METH_NOARGS},
38433861
{"pymem_api_misuse", pymem_api_misuse, METH_NOARGS},
3862+
{"pymem_malloc_without_gil", pymem_malloc_without_gil, METH_NOARGS},
38443863
{"pyobject_malloc_without_gil", pyobject_malloc_without_gil, METH_NOARGS},
38453864
{NULL, NULL} /* sentinel */
38463865
};

Objects/obmalloc.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ static PyMemAllocatorEx _PyMem_Raw = {
198198

199199
static PyMemAllocatorEx _PyMem = {
200200
#ifdef Py_DEBUG
201-
&_PyMem_Debug.mem, PYRAWDBG_FUNCS
201+
&_PyMem_Debug.mem, PYDBG_FUNCS
202202
#else
203203
NULL, PYMEM_FUNCS
204204
#endif
@@ -321,17 +321,17 @@ PyMem_SetupDebugHooks(void)
321321
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc);
322322
}
323323

324-
if (_PyMem.malloc != _PyMem_DebugRawMalloc) {
325-
alloc.ctx = &_PyMem_Debug.mem;
326-
PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &_PyMem_Debug.mem.alloc);
327-
PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
328-
}
329-
330324
alloc.malloc = _PyMem_DebugMalloc;
331325
alloc.calloc = _PyMem_DebugCalloc;
332326
alloc.realloc = _PyMem_DebugRealloc;
333327
alloc.free = _PyMem_DebugFree;
334328

329+
if (_PyMem.malloc != _PyMem_DebugMalloc) {
330+
alloc.ctx = &_PyMem_Debug.mem;
331+
PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &_PyMem_Debug.mem.alloc);
332+
PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
333+
}
334+
335335
if (_PyObject.malloc != _PyMem_DebugMalloc) {
336336
alloc.ctx = &_PyMem_Debug.obj;
337337
PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &_PyMem_Debug.obj.alloc);

0 commit comments

Comments
 (0)