From bfceeac6c8a3d55a91c76b5ac09939ea00f464f0 Mon Sep 17 00:00:00 2001 From: rocky Date: Sun, 27 Jan 2019 21:41:17 -0500 Subject: [PATCH] 2.7 can have two JUMP_BACKs at the end of a while loop Fixes #215 --- test/bytecode_2.7/05_while_elif.pyc | Bin 0 -> 528 bytes test/simple_source/bug27+/05_while_elif.py | 16 ++++++++++++++++ uncompyle6/parsers/parse27.py | 19 +++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 test/bytecode_2.7/05_while_elif.pyc create mode 100644 test/simple_source/bug27+/05_while_elif.py diff --git a/test/bytecode_2.7/05_while_elif.pyc b/test/bytecode_2.7/05_while_elif.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d79d9c817714c509a1ace813e55256375be14f62 GIT binary patch literal 528 zcmb78T}uK{5S{C;_JM}I1wn7YLXc5JFA;$c5y=u76cQ}!?r2x{tNTG33O)3X`vc8f z#Gc#BoIP`xnRC3K*6!Cdd`)2e3Hsks=@vl>@C`5|B47~INJ%_`1{F75DjgBbUtkHK zhKy4phrF=z;N63z08L0IYA_R^E?6w6^sp$8cFuM32qj08 z>?=8hWYJ|ZTg0O1shnY9_KA0`Qbc>Qz|iI+Q~@V8K7qz;Y`D80_oOzaNwkku7AKhU zykV2M*>mzlmc>AR;+>VLX>X)nyeO@^9*_nO^f56l^D4tgmsTa%8QIDC)k){%2^DhBwZUdiVu#32Z?C literal 0 HcmV?d00001 diff --git a/test/simple_source/bug27+/05_while_elif.py b/test/simple_source/bug27+/05_while_elif.py new file mode 100644 index 00000000..9ef7fbac --- /dev/null +++ b/test/simple_source/bug27+/05_while_elif.py @@ -0,0 +1,16 @@ +# Bug in Python 2.7. Bug is bytecode for while loop having +# two consecutive JUMP_BACKS at the end of 'elif' and 'while' +# to the same place +def PreprocessConditionalStatement(self, IfList, ReplacedLine): + while self: + if self.__Token: + x = 1 + elif not IfList: + if self <= 2: + continue + RegionSizeGuid = 3 + if not RegionSizeGuid: + RegionLayoutLine = 5 + continue + RegionLayoutLine = self.CurrentLineNumber + return 1 diff --git a/uncompyle6/parsers/parse27.py b/uncompyle6/parsers/parse27.py index b22d1f5a..004a0dff 100644 --- a/uncompyle6/parsers/parse27.py +++ b/uncompyle6/parsers/parse27.py @@ -156,7 +156,13 @@ class Python27Parser(Python2Parser): while1stmt ::= SETUP_LOOP returns bp_come_from while1stmt ::= SETUP_LOOP l_stmts_opt JUMP_BACK POP_BLOCK COME_FROM + whilestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK _come_froms + + # Should this be JUMP_BACK+ ? + # JUMP_BACK should all be to the same location + whilestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK JUMP_BACK POP_BLOCK _come_froms + while1elsestmt ::= SETUP_LOOP l_stmts JUMP_BACK POP_BLOCK else_suitel COME_FROM whileelsestmt ::= SETUP_LOOP testexpr l_stmts_opt JUMP_BACK POP_BLOCK @@ -211,14 +217,17 @@ class Python27Parser(Python2Parser): self.check_reduce['list_if_not'] = 'AST' self.check_reduce['list_if'] = 'AST' self.check_reduce['conditional_true'] = 'AST' + self.check_reduce['whilestmt'] = 'tokens' return def reduce_is_invalid(self, rule, ast, tokens, first, last): invalid = super(Python27Parser, self).reduce_is_invalid(rule, ast, tokens, first, last) + if invalid: return invalid + if rule == ('and', ('expr', 'jmp_false', 'expr', '\\e_come_from_opt')): # Test that jmp_false jumps to the end of "and" # or that it jumps to the same place as the end of "and" @@ -249,6 +258,16 @@ class Python27Parser(Python2Parser): jmp_target = jmp_true.offset + jmp_true.attr + 3 return not (jmp_target == tokens[last].offset or tokens[last].pattr == jmp_true.pattr) + + elif (rule[0] == 'whilestmt' and + rule[1][0:-2] == + ('SETUP_LOOP', 'testexpr', 'l_stmts_opt', + 'JUMP_BACK', 'JUMP_BACK')): + # Make sure that the jump backs all go to the same place + i = last-1 + while (tokens[i] != 'JUMP_BACK'): + i -= 1 + return tokens[i].attr != tokens[i-1].attr # elif rule[0] == ('conditional_true'): # # FIXME: the below is a hack: we check expr for # # nodes that could have possibly been a been a Boolean.