mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
bpo-30695: Add set_nomemory(start, stop) to _testcapi (GH-2406)
This commit is contained in:
parent
49bc743028
commit
85f643023f
3 changed files with 163 additions and 1 deletions
|
@ -3420,6 +3420,130 @@ test_pyobject_setallocators(PyObject *self)
|
|||
return test_setallocators(PYMEM_DOMAIN_OBJ);
|
||||
}
|
||||
|
||||
/* Most part of the following code is inherited from the pyfailmalloc project
|
||||
* written by Victor Stinner. */
|
||||
static struct {
|
||||
int installed;
|
||||
PyMemAllocatorEx raw;
|
||||
PyMemAllocatorEx mem;
|
||||
PyMemAllocatorEx obj;
|
||||
} FmHook;
|
||||
|
||||
static struct {
|
||||
int start;
|
||||
int stop;
|
||||
Py_ssize_t count;
|
||||
} FmData;
|
||||
|
||||
static int
|
||||
fm_nomemory(void)
|
||||
{
|
||||
FmData.count++;
|
||||
if (FmData.count > FmData.start &&
|
||||
(FmData.stop <= 0 || FmData.count <= FmData.stop)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *
|
||||
hook_fmalloc(void *ctx, size_t size)
|
||||
{
|
||||
PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
|
||||
if (fm_nomemory()) {
|
||||
return NULL;
|
||||
}
|
||||
return alloc->malloc(alloc->ctx, size);
|
||||
}
|
||||
|
||||
static void *
|
||||
hook_fcalloc(void *ctx, size_t nelem, size_t elsize)
|
||||
{
|
||||
PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
|
||||
if (fm_nomemory()) {
|
||||
return NULL;
|
||||
}
|
||||
return alloc->calloc(alloc->ctx, nelem, elsize);
|
||||
}
|
||||
|
||||
static void *
|
||||
hook_frealloc(void *ctx, void *ptr, size_t new_size)
|
||||
{
|
||||
PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
|
||||
if (fm_nomemory()) {
|
||||
return NULL;
|
||||
}
|
||||
return alloc->realloc(alloc->ctx, ptr, new_size);
|
||||
}
|
||||
|
||||
static void
|
||||
hook_ffree(void *ctx, void *ptr)
|
||||
{
|
||||
PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
|
||||
alloc->free(alloc->ctx, ptr);
|
||||
}
|
||||
|
||||
static void
|
||||
fm_setup_hooks(void)
|
||||
{
|
||||
PyMemAllocatorEx alloc;
|
||||
|
||||
if (FmHook.installed) {
|
||||
return;
|
||||
}
|
||||
FmHook.installed = 1;
|
||||
|
||||
alloc.malloc = hook_fmalloc;
|
||||
alloc.calloc = hook_fcalloc;
|
||||
alloc.realloc = hook_frealloc;
|
||||
alloc.free = hook_ffree;
|
||||
PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &FmHook.raw);
|
||||
PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &FmHook.mem);
|
||||
PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &FmHook.obj);
|
||||
|
||||
alloc.ctx = &FmHook.raw;
|
||||
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc);
|
||||
|
||||
alloc.ctx = &FmHook.mem;
|
||||
PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
|
||||
|
||||
alloc.ctx = &FmHook.obj;
|
||||
PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc);
|
||||
}
|
||||
|
||||
static void
|
||||
fm_remove_hooks(void)
|
||||
{
|
||||
if (FmHook.installed) {
|
||||
FmHook.installed = 0;
|
||||
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &FmHook.raw);
|
||||
PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &FmHook.mem);
|
||||
PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &FmHook.obj);
|
||||
}
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
set_nomemory(PyObject *self, PyObject *args)
|
||||
{
|
||||
/* Memory allocation fails after 'start' allocation requests, and until
|
||||
* 'stop' allocation requests except when 'stop' is negative or equal
|
||||
* to 0 (default) in which case allocation failures never stop. */
|
||||
FmData.count = 0;
|
||||
FmData.stop = 0;
|
||||
if (!PyArg_ParseTuple(args, "i|i", &FmData.start, &FmData.stop)) {
|
||||
return NULL;
|
||||
}
|
||||
fm_setup_hooks();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
remove_mem_hooks(PyObject *self)
|
||||
{
|
||||
fm_remove_hooks();
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(docstring_empty,
|
||||
""
|
||||
);
|
||||
|
@ -4287,6 +4411,10 @@ static PyMethodDef TestMethods[] = {
|
|||
(PyCFunction)test_pymem_setallocators, METH_NOARGS},
|
||||
{"test_pyobject_setallocators",
|
||||
(PyCFunction)test_pyobject_setallocators, METH_NOARGS},
|
||||
{"set_nomemory", (PyCFunction)set_nomemory, METH_VARARGS,
|
||||
PyDoc_STR("set_nomemory(start:int, stop:int = 0)")},
|
||||
{"remove_mem_hooks", (PyCFunction)remove_mem_hooks, METH_NOARGS,
|
||||
PyDoc_STR("Remove memory hooks.")},
|
||||
{"no_docstring",
|
||||
(PyCFunction)test_with_docstring, METH_NOARGS},
|
||||
{"docstring_empty",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue