tracer: fix STORE_DEREF handling, add EXTENDED_ARG support.

This fixes the following issues:

- on Python 3.10 and earlier, storing to free variables is now handled
  correctly
- on Python 3.11, `_varname_from_oparg` is now used, fixing problems
  with cell variables that are also arguments
- on all supported versions, EXTENDED_ARG is now parsed, ensuring proper
  handling for long functions

Fixes #792.
This commit is contained in:
Marcelina Kościelnicka 2023-06-01 20:03:51 +02:00 committed by Catherine
parent 2a45d0e9ad
commit c343e879d3
2 changed files with 105 additions and 10 deletions

View file

@ -26,24 +26,40 @@ def get_var_name(depth=2, default=_raise_exception):
break
if call_opc not in ("CALL_FUNCTION", "CALL_FUNCTION_KW", "CALL_FUNCTION_EX",
"CALL_METHOD", "CALL"):
return default
if default is _raise_exception:
raise NameNotFound
else:
return default
index = call_index + 2
imm = 0
while True:
opc = opname[code.co_code[index]]
if opc in ("STORE_NAME", "STORE_ATTR"):
name_index = int(code.co_code[index + 1])
return code.co_names[name_index]
if opc == 'EXTENDED_ARG':
imm |= int(code.co_code[index + 1])
imm <<= 8
index += 2
elif opc in ("STORE_NAME", "STORE_ATTR"):
imm |= int(code.co_code[index + 1])
return code.co_names[imm]
elif opc == "STORE_FAST":
name_index = int(code.co_code[index + 1])
return code.co_varnames[name_index]
elif opc == "STORE_DEREF":
name_index = int(code.co_code[index + 1])
imm |= int(code.co_code[index + 1])
if sys.version_info >= (3, 11):
name_index -= code.co_nlocals
return code.co_cellvars[name_index]
return code._varname_from_oparg(imm)
else:
return code.co_varnames[imm]
elif opc == "STORE_DEREF":
imm |= int(code.co_code[index + 1])
if sys.version_info >= (3, 11):
return code._varname_from_oparg(imm)
else:
if imm < len(code.co_cellvars):
return code.co_cellvars[imm]
else:
return code.co_freevars[imm - len(code.co_cellvars)]
elif opc in ("LOAD_GLOBAL", "LOAD_NAME", "LOAD_ATTR", "LOAD_FAST", "LOAD_DEREF",
"DUP_TOP", "BUILD_LIST", "CACHE", "COPY"):
imm = 0
index += 2
else:
if default is _raise_exception: