From b4efa62fad0ddc42eaafc8f2695689879e1556da Mon Sep 17 00:00:00 2001 From: rocky Date: Fri, 19 May 2017 07:13:20 -0400 Subject: [PATCH] EXTENDED_ARG handling... get_target() wasn't taking into account EXTENDED_ARG before opcode. This is mostly relevant in Python 3.6 where the max size before needing EXTENDED_ARG has been reduced to 256, but theoretically possible in earlier versions. --- uncompyle6/parsers/parse36.py | 2 ++ uncompyle6/scanners/scanner3.py | 21 +++++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/uncompyle6/parsers/parse36.py b/uncompyle6/parsers/parse36.py index 3856beef..b30ef1c2 100644 --- a/uncompyle6/parsers/parse36.py +++ b/uncompyle6/parsers/parse36.py @@ -61,6 +61,8 @@ class Python36Parser(Python35Parser): continue_stmt ::= EXTENDED_ARG CONTINUE_LOOP for_block ::= l_stmts_opt opt_come_from_loop jump_back + cmp_list1 ::= expr DUP_TOP ROT_THREE COMPARE_OP + EXTENDED_ARG JUMP_IF_FALSE_OR_POP cmp_list2 COME_FROM # 3.6 redoes how return_closure works diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 486f8068..846893e5 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -27,6 +27,7 @@ from array import array from uncompyle6.scanner import Scanner, op_has_argument from xdis.code import iscode +from xdis.util import code2num from xdis.bytecode import Bytecode from uncompyle6.scanner import Token, parse_fn_counts @@ -603,15 +604,27 @@ class Scanner3(Scanner): Get target offset for op located at given . """ op = self.code[offset] + rel_offset = 0 if self.version >= 3.6: target = self.code[offset+1] + arg_offset = 1 + extended_arg_mult = 1 << 8 if op in self.opc.hasjrel: - target += offset + 2 + rel_offset = offset + 2 else: target = self.code[offset+1] + self.code[offset+2] * 256 + arg_offset = 2 + extended_arg_mult = 1 << 16 if op in self.opc.hasjrel: - target += offset + 3 - + rel_offset = offset + 3 + pass + pass + target += rel_offset + prev_offset = self.prev_op[offset] + prev_op = code2num(self.code, prev_offset) + if prev_op == self.opc.EXTENDED_ARG: + target += (code2num(self.code, prev_offset + arg_offset) * extended_arg_mult) + pass return target def detect_control_flow(self, offset, targets): @@ -755,7 +768,7 @@ class Scanner3(Scanner): pre_rtarget = prev_op[rtarget] # Is it an "and" inside an "if" or "while" block - if op == self.opc.POP_JUMP_IF_FALSE: + if op == self.opc.POP_JUMP_IF_FALSE and self.version < 3.6: # Search for another POP_JUMP_IF_FALSE targetting the same op, # in current statement, starting from current offset, and filter