From 0fce4c6dc3b9cf02c9cfd663a8640a4871224541 Mon Sep 17 00:00:00 2001 From: rocky Date: Wed, 7 Sep 2016 04:03:21 -0400 Subject: [PATCH] Another 3.5+ erroneous RETURN_END_IF misclassify --- test/bytecode_3.5/05_return_in_else.pyc | Bin 344 -> 528 bytes test/simple_source/bug35/05_return_in_else.py | 12 +++++ uncompyle6/scanners/scanner3.py | 42 +++++++++++------- 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/test/bytecode_3.5/05_return_in_else.pyc b/test/bytecode_3.5/05_return_in_else.pyc index fe34b1017df03b4da5627898f3bcf5965c226d23..5a4498ce082aa785351d453eed4ddcfadbb3fd2e 100644 GIT binary patch delta 264 zcmYjLyKcfj5S%?bHZP;lP*EdYgVG>TMuM8g1(Kx*SsWmcG2~26 zA0U5_IjZd5%+5Y_KkDR<+EG-yoiCHA0#&|I0$TrJz%w~u6aW6DUjFD^#n>_ldTExG zLAu+`bE8!fnC&KA<%yrA`O;Q7>#|%h-3CMN;;$i_Hkpe`F3@r={Q9uS0L$D_EM3;}O SewvI$+>@U$s<8l-FaQ7v+6>wN diff --git a/test/simple_source/bug35/05_return_in_else.py b/test/simple_source/bug35/05_return_in_else.py index 0bb3d0c2..9c7ca13c 100644 --- a/test/simple_source/bug35/05_return_in_else.py +++ b/test/simple_source/bug35/05_return_in_else.py @@ -10,3 +10,15 @@ def parseline(self, line): else: return 3 if line[3] else 4 return 6 + +# From 3.5 gettext.py +# In the below code, the "return" was erroneously +# classifying RETURN_END_IF instead of RETURN_VALUE +def find(domain): + for lang in domain: + if lang: + if all: + domain.append(5) + else: + return lang + return domain diff --git a/uncompyle6/scanners/scanner3.py b/uncompyle6/scanners/scanner3.py index 89b639d0..77f9a824 100644 --- a/uncompyle6/scanners/scanner3.py +++ b/uncompyle6/scanners/scanner3.py @@ -779,21 +779,33 @@ class Scanner3(Scanner): self.fixed_jumps[offset] = unop_target else: self.fixed_jumps[offset] = self.restrict_to_parent(target, parent) - elif op == self.opc.JUMP_FORWARD and self.version >= 3.5: - # If we have: - # JUMP_FORWARD x, [non-jump, insns], RETURN_VALUE, x: - # then RETURN_VALUE is probably not RETURN_END_IF - rtarget = self.get_target(offset) - rtarget_prev = self.prev[rtarget] - if (code[rtarget_prev] == self.opc.RETURN_VALUE and - rtarget_prev in self.return_end_ifs): - i = rtarget_prev - while i != offset: - if code[i] in [op3.JUMP_FORWARD, op3.JUMP_ABSOLUTE]: - return - i = self.prev[i] - self.return_end_ifs.remove(rtarget_prev) - pass + pass + pass + elif self.version >= 3.5: + # 3.5+ has Jump optimization which too often causes RETURN_VALUE to get + # misclassified as RETURN_END_IF. Handle that here. + # In RETURN_VALUE, JUMP_ABSOLUTE, RETURN_VALUE is never RETURN_END_IF + if op == self.opc.RETURN_VALUE: + if (offset+1 < len(code) and code[offset+1] == self.opc.JUMP_ABSOLUTE and + offset in self.return_end_ifs): + self.return_end_ifs.remove(offset) + pass + pass + elif op == self.opc.JUMP_FORWARD: + # If we have: + # JUMP_FORWARD x, [non-jump, insns], RETURN_VALUE, x: + # then RETURN_VALUE is not RETURN_END_IF + rtarget = self.get_target(offset) + rtarget_prev = self.prev[rtarget] + if (code[rtarget_prev] == self.opc.RETURN_VALUE and + rtarget_prev in self.return_end_ifs): + i = rtarget_prev + while i != offset: + if code[i] in [op3.JUMP_FORWARD, op3.JUMP_ABSOLUTE]: + return + i = self.prev[i] + self.return_end_ifs.remove(rtarget_prev) + pass return def next_except_jump(self, start):