Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

BINARY_OP_SUBSCR_LIST_INT / STORE_SUBSCR_LIST_INT silently depend on _GUARD_TOS_INT enforcing compactness #150587

Copy link
Copy link

Description

@KRRT7
Issue body actions

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

Reactions are currently unavailable

Metadata

Metadata

Assignees

No one assigned

    Labels

    interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-bugAn unexpected behavior, bug, or errorAn unexpected behavior, bug, or error

    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

    Morty Proxy This is a proxified and sanitized view of the page, visit original site.