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