Skip to content

fix(extractor): PipeReader/PipeWriter are not IDisposable — stop flagging them as leaks (mined FP)#79

Merged
PhysShell merged 2 commits into
mainfrom
claude/fp-pipereader-not-disposable
Jun 22, 2026
Merged

fix(extractor): PipeReader/PipeWriter are not IDisposable — stop flagging them as leaks (mined FP)#79
PhysShell merged 2 commits into
mainfrom
claude/fp-pipereader-not-disposable

Conversation

@PhysShell

@PhysShell PhysShell commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Mined false positive

Running scripts/mine.sh over Pipelines.Sockets.Unofficial (a pool/pipe-heavy real repo) surfaced a systematic false positive. SocketConnection._input / _output — declared PipeReader / PipeWriter and assigned new WrappedReader(...) / new WrappedWriter(...) — were reported as OWN001 "IDisposable field never disposed (leak)".

But System.IO.Pipelines.PipeReader / PipeWriter are not IDisposable — they finish via Complete(), not Dispose() (the wrapper's Complete() calls the inner reader's Complete()). The cause is the field-disposable name heuristic in IsDisposableType, which matches anything ending in Reader/Writer. This would fire on essentially any code using System.IO.Pipelines (ubiquitous in modern .NET networking), so it's worth a precise fix.

Fix

New IsNonDisposableReaderWriter excludes PipeReader/PipeWriter from the EndsWith("Reader"/"Writer") branch, matched on the simple name so a qualified System.IO.Pipelines.PipeReader is covered too. The curated IDisposable names and the …Stream/…Subscription families are unchanged; no existing corpus or sample uses these types, so behaviour elsewhere is unaffected (the recall floor is unchanged).

static bool IsNonDisposableReaderWriter(string t) =>
    (t.Contains('.') ? t[(t.LastIndexOf('.') + 1)..] : t) is "PipeReader" or "PipeWriter";

Regression guard

frontend/roslyn/samples/PipeFieldsSample.cs — a class that constructs PipeReader/PipeWriter fields and never disposes them — is added to the wpf-extractor CI job, which asserts it produces no finding.

Validation

  • Python suite green (the .own corpus + core are unaffected by this C# change).
  • The C# fix is validated by CI: the new wpf-extractor assertion (PipeFieldsSample.cs → no finding) fails on the pre-fix heuristic and passes with the exclusion. I can't run the extractor without a local SDK, so CI is the check.

Out of scope (noted)

The same mine run surfaced a second, harder FP — a pooled buffer passed to an ownership-taking constructor and returned (ArrayPoolBufferWriter.CreateNewSegment: var array = pool.Rent(...); return new ArrayPoolRefCountedSegment(pool, array, prev);). The intra-procedural escape analysis treats a pool buffer passed as an argument as a borrow and expects a same-method Return, missing the ownership transfer through the constructor. That needs a deeper change and is a separate follow-up.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Rg8kSk1YT14x7A1vo5zgED


Generated by Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved leak-check classification for PipeReader/PipeWriter fields: these are now correctly treated as completing via Complete() (not Dispose()), preventing false undisposed-disposable leak reports.
  • Tests
    • Added a dedicated PipeReader/PipeWriter sample to guard against regressions.
    • Updated CI leak-check coverage to include the new sample and to fail if it’s incorrectly flagged.

…ging them as leaks (mined FP)

Mining Pipelines.Sockets.Unofficial surfaced a systematic false positive: the
field-disposable name heuristic in IsDisposableType matches anything ending in
"Reader"/"Writer", so `System.IO.Pipelines` PipeReader/PipeWriter fields
(SocketConnection._input/_output, assigned `new WrappedReader/WrappedWriter`) were
reported as undisposed-IDisposable leaks (OWN001). But PipeReader/PipeWriter are
NOT IDisposable — they finish via Complete(), not Dispose() — so this is a false
alarm, and it would fire on essentially any code using System.IO.Pipelines.

New IsNonDisposableReaderWriter excludes PipeReader/PipeWriter (matched on the
simple name, so a qualified `System.IO.Pipelines.PipeReader` is covered too) from
the EndsWith("Reader"/"Writer") heuristic. The curated IDisposable names and the
…Stream/…Subscription families are unchanged; no existing corpus/sample uses these
types, so behaviour elsewhere is unaffected.

Regression guard: frontend/roslyn/samples/PipeFieldsSample.cs (a class that
constructs PipeReader/PipeWriter fields and never disposes them) is added to the
wpf-extractor CI job, which asserts it produces NO finding.

Found by `scripts/mine.sh` over a real repo; not reproducible without a .NET SDK
locally, so validated by CI + a re-mine.

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

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e511e592-66b7-48fd-b177-f062a20f5f5b

📥 Commits

Reviewing files that changed from the base of the PR and between 7a607a7 and 7f39a7d.

📒 Files selected for processing (1)
  • frontend/roslyn/OwnSharp.Extractor/Program.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/roslyn/OwnSharp.Extractor/Program.cs

📝 Walkthrough

Walkthrough

IsDisposableType in Program.cs is refined to exclude BCL PipeReader/PipeWriter from the *Reader/*Writer suffix heuristic via a new IsNonDisposableReaderWriter helper. A sample file PipeFieldsSample.cs documents the non-leak classification, and the CI workflow adds it as an input with a negative assertion.

Changes

PipeReader/PipeWriter false-positive fix

Layer / File(s) Summary
IsDisposableType exclusion and regression sample
frontend/roslyn/samples/PipeFieldsSample.cs, frontend/roslyn/OwnSharp.Extractor/Program.cs
IsDisposableType now calls new IsNonDisposableReaderWriter helper to exclude PipeReader/PipeWriter from the *Reader/*Writer suffix match. PipeFieldsSample.cs defines PipeHolder with PipeReader and PipeWriter fields as a regression fixture documenting that these types complete via Complete() rather than Dispose().
CI negative assertion
.github/workflows/ci.yml
PipeFieldsSample.cs is added to the extractor's input file list, and a negative assertion is inserted to fail the job if the file appears in extractor output.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 A Pipe completes, it does not Dispose,
So the rabbit fixed the heuristic that froze.
PipeReader, PipeWriter — no leak to detect,
A sample and CI keep the logic correct.
Hop hop, no false alarm, the extractor's in check! ✅

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title precisely describes the main change: fixing a false positive where PipeReader/PipeWriter fields were incorrectly flagged as IDisposable leaks, including reference to the mining context that discovered the issue.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/fp-pipereader-not-disposable

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: 7a607a7aa0

ℹ️ 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 on lines +1425 to +1426
static bool IsNonDisposableReaderWriter(string t) =>
(t.Contains('.') ? t[(t.LastIndexOf('.') + 1)..] : t) is "PipeReader" or "PipeWriter";

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 Limit PipeReader exclusion to pipelines types

This helper strips the namespace and suppresses every type whose simple name is PipeReader or PipeWriter, not just System.IO.Pipelines.PipeReader/PipeWriter. In a project that owns a disposable MyLib.PipeReader field/local (or a third-party disposable type with that simple name), the EndsWith("Reader"/"Writer") heuristic on lines 1415-1417 no longer emits the disposable fact, so WPF003/D1/flow-locals silently miss a leak that was previously reported. Please constrain the exemption to the actual System.IO.Pipelines symbols/qualified names rather than all simple-name matches.

Useful? React with 👍 / 👎.

…der/PipeWriter (Codex)

Codex: stripping the namespace excluded any type whose simple name is
PipeReader/PipeWriter, so a project's own disposable `MyLib.PipeReader` would be
silently dropped (a false negative). Match the exact bare or
`System.IO.Pipelines`-qualified spelling instead; the bare spelling (the mined FP
and the regression sample) stays excluded, a differently-namespaced type does not.

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