Skip to content

compiler can incorrectly optimize a run of stores to the same name preceded by a SWAP #104615

Description

@carljm

If the apply_static_swaps optimization in the compiler sees the instruction sequence SWAP 2; STORE_FAST a; STORE_FAST a, it will optimize that by removing the SWAP and swapping the two instructions, resulting in STORE_FAST a; STORE_FAST a.

But of course, in this case the two instructions are identical, and their ordering matters because they store to the same location. So this change results in the wrong value being stored to a.

This was exposed by comprehension inlining, since it can result in this bytecode sequence for code in the form a = [1 for a in [0]] (where the first STORE_FAST a is restoring the previous value of a from before the comprehension, if any, and the second STORE_FAST a is storing the result of the comprehension to a.).

Linked PRs

Activity

  1. added
    type-bugAn unexpected behavior, bug, or error
    on May 18, 2023
  2. self-assigned this
    on May 18, 2023
  3. carljm commented on May 18, 2023

    @carljm
    MemberAuthor

    I see two options for fixing this:

    1. Change apply_static_swaps to also track store locations and consider instructions not swappable if they store to the same location.
    2. Add redundant store elimination, so prior to apply_static_swaps we would reduce SWAP 2; STORE_FAST a; STORE_FAST a to SWAP_2; POP_TOP; STORE_FAST a, which apply_static_swaps would correctly optimize to STORE_FAST a; POP_TOP.

    Probably the ideal is to do both; (2) because it results in the best compiler output, and (1) because it is more robust and avoids implicit dependency of one optimization on another.

  4. brandtbucher commented on May 18, 2023

    @brandtbucher
    Member

    This is definitely a bug in apply_static_swaps:

    3.10:

    >>> def f(x, y):
    ...     a, a = x, y
    ...     return a
    ... 
    >>> f(True, False)
    False

    3.11:

    >>> def f(x, y):
    ...     a, a = x, y
    ...     return a
    ... 
    >>> f(True, False)
    True
  5. added 3 commits that reference this issue on May 18, 2023
  6. carljm commented on May 18, 2023

    @carljm
    MemberAuthor

    I'm considering this issue fixed by the merged PR. I filed #104635 for the separate question of improving compiler output in these cases with dead store elimination.

  7. added 3 commits that reference this issue on May 18, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

3.11only security fixes3.12only security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)release-blockertype-bugAn unexpected behavior, bug, or error

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions