From ec69d0ed5575d10f6822165e2f2dfcadedecf241 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 11 Sep 2017 21:53:55 +0000 Subject: [PATCH 1/6] Drop warnoptions from PyInterpreterState. --- Include/pystate.h | 1 - Python/pystate.c | 1 - Python/sysmodule.c | 12 ++++++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Include/pystate.h b/Include/pystate.h index d986e35ae3b702..5c6b389d79a2e2 100644 --- a/Include/pystate.h +++ b/Include/pystate.h @@ -60,7 +60,6 @@ typedef struct _is { /* Used in Python/sysmodule.c. */ int check_interval; - PyObject *warnoptions; PyObject *xoptions; /* Used in Modules/_threadmodule.c. */ diff --git a/Python/pystate.c b/Python/pystate.c index be012d7d46a9e5..ba90539b2436c4 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -96,7 +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; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 3ecd7fca54ab8d..5f7fc1ea27e915 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -42,6 +42,7 @@ _Py_IDENTIFIER(encoding); _Py_IDENTIFIER(path); _Py_IDENTIFIER(stdout); _Py_IDENTIFIER(stderr); +_Py_IDENTIFIER(warnoptions); _Py_IDENTIFIER(write); PyObject * @@ -1479,13 +1480,16 @@ 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; + } } return warnoptions; } @@ -1493,7 +1497,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,7 +1526,7 @@ 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; } From 1c951caedf44af489a1274903724f7125b4271f1 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 11 Sep 2017 22:00:06 +0000 Subject: [PATCH 2/6] Drop xoptions from PyInterpreterState. --- Include/pystate.h | 1 - Python/pystate.c | 1 - Python/sysmodule.c | 8 ++++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Include/pystate.h b/Include/pystate.h index 5c6b389d79a2e2..5b75bb080fe8ec 100644 --- a/Include/pystate.h +++ b/Include/pystate.h @@ -60,7 +60,6 @@ typedef struct _is { /* Used in Python/sysmodule.c. */ int check_interval; - PyObject *xoptions; /* Used in Modules/_threadmodule.c. */ long num_threads; diff --git a/Python/pystate.c b/Python/pystate.c index ba90539b2436c4..08048428610dfd 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -96,7 +96,6 @@ PyInterpreterState_New(void) interp->builtins_copy = NULL; interp->tstate_head = NULL; interp->check_interval = 100; - interp->xoptions = NULL; interp->num_threads = 0; interp->pythread_stacksize = 0; interp->codec_search_path = NULL; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 5f7fc1ea27e915..39fde3e02b9cf3 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -36,6 +36,7 @@ extern const char *PyWin_DLLVersionString; _Py_IDENTIFIER(_); _Py_IDENTIFIER(__sizeof__); +_Py_IDENTIFIER(_xoptions); _Py_IDENTIFIER(buffer); _Py_IDENTIFIER(builtins); _Py_IDENTIFIER(encoding); @@ -1533,13 +1534,16 @@ PySys_HasWarnOptions(void) 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; + } } return xoptions; } From 006d9a06d0c1e4fb44ca98247c7b5e397b3a5069 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 11 Sep 2017 22:25:43 +0000 Subject: [PATCH 3/6] Don't set warnoptions and _xoptions again. --- Python/sysmodule.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 39fde3e02b9cf3..2867d8d8423f29 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2146,15 +2146,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; From d789ea6983ff7a7b5c2053545cd5db9261674bd1 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 11 Sep 2017 22:49:57 +0000 Subject: [PATCH 4/6] Decref after adding to sys.__dict__. --- Python/sysmodule.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 2867d8d8423f29..44b54e71044ca6 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -1491,6 +1491,7 @@ get_warnoptions(void) Py_DECREF(warnoptions); return NULL; } + Py_DECREF(warnoptions); } return warnoptions; } @@ -1544,6 +1545,7 @@ get_xoptions(void) Py_DECREF(xoptions); return NULL; } + Py_DECREF(xoptions); } return xoptions; } From 2207aeefbe7ddeb8aff2e985019c3e641f2e9956 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Mon, 11 Sep 2017 22:51:21 +0000 Subject: [PATCH 5/6] Drop an unused macro. --- Python/sysmodule.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 44b54e71044ca6..5bde4b7b7028f7 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2094,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); \ @@ -2160,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) From fd6830a7b68a12a9222d2c9438c1990d1f9b45b9 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 12 Sep 2017 00:23:57 +0000 Subject: [PATCH 6/6] Check sys.xoptions *before* we delete it. --- Include/object.h | 3 +-- Objects/object.c | 27 +++++++++++++++------------ Python/pylifecycle.c | 10 +++++++++- Python/pythonrun.c | 5 ++++- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/Include/object.h b/Include/object.h index b46d4c30e1e964..9bb780e28bcca1 100644 --- a/Include/object.h +++ b/Include/object.h @@ -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 diff --git a/Objects/object.c b/Objects/object.c index 74893e38c717fd..ed8a62a163aa65 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -29,20 +29,23 @@ _Py_GetRefTotal(void) return total; } -void -_PyDebug_PrintTotalRefs(void) { - PyObject *xoptions, *value; +PyObject * +_PyDebug_XOptionShowRefCount(void) +{ + PyObject *xoptions = PySys_GetXOptions(); + if (xoptions == NULL) + return NULL; + _Py_IDENTIFIER(showrefcount); + return _PyDict_GetItemId(xoptions, &PyId_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()); +void +_PyDebug_PrintTotalRefs(void) { + fprintf(stderr, + "[%" PY_FORMAT_SIZE_T "d refs, " + "%" PY_FORMAT_SIZE_T "d blocks]\n", + _Py_GetRefTotal(), _Py_GetAllocatedBlocks()); } #endif /* Py_REF_DEBUG */ diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index caa324e3afa250..3265d701810621 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -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 diff --git a/Python/pythonrun.c b/Python/pythonrun.c index d1d4a69a8dd8f6..df814fbed97b30 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -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;