Python 3.4 assertion handling. Improve verify

3.4 has jump optimization like 3.5.
verify.py: show mismatch on verification mismatch
This commit is contained in:
rocky
2016-07-14 05:19:16 -04:00
parent 1e25ffa879
commit 7b7a9fa4cf
10 changed files with 35 additions and 10 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -148,6 +148,7 @@ def main(in_base, out_base, files, codes, outfile=None,
else: else:
print('\n# %s\n\t%s', infile, msg) print('\n# %s\n\t%s', infile, msg)
except verify.VerifyCmpError as e: except verify.VerifyCmpError as e:
print(e)
verify_failed_files += 1 verify_failed_files += 1
os.rename(outfile, outfile + '_unverified') os.rename(outfile, outfile + '_unverified')
if not outfile: if not outfile:

View File

@@ -247,7 +247,7 @@ class Python3Parser(PythonParser):
''' '''
def p_misc(self, args): def p_misc3(self, args):
""" """
try_middle ::= JUMP_FORWARD COME_FROM except_stmts END_FINALLY NOP COME_FROM try_middle ::= JUMP_FORWARD COME_FROM except_stmts END_FINALLY NOP COME_FROM
""" """
@@ -288,7 +288,6 @@ class Python3Parser(PythonParser):
def p_expr3(self, args): def p_expr3(self, args):
''' '''
expr ::= LOAD_CLASSNAME expr ::= LOAD_CLASSNAME
expr ::= LOAD_ASSERT
# Python 3.4+ # Python 3.4+
expr ::= LOAD_CLASSDEREF expr ::= LOAD_CLASSDEREF
@@ -615,7 +614,7 @@ class Python35onParser(Python3Parser):
expr ::= yield_from expr ::= yield_from
yield_from ::= expr GET_YIELD_FROM_ITER LOAD_CONST YIELD_FROM yield_from ::= expr GET_YIELD_FROM_ITER LOAD_CONST YIELD_FROM
# Python 3.5 has more loop optimization that removes # Python 3.4+ has more loop optimization that removes
# JUMP_FORWARD in some cases, and hence we also don't # JUMP_FORWARD in some cases, and hence we also don't
# see COME_FROM # see COME_FROM
_ifstmts_jump ::= c_stmts_opt _ifstmts_jump ::= c_stmts_opt

View File

@@ -37,6 +37,10 @@ class Python34Parser(Python3Parser):
# Is this 3.4 only? # Is this 3.4 only?
yield_from ::= expr GET_ITER LOAD_CONST YIELD_FROM yield_from ::= expr GET_ITER LOAD_CONST YIELD_FROM
# Python 3.4+ has more loop optimization that removes
# JUMP_FORWARD in some cases, and hence we also don't
# see COME_FROM
_ifstmts_jump ::= c_stmts_opt
""" """
class Python34ParserSingle(Python34Parser, PythonParserSingle): class Python34ParserSingle(Python34Parser, PythonParserSingle):
pass pass

View File

@@ -89,8 +89,14 @@ class Scanner2(scan.Scanner):
varnames = co.co_varnames varnames = co.co_varnames
self.names = names self.names = names
# Scan for assertions. Later we will
# turn 'LOAD_GLOBAL' to 'LOAD_ASSERT'.
# 'LOAD_ASSERT' is used in assert statements.
self.load_asserts = set() self.load_asserts = set()
for i in self.op_range(0, n): for i in self.op_range(0, n):
# We need to detect the difference between
# "raise AssertionError" and
# "assert"
if self.code[i] == self.opc.PJIT and self.code[i+3] == self.opc.LOAD_GLOBAL: if self.code[i] == self.opc.PJIT and self.code[i+3] == self.opc.LOAD_GLOBAL:
if names[self.get_argument(i+3)] == 'AssertionError': if names[self.get_argument(i+3)] == 'AssertionError':
self.load_asserts.add(i+3) self.load_asserts.add(i+3)

View File

@@ -125,8 +125,14 @@ class Scanner26(scan.Scanner2):
codelen = len(self.code) codelen = len(self.code)
# Scan for assertions. Later we will
# turn 'LOAD_GLOBAL' to 'LOAD_ASSERT'.
# 'LOAD_ASSERT' is used in assert statements.
self.load_asserts = set() self.load_asserts = set()
for i in self.op_range(0, n): for i in self.op_range(0, n):
# We need to detect the difference between
# "raise AssertionError" and
# "assert"
if (self.code[i] == self.opc.JUMP_IF_TRUE and if (self.code[i] == self.opc.JUMP_IF_TRUE and
i + 4 < codelen and i + 4 < codelen and
self.code[i+3] == self.opc.POP_TOP and self.code[i+3] == self.opc.POP_TOP and

View File

@@ -134,16 +134,19 @@ class Scanner3(scan.Scanner):
bytecode = Bytecode(co, self.opc) bytecode = Bytecode(co, self.opc)
# Scan for assertions. Later we will # Scan for assertions. Later we will
# turn 'LOAD_GLOBAL' to 'LOAD_ASSERT' for those # turn 'LOAD_GLOBAL' to 'LOAD_ASSERT'.
# assertions # 'LOAD_ASSERT' is used in assert statements.
self.load_asserts = set() self.load_asserts = set()
bs = list(bytecode) bs = list(bytecode)
n = len(bs) n = len(bs)
for i in range(n): for i in range(n):
inst = bs[i] inst = bs[i]
if inst.opname == 'POP_JUMP_IF_TRUE' and i+1 < n: # We need to detect the difference between
next_inst = bs[i+1] # "raise AssertionError" and
# "assert"
if inst.opname == 'POP_JUMP_IF_TRUE' and i+3 < n:
next_inst = bs[i+3]
if (next_inst.opname == 'LOAD_GLOBAL' and if (next_inst.opname == 'LOAD_GLOBAL' and
next_inst.argval == 'AssertionError'): next_inst.argval == 'AssertionError'):
self.load_asserts.add(next_inst.offset) self.load_asserts.add(next_inst.offset)

View File

@@ -180,7 +180,13 @@ def cmp_code_objects(version, code_obj1, code_obj2, name=''):
if member in __IGNORE_CODE_MEMBERS__: if member in __IGNORE_CODE_MEMBERS__:
pass pass
elif member == 'co_code': elif member == 'co_code':
if version == 2.5: if version == 2.3:
import uncompyle6.scanners.scanner23 as scan
scanner = scan.Scanner26()
elif version == 2.4:
import uncompyle6.scanners.scanner24 as scan
scanner = scan.Scanner25()
elif version == 2.5:
import uncompyle6.scanners.scanner25 as scan import uncompyle6.scanners.scanner25 as scan
scanner = scan.Scanner25() scanner = scan.Scanner25()
elif version == 2.6: elif version == 2.6:
@@ -206,8 +212,8 @@ def cmp_code_objects(version, code_obj1, code_obj2, name=''):
JUMP_OPs = list(scan.JUMP_OPs) + ['JUMP_BACK'] JUMP_OPs = list(scan.JUMP_OPs) + ['JUMP_BACK']
# use changed Token class # use changed Token class
# We (re)set this here to save exception handling, # We (re)set this here to save exception handling,
# which would get confusing. # which would get confusing.
scanner.setTokenClass(Token) scanner.setTokenClass(Token)
try: try:
# disassemble both code-objects # disassemble both code-objects