question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Labels don't seem to be handled correctly with Python<3.9

See original GitHub issue

I am currently working with the following abstract code

            stopiter = Label()
            loop = Label()
            genexit = Label()
            exc = Label()
            propagate = Label()
            instrs[-1:-1] = [
                Instr("DUP_TOP", lineno=lineno),
                Instr("STORE_FAST", "__ddgen", lineno=lineno),
                Instr("LOAD_ATTR", "asend", lineno=lineno),
                Instr("STORE_FAST", "__ddgensend", lineno=lineno),
                Instr("LOAD_FAST", "__ddgen", lineno=lineno),
                Instr("LOAD_ATTR", "__anext__", lineno=lineno),
                Instr("CALL_FUNCTION", 0, lineno=lineno),
                loop,
                Instr("SETUP_EXCEPT" if PY < (3, 8) else "SETUP_FINALLY", stopiter, lineno=lineno),
                Instr("GET_AWAITABLE", lineno=lineno),
                Instr("LOAD_CONST", None, lineno=lineno),
                Instr("YIELD_FROM", lineno=lineno),
                Instr("POP_BLOCK", lineno=lineno),
                Instr("SETUP_EXCEPT" if PY < (3, 8) else "SETUP_FINALLY", genexit, lineno=lineno),
                Instr("YIELD_VALUE", lineno=lineno),
                Instr("POP_BLOCK", lineno=lineno),
                Instr("LOAD_FAST", "__ddgensend", lineno=lineno),
                Instr("ROT_TWO", lineno=lineno),
                Instr("CALL_FUNCTION", 1, lineno=lineno),
                Instr("JUMP_ABSOLUTE", loop, lineno=lineno),
                stopiter,  # except StopAsyncIteration:
                Instr("DUP_TOP", lineno=lineno),
                Instr("LOAD_CONST", StopAsyncIteration, lineno=lineno),
                compare_exc(propagate, lineno),
                jump_if_false(propagate, lineno),
                Instr("POP_TOP", lineno=lineno),
                Instr("POP_TOP", lineno=lineno),
                Instr("POP_TOP", lineno=lineno),
                Instr("POP_EXCEPT", lineno=lineno),
                Instr("LOAD_CONST", None, lineno=lineno),
                Instr("RETURN_VALUE", lineno=lineno),
                propagate,  # finally:
                Instr("END_FINALLY" if PY < (3, 9) else "RERAISE", lineno=lineno),
                genexit,  # except GeneratorExit:
                Instr("DUP_TOP", lineno=lineno),
                Instr("LOAD_CONST", GeneratorExit, lineno=lineno),
                compare_exc(exc, lineno),
                jump_if_false(exc, lineno),
                Instr("POP_TOP", lineno=lineno),
                Instr("POP_TOP", lineno=lineno),
                Instr("POP_TOP", lineno=lineno),
                Instr("LOAD_FAST", "__ddgen", lineno=lineno),
                Instr("LOAD_ATTR", "aclose", lineno=lineno),
                Instr("CALL_FUNCTION", 0, lineno=lineno),
                Instr("GET_AWAITABLE", lineno=lineno),
                Instr("LOAD_CONST", None, lineno=lineno),
                Instr("YIELD_FROM", lineno=lineno),
                Instr("POP_EXCEPT", lineno=lineno),
                Instr("RETURN_VALUE", lineno=lineno),
                exc,  # except:
                Instr("POP_TOP", lineno=lineno),
                Instr("POP_TOP", lineno=lineno),
                Instr("POP_TOP", lineno=lineno),
                Instr("LOAD_FAST", "__ddgen", lineno=lineno),
                Instr("LOAD_ATTR", "athrow", lineno=lineno),
                Instr("LOAD_CONST", sys.exc_info, lineno=lineno),
                Instr("CALL_FUNCTION", 0, lineno=lineno),
                Instr("CALL_FUNCTION_EX", 0, lineno=lineno),
                Instr("GET_AWAITABLE", lineno=lineno),
                Instr("LOAD_CONST", None, lineno=lineno),
                Instr("YIELD_FROM", lineno=lineno),
                Instr("POP_EXCEPT", lineno=lineno),
                Instr("RETURN_VALUE", lineno=lineno),
            ]

When compiled to concrete Python 3.9 bytecode I get what I would expect (note the correct jump to RERAISE)

             12 DUP_TOP
             14 STORE_FAST               1 (__ddgen)
             16 LOAD_ATTR                0 (asend)
             18 STORE_FAST               2 (__ddgensend)
             20 LOAD_FAST                1 (__ddgen)
             22 LOAD_ATTR                1 (__anext__)
             24 CALL_FUNCTION            0
        >>   26 SETUP_FINALLY           22 (to 50)
             28 GET_AWAITABLE
             30 LOAD_CONST               2 (None)
             32 YIELD_FROM
             34 POP_BLOCK
             36 SETUP_FINALLY           34 (to 72)
             38 YIELD_VALUE
             40 POP_BLOCK
             42 LOAD_FAST                2 (__ddgensend)
             44 ROT_TWO
             46 CALL_FUNCTION            1
             48 JUMP_ABSOLUTE           26
        >>   50 DUP_TOP
             52 LOAD_CONST               3 (<class 'StopAsyncIteration'>)
             54 JUMP_IF_NOT_EXC_MATCH    70
             56 NOP
             58 POP_TOP
             60 POP_TOP
             62 POP_TOP
             64 POP_EXCEPT
             66 LOAD_CONST               2 (None)
             68 RETURN_VALUE
        >>   70 RERAISE
        >>   72 DUP_TOP
             74 LOAD_CONST               4 (<class 'GeneratorExit'>)
             76 JUMP_IF_NOT_EXC_MATCH   102
             78 NOP
             80 POP_TOP
             82 POP_TOP
             84 POP_TOP
             86 LOAD_FAST                1 (__ddgen)
             88 LOAD_ATTR                2 (aclose)
             90 CALL_FUNCTION            0
             92 GET_AWAITABLE
             94 LOAD_CONST               2 (None)
             96 YIELD_FROM
             98 POP_EXCEPT
            100 RETURN_VALUE
        >>  102 POP_TOP
            104 POP_TOP
            106 POP_TOP
            108 LOAD_FAST                1 (__ddgen)
            110 LOAD_ATTR                3 (athrow)
            112 LOAD_CONST               5 (<built-in function exc_info>)
            114 CALL_FUNCTION            0
            116 CALL_FUNCTION_EX         0
            118 GET_AWAITABLE
            120 LOAD_CONST               2 (None)
            122 YIELD_FROM
            124 POP_EXCEPT
            126 RETURN_VALUE
            128 RETURN_VALUE

However, with earlier Python versions the jump to the propagate label is not resolved correctly and actually ends up targeting the exc label (END_FINALLY is now in place of the newer RERASE, but the jump is not there!):

             12 DUP_TOP
             14 STORE_FAST               1 (__ddgen)
             16 LOAD_ATTR                0 (asend)
             18 STORE_FAST               2 (__ddgensend)
             20 LOAD_FAST                1 (__ddgen)
             22 LOAD_ATTR                1 (__anext__)
             24 CALL_FUNCTION            0
        >>   26 SETUP_FINALLY           22 (to 50)
             28 GET_AWAITABLE
             30 LOAD_CONST               2 (None)
             32 YIELD_FROM
             34 POP_BLOCK
             36 SETUP_FINALLY           34 (to 72)
             38 YIELD_VALUE
             40 POP_BLOCK
             42 LOAD_FAST                2 (__ddgensend)
             44 ROT_TWO
             46 CALL_FUNCTION            1
             48 JUMP_ABSOLUTE           26
        >>   50 DUP_TOP
             52 LOAD_CONST               3 (<class 'StopAsyncIteration'>)
             54 COMPARE_OP              10 (exception match)
             56 POP_JUMP_IF_FALSE      102
             58 POP_TOP
             60 POP_TOP
             62 POP_TOP
             64 POP_EXCEPT
             66 LOAD_CONST               2 (None)
             68 RETURN_VALUE
             70 END_FINALLY
        >>   72 DUP_TOP
             74 LOAD_CONST               4 (<class 'GeneratorExit'>)
             76 COMPARE_OP              10 (exception match)
             78 POP_JUMP_IF_FALSE      102
             80 POP_TOP
             82 POP_TOP
             84 POP_TOP
             86 LOAD_FAST                1 (__ddgen)
             88 LOAD_ATTR                2 (aclose)
             90 CALL_FUNCTION            0
             92 GET_AWAITABLE
             94 LOAD_CONST               2 (None)
             96 YIELD_FROM
             98 POP_EXCEPT
            100 RETURN_VALUE
        >>  102 POP_TOP
            104 POP_TOP
            106 POP_TOP
            108 LOAD_FAST                1 (__ddgen)
            110 LOAD_ATTR                3 (athrow)
            112 LOAD_CONST               5 (<built-in function exc_info>)
            114 CALL_FUNCTION            0
            116 CALL_FUNCTION_EX         0
            118 GET_AWAITABLE
            120 LOAD_CONST               2 (None)
            122 YIELD_FROM
            124 POP_EXCEPT
            126 RETURN_VALUE
            128 RETURN_VALUE

This seems to point to a wrong resolution of the branching label.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:5 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
MatthieuDartiailhcommented, Feb 24, 2022

Always happy to help !

0reactions
P403n1x87commented, Feb 24, 2022

Big facepalm moment! Your last question helped me find the actual issue, which was due to copy-pasta in my code! 😢 These are the functions

    def compare_exc(label, lineno):
        return (
            Instr("COMPARE_OP", Compare.EXC_MATCH, lineno=lineno)
            if PY < (3, 9)
            else Instr("JUMP_IF_NOT_EXC_MATCH", label, lineno=lineno)
        )

    def jump_if_false(label, lineno):
        return Instr("POP_JUMP_IF_FALSE", label, lineno=lineno) if PY < (3, 9) else Instr("NOP", lineno=lineno)

which are defined locally inside another function. I had exc in place of label in jump_if_false. So indeed the generated bytecode was correct as it was getting exc from the outer scope! 😭 . Now that gives me RuntimeError: Failed to compute stacksize, got negative size but I should be able to fix this.

Apologies for this non-issue!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Cannot install fairseq==0.10.2 with python 3.9 #3535 - GitHub
I don't seem to be able to install fairseq==0.10.2 with python 3.9 on macOS 11.3 $ pip install fairseq==0.10.2 Collecting fairseq==0.10.2 ...
Read more >
No handles with labels found to put in legend - Stack Overflow
No handles with labels found to put in legend. I'm not sure why, because, based on the documentation for plt.arrow() , label is...
Read more >
Changelog — Python 3.11.1 documentation
gh-84461: run_tests.py now handles cross compiling env vars correctly and pass HOSTRUNNER to regression tests. gh-93616: test_modulefinder now ...
Read more >
[Errno 24] "Too many open files" when running a docker agent ...
_execute('get', server) File "/home/Skam/.local/lib/python3.9/site-packages/ ... seems to handle that at every pull), and if this was the case I don't think ...
Read more >
IO tools (text, CSV, HDF5, …) — pandas 1.5.2 documentation
Column(s) to use as the row labels of the DataFrame , either given as string ... [53]: pd.read_csv(StringIO(data)) Out[53]: a b ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found