mirror of
https://github.com/python/cpython.git
synced 2025-11-01 18:51:43 +00:00
Issue #3329: Implement the PEP 445
Add new enum: * PyMemAllocatorDomain Add new structures: * PyMemAllocator * PyObjectArenaAllocator Add new functions: * PyMem_RawMalloc(), PyMem_RawRealloc(), PyMem_RawFree() * PyMem_GetAllocator(), PyMem_SetAllocator() * PyObject_GetArenaAllocator(), PyObject_SetArenaAllocator() * PyMem_SetupDebugHooks() Changes: * PyMem_Malloc()/PyObject_Realloc() now always call malloc()/realloc(), instead of calling PyObject_Malloc()/PyObject_Realloc() in debug mode. * PyObject_Malloc()/PyObject_Realloc() now falls back to PyMem_Malloc()/PyMem_Realloc() for allocations larger than 512 bytes. * Redesign debug checks on memory block allocators as hooks, instead of using C macros
This commit is contained in:
parent
df715ba54d
commit
0507bf56f0
8 changed files with 797 additions and 238 deletions
|
|
@ -2511,6 +2511,161 @@ test_decref_doesnt_leak(PyObject *ob)
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_pymem_alloc0(PyObject *self)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = PyMem_Malloc(0);
|
||||
if (ptr == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "PyMem_Malloc(0) returns NULL");
|
||||
return NULL;
|
||||
}
|
||||
PyMem_Free(ptr);
|
||||
|
||||
ptr = PyObject_Malloc(0);
|
||||
if (ptr == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "PyObject_Malloc(0) returns NULL");
|
||||
return NULL;
|
||||
}
|
||||
PyObject_Free(ptr);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
PyMemAllocator alloc;
|
||||
|
||||
size_t malloc_size;
|
||||
void *realloc_ptr;
|
||||
size_t realloc_new_size;
|
||||
void *free_ptr;
|
||||
} alloc_hook_t;
|
||||
|
||||
static void* hook_malloc (void* ctx, size_t size)
|
||||
{
|
||||
alloc_hook_t *hook = (alloc_hook_t *)ctx;
|
||||
hook->malloc_size = size;
|
||||
return hook->alloc.malloc(hook->alloc.ctx, size);
|
||||
}
|
||||
|
||||
static void* hook_realloc (void* ctx, void* ptr, size_t new_size)
|
||||
{
|
||||
alloc_hook_t *hook = (alloc_hook_t *)ctx;
|
||||
hook->realloc_ptr = ptr;
|
||||
hook->realloc_new_size = new_size;
|
||||
return hook->alloc.realloc(hook->alloc.ctx, ptr, new_size);
|
||||
}
|
||||
|
||||
static void hook_free (void *ctx, void *ptr)
|
||||
{
|
||||
alloc_hook_t *hook = (alloc_hook_t *)ctx;
|
||||
hook->free_ptr = ptr;
|
||||
hook->alloc.free(hook->alloc.ctx, ptr);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_setallocators(PyMemAllocatorDomain domain)
|
||||
{
|
||||
PyObject *res = NULL;
|
||||
const char *error_msg;
|
||||
alloc_hook_t hook;
|
||||
PyMemAllocator alloc;
|
||||
size_t size, size2;
|
||||
void *ptr, *ptr2;
|
||||
|
||||
hook.malloc_size = 0;
|
||||
hook.realloc_ptr = NULL;
|
||||
hook.realloc_new_size = 0;
|
||||
hook.free_ptr = NULL;
|
||||
|
||||
alloc.ctx = &hook;
|
||||
alloc.malloc = &hook_malloc;
|
||||
alloc.realloc = &hook_realloc;
|
||||
alloc.free = &hook_free;
|
||||
PyMem_GetAllocator(domain, &hook.alloc);
|
||||
PyMem_SetAllocator(domain, &alloc);
|
||||
|
||||
size = 42;
|
||||
switch(domain)
|
||||
{
|
||||
case PYMEM_DOMAIN_RAW: ptr = PyMem_RawMalloc(size); break;
|
||||
case PYMEM_DOMAIN_MEM: ptr = PyMem_Malloc(size); break;
|
||||
case PYMEM_DOMAIN_OBJ: ptr = PyObject_Malloc(size); break;
|
||||
default: ptr = NULL; break;
|
||||
}
|
||||
|
||||
if (ptr == NULL) {
|
||||
error_msg = "malloc failed";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (hook.malloc_size != size) {
|
||||
error_msg = "malloc invalid size";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
size2 = 200;
|
||||
switch(domain)
|
||||
{
|
||||
case PYMEM_DOMAIN_RAW: ptr2 = PyMem_RawRealloc(ptr, size2); break;
|
||||
case PYMEM_DOMAIN_MEM: ptr2 = PyMem_Realloc(ptr, size2); break;
|
||||
case PYMEM_DOMAIN_OBJ: ptr2 = PyObject_Realloc(ptr, size2); break;
|
||||
}
|
||||
|
||||
if (ptr2 == NULL) {
|
||||
error_msg = "realloc failed";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (hook.realloc_ptr != ptr
|
||||
|| hook.realloc_new_size != size2) {
|
||||
error_msg = "realloc invalid parameters";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
switch(domain)
|
||||
{
|
||||
case PYMEM_DOMAIN_RAW: PyMem_RawFree(ptr2); break;
|
||||
case PYMEM_DOMAIN_MEM: PyMem_Free(ptr2); break;
|
||||
case PYMEM_DOMAIN_OBJ: PyObject_Free(ptr2); break;
|
||||
}
|
||||
|
||||
if (hook.free_ptr != ptr2) {
|
||||
error_msg = "free invalid pointer";
|
||||
goto fail;
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
res = Py_None;
|
||||
goto finally;
|
||||
|
||||
fail:
|
||||
PyErr_SetString(PyExc_RuntimeError, error_msg);
|
||||
|
||||
finally:
|
||||
PyMem_SetAllocator(domain, &hook.alloc);
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_pymem_setrawallocators(PyObject *self)
|
||||
{
|
||||
return test_setallocators(PYMEM_DOMAIN_RAW);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_pymem_setallocators(PyObject *self)
|
||||
{
|
||||
return test_setallocators(PYMEM_DOMAIN_MEM);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
test_pyobject_setallocators(PyObject *self)
|
||||
{
|
||||
return test_setallocators(PYMEM_DOMAIN_OBJ);
|
||||
}
|
||||
|
||||
static PyMethodDef TestMethods[] = {
|
||||
{"raise_exception", raise_exception, METH_VARARGS},
|
||||
{"raise_memoryerror", (PyCFunction)raise_memoryerror, METH_NOARGS},
|
||||
|
|
@ -2611,6 +2766,14 @@ static PyMethodDef TestMethods[] = {
|
|||
{"pytime_object_to_time_t", test_pytime_object_to_time_t, METH_VARARGS},
|
||||
{"pytime_object_to_timeval", test_pytime_object_to_timeval, METH_VARARGS},
|
||||
{"pytime_object_to_timespec", test_pytime_object_to_timespec, METH_VARARGS},
|
||||
{"test_pymem",
|
||||
(PyCFunction)test_pymem_alloc0, METH_NOARGS},
|
||||
{"test_pymem_alloc0",
|
||||
(PyCFunction)test_pymem_setrawallocators, METH_NOARGS},
|
||||
{"test_pymem_setallocators",
|
||||
(PyCFunction)test_pymem_setallocators, METH_NOARGS},
|
||||
{"test_pyobject_setallocators",
|
||||
(PyCFunction)test_pyobject_setallocators, METH_NOARGS},
|
||||
{NULL, NULL} /* sentinel */
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue