Block uninterruptible big-int operations in the local Python executor - #2551
Block uninterruptible big-int operations in the local Python executor#2551himanshu748 wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ce9da1297f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| """ | ||
| if type(left) is not int or type(right) is not int: |
There was a problem hiding this comment.
Include bool/int subclasses in the big-int guard
When either operand is bool or another int subclass, this exact-type check returns before applying the limit even though CPython still dispatches to inherited integer arithmetic. That leaves trivial bypasses such as True << 10**9 or class I(int): pass; I(10) ** (10**8) that still enter the same uninterruptible big-int C operations and can hang LocalPythonExecutor despite this mitigation.
Useful? React with 👍 / 👎.
Fixes #2473 and complements #2464.
What happens today
A single model-generated expression like
10 ** 10 ** 8freezes the entireprocess, and
timeout_secondscannot save you. CPython computes arbitraryprecision
**,<<and*in one C call that holds the GIL without evercrossing a bytecode boundary, so the thread-based
timeout()watchdog nevergets scheduled. A faulthandler dump from the repro shows the main thread stuck
inside
ThreadPoolExecutor.submit->Thread.start: the timeout never evenarmed.
MAX_OPERATIONSdoes not help because the entire cost sits inside asingle AST operation.
Repro (freezes forever on main, needs an external kill):
The fix
Since the operation cannot be interrupted once started, refuse to start it.
A new
check_safe_int_operationestimates the result bit length from operandbit lengths and raises an informative
InterpreterErroraboveMAX_INT_BITS(1,000,000 bits, roughly 300k digits):
**:left.bit_length() * right, an upper bound<<:left.bit_length() + right*:left.bit_length() + right.bit_length()The guard is applied in
evaluate_binop,evaluate_augassignand the exposedpowbuiltin, covering**,<<,*, the augmented variants andpow(a, b). Modularpow(a, b, m)stays unrestricted. The error messagepoints the model at smaller operands or modular exponentiation, so an agent
recovers in the next step instead of hanging the host process.
Repeated multiplication (
a = 10**300000thenb = a * a * a * ...), theother vector from the issue, is caught by the
*guard once operands growpast the cap.
Tests
15 new parametrized tests in tests/test_local_python_executor.py: 7 explosive
patterns now raise
InterpreterError(they hang forever on main) and 8legitimate operations keep working, including 100! via repeated
*=,pow(7, 2**64, 97), float pow and1 ** 10**9. Full file: 412 passed,2 skipped. Ruff check and format are clean.