Skip to content

The JIT's understanding of ** is wrong #127809

Description

@brandtbucher

Crash report

** is weird in that the type of the result depends on the values of the inputs. The logic for int/float power is:

def type_of_pow(lhs: float, rhs: float) -> type[complex]:
    if isinstance(lhs, int) and isinstance(rhs, int) and rhs >= 0:
        return int
    if lhs < 0 and not rhs.is_integer():
        return complex
    return float

However, our optimizer wrongly assumes:

def type_of_pow(lhs: float, rhs: float) -> type[float]:
    if isinstance(lhs, int) and isinstance(rhs, int):
        return int
    return float

This means that tons of different poorly-chosen values can cause JIT code to crash:

import _testinternalcapi
import itertools

def f(a, b):
    for _ in range(_testinternalcapi.TIER2_THRESHOLD):
        a + b  # Remove guards...
        a ** b + a  # ...BOOM!

for la, ra, lb, rb in itertools.product([1, -1, 1.0, -1.0, 0.5, -0.5], repeat=4):
    f(la, ra)
    f(lb, rb)

Normally we could just ignore the problem and produce an unknown type during abstract interpretation, but a ** containing at least one constant value is actually reasonably common (think x ** 2, 2 ** n, or s ** 0.5).

We should probably teach the optimizer how to handle these properly.

Linked PRs

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

3.14bugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)topic-JITtype-crashA hard crash of the interpreter, possibly with a core dump

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions