mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	[3.14] gh-135437: Account For Duplicate Names in _PyCode_SetUnboundVarCounts() (gh-135493)
(cherry picked from commit 56eabea, AKA gh-135438)
Co-authored-by: Eric Snow <ericsnowcurrently@gmail.com>
			
			
This commit is contained in:
		
							parent
							
								
									d851f8e258
								
							
						
					
					
						commit
						f77a911c52
					
				
					 3 changed files with 40 additions and 5 deletions
				
			
		|  | @ -57,6 +57,13 @@ def spam_with_globals_and_builtins(): | |||
|     print(res) | ||||
| 
 | ||||
| 
 | ||||
| def spam_with_global_and_attr_same_name(): | ||||
|     try: | ||||
|         spam_minimal.spam_minimal | ||||
|     except AttributeError: | ||||
|         pass | ||||
| 
 | ||||
| 
 | ||||
| def spam_full_args(a, b, /, c, d, *args, e, f, **kwargs): | ||||
|     return (a, b, c, d, e, f, args, kwargs) | ||||
| 
 | ||||
|  | @ -190,6 +197,7 @@ def ham_C_closure(z): | |||
|     spam_minimal, | ||||
|     spam_with_builtins, | ||||
|     spam_with_globals_and_builtins, | ||||
|     spam_with_global_and_attr_same_name, | ||||
|     spam_full_args, | ||||
|     spam_full_args_with_defaults, | ||||
|     spam_args_attrs_and_builtins, | ||||
|  | @ -258,6 +266,7 @@ def ham_C_closure(z): | |||
|     script_with_globals, | ||||
|     spam_full_args_with_defaults, | ||||
|     spam_with_globals_and_builtins, | ||||
|     spam_with_global_and_attr_same_name, | ||||
|     spam_full, | ||||
| ] | ||||
| 
 | ||||
|  | @ -275,6 +284,7 @@ def ham_C_closure(z): | |||
|     *PURE_SCRIPT_FUNCTIONS, | ||||
|     script_with_globals, | ||||
|     spam_with_globals_and_builtins, | ||||
|     spam_with_global_and_attr_same_name, | ||||
| ] | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -701,6 +701,7 @@ def test_local_kinds(self): | |||
|                 'checks': CO_FAST_LOCAL, | ||||
|                 'res': CO_FAST_LOCAL, | ||||
|             }, | ||||
|             defs.spam_with_global_and_attr_same_name: {}, | ||||
|             defs.spam_full_args: { | ||||
|                 'a': POSONLY, | ||||
|                 'b': POSONLY, | ||||
|  | @ -955,6 +956,10 @@ def new_var_counts(*, | |||
|                 purelocals=5, | ||||
|                 globalvars=6, | ||||
|             ), | ||||
|             defs.spam_with_global_and_attr_same_name: new_var_counts( | ||||
|                 globalvars=2, | ||||
|                 attrs=1, | ||||
|             ), | ||||
|             defs.spam_full_args: new_var_counts( | ||||
|                 posonly=2, | ||||
|                 posorkw=2, | ||||
|  |  | |||
|  | @ -1714,7 +1714,7 @@ static int | |||
| identify_unbound_names(PyThreadState *tstate, PyCodeObject *co, | ||||
|                        PyObject *globalnames, PyObject *attrnames, | ||||
|                        PyObject *globalsns, PyObject *builtinsns, | ||||
|                        struct co_unbound_counts *counts) | ||||
|                        struct co_unbound_counts *counts, int *p_numdupes) | ||||
| { | ||||
|     // This function is inspired by inspect.getclosurevars().
 | ||||
|     // It would be nicer if we had something similar to co_localspluskinds,
 | ||||
|  | @ -1729,6 +1729,7 @@ identify_unbound_names(PyThreadState *tstate, PyCodeObject *co, | |||
|     assert(builtinsns == NULL || PyDict_Check(builtinsns)); | ||||
|     assert(counts == NULL || counts->total == 0); | ||||
|     struct co_unbound_counts unbound = {0}; | ||||
|     int numdupes = 0; | ||||
|     Py_ssize_t len = Py_SIZE(co); | ||||
|     for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) { | ||||
|         _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(co, i); | ||||
|  | @ -1747,6 +1748,12 @@ identify_unbound_names(PyThreadState *tstate, PyCodeObject *co, | |||
|             if (PySet_Add(attrnames, name) < 0) { | ||||
|                 return -1; | ||||
|             } | ||||
|             if (PySet_Contains(globalnames, name)) { | ||||
|                 if (_PyErr_Occurred(tstate)) { | ||||
|                     return -1; | ||||
|                 } | ||||
|                 numdupes += 1; | ||||
|             } | ||||
|         } | ||||
|         else if (inst.op.code == LOAD_GLOBAL) { | ||||
|             int oparg = GET_OPARG(co, i, inst.op.arg); | ||||
|  | @ -1778,11 +1785,20 @@ identify_unbound_names(PyThreadState *tstate, PyCodeObject *co, | |||
|             if (PySet_Add(globalnames, name) < 0) { | ||||
|                 return -1; | ||||
|             } | ||||
|             if (PySet_Contains(attrnames, name)) { | ||||
|                 if (_PyErr_Occurred(tstate)) { | ||||
|                     return -1; | ||||
|                 } | ||||
|                 numdupes += 1; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     if (counts != NULL) { | ||||
|         *counts = unbound; | ||||
|     } | ||||
|     if (p_numdupes != NULL) { | ||||
|         *p_numdupes = numdupes; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
| 
 | ||||
|  | @ -1932,20 +1948,24 @@ _PyCode_SetUnboundVarCounts(PyThreadState *tstate, | |||
| 
 | ||||
|     // Fill in unbound.globals and unbound.numattrs.
 | ||||
|     struct co_unbound_counts unbound = {0}; | ||||
|     int numdupes = 0; | ||||
|     Py_BEGIN_CRITICAL_SECTION(co); | ||||
|     res = identify_unbound_names( | ||||
|             tstate, co, globalnames, attrnames, globalsns, builtinsns, | ||||
|             &unbound); | ||||
|             &unbound, &numdupes); | ||||
|     Py_END_CRITICAL_SECTION(); | ||||
|     if (res < 0) { | ||||
|         goto finally; | ||||
|     } | ||||
|     assert(unbound.numunknown == 0); | ||||
|     assert(unbound.total <= counts->unbound.total); | ||||
|     assert(unbound.total - numdupes <= counts->unbound.total); | ||||
|     assert(counts->unbound.numunknown == counts->unbound.total); | ||||
|     unbound.numunknown = counts->unbound.total - unbound.total; | ||||
|     unbound.total = counts->unbound.total; | ||||
|     // There may be a name that is both a global and an attr.
 | ||||
|     int totalunbound = counts->unbound.total + numdupes; | ||||
|     unbound.numunknown = totalunbound - unbound.total; | ||||
|     unbound.total = totalunbound; | ||||
|     counts->unbound = unbound; | ||||
|     counts->total += numdupes; | ||||
|     res = 0; | ||||
| 
 | ||||
| finally: | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Miss Islington (bot)
						Miss Islington (bot)