Skip to content

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

Closed
@brandtbucher

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

Metadata

Metadata

Assignees

Labels

3.14new features, bugs 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