-
-
Notifications
You must be signed in to change notification settings - Fork 32k
code.replace() fails to preserve CO_FAST_HIDDEN flag on locals #110543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
|
Possible solution: iterate over the bytecode and if we encounter a LOAD_FAST_AND_CLEAR and we're in a non-function scope, set CO_FAST_HIDDEN on that name. Also note that the bizarre errors happen only if you call |
…ythonGH-110586) (cherry picked from commit 0b718e6) Co-authored-by: Jelle Zijlstra <[email protected]>
Thanks! |
Per discussion on the merged PR, I would like to leave this issue open to track a cleaner fix for main (that we weren't comfortable putting in 3.12.) |
Sure, sorry for the premature close. |
@carljm I just stumbled on this issue because it's still assigned to me. Are you interested in implementing your proposed change in #110586 (comment) for 3.14? |
In theory, yes :) I have some half-finished work on it in a branch somewhere. Let's see if I can get back to it during the sprint. |
Bug report
Bug description:
Support for inlining list/dict/set comprehensions in c3b595e introduced a
CO_FAST_HIDDEN
, which is applied in combination with a different type code, for exampleCO_FAST_LOCAL
. However, when thecode
object is copied viacode.replace()
function call, this additional flag is lost; consequently, execution of the returned code object results in a bizarre-looking error.Example:
Consider the following example program
and the following script that compiles the program to byte-code .pyc:
For some context, the above example is a distilled reproduction of what is going in
PyInstaller
andscipy.stats._distn_infrastructure
module in pyinstaller/pyinstaller#7992: the collected module is byte-compiled, and the absolute filename in the code-object is anonymized into environment-relative path viaco.replace()
(see here for details).But in the above example, no replacement is done, and so one would expect of
co.replace()
to return an identical code object.However, this is not the case (even though
co == co.replace()
in python claims that they are identical):$ sha256sum *.pyc 2e03af03bcbb41b3a6cc6f592f5143acf7d82edc089913504c1f8446764795e1 compiled-copy.pyc 5034955819efba0dc7ff3ee94101c1f6dfe33b102d547efc77577d77a99f1732 compiled-orig.pyc
Running the original version:
Running the version with
co.replace()
:Comparing the compiled-orig.pyc and compiled-copy.pyc in a hex editor, there is one byte of difference; its position corresponds to marshaled
co_localspluskinds
, and the value is 0x30 (CO_FAST_LOCAL | CO_FAST_HIDDEN
) in original and 0x20 (CO_FAST_LOCAL
) in copy variant.CPython versions tested on:
3.12
Operating systems tested on:
Linux, Windows
Linked PRs
The text was updated successfully, but these errors were encountered: