Skip to content

fix(extractor): resolve member-group symbols in IsStaticHandler (mined ImageSharp FP #4/4)#85

Merged
PhysShell merged 2 commits into
claude/fp-field-release-recognitionfrom
claude/fp-static-class-escape
Jun 22, 2026
Merged

fix(extractor): resolve member-group symbols in IsStaticHandler (mined ImageSharp FP #4/4)#85
PhysShell merged 2 commits into
claude/fp-field-release-recognitionfrom
claude/fp-static-class-escape

Conversation

@PhysShell

@PhysShell PhysShell commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Mined from SixLabors/ImageSharp — fix 4 of 4 (final)

Stacked on #84.

The bug

ImageSharp's MemoryAllocatorValidator (a static class whose static ctor hooks the static MemoryDiagnostics.MemoryAllocated/MemoryReleased events with static-method handlers) was reported with OWN014 region-escape — "promotes MemoryAllocatorValidator to process lifetime" — but a static-method handler stores a null-target delegate (no instance retained), so the existing IsStaticHandler exemption should have silenced it.

Why it slipped through

A method group's symbol can surface as a member group (GetSymbolInfo(handler).Symbol == null, CandidateSymbols populated) instead of the bound method, so IsStaticHandler's .Symbol is IMethodSymbol { IsStatic: true } check missed it.

The fix

IsStaticHandler now falls back to CandidateSymbols (requiring all candidates static, so a mixed overload set isn't wrongly exempted). A static-method handler in a static class is exempted (null target); a capturing lambda there still escapes (its closure display-class is retained) — sound.

Reverted from the first cut (per Codex P2): a blanket "static class ⇒ no OWN014" suppression was unsound — a capturing lambda retains the compiler-generated display-class even with no this. Dropped entirely in favor of the targeted IsStaticHandler fix.

Regression guard

StaticClassEscapeSample.cs — a static class's static ctor subscribing a static-method handler to a static event stays silent; the existing StaticEventEscapeViewModel proves an instance handler on a static event still raises OWN014.

Batch (4/4) + validation

  1. ✅ resolve-aware disposability — fix(extractor): resolve-aware field disposability (mined ImageSharp FP #1/4) #83
  2. ✅ null-conditional dispose — fix(extractor): null-conditional dispose + cross-member pool release (mined ImageSharp FP #2,#3/4) #84
  3. ✅ cross-member pool release — fix(extractor): null-conditional dispose + cross-member pool release (mined ImageSharp FP #2,#3/4) #84
  4. ✅ robust static-handler exemption — here

After the stack merges I'll re-mine ImageSharp — that's the real validation that MemoryAllocatorValidator clears (the member-group hypothesis is best-effort; I can't run the extractor locally). Left honest: the MemoryDiagnosticsTests closures, SharedArrayPoolBuffer's guard-indirection, and the WrapMemory projection-escape.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Rg8kSk1YT14x7A1vo5zgED

…ned ImageSharp FP #4/4)

A `static class` has no instance, so a static-source subscription from it cannot promote an
instance to the source's lifetime — the OWN014 region escape is vacuous. Mined:
SixLabors/ImageSharp's MemoryAllocatorValidator, a `static class` whose static ctor hooks the
static `MemoryDiagnostics.MemoryAllocated`/`MemoryReleased` events, was wrongly reported as
"promotes MemoryAllocatorValidator to process lifetime" — there is no instance to promote.

The static-source escape skip now also fires when the enclosing type is a static class (next
to the existing process-lived `App` case). Scoped to the OWN014 escape only — OWN001 token
leaks are untouched — and to non-timers, like the App case.

(The two MemoryDiagnosticsTests OWN014s — lambdas in `static void RunTest` local functions of
an INSTANCE class — are left honest: no `this` is captured so the named-instance claim is
wrong, but the closure is retained, so this is the murky static-context territory, not a clean
static-class drop.)

Regression sample StaticClassEscapeSample.cs: a static class subscribing a LAMBDA (not covered
by the static-method-handler exemption) to a static event stays silent; the existing
StaticEventEscapeViewModel proves an INSTANCE class on the same shape still raises OWN014.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rg8kSk1YT14x7A1vo5zgED
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 192b8657-bc1f-4fca-b1d0-46ae3c9e3973

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/fp-static-class-escape

Comment @coderabbitai help to get the list of available commands and usage tips.

@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: 8e80d668ce

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

// mined: ImageSharp MemoryAllocatorValidator). Scoped to NON-timers: a timer is
// forced to source "static" above, but a never-stopped timer is still a real
// leak (CodeRabbit).
if (!isTimer && source == "static" && (clsIsApp || clsIsStaticClass))

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 Keep capture facts for static-class closures

When a static class subscribes with a lambda or delegate that closes over a local, e.g. from a static ctor, the static event still retains the generated display-class instance for the process even though there is no this instance. This new condition skips every static-source subscription in a static class, so those closure-retention cases no longer emit the capture fact/OWN014; the earlier IsStaticHandler exemption already covers handlers proven to have no delegate target, so this suppression should be limited to non-capturing handlers.

Useful? React with 👍 / 👎.

…op static-class escape suppression (Codex)

Codex P2: blanket-suppressing OWN014 for ALL static-source subscriptions in a static class is
unsound — a CAPTURING lambda still retains its compiler-generated display-class instance for the
process, even with no `this`. Codex's pointer is right: the mined case (MemoryAllocatorValidator)
uses static-METHOD handlers, which the existing IsStaticHandler is meant to exempt; it missed them
because a method group's symbol can surface as a member group (Symbol == null, CandidateSymbols
populated).

So: make IsStaticHandler fall back to CandidateSymbols (requiring ALL candidates static, so a
mixed overload set is not wrongly exempted), and revert the static-class suppression entirely. A
static-method handler in a static class is now exempted by IsStaticHandler (null target, no
instance), while a capturing lambda there still escapes — sound.

Sample now uses a static-METHOD handler on a static event from a static class's static ctor
(replicating MemoryAllocatorValidator) and must stay silent; StaticEventEscapeViewModel still
proves an instance handler on a static event escapes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Rg8kSk1YT14x7A1vo5zgED
@PhysShell PhysShell changed the title fix(extractor): suppress OWN014 region-escape from a static class (mined ImageSharp FP #4/4) fix(extractor): resolve member-group symbols in IsStaticHandler (mined ImageSharp FP #4/4) Jun 22, 2026
@PhysShell
PhysShell merged commit eeafdb6 into claude/fp-field-release-recognition Jun 22, 2026
22 checks passed
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.

2 participants