Skip to content

Commit 8728018

Browse files
ericsnowcurrentlyvstinner
authored andcommitted
bpo-30860: Fix a refleak. (#3506)
* Drop warnoptions from PyInterpreterState. * Drop xoptions from PyInterpreterState. * Don't set warnoptions and _xoptions again. * Decref after adding to sys.__dict__. * Drop an unused macro. * Check sys.xoptions *before* we delete it.
1 parent ba6d5d1 commit 8728018

File tree

7 files changed

+47
-43
lines changed

7 files changed

+47
-43
lines changed

Include/object.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -727,14 +727,13 @@ PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void);
727727
/* Py_REF_DEBUG also controls the display of refcounts and memory block
728728
* allocations at the interactive prompt and at interpreter shutdown
729729
*/
730+
PyAPI_FUNC(PyObject *) _PyDebug_XOptionShowRefCount(void);
730731
PyAPI_FUNC(void) _PyDebug_PrintTotalRefs(void);
731-
#define _PY_DEBUG_PRINT_TOTAL_REFS() _PyDebug_PrintTotalRefs()
732732
#else
733733
#define _Py_INC_REFTOTAL
734734
#define _Py_DEC_REFTOTAL
735735
#define _Py_REF_DEBUG_COMMA
736736
#define _Py_CHECK_REFCNT(OP) /* a semicolon */;
737-
#define _PY_DEBUG_PRINT_TOTAL_REFS()
738737
#endif /* Py_REF_DEBUG */
739738

740739
#ifdef COUNT_ALLOCS

Include/pystate.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,6 @@ typedef struct _is {
6060

6161
/* Used in Python/sysmodule.c. */
6262
int check_interval;
63-
PyObject *warnoptions;
64-
PyObject *xoptions;
6563

6664
/* Used in Modules/_threadmodule.c. */
6765
long num_threads;

Objects/object.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,23 @@ _Py_GetRefTotal(void)
2929
return total;
3030
}
3131

