Skip to content

fix[venom]: register self in global analyses cache fallback#5084

Open
banteg wants to merge 2 commits into
vyperlang:masterfrom
banteg:fix/analyses-cache-self-registration
Open

fix[venom]: register self in global analyses cache fallback#5084
banteg wants to merge 2 commits into
vyperlang:masterfrom
banteg:fix/analyses-cache-self-registration

Conversation

@banteg

@banteg banteg commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

What I did

Fixes #5046.

IRAnalysesCache._ensure_global_analyses_cache had a fallback path (taken when a global analyses cache already exists) that never registered self: the loop inserted a fresh IRAnalysesCache for every missing function including self.function, making the trailing self-registration check dead code. Global analyses could then store per-function analyses in a parallel cache object, so the active pass's invalidations would not invalidate what later consumers read — a stale-analysis hazard.

How I did it

Caches auto-created by _ensure_global_analyses_cache are now marked as placeholders. The registration rule: a requesting cache displaces a placeholder entry (or fills an absent one), but never a non-placeholder cache registered by a real consumer such as the pass pipeline — its consumers rely on its invalidations. Plain "register only when absent" would not fix #5046, since both branches pre-fill placeholder caches for every function in the context.

How to verify it

New tests/unit/compiler/venom/test_analyses_cache.py: the regression test makes a first global-analysis request from one function's cache (creating the global cache), then a second request from a fresh IRAnalysesCache — the fallback path — and asserts the global cache maps the function to that same cache object. Fails on master with two distinct cache objects. (Note the single-request shape exercises the already-correct global_cache is None branch, which is why the test needs the two-step setup.)

Commit message

`IRAnalysesCache._ensure_global_analyses_cache` has a fallback path,
taken when a global analyses cache already exists, which inserted a
fresh `IRAnalysesCache` for every missing function including
`self.function` -- so the trailing self-registration check was dead
code and `self` was never registered. global analyses would then
compute and store per-function analyses in a parallel cache object
instead of the one owned by the active pass, so the pass's
invalidations could diverge from what later consumers read.

track placeholder caches created by the pre-fill, and let a
requesting cache displace a placeholder (or fill an absent entry) but
never a cache registered by a real consumer such as the pass
pipeline, whose invalidations downstream consumers rely on.

Description for the changelog

Fix: Venom global analyses cache registers the active function's analyses cache correctly on the fallback path, avoiding stale-analysis hazards outside the curated pass pipeline.

Cute Animal Picture

cute animal

`IRAnalysesCache._ensure_global_analyses_cache` filled in a fresh
`IRAnalysesCache` for every function missing from an existing global
cache -- including `self.function` -- so the subsequent self-registration
check was always false and `self` was never registered. global analyses
would then operate on a parallel per-function cache, diverging from the
cache owned by the active pass and risking stale analyses.

register `self` first (matching the `global_cache is None` branch),
then fill in fresh caches for the remaining functions.

fixes vyperlang#5046

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 31402cc9c9

ℹ️ 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".

Comment thread vyper/venom/analysis/analysis.py Outdated
self.function.ctx.global_analyses_cache = global_cache
return global_cache

global_cache.function_analyses_caches[self.function] = self

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid clobbering the registered function cache

When a global cache already exists, this unconditionally replaces the cache registered for self.function. If another IRAnalysesCache for the same function had already been installed by the pass pipeline, a temporary cache can now displace it; subsequent global analyses such as ReadonlyMemoryArgsGlobalAnalysis read per-function analyses through self.analyses_caches[fn].request_analysis(DFGAnalysis), so they can start using stale analyses from the temporary cache that the real pass cache never invalidates after IR mutations. This should only register self when the function has no cache entry, or otherwise avoid overwriting an existing authoritative cache for the same function.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — the unconditional overwrite traded one divergence hazard for another. Addressed in 33a528d:

IRAnalysesCache now tracks whether it was auto-created as a placeholder by _ensure_global_analyses_cache. The registration rule is: a requesting cache displaces a placeholder entry (or fills an absent one), but never a non-placeholder cache registered by a real consumer such as the pass pipeline.

"Register only when absent" alone wouldn't work here: both branches pre-fill caches for every function in the context, so a later real cache for one of those functions would find an entry already present (the placeholder) and the original #5046 bug — global analyses living in a parallel cache the active pass never invalidates — would persist. Distinguishing placeholders resolves both directions; test_existing_authoritative_cache_not_displaced pins the no-clobbering behavior alongside the original regression test.

@charles-cooper charles-cooper requested a review from harkal June 15, 2026 17:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IRAnalysesCache fallback global cache does not register self

1 participant