From af5fa13ef6f648fc7a7a33a7556db13887e7d643 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Sun, 28 Feb 2021 22:41:09 +0000 Subject: bpo-37146: Deactivate opcode cache only when using huntrleaks in the test suite (GH-24643) --- Include/cpython/ceval.h | 2 ++ Lib/test/libregrtest/setup.py | 1 + Python/ceval.c | 22 ++++++++++++---------- Python/clinic/sysmodule.c.h | 20 +++++++++++++++++++- Python/sysmodule.c | 15 +++++++++++++++ 5 files changed, 49 insertions(+), 11 deletions(-) diff --git a/Include/cpython/ceval.h b/Include/cpython/ceval.h index 0633892..05dcfac 100644 --- a/Include/cpython/ceval.h +++ b/Include/cpython/ceval.h @@ -28,3 +28,5 @@ PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc); PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *); PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *); + +PyAPI_FUNC(void) _PyEval_DeactivateOpCache(void); diff --git a/Lib/test/libregrtest/setup.py b/Lib/test/libregrtest/setup.py index 1f264c1..7738d4f 100644 --- a/Lib/test/libregrtest/setup.py +++ b/Lib/test/libregrtest/setup.py @@ -62,6 +62,7 @@ def setup_tests(ns): if ns.huntrleaks: unittest.BaseTestSuite._cleanup = False + sys._deactivate_opcache() if ns.memlimit is not None: support.set_memlimit(ns.memlimit) diff --git a/Python/ceval.c b/Python/ceval.c index 7862643..8ec00bc 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -107,17 +107,19 @@ static long dxp[256]; #endif /* per opcode cache */ -#ifdef Py_DEBUG -// --with-pydebug is used to find memory leak. opcache makes it harder. -// So we disable opcache when Py_DEBUG is defined. -// See bpo-37146 -#define OPCACHE_MIN_RUNS 0 /* disable opcache */ -#else -#define OPCACHE_MIN_RUNS 1024 /* create opcache when code executed this time */ -#endif +static int opcache_min_runs = 1024; /* create opcache when code executed this many times */ #define OPCODE_CACHE_MAX_TRIES 20 #define OPCACHE_STATS 0 /* Enable stats */ +// This function allows to deactivate the opcode cache. As different cache mechanisms may hold +// references, this can mess with the reference leak detector functionality so the cache needs +// to be deactivated in such scenarios to avoid false positives. See bpo-3714 for more information. +void +_PyEval_DeactivateOpCache(void) +{ + opcache_min_runs = 0; +} + #if OPCACHE_STATS static size_t opcache_code_objects = 0; static size_t opcache_code_objects_extra_mem = 0; @@ -1705,9 +1707,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) f->f_stackdepth = -1; f->f_state = FRAME_EXECUTING; - if (co->co_opcache_flag < OPCACHE_MIN_RUNS) { + if (co->co_opcache_flag < opcache_min_runs) { co->co_opcache_flag++; - if (co->co_opcache_flag == OPCACHE_MIN_RUNS) { + if (co->co_opcache_flag == opcache_min_runs) { if (_PyCode_InitOpcache(co) < 0) { goto exit_eval_frame; } diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h index addd589..04c8481 100644 --- a/Python/clinic/sysmodule.c.h +++ b/Python/clinic/sysmodule.c.h @@ -938,6 +938,24 @@ sys_getandroidapilevel(PyObject *module, PyObject *Py_UNUSED(ignored)) #endif /* defined(ANDROID_API_LEVEL) */ +PyDoc_STRVAR(sys__deactivate_opcache__doc__, +"_deactivate_opcache($module, /)\n" +"--\n" +"\n" +"Deactivate the opcode cache permanently"); + +#define SYS__DEACTIVATE_OPCACHE_METHODDEF \ + {"_deactivate_opcache", (PyCFunction)sys__deactivate_opcache, METH_NOARGS, sys__deactivate_opcache__doc__}, + +static PyObject * +sys__deactivate_opcache_impl(PyObject *module); + +static PyObject * +sys__deactivate_opcache(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return sys__deactivate_opcache_impl(module); +} + #ifndef SYS_GETWINDOWSVERSION_METHODDEF #define SYS_GETWINDOWSVERSION_METHODDEF #endif /* !defined(SYS_GETWINDOWSVERSION_METHODDEF) */ @@ -965,4 +983,4 @@ sys_getandroidapilevel(PyObject *module, PyObject *Py_UNUSED(ignored)) #ifndef SYS_GETANDROIDAPILEVEL_METHODDEF #define SYS_GETANDROIDAPILEVEL_METHODDEF #endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */ -/*[clinic end generated code: output=bbc4963fe86a29d9 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=68c62b9ca317a0c8 input=a9049054013a1b77]*/ diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 13b9034..686b6ca 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1958,6 +1958,20 @@ sys_getandroidapilevel_impl(PyObject *module) #endif /* ANDROID_API_LEVEL */ +/*[clinic input] +sys._deactivate_opcache + +Deactivate the opcode cache permanently +[clinic start generated code]*/ + +static PyObject * +sys__deactivate_opcache_impl(PyObject *module) +/*[clinic end generated code: output=00e20982bd012122 input=501eac146735ccf9]*/ +{ + _PyEval_DeactivateOpCache(); + Py_RETURN_NONE; +} + static PyMethodDef sys_methods[] = { /* Might as well keep this in alphabetic order */ @@ -2011,6 +2025,7 @@ static PyMethodDef sys_methods[] = { SYS_GET_ASYNCGEN_HOOKS_METHODDEF SYS_GETANDROIDAPILEVEL_METHODDEF SYS_UNRAISABLEHOOK_METHODDEF + SYS__DEACTIVATE_OPCACHE_METHODDEF {NULL, NULL} /* sentinel */ }; -- cgit v0.12