fix: terminate call-graph alias fixpoint on oscillating rebinds (#1247)#1259
Conversation
Scanning a pickle that references certain stdlib modules (imaplib,
http.server, nntplib) caused modelaudit to hang indefinitely. A
faulthandler trace showed the hang was not in the Rust scanner, as
originally reported, but in pure-Python call-graph analysis:
_collect_assignment_aliases.
When call-graph analysis imports such a module's source, it flattens
all module-level statements -- including both branches of the
`if __name__ == '__main__'` block. imaplib binds the same name twice:
M = IMAP4_stream(stream_command)
M = IMAP4(host)
The alias fixpoint loop flips `M` between `imaplib.IMAP4` and
`imaplib.IMAP4_stream` on every pass, always marking `changed = True`.
The only loop guard checks the alias dict size, which never grows past
1, so the loop spins forever. http.server and nntplib hit the same
`__main__`-block rebind pattern.
Track every (target, resolved) pair already applied. Re-applying a
previously seen pair no longer counts as progress, so an oscillating
bind converges once both values have been observed instead of looping
forever. The alias is still applied so later nodes resolve correctly;
detection severity is unchanged (affected files still report CRITICAL).
Adds test_call_graph_assignment_alias_cycle.py: a deterministic unit
test for the oscillating-bind fixpoint plus an end-to-end imaplib
proof-of-concept scan, both guarded by thread watchdogs that fail
rather than hang on regression. Registers the file in the reduced-CI
allowlist in tests/conftest.py.
Fixes #1247
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Performance BenchmarksCompared
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9feb7bc97d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d78c997c7a
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 26655add3a
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 21fcf1a7ef
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c617e8ea85
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 42e7702a61
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3acc6a8ae8
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f670f86681
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dbcdffbf84
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6cd7de3e79
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 78eb56db50
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8f2c0b4fd0
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 183869a10f
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 95642a4ac9
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2d00183f36
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8ca3b53efe
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 71925b19c1
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 06b7a3caab
ℹ️ 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".
Summary
Fixes #1247 — scanning a pickle that references
imaplib,http.server, ornntplibcausedmodelauditto hang forever, blocking every other file in a directory scan.Huge thanks to @HalaAli198 for the exceptionally well-researched report. 🙏 The hex dump, the minimal 42-byte proof-of-concept, the public Hugging Face repros, the workaround (
--exclude-scanner pickle), and the cross-reference to promptfoo/promptfoo#6266 made this fast to reproduce and diagnose. That is exactly the kind of issue maintainers dream of receiving.Root cause
The report attributed the hang to the compiled Rust scanner (
_rust.abi3.so), which was a very reasonable inference given--timeouthad no effect. Afaulthandlertraceback showed the hang is actually in pure-Python call-graph analysis, before the slow Rust path is even reached:When call-graph analysis imports such a module's source, it flattens every module-level statement — including both branches of the
if __name__ == '__main__'block.imaplib.pybinds the same name twice:The alias fixpoint loop in
_collect_assignment_aliasesflipsMbetweenimaplib.IMAP4andimaplib.IMAP4_streamon every pass, always markingchanged = True. The loop's only guard checks the alias dict size, which never grows past 1 — so it spins forever.http.serverandnntplibhit the identical__main__-block rebind pattern.Fix
Track every
(target, resolved)pair already applied. Re-applying a previously seen pair no longer counts as progress, so an oscillating bind converges once both values have been observed (~3 passes) instead of looping forever. The alias is still applied so later nodes resolve correctly, and detection severity is unchanged — all affected files still report CRITICAL.Verification
test_call_graph_assignment_alias_cycle.py: a deterministic unit test for the oscillating-bind fixpoint plus an end-to-endimaplibPoC scan, both guarded by thread watchdogs that fail rather than hang on regression. Registered in the reduced-CI allowlist intests/conftest.py.test_pickle_scanner.py(131 passed),ruff format/check, andmypyall clean.Note on
--timeoutThe report also observed that
--timeoutdoes not interrupt the hang. That is a separate architectural limitation: the timeout is checked cooperatively between scanners, so any CPU-bound single-threaded stretch (Rust or Python) cannot be preempted mid-call. Fixing the actual infinite loop resolves the reported denial-of-service; making long-running scans pre-emptible would be a larger, separate change worth tracking on its own.Thanks again, @HalaAli198 — this was a genuinely valuable find, and the care you put into the report is much appreciated. Wishing you well, and happy (safe) scanning! 🛡️
🤖 Generated with Claude Code