You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-04 01:09:52 +08:00
Python 2.6- bug: RETURN_ENDIF, POP_TOP ..
POP_TOP should be excluded as a potentional statement beginning
This commit is contained in:
BIN
test/bytecode_2.6/06_return_pop.pyc
Normal file
BIN
test/bytecode_2.6/06_return_pop.pyc
Normal file
Binary file not shown.
34
test/simple_source/bug26/06_return_pop.py
Normal file
34
test/simple_source/bug26/06_return_pop.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
# From python 2.6 StringIO.py
|
||||||
|
# Bug was turning emitting code like:
|
||||||
|
# if spos == slen:
|
||||||
|
# self.len = self.pos = spos + len(s)
|
||||||
|
# return None
|
||||||
|
# # wrong indent below
|
||||||
|
# if spos > slen:
|
||||||
|
# ...
|
||||||
|
# if self.buflist:
|
||||||
|
# # Invalid "and" below
|
||||||
|
# self.buflist and self.buf += ''.join(self.buflist)
|
||||||
|
#
|
||||||
|
# This was caused by POP_TOP in RETURN_VALUE, POP_TOP getting treated
|
||||||
|
# as the beginning of a statement
|
||||||
|
def write(self, s, spos):
|
||||||
|
if not s: return
|
||||||
|
# Force s to be a string or unicode
|
||||||
|
if not isinstance(s, basestring):
|
||||||
|
s = str(s)
|
||||||
|
slen = self.len
|
||||||
|
if spos == slen:
|
||||||
|
self.len = self.pos = spos + len(s)
|
||||||
|
return
|
||||||
|
if spos > slen:
|
||||||
|
slen = spos
|
||||||
|
newpos = spos + len(s)
|
||||||
|
if spos < slen:
|
||||||
|
if self.buflist:
|
||||||
|
self.buf += ''.join(self.buflist)
|
||||||
|
self.buflist = [self.buf[:spos], s, self.buf[newpos:]]
|
||||||
|
if newpos > slen:
|
||||||
|
slen = newpos
|
||||||
|
else:
|
||||||
|
self.buflist.append(s)
|
@@ -199,9 +199,12 @@ class Python26Parser(Python2Parser):
|
|||||||
'''
|
'''
|
||||||
ret_and ::= expr jmp_false ret_expr_or_cond COME_FROM
|
ret_and ::= expr jmp_false ret_expr_or_cond COME_FROM
|
||||||
ret_or ::= expr jmp_true ret_expr_or_cond COME_FROM
|
ret_or ::= expr jmp_true ret_expr_or_cond COME_FROM
|
||||||
ret_cond ::= expr jmp_false expr RETURN_END_IF come_from_pop ret_expr_or_cond
|
ret_cond ::= expr jmp_false expr RETURN_END_IF POP_TOP ret_expr_or_cond
|
||||||
ret_cond ::= expr jmp_false expr ret_expr_or_cond
|
ret_cond ::= expr jmp_false expr ret_expr_or_cond
|
||||||
ret_cond_not ::= expr jmp_true expr RETURN_END_IF come_from_pop ret_expr_or_cond
|
ret_cond_not ::= expr jmp_true expr RETURN_END_IF POP_TOP ret_expr_or_cond
|
||||||
|
|
||||||
|
return_if_stmt ::= ret_expr RETURN_END_IF POP_TOP
|
||||||
|
return_stmt ::= ret_expr RETURN_VALUE POP_TOP
|
||||||
|
|
||||||
# FIXME: split into Python 2.5
|
# FIXME: split into Python 2.5
|
||||||
ret_or ::= expr jmp_true ret_expr_or_cond come_froms
|
ret_or ::= expr jmp_true ret_expr_or_cond come_froms
|
||||||
|
@@ -393,14 +393,16 @@ class Scanner2(scan.Scanner):
|
|||||||
continue
|
continue
|
||||||
elif code[s] == self.opc.POP_TOP:
|
elif code[s] == self.opc.POP_TOP:
|
||||||
# The POP_TOP in:
|
# The POP_TOP in:
|
||||||
# ROT_TWO, POP_TOP or
|
# ROT_TWO, POP_TOP,
|
||||||
# JUMP_IF_{FALSE,TRUE}, POP_TOP
|
# RETURN_xxx, POP_TOP (in 2.6-), or
|
||||||
|
# JUMP_IF_{FALSE,TRUE}, POP_TOP (in 2.6-)
|
||||||
# is part of the previous instruction and not the
|
# is part of the previous instruction and not the
|
||||||
# beginning of a new statement
|
# beginning of a new statement
|
||||||
prev = code[self.prev[s]]
|
prev = code[self.prev[s]]
|
||||||
if (prev == self.opc.ROT_TWO or
|
if (prev == self.opc.ROT_TWO or
|
||||||
self.version <= 2.6 and prev in
|
self.version <= 2.6 and prev in
|
||||||
(self.opc.JUMP_IF_FALSE, self.opc.JUMP_IF_TRUE)):
|
(self.opc.JUMP_IF_FALSE, self.opc.JUMP_IF_TRUE,
|
||||||
|
self.opc.RETURN_VALUE)):
|
||||||
stmts.remove(s)
|
stmts.remove(s)
|
||||||
continue
|
continue
|
||||||
elif code[s] in self.designator_ops:
|
elif code[s] in self.designator_ops:
|
||||||
@@ -793,12 +795,11 @@ class Scanner2(scan.Scanner):
|
|||||||
|
|
||||||
def find_jump_targets(self):
|
def find_jump_targets(self):
|
||||||
'''
|
'''
|
||||||
Detect all offsets in a byte code which are jump targets.
|
Detect all offsets in a byte code which are jump targets
|
||||||
|
where we might insert a COME_FROM instruction.
|
||||||
|
|
||||||
Return the list of offsets.
|
Return the list of offsets. An instruction can be jumped
|
||||||
|
to in from multiple instructions.
|
||||||
This procedure is modelled after dis.findlabels(), but here
|
|
||||||
for each target the number of jumps are counted.
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
n = len(self.code)
|
n = len(self.code)
|
||||||
@@ -836,6 +837,13 @@ class Scanner2(scan.Scanner):
|
|||||||
label = oparg
|
label = oparg
|
||||||
|
|
||||||
if label is not None and label != -1:
|
if label is not None and label != -1:
|
||||||
|
# In Python <= 2.6, the POP_TOP in:
|
||||||
|
# RETURN_VALUE, POP_TOP
|
||||||
|
# does now start a new statement
|
||||||
|
# Otherwise, we have want to add a "COME_FROM"
|
||||||
|
if not (self.version <= 2.6 and
|
||||||
|
self.code[label] == self.opc.POP_TOP and
|
||||||
|
self.code[self.prev[label]] == self.opc.RETURN_VALUE):
|
||||||
targets[label] = targets.get(label, []) + [offset]
|
targets[label] = targets.get(label, []) + [offset]
|
||||||
elif op == self.opc.END_FINALLY and offset in self.fixed_jumps:
|
elif op == self.opc.END_FINALLY and offset in self.fixed_jumps:
|
||||||
label = self.fixed_jumps[offset]
|
label = self.fixed_jumps[offset]
|
||||||
|
Reference in New Issue
Block a user