summaryrefslogtreecommitdiffstats
path: root/Modules/_testcapimodule.c
diff options
context:
space:
mode:
authorxdegaye <xdegaye@gmail.com>2017-07-01 12:14:45 (GMT)
committerGitHub <noreply@github.com>2017-07-01 12:14:45 (GMT)
commit85f643023fed3d4e2fb8e399f9ad57f3a65ef237 (patch)
tree8f2e1a9f115559d6449dcdcd64bb3e89eb33c1e8 /Modules/_testcapimodule.c
parent49bc7430284ba09247fb9a0401f87aebd087a61a (diff)
downloadcpython-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.c128
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",