Unsupported opcode: SWAP
Hi, I tried using this tool to help a friend with a .pyc file that was written in Python 3.11.4 and I got an error that about the SWAP opcode being unsupported.
I found a suggestion here to try and comment out a line in ASTree.cpp to make the decompiler not stop the moment it sees an unsupported opcode, but that gives me a "bad cast" error instead.
What can I do?
attach your sample for the beginning :)
attach your sample for the beginning :)
unfortunately for the sake of my friend's privacy, I don't think I can do so, sucks.
well, then the only option is to sit and wait... or try to do PR and fix! :)
Source Generated with Decompyle++
File: test.pyc (Python 3.11)
def a(): Unsupported opcode: SWAP pass
WARNING: Decompyle incomplete
SWAP demo
def a(): for dir in "": path = dir return path pass dis.dis(a)
26 0 RESUME 0
27 2 LOAD_CONST 1 ('') 4 GET_ITER 6 FOR_ITER 7 (to 22) 8 STORE_FAST 0 (dir)
28 10 LOAD_FAST 0 (dir) 12 STORE_FAST 1 (path)
29 14 LOAD_FAST 1 (path) 16 SWAP 2 18 POP_TOP 20 RETURN_VALUE
30 >> 22 LOAD_CONST 0 (None) 24 RETURN_VALUE
SWAP demo
I solved it myself and modified the source code to support the directive
great news! how about creating PR for it? :)
Let swap press the stack,
stack.push(nullptr);
I've fixed about 10 py3.11 commands myself so far. Is currently solving the try except instruction, card for a long time, do not understand how to repair
try: pass except: raise try: pass except: print("123")
Hmm but why push NULL to the TOS (top of stack)?
the standard python doc says something else about how exactly SWAP opcode behaves:
void swap(int index)
{
if (m_ptr > -1)
{
PycRef<ASTNode> node = top();
if (node) {
m_stack[m_ptr] = m_stack[index - 1];
m_stack[index - 1] = node;
}
}
}
I tried to write according to the document, and found that it did not show the expected results, so I gave up, and directly pressed into the empty stack to parse normally.
OK, your impl looks valid but why do you push extra val (NULL) to the stack? it definitely violates the opcode mechanics...
one could agree with pushing NULL when the opcode is COPY (similar to SWAP)... any ideas?
I'm still working on the parsing of try, help me
try: pass except: raise try: pass except: print("123")
Python 3.11 uses totally different scheme known as "zero-cost" exception handling. Before 3.11, exceptions were handled by a runtime opcodes present in bytecode...
I guess you have to start parsing/using the exception table present in pyc structure but it's a bit complicated as you might have nested exceptions/etc
I guess it is good idea to read some theory - it is inside Python sources in teh following path: Python-3.11.6.tar\Python-3.11.6\Objects\exception_handling_notes.txt
https://github.com/zrax/pycdc/issues/409
I saw in other posts that you have solved the problem, can you tell me how to solve it? Share the code
def a(): try: print("123") finally: print("finally")
Please help me to solve this PR - https://github.com/zrax/pycdc/pull/411 collaboration to the rescue!
Duplicate #452