python: emit more robust generated code to avoid self-inflicted crashes - #192
Merged
Merged
Conversation
…hes" Triaging a cereggii fleet, the non-target noise was dominated by sessions the generated script kills itself in, not real target crashes. Three fixes remove them: 1. sigint (~all of them): _BOMB_EXCEPTIONS included KeyboardInterrupt, a BaseException subclass. The generated call sites catch `except Exception`, so a bomb that draws KeyboardInterrupt escapes and aborts the whole session (SIGINT). Drop it -- the pool is now Exception-only (bombs exist to exercise error paths, not to kill the interpreter). +regression test that the pool stays Exception-only. 2. exitcode1 (the AttributeError subset): the generated boilerplate did `from random import ..., random, ...`, rebinding the bare name `random` to the random() *function* and shadowing the module that embedded tricky-object code imports and calls as `random.randint(...)` -> AttributeError at module load. The name is never used bare in generated scripts, so just stop importing it; `random` now reliably resolves to the module. (Complements the existing `_bomb_random` alias that already hardened the core bomb source.) 3. exitcode1 (the rest): a call's arguments are constructed inline, BEFORE callMethod/callFunc runs -- so a hostile literal argument (a set of an unhashable object, a dict keyed on a __hash__ that raises, a bomb object) raises during argument construction, which callMethod's own handler cannot catch, and escapes at module level. Wrap the whole `res_X = callMethod(...)` statement in try/except so the call is skipped and fuzzing continues. The thread/async call wrappers already protect their own argument construction; this closes the synchronous path. Golden regenerated. Every exitcode1 in the sampled fleet was one of these; every sigint was a bomb KeyboardInterrupt. Suite green (1038), golden output validated as parseable Python. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Aug 18, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Triaging a cereggii fleet, the non-target noise (after the SystemError-ignore change) was dominated by sessions the generated script kills itself in, not real target crashes: ~100
sigintand ~148exitcode1. All are avoidable by emitting more robust code.Fixes
1.
sigint— bomb objects drawingKeyboardInterrupt._BOMB_EXCEPTIONSincludedKeyboardInterrupt, aBaseExceptionsubclass. The generated call sites catchexcept Exception, so a bomb that draws it escapes and aborts the whole session (SIGINT) as a false crash. Dropped it — the pool is nowException-only (bombs exist to exercise error paths, not to kill the interpreter). +regression test.2.
exitcode1(AttributeError subset) —randommodule shadowed. The generated boilerplate didfrom random import …, random, …, rebinding the bare namerandomto therandom()function and shadowing therandommodule that embedded tricky-object code imports and calls asrandom.randint(...)→AttributeErrorat module load. The name is never used bare in generated scripts, so we stop importing it;randomnow reliably resolves to the module. (Complements the existing_bomb_randomalias that already hardened the core bomb source.)3.
exitcode1(the rest) — unprotected argument construction. A call's arguments are constructed inline, beforecallMethod/callFuncruns — so a hostile literal argument (a set containing an unhashable object, a dict keyed on a__hash__that raises, a bomb object) raises during argument construction, whichcallMethod's own handler can't catch, and escapes at module level. Wrap the wholeres_X = callMethod(...)statement in try/except so the call is skipped and fuzzing continues. The thread/async call wrappers already protect their own argument construction; this closes the synchronous path.Impact / validation
In the sampled fleet, every
exitcode1was ares_X = callMethod/callFunc(...)whose argument construction raised, and everysigintwas a bombKeyboardInterrupt— all now avoided. All three fixes verified at runtime; golden output regenerated and validated as parseable Python.Tests
TestBombExceptionPool(pool staysException-only;_bomb_exc()never returns aBaseException-only type).fakemod_seed1234.pyregenerated (locks in the call wrapping + therandomimport).ruff check+ruff format --checkclean.🤖 Generated with Claude Code