Fix if return boundary in 3.6+

Fixes #209
This commit is contained in:
rocky
2019-03-10 05:59:15 -04:00
parent bfceeac6c8
commit dcad6cf6ce
10 changed files with 43 additions and 21 deletions

View File

@@ -57,7 +57,7 @@ entry_points = {
]}
ftp_url = None
install_requires = ['spark-parser >= 1.8.7, < 1.9.0',
'xdis >= 3.8.9, < 3.9.0']
'xdis >= 3.8.10, < 3.9.0']
license = 'GPL3'
mailing_list = 'python-debugger@googlegroups.com'

Binary file not shown.

View File

@@ -0,0 +1,10 @@
# Bug in 3.6 and above.
#Not detecting 2nd return is outside of
# if/then. Fix was to ensure COME_FROM
def return_return_bug(foo):
if foo =='say_hello':
return "hello"
return "world"
assert return_return_bug('say_hello') == 'hello'
assert return_return_bug('world') == 'world'

View File

@@ -3,7 +3,7 @@
[flake8]
exclude = .tox,./build,./trepan/processor/command/tmp
filename = *.py
ignore = C901,E113,E121,E122,E123,E124,E125,E126,E127,E128,E129,E201,E202,E203,E221,E222,E225,E226,E241,E242,E251,E261,E271,E272,E302,E401,E501,F401,E701,E702
ignore = C901,E113,E121,E122,E123,E124,E125,E126,E127,E128,E129,E201,E202,E203,E221,E222,E225,E226,E241,E242,E251,E261,E271,E272,E302,E401,E402,E501,F401,E701,E702
[tox]
envlist = py27, py34, pypy

View File

@@ -1,4 +1,4 @@
# Copyright (c) 2015-2016, 2818 by Rocky Bernstein
# Copyright (c) 2015-2016, 2818-2019 by Rocky Bernstein
# Copyright (c) 2005 by Dan Pascu <dan@windowmaker.org>
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
# Copyright (c) 1999 John Aycock
@@ -77,18 +77,18 @@ def disco_loop(disasm, queue, real_out):
pass
pass
def disassemble_fp(fp, outstream=None):
"""
disassemble Python byte-code from an open file
"""
(version, timestamp, magic_int, co, is_pypy,
source_size) = load_from_fp(fp)
if type(co) == list:
for con in co:
disco(version, con, outstream)
else:
disco(version, co, outstream, is_pypy=is_pypy)
co = None
# def disassemble_fp(fp, outstream=None):
# """
# disassemble Python byte-code from an open file
# """
# (version, timestamp, magic_int, co, is_pypy,
# source_size) = load_from_fp(fp)
# if type(co) == list:
# for con in co:
# disco(version, con, outstream)
# else:
# disco(version, co, outstream, is_pypy=is_pypy)
# co = None
def disassemble_file(filename, outstream=None):
"""
@@ -120,5 +120,6 @@ def _test():
fn = sys.argv[1]
disassemble_file(fn)
if __name__ == "__main__":
_test()

View File

@@ -37,7 +37,9 @@ class ParserError(Exception):
return "Parse error at or near `%r' instruction at offset %s\n" % \
(self.token, self.offset)
nop_func = lambda self, args: None
def nop_func(self, args):
return None
class PythonParser(GenericASTBuilder):
@@ -792,6 +794,7 @@ def python_parser(version, co, out=sys.stdout, showasm=False,
p = get_python_parser(version, parser_debug)
return parse(p, tokens, customize)
if __name__ == '__main__':
def parse_test(co):
from uncompyle6 import PYTHON_VERSION, IS_PYPY

View File

@@ -309,7 +309,7 @@ class Python3Parser(PythonParser):
# FIXME: Common with 2.7
ret_and ::= expr JUMP_IF_FALSE_OR_POP ret_expr_or_cond COME_FROM
ret_or ::= expr JUMP_IF_TRUE_OR_POP ret_expr_or_cond COME_FROM
ret_cond ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF ret_expr_or_cond
ret_cond ::= expr POP_JUMP_IF_FALSE expr RETURN_END_IF COME_FROM ret_expr_or_cond
or ::= expr JUMP_IF_TRUE_OR_POP expr COME_FROM
and ::= expr JUMP_IF_FALSE_OR_POP expr COME_FROM
@@ -583,7 +583,6 @@ class Python3Parser(PythonParser):
stmt ::= assign2_pypy
assign3_pypy ::= expr expr expr store store store
assign2_pypy ::= expr expr store store
return_if_lambda ::= RETURN_END_IF_LAMBDA
stmt ::= conditional_lambda
stmt ::= conditional_not_lambda
conditional_lambda ::= expr jmp_false expr return_if_lambda

View File

@@ -46,6 +46,10 @@ class Python36Parser(Python35Parser):
# RETURN_VALUE is meant. Specifcally this can happen in
# ifelsestmt -> ...else_suite _. suite_stmts... (last) stmt
return ::= ret_expr RETURN_END_IF
return ::= ret_expr RETURN_VALUE COME_FROM
return_stmt_lambda ::= ret_expr RETURN_VALUE_LAMBDA COME_FROM
return_if_lambda ::= RETURN_END_IF_LAMBDA COME_FROM
# A COME_FROM is dropped off because of JUMP-to-JUMP optimization
and ::= expr jmp_false expr

View File

@@ -351,9 +351,9 @@ class Scanner(object):
return result
# FIXME: this is broken on 3.6+. Replace remaining (2.x-based) calls
# with inst_matches
def all_instr(self, start, end, instr, target=None, include_beyond_target=False):
"""
Find all `instr` in the block from start to end.
@@ -423,8 +423,8 @@ class Scanner(object):
last_was_extarg = False
n = len(instructions)
for i, inst in enumerate(instructions):
if (inst.opname == 'EXTENDED_ARG' and
i+1 < n and instructions[i+1].opname != 'MAKE_FUNCTION'):
if (inst.opname == 'EXTENDED_ARG'
and i+1 < n and instructions[i+1].opname != 'MAKE_FUNCTION'):
last_was_extarg = True
starts_line = inst.starts_line
is_jump_target = inst.is_jump_target
@@ -527,6 +527,7 @@ def get_scanner(version, is_pypy=False, show_asm=None):
raise RuntimeError("Unsupported Python version %s" % version)
return scanner
if __name__ == "__main__":
import inspect, uncompyle6
co = inspect.currentframe().f_code

View File

@@ -920,6 +920,10 @@ class Scanner3(Scanner):
return
pass
pass
if self.version >= 3.4:
self.fixed_jumps[offset] = rtarget
if code[pre_rtarget] == self.opc.RETURN_VALUE:
# If we are at some sort of POP_JUMP_IF and the instruction before was
# COMPARE_OP exception-match, then pre_rtarget is not an end_if