32-
void
33-
_PyDebug_PrintTotalRefs(void) {
34-
PyObject *xoptions, *value;
32+
PyObject *
33+
_PyDebug_XOptionShowRefCount(void)
34+
{
35+
PyObject *xoptions = PySys_GetXOptions();
36+
if (xoptions == NULL)
37+
return NULL;
38+
3539
_Py_IDENTIFIER(showrefcount);
40+
return _PyDict_GetItemId(xoptions, &PyId_showrefcount);
41+
}
3642

37-
xoptions = PySys_GetXOptions();
38-
if (xoptions == NULL)
39-
return;
40-
value = _PyDict_GetItemId(xoptions, &PyId_showrefcount);
41-
if (value == Py_True)
42-
fprintf(stderr,
43-
"[%" PY_FORMAT_SIZE_T "d refs, "
44-
"%" PY_FORMAT_SIZE_T "d blocks]\n",
45-
_Py_GetRefTotal(), _Py_GetAllocatedBlocks());
43+
void
44+
_PyDebug_PrintTotalRefs(void) {
45+
fprintf(stderr,
46+
"[%" PY_FORMAT_SIZE_T "d refs, "
47+
"%" PY_FORMAT_SIZE_T "d blocks]\n",
48+
_Py_GetRefTotal(), _Py_GetAllocatedBlocks());
4649
}
4750
#endif /* Py_REF_DEBUG */
4851

Python/pylifecycle.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,11 @@ Py_FinalizeEx(void)
10061006
while (_PyGC_CollectIfEnabled() > 0)
10071007
/* nothing */;
10081008
#endif
1009+
1010+
#ifdef Py_REF_DEBUG
1011+
PyObject *showrefcount = _PyDebug_XOptionShowRefCount();
1012+
#endif
1013+
10091014
/* Destroy all modules */
10101015
PyImport_Cleanup();
10111016

@@ -1053,7 +1058,10 @@ Py_FinalizeEx(void)
10531058
/* dump hash stats */
10541059
_PyHash_Fini();
10551060

1056-
_PY_DEBUG_PRINT_TOTAL_REFS();
1061+
#ifdef Py_REF_DEBUG
1062+
if (showrefcount == Py_True)
1063+
_PyDebug_PrintTotalRefs();
1064+
#endif
10571065

10581066
#ifdef Py_TRACE_REFS
10591067
/* Display all objects still alive -- this can invoke arbitrary

Python/pystate.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,6 @@ PyInterpreterState_New(void)
9696
interp->builtins_copy = NULL;
9797
interp->tstate_head = NULL;
9898
interp->check_interval = 100;
99-
interp->warnoptions = NULL;
100-
interp->xoptions = NULL;
10199
interp->num_threads = 0;
102100
interp->pythread_stacksize = 0;
103101
interp->codec_search_path = NULL;

Python/pythonrun.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ PyRun_InteractiveLoopFlags(FILE *fp, const char *filename_str, PyCompilerFlags *
113113
err = -1;
114114
for (;;) {
115115
ret = PyRun_InteractiveOneObject(fp, filename, flags);
116-
_PY_DEBUG_PRINT_TOTAL_REFS();
116+
#ifdef Py_REF_DEBUG
117+
if (_PyDebug_XOptionShowRefCount() == Py_True)
118+
_PyDebug_PrintTotalRefs();
119+
#endif
117120
if (ret == E_EOF) {
118121
err = 0;
119122
break;

Python/sysmodule.c

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,14 @@ extern const char *PyWin_DLLVersionString;
3636

3737
_Py_IDENTIFIER(_);
3838
_Py_IDENTIFIER(__sizeof__);
39+
_Py_IDENTIFIER(_xoptions);
3940
_Py_IDENTIFIER(buffer);
4041
_Py_IDENTIFIER(builtins);
4142
_Py_IDENTIFIER(encoding);
4243
_Py_IDENTIFIER(path);
4344
_Py_IDENTIFIER(stdout);
4445
_Py_IDENTIFIER(stderr);
46+
_Py_IDENTIFIER(warnoptions);
4547
_Py_IDENTIFIER(write);
4648

4749
PyObject *
@@ -1479,21 +1481,25 @@ list_builtin_module_names(void)
14791481
static PyObject *
14801482
get_warnoptions(void)
14811483
{
1482-
PyObject *warnoptions = PyThreadState_GET()->interp->warnoptions;
1484+
PyObject *warnoptions = _PySys_GetObjectId(&PyId_warnoptions);
14831485
if (warnoptions == NULL || !PyList_Check(warnoptions)) {
14841486
Py_XDECREF(warnoptions);
14851487
warnoptions = PyList_New(0);
14861488
if (warnoptions == NULL)
14871489
return NULL;
1488-
PyThreadState_GET()->interp->warnoptions = warnoptions;
1490+
if (_PySys_SetObjectId(&PyId_warnoptions, warnoptions)) {
1491+
Py_DECREF(warnoptions);
1492+
return NULL;
1493+
}
1494+
Py_DECREF(warnoptions);
14891495
}
14901496
return warnoptions;
14911497
}
14921498

14931499
void
14941500
PySys_ResetWarnOptions(void)
14951501
{
1496-
PyObject *warnoptions = PyThreadState_GET()->interp->warnoptions;
1502+
PyObject *warnoptions = _PySys_GetObjectId(&PyId_warnoptions);
14971503
if (warnoptions == NULL || !PyList_Check(warnoptions))
14981504
return;
14991505
PyList_SetSlice(warnoptions, 0, PyList_GET_SIZE(warnoptions), NULL);
@@ -1522,20 +1528,24 @@ PySys_AddWarnOption(const wchar_t *s)
15221528
int
15231529
PySys_HasWarnOptions(void)
15241530
{
1525-
PyObject *warnoptions = PyThreadState_GET()->interp->warnoptions;
1531+
PyObject *warnoptions = _PySys_GetObjectId(&PyId_warnoptions);
15261532
return (warnoptions != NULL && (PyList_Size(warnoptions) > 0)) ? 1 : 0;
15271533
}
15281534

15291535
static PyObject *
15301536
get_xoptions(void)
15311537
{
1532-
PyObject *xoptions = PyThreadState_GET()->interp->xoptions;
1538+
PyObject *xoptions = _PySys_GetObjectId(&PyId__xoptions);
15331539
if (xoptions == NULL || !PyDict_Check(xoptions)) {
15341540
Py_XDECREF(xoptions);
15351541
xoptions = PyDict_New();
15361542
if (xoptions == NULL)
15371543
return NULL;
1538-
PyThreadState_GET()->interp->xoptions = xoptions;
1544+
if (_PySys_SetObjectId(&PyId__xoptions, xoptions)) {
1545+
Py_DECREF(xoptions);
1546+
return NULL;
1547+
}
1548+
Py_DECREF(xoptions);
15391549
}
15401550
return xoptions;
15411551
}
@@ -2084,16 +2094,6 @@ _PySys_BeginInit(void)
20842094
#undef SET_SYS_FROM_STRING_BORROW
20852095

20862096
/* Updating the sys namespace, returning integer error codes */
2087-
#define SET_SYS_FROM_STRING_BORROW_INT_RESULT(key, value) \
2088-
do { \
2089-
PyObject *v = (value); \
2090-
if (v == NULL) \
2091-
return -1; \
2092-
res = PyDict_SetItemString(sysdict, key, v); \
2093-
if (res < 0) { \
2094-
return res; \
2095-
} \
2096-
} while (0)
20972097
#define SET_SYS_FROM_STRING_INT_RESULT(key, value) \
20982098
do { \
20992099
PyObject *v = (value); \
@@ -2138,23 +2138,18 @@ _PySys_EndInit(PyObject *sysdict)
21382138
SET_SYS_FROM_STRING_INT_RESULT("base_exec_prefix",
21392139
PyUnicode_FromWideChar(Py_GetExecPrefix(), -1));
21402140

2141-
PyObject *warnoptions = get_warnoptions();
2142-
if (warnoptions == NULL)
2141+
if (get_warnoptions() == NULL)
21432142
return -1;
2144-
SET_SYS_FROM_STRING_BORROW_INT_RESULT("warnoptions", warnoptions);
21452143

2146-
PyObject *xoptions = get_xoptions();
2147-
if (xoptions == NULL)
2144+
if (get_xoptions() == NULL)
21482145
return -1;
2149-
SET_SYS_FROM_STRING_BORROW_INT_RESULT("_xoptions", xoptions);
21502146

21512147
if (PyErr_Occurred())
21522148
return -1;
21532149
return 0;
21542150
}
21552151

21562152
#undef SET_SYS_FROM_STRING_INT_RESULT
2157-
#undef SET_SYS_FROM_STRING_BORROW_INT_RESULT
21582153

21592154
static PyObject *
21602155
makepathobject(const wchar_t *path, wchar_t delim)

0 commit comments

Comments
 (0)