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
 | ||||
|  * 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,16 +29,19 @@ _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", | ||||
|  |  | |||
|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Eric Snow
						Eric Snow