Skip to content

Commit af5fa13

Browse files
authored
bpo-37146: Deactivate opcode cache only when using huntrleaks in the test suite (GH-24643)
1 parent e8f5ddd commit af5fa13

File tree

5 files changed

+49
-11
lines changed

5 files changed

+49
-11
lines changed

Include/cpython/ceval.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,5 @@ PyAPI_FUNC(Py_ssize_t) _PyEval_RequestCodeExtraIndex(freefunc);
2828

2929
PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *);
3030
PyAPI_FUNC(int) _PyEval_SliceIndexNotNone(PyObject *, Py_ssize_t *);
31+
32+
PyAPI_FUNC(void) _PyEval_DeactivateOpCache(void);

Lib/test/libregrtest/setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def setup_tests(ns):
6262

6363
if ns.huntrleaks:
6464
unittest.BaseTestSuite._cleanup = False
65+
sys._deactivate_opcache()
6566

6667
if ns.memlimit is not None:
6768
support.set_memlimit(ns.memlimit)

Python/ceval.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -107,17 +107,19 @@ static long dxp[256];
107107
#endif
108108

109109
/* per opcode cache */
110-
#ifdef Py_DEBUG
111-
// --with-pydebug is used to find memory leak. opcache makes it harder.
112-
// So we disable opcache when Py_DEBUG is defined.
113-
// See bpo-37146
114-
#define OPCACHE_MIN_RUNS 0 /* disable opcache */
115-
#else
116-
#define OPCACHE_MIN_RUNS 1024 /* create opcache when code executed this time */
117-
#endif
110+
static int opcache_min_runs = 1024; /* create opcache when code executed this many times */
118111
#define OPCODE_CACHE_MAX_TRIES 20
119112
#define OPCACHE_STATS 0 /* Enable stats */
120113

114+
// This function allows to deactivate the opcode cache. As different cache mechanisms may hold
115+
// references, this can mess with the reference leak detector functionality so the cache needs
116+
// to be deactivated in such scenarios to avoid false positives. See bpo-3714 for more information.
117+
void
118+
_PyEval_DeactivateOpCache(void)
119+
{
120+
opcache_min_runs = 0;
121+
}
122+
121123
#if OPCACHE_STATS
122124
static size_t opcache_code_objects = 0;
123125
static size_t opcache_code_objects_extra_mem = 0;
@@ -1705,9 +1707,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag)
17051707
f->f_stackdepth = -1;
17061708
f->f_state = FRAME_EXECUTING;
17071709

1708-
if (co->co_opcache_flag < OPCACHE_MIN_RUNS) {
1710+
if (co->co_opcache_flag < opcache_min_runs) {
17091711
co->co_opcache_flag++;
1710-
if (co->co_opcache_flag == OPCACHE_MIN_RUNS) {
1712+
if (co->co_opcache_flag == opcache_min_runs) {
17111713
if (_PyCode_InitOpcache(co) < 0) {
17121714
goto exit_eval_frame;
17131715
}

Python/clinic/sysmodule.c.h

Lines changed: 19 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/sysmodule.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1958,6 +1958,20 @@ sys_getandroidapilevel_impl(PyObject *module)
19581958
#endif /* ANDROID_API_LEVEL */
19591959

19601960

1961+
/*[clinic input]
1962+
sys._deactivate_opcache
1963+
1964+
Deactivate the opcode cache permanently
1965+
[clinic start generated code]*/
1966+
1967+
static PyObject *
1968+
sys__deactivate_opcache_impl(PyObject *module)
1969+
/*[clinic end generated code: output=00e20982bd012122 input=501eac146735ccf9]*/
1970+
{
1971+
_PyEval_DeactivateOpCache();
1972+
Py_RETURN_NONE;
1973+
}
1974+
19611975

19621976
static PyMethodDef sys_methods[] = {
19631977
/* Might as well keep this in alphabetic order */
@@ -2011,6 +2025,7 @@ static PyMethodDef sys_methods[] = {
20112025
SYS_GET_ASYNCGEN_HOOKS_METHODDEF
20122026
SYS_GETANDROIDAPILEVEL_METHODDEF
20132027
SYS_UNRAISABLEHOOK_METHODDEF
2028+
SYS__DEACTIVATE_OPCACHE_METHODDEF
20142029
{NULL, NULL} /* sentinel */
20152030
};
20162031

0 commit comments

Comments
 (0)