Skip to content

Specialized list subscript/store can mishandle non-compact int indices #153002

Description

@KRRT7

Bug description:

The specialized list/int subscript and store paths can be entered after a code object was specialized with a compact non-negative int index, then later called with a non-compact exact int index.

At specialization time, BINARY_OP_SUBSCR_LIST_INT and STORE_SUBSCR_LIST_INT require _PyLong_IsNonNegativeCompact(sub), but the runtime macro only guards with _GUARD_TOS_INT. The specialized operation then calls _PyLong_CompactValue() without rechecking compactness.

On debug builds this can trip the _PyLong_CompactValue() assertion. On release builds, a non-compact value whose low digit is zero, such as 1 << 64, can be treated as index 0 rather than falling back to generic list indexing and raising IndexError.

Minimal CPython-internal reproducer:

import dis
import _testinternalcapi

def get(index):
    a = [1, 2, 3]
    return a[index]

for _ in range(_testinternalcapi.SPECIALIZATION_THRESHOLD):
    assert get(0) == 1

assert "BINARY_OP_SUBSCR_LIST_INT" in {
    instruction.opname for instruction in dis.get_instructions(get, adaptive=True)
}
get(1 << 64)

The same invariant issue applies to STORE_SUBSCR_LIST_INT after warming with index 0 and then storing with 1 << 64.

CPython versions tested on:

CPython main branch

Operating systems tested on:

macOS

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions