mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +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) |     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): | def spam_full_args(a, b, /, c, d, *args, e, f, **kwargs): | ||||||
|     return (a, b, c, d, e, f, args, kwargs) |     return (a, b, c, d, e, f, args, kwargs) | ||||||
| 
 | 
 | ||||||
|  | @ -190,6 +197,7 @@ def ham_C_closure(z): | ||||||
|     spam_minimal, |     spam_minimal, | ||||||
|     spam_with_builtins, |     spam_with_builtins, | ||||||
|     spam_with_globals_and_builtins, |     spam_with_globals_and_builtins, | ||||||
|  |     spam_with_global_and_attr_same_name, | ||||||
|     spam_full_args, |     spam_full_args, | ||||||
|     spam_full_args_with_defaults, |     spam_full_args_with_defaults, | ||||||
|     spam_args_attrs_and_builtins, |     spam_args_attrs_and_builtins, | ||||||
|  | @ -258,6 +266,7 @@ def ham_C_closure(z): | ||||||
|     script_with_globals, |     script_with_globals, | ||||||
|     spam_full_args_with_defaults, |     spam_full_args_with_defaults, | ||||||
|     spam_with_globals_and_builtins, |     spam_with_globals_and_builtins, | ||||||
|  |     spam_with_global_and_attr_same_name, | ||||||
|     spam_full, |     spam_full, | ||||||
| ] | ] | ||||||
| 
 | 
 | ||||||
|  | @ -275,6 +284,7 @@ def ham_C_closure(z): | ||||||
|     *PURE_SCRIPT_FUNCTIONS, |     *PURE_SCRIPT_FUNCTIONS, | ||||||
|     script_with_globals, |     script_with_globals, | ||||||
|     spam_with_globals_and_builtins, |     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, |                 'checks': CO_FAST_LOCAL, | ||||||
|                 'res': CO_FAST_LOCAL, |                 'res': CO_FAST_LOCAL, | ||||||
|             }, |             }, | ||||||
|  |             defs.spam_with_global_and_attr_same_name: {}, | ||||||
|             defs.spam_full_args: { |             defs.spam_full_args: { | ||||||
|                 'a': POSONLY, |                 'a': POSONLY, | ||||||
|                 'b': POSONLY, |                 'b': POSONLY, | ||||||
|  | @ -955,6 +956,10 @@ def new_var_counts(*, | ||||||
|                 purelocals=5, |                 purelocals=5, | ||||||
|                 globalvars=6, |                 globalvars=6, | ||||||
|             ), |             ), | ||||||
|  |             defs.spam_with_global_and_attr_same_name: new_var_counts( | ||||||
|  |                 globalvars=2, | ||||||
|  |                 attrs=1, | ||||||
|  |             ), | ||||||
|             defs.spam_full_args: new_var_counts( |             defs.spam_full_args: new_var_counts( | ||||||
|                 posonly=2, |                 posonly=2, | ||||||
|                 posorkw=2, |                 posorkw=2, | ||||||
|  |  | ||||||
|  | @ -1714,7 +1714,7 @@ static int | ||||||
| identify_unbound_names(PyThreadState *tstate, PyCodeObject *co, | identify_unbound_names(PyThreadState *tstate, PyCodeObject *co, | ||||||
|                        PyObject *globalnames, PyObject *attrnames, |                        PyObject *globalnames, PyObject *attrnames, | ||||||
|                        PyObject *globalsns, PyObject *builtinsns, |                        PyObject *globalsns, PyObject *builtinsns, | ||||||
|                        struct co_unbound_counts *counts) |                        struct co_unbound_counts *counts, int *p_numdupes) | ||||||
| { | { | ||||||
|     // This function is inspired by inspect.getclosurevars().
 |     // This function is inspired by inspect.getclosurevars().
 | ||||||
|     // It would be nicer if we had something similar to co_localspluskinds,
 |     // 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(builtinsns == NULL || PyDict_Check(builtinsns)); | ||||||
|     assert(counts == NULL || counts->total == 0); |     assert(counts == NULL || counts->total == 0); | ||||||
|     struct co_unbound_counts unbound = {0}; |     struct co_unbound_counts unbound = {0}; | ||||||
|  |     int numdupes = 0; | ||||||
|     Py_ssize_t len = Py_SIZE(co); |     Py_ssize_t len = Py_SIZE(co); | ||||||
|     for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) { |     for (int i = 0; i < len; i += _PyInstruction_GetLength(co, i)) { | ||||||
|         _Py_CODEUNIT inst = _Py_GetBaseCodeUnit(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) { |             if (PySet_Add(attrnames, name) < 0) { | ||||||
|                 return -1; |                 return -1; | ||||||
|             } |             } | ||||||
|  |             if (PySet_Contains(globalnames, name)) { | ||||||
|  |                 if (_PyErr_Occurred(tstate)) { | ||||||
|  |                     return -1; | ||||||
|  |                 } | ||||||
|  |                 numdupes += 1; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         else if (inst.op.code == LOAD_GLOBAL) { |         else if (inst.op.code == LOAD_GLOBAL) { | ||||||
|             int oparg = GET_OPARG(co, i, inst.op.arg); |             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) { |             if (PySet_Add(globalnames, name) < 0) { | ||||||
|                 return -1; |                 return -1; | ||||||
|             } |             } | ||||||
|  |             if (PySet_Contains(attrnames, name)) { | ||||||
|  |                 if (_PyErr_Occurred(tstate)) { | ||||||
|  |                     return -1; | ||||||
|  |                 } | ||||||
|  |                 numdupes += 1; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     if (counts != NULL) { |     if (counts != NULL) { | ||||||
|         *counts = unbound; |         *counts = unbound; | ||||||
|     } |     } | ||||||
|  |     if (p_numdupes != NULL) { | ||||||
|  |         *p_numdupes = numdupes; | ||||||
|  |     } | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1932,20 +1948,24 @@ _PyCode_SetUnboundVarCounts(PyThreadState *tstate, | ||||||
| 
 | 
 | ||||||
|     // Fill in unbound.globals and unbound.numattrs.
 |     // Fill in unbound.globals and unbound.numattrs.
 | ||||||
|     struct co_unbound_counts unbound = {0}; |     struct co_unbound_counts unbound = {0}; | ||||||
|  |     int numdupes = 0; | ||||||
|     Py_BEGIN_CRITICAL_SECTION(co); |     Py_BEGIN_CRITICAL_SECTION(co); | ||||||
|     res = identify_unbound_names( |     res = identify_unbound_names( | ||||||
|             tstate, co, globalnames, attrnames, globalsns, builtinsns, |             tstate, co, globalnames, attrnames, globalsns, builtinsns, | ||||||
|             &unbound); |             &unbound, &numdupes); | ||||||
|     Py_END_CRITICAL_SECTION(); |     Py_END_CRITICAL_SECTION(); | ||||||
|     if (res < 0) { |     if (res < 0) { | ||||||
|         goto finally; |         goto finally; | ||||||
|     } |     } | ||||||
|     assert(unbound.numunknown == 0); |     assert(unbound.numunknown == 0); | ||||||
|     assert(unbound.total <= counts->unbound.total); |     assert(unbound.total - numdupes <= counts->unbound.total); | ||||||
|     assert(counts->unbound.numunknown == counts->unbound.total); |     assert(counts->unbound.numunknown == counts->unbound.total); | ||||||
|     unbound.numunknown = counts->unbound.total - unbound.total; |     // There may be a name that is both a global and an attr.
 | ||||||
|     unbound.total = counts->unbound.total; |     int totalunbound = counts->unbound.total + numdupes; | ||||||
|  |     unbound.numunknown = totalunbound - unbound.total; | ||||||
|  |     unbound.total = totalunbound; | ||||||
|     counts->unbound = unbound; |     counts->unbound = unbound; | ||||||
|  |     counts->total += numdupes; | ||||||
|     res = 0; |     res = 0; | ||||||
| 
 | 
 | ||||||
| finally: | finally: | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Miss Islington (bot)
						Miss Islington (bot)