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.
This commit is contained in:
parent
ba6d5d1def
commit
8728018624
|
@ -727,14 +727,13 @@ PyAPI_FUNC(Py_ssize_t) _Py_GetRefTotal(void);
|
|||
/* Py_REF_DEBUG also controls the display of refcounts and memory block
|
||||
* allocations at the interactive prompt and at interpreter shutdown
|
||||
*/
|
||||
PyAPI_FUNC(PyObject *) _PyDebug_XOptionShowRefCount(void);
|
||||
PyAPI_FUNC(void) _PyDebug_PrintTotalRefs(void);
|
||||
#define _PY_DEBUG_PRINT_TOTAL_REFS() _PyDebug_PrintTotalRefs()
|
||||
#else
|
||||
#define _Py_INC_REFTOTAL
|
||||
#define _Py_DEC_REFTOTAL
|
||||
#define _Py_REF_DEBUG_COMMA
|
||||
#define _Py_CHECK_REFCNT(OP) /* a semicolon */;
|
||||
#define _PY_DEBUG_PRINT_TOTAL_REFS()
|
||||
#endif /* Py_REF_DEBUG */
|
||||
|
||||
#ifdef COUNT_ALLOCS
|
||||
|
|
|
@ -60,8 +60,6 @@ typedef struct _is {
|
|||
|
||||
/* Used in Python/sysmodule.c. */
|
||||
int check_interval;
|
||||
PyObject *warnoptions;
|
||||
PyObject *xoptions;
|
||||
|
||||
/* Used in Modules/_threadmodule.c. */
|
||||
long num_threads;
|
||||
|
|
|
@ -29,20 +29,23 @@ _Py_GetRefTotal(void)
|
|||
return total;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
_PyDebug_XOptionShowRefCount(void)
|
||||
{
|
||||
PyObject *xoptions = PySys_GetXOptions();
|
||||
if (xoptions == NULL)
|
||||
return NULL;
|
||||
|
||||
_Py_IDENTIFIER(showrefcount);
|
||||
return _PyDict_GetItemId(xoptions, &PyId_showrefcount);
|
||||
}
|
||||
|
||||
void
|
||||
_PyDebug_PrintTotalRefs(void) {
|
||||
PyObject *xoptions, *value;
|
||||
_Py_IDENTIFIER(showrefcount);
|
||||
|
||||
xoptions = PySys_GetXOptions();
|
||||
if (xoptions == NULL)
|
||||
return;
|
||||
value = _PyDict_GetItemId(xoptions, &PyId_showrefcount);
|
||||
if (value == Py_True)
|
||||
fprintf(stderr,
|
||||
"[%" PY_FORMAT_SIZE_T "d refs, "
|
||||
"%" PY_FORMAT_SIZE_T "d blocks]\n",
|
||||
_Py_GetRefTotal(), _Py_GetAllocatedBlocks());
|
||||
fprintf(stderr,
|
||||
"[%" PY_FORMAT_SIZE_T "d refs, "
|
||||
"%" PY_FORMAT_SIZE_T "d blocks]\n",
|
||||
_Py_GetRefTotal(), _Py_GetAllocatedBlocks());
|
||||
}
|
||||
#endif /* Py_REF_DEBUG */
|
||||
|
||||
|
|
|
@ -1006,6 +1006,11 @@ Py_FinalizeEx(void)
|
|||
while (_PyGC_CollectIfEnabled() > 0)
|
||||
/* nothing */;
|
||||
#endif
|
||||
|
||||
#ifdef Py_REF_DEBUG
|
||||
PyObject *showrefcount = _PyDebug_XOptionShowRefCount();
|
||||
#endif
|
||||
|
||||
/* Destroy all modules */
|
||||
PyImport_Cleanup();
|
||||
|
||||
|
@ -1053,7 +1058,10 @@ Py_FinalizeEx(void)
|
|||
/* dump hash stats */
|
||||
_PyHash_Fini();
|
||||
|
||||
_PY_DEBUG_PRINT_TOTAL_REFS();
|
||||
#ifdef Py_REF_DEBUG
|
||||
if (showrefcount == Py_True)
|
||||
_PyDebug_PrintTotalRefs();
|
||||
#endif
|
||||
|
||||
#ifdef Py_TRACE_REFS
|
||||
/* Display all objects still alive -- this can invoke arbitrary
|
||||
|
|
|
@ -96,8 +96,6 @@ PyInterpreterState_New(void)
|
|||
interp->builtins_copy = NULL;
|
||||
interp->tstate_head = NULL;
|
||||
interp->check_interval = 100;
|
||||
interp->warnoptions = NULL;
|
||||
interp->xoptions = NULL;
|
||||
interp->num_threads = 0;
|
||||
interp->pythread_stacksize = 0;
|
||||
interp->codec_search_path = NULL;
|
||||
|
|
|
@ -113,7 +113,10 @@ PyRun_InteractiveLoopFlags(FILE *fp, const char *filename_str, PyCompilerFlags *
|
|||
err = -1;
|
||||
for (;;) {
|
||||
ret = PyRun_InteractiveOneObject(fp, filename, flags);
|
||||
_PY_DEBUG_PRINT_TOTAL_REFS();
|
||||
#ifdef Py_REF_DEBUG
|
||||
if (_PyDebug_XOptionShowRefCount() == Py_True)
|
||||
_PyDebug_PrintTotalRefs();
|
||||
#endif
|
||||
if (ret == E_EOF) {
|
||||
err = 0;
|
||||
break;
|
||||
|
|
|
@ -36,12 +36,14 @@ extern const char *PyWin_DLLVersionString;
|
|||
|
||||
_Py_IDENTIFIER(_);
|
||||
_Py_IDENTIFIER(__sizeof__);
|
||||
_Py_IDENTIFIER(_xoptions);
|
||||
_Py_IDENTIFIER(buffer);
|
||||
_Py_IDENTIFIER(builtins);
|
||||
_Py_IDENTIFIER(encoding);
|
||||
_Py_IDENTIFIER(path);
|
||||
_Py_IDENTIFIER(stdout);
|
||||
_Py_IDENTIFIER(stderr);
|
||||
_Py_IDENTIFIER(warnoptions);
|
||||
_Py_IDENTIFIER(write);
|
||||
|
||||
PyObject *
|
||||
|
@ -1479,13 +1481,17 @@ list_builtin_module_names(void)
|
|||
static PyObject *
|
||||
get_warnoptions(void)
|
||||
{
|
||||
PyObject *warnoptions = PyThreadState_GET()->interp->warnoptions;
|
||||
PyObject *warnoptions = _PySys_GetObjectId(&PyId_warnoptions);
|
||||
if (warnoptions == NULL || !PyList_Check(warnoptions)) {
|
||||
Py_XDECREF(warnoptions);
|
||||
warnoptions = PyList_New(0);
|
||||
if (warnoptions == NULL)
|
||||
return NULL;
|
||||
PyThreadState_GET()->interp->warnoptions = warnoptions;
|
||||
if (_PySys_SetObjectId(&PyId_warnoptions, warnoptions)) {
|
||||
Py_DECREF(warnoptions);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(warnoptions);
|
||||
}
|
||||
return warnoptions;
|
||||
}
|
||||
|
@ -1493,7 +1499,7 @@ get_warnoptions(void)
|
|||
void
|
||||
PySys_ResetWarnOptions(void)
|
||||
{
|
||||
PyObject *warnoptions = PyThreadState_GET()->interp->warnoptions;
|
||||
PyObject *warnoptions = _PySys_GetObjectId(&PyId_warnoptions);
|
||||
if (warnoptions == NULL || !PyList_Check(warnoptions))
|
||||
return;
|
||||
PyList_SetSlice(warnoptions, 0, PyList_GET_SIZE(warnoptions), NULL);
|
||||
|
@ -1522,20 +1528,24 @@ PySys_AddWarnOption(const wchar_t *s)
|
|||
int
|
||||
PySys_HasWarnOptions(void)
|
||||
{
|
||||
PyObject *warnoptions = PyThreadState_GET()->interp->warnoptions;
|
||||
PyObject *warnoptions = _PySys_GetObjectId(&PyId_warnoptions);
|
||||
return (warnoptions != NULL && (PyList_Size(warnoptions) > 0)) ? 1 : 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
get_xoptions(void)
|
||||
{
|
||||
PyObject *xoptions = PyThreadState_GET()->interp->xoptions;
|
||||
PyObject *xoptions = _PySys_GetObjectId(&PyId__xoptions);
|
||||
if (xoptions == NULL || !PyDict_Check(xoptions)) {
|
||||
Py_XDECREF(xoptions);
|
||||
xoptions = PyDict_New();
|
||||
if (xoptions == NULL)
|
||||
return NULL;
|
||||
PyThreadState_GET()->interp->xoptions = xoptions;
|
||||
if (_PySys_SetObjectId(&PyId__xoptions, xoptions)) {
|
||||
Py_DECREF(xoptions);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(xoptions);
|
||||
}
|
||||
return xoptions;
|
||||
}
|
||||
|
@ -2084,16 +2094,6 @@ _PySys_BeginInit(void)
|
|||
#undef SET_SYS_FROM_STRING_BORROW
|
||||
|
||||
/* Updating the sys namespace, returning integer error codes */
|
||||
#define SET_SYS_FROM_STRING_BORROW_INT_RESULT(key, value) \
|
||||
do { \
|
||||
PyObject *v = (value); \
|
||||
if (v == NULL) \
|
||||
return -1; \
|
||||
res = PyDict_SetItemString(sysdict, key, v); \
|
||||
if (res < 0) { \
|
||||
return res; \
|
||||
} \
|
||||
} while (0)
|
||||
#define SET_SYS_FROM_STRING_INT_RESULT(key, value) \
|
||||
do { \
|
||||
PyObject *v = (value); \
|
||||
|
@ -2138,15 +2138,11 @@ _PySys_EndInit(PyObject *sysdict)
|
|||
SET_SYS_FROM_STRING_INT_RESULT("base_exec_prefix",
|
||||
PyUnicode_FromWideChar(Py_GetExecPrefix(), -1));
|
||||
|
||||
PyObject *warnoptions = get_warnoptions();
|
||||
if (warnoptions == NULL)
|
||||
if (get_warnoptions() == NULL)
|
||||
return -1;
|
||||
SET_SYS_FROM_STRING_BORROW_INT_RESULT("warnoptions", warnoptions);
|
||||
|
||||
PyObject *xoptions = get_xoptions();
|
||||
if (xoptions == NULL)
|
||||
if (get_xoptions() == NULL)
|
||||
return -1;
|
||||
SET_SYS_FROM_STRING_BORROW_INT_RESULT("_xoptions", xoptions);
|
||||
|
||||
if (PyErr_Occurred())
|
||||
return -1;
|
||||
|
@ -2154,7 +2150,6 @@ _PySys_EndInit(PyObject *sysdict)
|
|||
}
|
||||
|
||||
#undef SET_SYS_FROM_STRING_INT_RESULT
|
||||
#undef SET_SYS_FROM_STRING_BORROW_INT_RESULT
|
||||
|
||||
static PyObject *
|
||||
makepathobject(const wchar_t *path, wchar_t delim)
|
||||
|
|
Loading…
Reference in New Issue