diff options
author | xdegaye <xdegaye@gmail.com> | 2017-07-01 12:14:45 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-07-01 12:14:45 (GMT) |
commit | 85f643023fed3d4e2fb8e399f9ad57f3a65ef237 (patch) | |
tree | 8f2e1a9f115559d6449dcdcd64bb3e89eb33c1e8 /Modules/_testcapimodule.c | |
parent | 49bc7430284ba09247fb9a0401f87aebd087a61a (diff) | |
download | cpython-85f643023fed3d4e2fb8e399f9ad57f3a65ef237.zip cpython-85f643023fed3d4e2fb8e399f9ad57f3a65ef237.tar.gz cpython-85f643023fed3d4e2fb8e399f9ad57f3a65ef237.tar.bz2 |
bpo-30695: Add set_nomemory(start, stop) to _testcapi (GH-2406)
Diffstat (limited to 'Modules/_testcapimodule.c')
-rw-r--r-- | Modules/_testcapimodule.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index 83ba33d..c9c2798 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -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", |