Skip to content

BINARY_OP_SUBSCR_LIST_INT / STORE_SUBSCR_LIST_INT silently depend on _GUARD_TOS_INT enforcing compactness #150587

@KRRT7

Description

@KRRT7

Summary

_BINARY_OP_SUBSCR_LIST_INT and _STORE_SUBSCR_LIST_INT call _PyLong_CompactValue
on the subscript without verifying compactness themselves. They rely entirely on
_GUARD_TOS_INT to have already rejected any non-compact int. This is an undocumented
invariant: if _GUARD_TOS_INT is ever relaxed, _PyLong_CompactValue will be called
on a wide int, reading ob_digit[0] as the index instead of the full value and
silently returning the wrong list element.

Details

The specializer gates BINARY_OP_SUBSCR_LIST_INT
(specialize.c:2391)
and STORE_SUBSCR_LIST_INT
(specialize.c:1575)
on _PyLong_IsNonNegativeCompact — only compact non-negative subscripts trigger
specialization. The runtime guard _GUARD_TOS_INT
(bytecodes.c:640)
currently checks _PyLong_CheckExactAndCompact, so the invariant holds today.

However, the opcode bodies
(_BINARY_OP_SUBSCR_LIST_INT,
_STORE_SUBSCR_LIST_INT)
do not re-verify compactness before calling _PyLong_CompactValue
(longintrepr.h:130).
If _GUARD_TOS_INT were relaxed to accept wider ints (e.g. to PyLong_CheckExact),
a wide int subscript would pass the guard and reach _PyLong_CompactValue in an
invalid state. For a wide positive int n = ob_digit[0] + ob_digit[1] * 2^30 + ...,
_PyLong_CompactValue reads only ob_digit[0], silently producing the wrong index.
On a debug build this fires assert(PyUnstable_Long_IsCompact(op)) inside
_PyLong_CompactValue.

Fix

Add EXIT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub)) to
_BINARY_OP_SUBSCR_LIST_INT and DEOPT_IF(!_PyLong_IsNonNegativeCompact((PyLongObject *)sub))
to _STORE_SUBSCR_LIST_INT, immediately before the _PyLong_CompactValue call.
Each opcode then enforces its own precondition rather than relying on the guard's
current strength.

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or error
    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