feat: PoC oficially proven?#16
Conversation
…e), exempt dispose-optional types, default the wrappers to flow
…on leak Pin the real GTM CatalogService.GetProductsFromCatalogWODocuments finding: a local UnitOfWork (IDisposable) used only through member access to build a returned DEFERRED IQueryable. The bare `uow` never escapes, so the flow detector keeps it tracked and reports OWN001 (disposed on no path) — a leak a naive `using` cannot fix (the deferred query would run after dispose). - frontend/roslyn/samples/UnitOfWorkFlowSample.cs: self-contained distillation of the GTM method, plus the using-var/materialize fix that must stay silent. - tests/fixtures/ownir/unitofwork_flow.facts.json + tests/test_ownir.py: the dotnet-free bridge+core pin (OWN001 on 'uow' at the C# line, tag disposable). - .github/workflows/ci.yml: end-to-end extractor->core assertion on the sample. https://claude.ai/code/session_01Rg8kSk1YT14x7A1vo5zgED
…ship-transfer sample Two follow-ups on the GTM UnitOfWork pin: - ownir bridge: word the flow-local OWN001 from whether the local is released anywhere in the body (ever_released). Released on no path -> "is never disposed"; released on some branch but leaked on another -> "may not be disposed on every path". Both stay the core's OWN001 — computed in the bridge from the flow body the extractor already emits (no schema change, no version bump). - UnitOfWorkFlowSample: add the Option B (ownership-transfer) fixes as silent contrasts to the materialize fix — uow returned (uowOwned) and moved out as an argument (uowMoved) both escape, so the flow detector does not flag them. - tests/CI: new flow_leak_on_else fixture pins the partial-path wording dotnet- free; test_ownir asserts both phrasings; the FlowLocals + UnitOfWork CI steps assert never-vs-every-path wording on real C# and that all three fixes stay silent. https://claude.ai/code/session_01Rg8kSk1YT14x7A1vo5zgED
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📝 WalkthroughWalkthroughImplements P-016 B0b/B2 path-sensitive ChangesFlow-sensitive local IDisposable leak detection (P-016 B0b/B2)
Sequence Diagram(s)sequenceDiagram
participant User as User / CI
participant Script as own-check.sh / .ps1
participant Extractor as OwnSharp.Extractor (--flow-locals)
participant FactsJSON as facts.json (functions[])
participant OwnIR as ownlang/ownir.py (to_module + check_facts)
participant Output as OWN001/002/003 Findings
User->>Script: run (no --legacy)
Script->>Extractor: dotnet run -- paths --flow-locals -o facts.json
Extractor->>Extractor: lower method bodies into acquire/use/release/if/return
Extractor->>FactsJSON: emit { components, functions[] }
Script->>OwnIR: load(facts.json)
OwnIR->>OwnIR: _lower_flow() → loc_<n> stmts + ever_released
OwnIR->>OwnIR: check_facts() → flow-local branch
OwnIR->>Output: Finding(OWN001, "never disposed" or "not on every path")
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@frontend/roslyn/OwnSharp.Extractor/Program.cs`:
- Around line 226-229: The UsingStatementSyntax case (line 226) does not emit a
release when the using statement wraps an existing local variable, and the
disposal method matching logic (lines 243-246) only recognizes Dispose and Close
invocations but misses DisposeAsync calls including awaited variants. Fix the
using statement handler to emit a release for the variable being disposed when
using(existingLocal) is encountered, and extend the disposal method matching at
lines 243-246 to also recognize DisposeAsync method invocations so that both
synchronous and asynchronous disposal paths are properly tracked by the flow
analysis.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: f46555e8-d24c-4f23-ad63-9470fceaa3d6
📒 Files selected for processing (11)
.github/workflows/ci.ymldocs/proposals/P-016-deep-fact-extraction.mdfrontend/roslyn/OwnSharp.Extractor/Program.csfrontend/roslyn/samples/FlowLocalsSample.csfrontend/roslyn/samples/UnitOfWorkFlowSample.csownlang/ownir.pyscripts/own-check.ps1scripts/own-check.shtests/fixtures/ownir/flow_leak_on_else.facts.jsontests/fixtures/ownir/unitofwork_flow.facts.jsontests/test_ownir.py
| case UsingStatementSyntax us: | ||
| // using(...) {body}: the using local is auto-disposed (untracked); still | ||
| // lower the body so a tracked plain local used inside is seen. | ||
| return us.Statement is null || LowerFlowStmt(us.Statement, tracked, nodes); |
There was a problem hiding this comment.
Flow lowering currently misses valid disposal paths and can misreport leaks.
Line 226 lowers using bodies but does not emit a release for using(existingLocal).
Lines 243-246 only match direct Dispose/Close invocations and miss DisposeAsync (including await x.DisposeAsync()). With --flow-locals enabled (and D1 suppressed), these become false OWN001/OWN009-style outcomes.
Proposed fix
@@
case UsingStatementSyntax us:
// using(...) {body}: the using local is auto-disposed (untracked); still
// lower the body so a tracked plain local used inside is seen.
- return us.Statement is null || LowerFlowStmt(us.Statement, tracked, nodes);
+ if (us.Statement is not null && !LowerFlowStmt(us.Statement, tracked, nodes))
+ return false;
+ // using(existingTrackedLocal) disposes that local at scope end.
+ if (us.Expression is IdentifierNameSyntax uid
+ && tracked.Contains(uid.Identifier.Text))
+ nodes.Add(new { op = "release", var = uid.Identifier.Text, line = LineOf(us) });
+ return true;
@@
static void EmitFlowExpr(ExpressionSyntax expr, HashSet<string> tracked, List<object> nodes)
{
// x.Dispose()/x.Close() on a tracked local -> release.
- if (expr is InvocationExpressionSyntax inv
+ var call = expr switch
+ {
+ InvocationExpressionSyntax i => i,
+ AwaitExpressionSyntax { Expression: InvocationExpressionSyntax i } => i,
+ _ => null,
+ };
+ if (call is InvocationExpressionSyntax inv
&& inv.Expression is MemberAccessExpressionSyntax ma
- && ma.Name.Identifier.Text is "Dispose" or "Close"
+ && ma.Name.Identifier.Text is "Dispose" or "Close" or "DisposeAsync"
&& ma.Expression is IdentifierNameSyntax rid
&& tracked.Contains(rid.Identifier.Text))
{
nodes.Add(new { op = "release", var = rid.Identifier.Text, line = LineOf(inv) });
return;
}Also applies to: 243-246
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@frontend/roslyn/OwnSharp.Extractor/Program.cs` around lines 226 - 229, The
UsingStatementSyntax case (line 226) does not emit a release when the using
statement wraps an existing local variable, and the disposal method matching
logic (lines 243-246) only recognizes Dispose and Close invocations but misses
DisposeAsync calls including awaited variants. Fix the using statement handler
to emit a release for the variable being disposed when using(existingLocal) is
encountered, and extend the disposal method matching at lines 243-246 to also
recognize DisposeAsync method invocations so that both synchronous and
asynchronous disposal paths are properly tracked by the flow analysis.
Summary by CodeRabbit
New Features
Tests
Documentation