You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-02 16:44:46 +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_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_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
|
||||
ret_or ::= expr jmp_true ret_expr_or_cond come_froms
|
||||
|
@@ -393,14 +393,16 @@ class Scanner2(scan.Scanner):
|
||||
continue
|
||||
elif code[s] == self.opc.POP_TOP:
|
||||
# The POP_TOP in:
|
||||
# ROT_TWO, POP_TOP or
|
||||
# JUMP_IF_{FALSE,TRUE}, POP_TOP
|
||||
# ROT_TWO, 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
|
||||
# beginning of a new statement
|
||||
prev = code[self.prev[s]]
|
||||
if (prev == self.opc.ROT_TWO or
|
||||
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)
|
||||
continue
|
||||
elif code[s] in self.designator_ops:
|
||||
@@ -793,12 +795,11 @@ class Scanner2(scan.Scanner):
|
||||
|
||||
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.
|
||||
|
||||
This procedure is modelled after dis.findlabels(), but here
|
||||
for each target the number of jumps are counted.
|
||||
Return the list of offsets. An instruction can be jumped
|
||||
to in from multiple instructions.
|
||||
'''
|
||||
|
||||
n = len(self.code)
|
||||
@@ -836,7 +837,14 @@ class Scanner2(scan.Scanner):
|
||||
label = oparg
|
||||
|
||||
if label is not None and label != -1:
|
||||
targets[label] = targets.get(label, []) + [offset]
|
||||
# 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]
|
||||
elif op == self.opc.END_FINALLY and offset in self.fixed_jumps:
|
||||
label = self.fixed_jumps[offset]
|
||||
targets[label] = targets.get(label, []) + [offset]
|
||||
|
Reference in New Issue
Block a user