--gc-aggressive killed every session on a PyPy target, silently - #270
Merged
Conversation
`gc.set_threshold` is CPython-only. The prelude runs on the TARGET, so on PyPy the
unguarded call raised AttributeError at MODULE LEVEL, at line 55, before a single
target call:
import gc
gc.set_threshold(1, 1, 1)
AttributeError: module 'gc' has no attribute 'set_threshold'
The failure mode is the bad part: the sessions do not look broken, they look CLEAN.
A 43 368-session PyPy fleet ran to completion reporting zero crashes, zero timeouts,
zero cpu-load kills and 0.3-second sessions, and nothing in any log said why. Every
one of those sessions was dead on arrival.
Verified on a real script out of that fleet: before the guard it produces 6 lines of
output and exits 1; after, 500 lines and it is fuzzing (`--- Fuzzing 40 functions in
traceback ---`).
The flag stays a no-op rather than an error on such a target -- it is a tuning knob,
not a request, and PyPy's GC is not generational in CPython's sense so there is
nothing to coerce.
Two tests: one asserts the call is inside a try/except AttributeError by walking the
AST rather than matching text, and one execs the emitted snippet against a gc module
with no set_threshold, which is what PyPy looks like from the prelude's point of view.
Same shape as the pre-3.13 target-compat break fixed in #256. The general rule that
keeps being relearned: anything CPython-specific in the prelude must be guarded,
because the prelude runs on the target.
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.
Found triaging
~/crashers/fusil-fleet-pypy_01, which reported 43 368 sessions, 0 crashes,0 timeouts, 0 cpu-load kills. None of those sessions ran.
The bug
gc.set_thresholdis CPython-only, and the prelude runs on the target. On PyPy theunguarded call raises
AttributeErrorat module level — line 55 of every generated script,before a single target call:
The failure mode is the dangerous part: the sessions don't look broken, they look clean.
Score 0.0%, duration 0.3 s, no crash, no timeout, nothing in any log saying why. A fleet can
run for hours reporting a tidy zero.
Verified on a real script from that fleet
AttributeError--- Fuzzing 40 functions in traceback ---The fix
A no-op rather than an error on such a target:
--gc-aggressiveis a tuning knob, not arequest, and PyPy's GC is not generational in CPython's sense, so there is nothing to coerce.
Tests
Two, both resistant to the obvious ways this could regress:
set_thresholdcall sits inside atry/except AttributeError, rather than matching source text that a reformat could break;gcmodule with noset_threshold— which isexactly what PyPy looks like from the prelude's point of view.
The recurring lesson
This is the same shape as the pre-3.13 target-compat break fixed in #256, where every session
also died in the prelude. The rule that keeps being relearned: anything CPython-specific in
the prelude must be guarded, because the prelude runs on the target. The faulthandler block
right above already does this and says so in its comment.
1286 tests OK,
ruff checkandruff format --checkclean.