You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 16:59:52 +08:00
Python 3.6 control flow bug...
Much more is needed, but it's a start
This commit is contained in:
BIN
test/bytecode_3.6/10_extended_arg_loop.pyc
Normal file
BIN
test/bytecode_3.6/10_extended_arg_loop.pyc
Normal file
Binary file not shown.
49
test/simple_source/bug36/10_extended_arg_loop.py
Normal file
49
test/simple_source/bug36/10_extended_arg_loop.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# Bug in 3.6 has to do with parsing jumps where
|
||||
# the offset is more than 256 bytes so an EXTENDED_ARG
|
||||
# instruction is inserted. find_jump_targets() and
|
||||
# detect_control_flow need to be able to work in the presence
|
||||
# of EXTENDED_ARG.
|
||||
|
||||
# This is a problem theoretically in Python before 3.6
|
||||
# but since offsets are very large it isn't noticed.
|
||||
|
||||
# Code is simplified from trepan2/trepan/cli.py
|
||||
import sys
|
||||
def main(dbg=None, sys_argv=list(sys.argv)):
|
||||
|
||||
if sys_argv:
|
||||
mainpyfile = None
|
||||
else:
|
||||
mainpyfile = "10"
|
||||
sys.path[0] = "20"
|
||||
|
||||
while True:
|
||||
try:
|
||||
if dbg.program_sys_argv and mainpyfile:
|
||||
normal_termination = dbg.run_script(mainpyfile)
|
||||
if not normal_termination: break
|
||||
else:
|
||||
dbg.core.execution_status = 'No program'
|
||||
dbg.core.processor.process_commands()
|
||||
pass
|
||||
|
||||
dbg.core.execution_status = 'Terminated'
|
||||
dbg.intf[-1].msg("The program finished - quit or restart")
|
||||
dbg.core.processor.process_commands()
|
||||
except IOError:
|
||||
break
|
||||
except RuntimeError:
|
||||
dbg.core.execution_status = 'Restart requested'
|
||||
if dbg.program_sys_argv:
|
||||
sys.argv = list(dbg.program_sys_argv)
|
||||
part1 = ('Restarting %s with arguments:' %
|
||||
dbg.core.filename(mainpyfile))
|
||||
args = ' '.join(dbg.program_sys_argv[1:])
|
||||
dbg.intf[-1].msg(args + part1)
|
||||
else: break
|
||||
except SystemExit:
|
||||
break
|
||||
pass
|
||||
|
||||
sys.argv = 5
|
||||
return
|
@@ -32,6 +32,11 @@ class Python36Parser(Python35Parser):
|
||||
|
||||
call_function ::= expr expr CALL_FUNCTION_EX
|
||||
call_function ::= expr expr expr CALL_FUNCTION_EX_KW_1
|
||||
|
||||
# This might be valid in < 3.6
|
||||
and ::= expr jmp_false expr
|
||||
|
||||
except_suite ::= c_stmts_opt COME_FROM POP_EXCEPT jump_except COME_FROM
|
||||
"""
|
||||
|
||||
def add_custom_rules(self, tokens, customize):
|
||||
|
@@ -213,7 +213,7 @@ class Scanner3(Scanner):
|
||||
# Get jump targets
|
||||
# Format: {target offset: [jump offsets]}
|
||||
jump_targets = self.find_jump_targets(show_asm)
|
||||
## print("XXX2", jump_targets)
|
||||
# print("XXX2", jump_targets)
|
||||
last_op_was_break = False
|
||||
|
||||
extended_arg = 0
|
||||
@@ -797,7 +797,7 @@ class Scanner3(Scanner):
|
||||
'end': prev_op[target]})
|
||||
return
|
||||
|
||||
# The op offset just before the target jump offset is important
|
||||
# The opcode *two* instructions before the target jump offset is important
|
||||
# in making a determination of what we have. Save that.
|
||||
pre_rtarget = prev_op[rtarget]
|
||||
|
||||
@@ -966,8 +966,16 @@ class Scanner3(Scanner):
|
||||
self.not_continue.add(pre_rtarget)
|
||||
else:
|
||||
# For now, we'll only tag forward jump.
|
||||
if rtarget > offset:
|
||||
self.fixed_jumps[offset] = rtarget
|
||||
if self.version >= 3.6:
|
||||
if target > offset:
|
||||
self.fixed_jumps[offset] = target
|
||||
pass
|
||||
else:
|
||||
# FIXME: This is probably a bug in < 3.6 and we should
|
||||
# instead use the above code. But until we smoke things
|
||||
# out we'll stick with it.
|
||||
if rtarget > offset:
|
||||
self.fixed_jumps[offset] = rtarget
|
||||
|
||||
elif op == self.opc.SETUP_EXCEPT:
|
||||
target = self.get_target(offset, extended_arg)
|
||||
|
Reference in New Issue
Block a user