Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ jobs:
if echo "$out" | grep -q "CleanReportViewModel"; then
echo "FAIL: disposed field wrongly reported"; exit 1
fi
# a static IDisposable field is a process-lifetime singleton (Dapper's
# DisposedReader.Instance) — never an owned leak, so it stays silent.
if echo "$out" | grep -q "SharedTokenHolder"; then
echo "FAIL: a static singleton IDisposable field was wrongly reported"; exit 1
fi
# WPF004: an ignored `X.Subscribe(...)` result leaks; the captured+
# disposed one stays silent. "ignored" is unique to the WPF004 message.
echo "$out" | grep -q "MessengerViewModel.cs" \
Expand Down Expand Up @@ -216,7 +221,9 @@ jobs:
# dispose-optional (Task), disposed/escaping locals, a `for` loop (still
# skipped: `looped`), and a balanced acquire+dispose in a loop (`whileClean`)
# must stay silent:
for ok in clean looped esc exemptTask whileClean; do
# released via `await x.DisposeAsync()` (asyncDisposed) and the chained
# `.ConfigureAwait(false)` form (asyncDisposedCfg) -> both must stay silent.
for ok in clean looped esc exemptTask whileClean asyncDisposed asyncDisposedCfg; do
if echo "$out" | grep -q "'$ok'"; then echo "FAIL: silent/exempt case '$ok' was reported"; exit 1; fi
done
echo "OK: flow-sensitive OWN001/002/003 on real C# (path-sensitive, loops via while/foreach, never-vs-every-path wording, dispose-optional exempt, beyond flat)"
Expand Down
20 changes: 18 additions & 2 deletions frontend/roslyn/OwnSharp.Extractor/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -265,10 +265,21 @@ static bool LowerFlowStmt(StatementSyntax st, HashSet<string> tracked, List<obje

static void EmitFlowExpr(ExpressionSyntax expr, HashSet<string> tracked, List<object> nodes)
{
// x.Dispose()/x.Close() on a tracked local -> release.
// `await x.DisposeAsync()` is the IAsyncDisposable release — look through the
// await to the inner call so it counts as disposal, not a bare use.
if (expr is AwaitExpressionSyntax awaited)
expr = awaited.Expression;
// ... and through a trailing `.ConfigureAwait(false)` — the library-idiomatic
// `await x.DisposeAsync().ConfigureAwait(false)` awaits the ConfigureAwait call.
if (expr is InvocationExpressionSyntax cfg
&& cfg.Expression is MemberAccessExpressionSyntax cfgMa
&& cfgMa.Name.Identifier.Text == "ConfigureAwait"
&& cfgMa.Expression is InvocationExpressionSyntax inner)
expr = inner;
// x.Dispose()/x.Close()/x.DisposeAsync() on a tracked local -> release.
if (expr 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
Comment thread
coderabbitai[bot] marked this conversation as resolved.
&& tracked.Contains(rid.Identifier.Text))
{
Expand Down Expand Up @@ -449,6 +460,11 @@ or ImplicitObjectCreationExpressionSyntax

foreach (var fd in cls.Members.OfType<FieldDeclarationSyntax>())
{
// a `static` IDisposable field is a process-lifetime singleton (a shared
// HttpClient, a sentinel like Dapper's DisposedReader.Instance) — it is
// intentionally never disposed, so it is not an owned leak.
if (fd.Modifiers.Any(m => m.IsKind(SyntaxKind.StaticKeyword)))
continue;
var tname = fd.Declaration.Type.ToString();
if (!IsDisposableType(tname))
continue;
Expand Down
8 changes: 8 additions & 0 deletions frontend/roslyn/samples/DisposableFieldViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// leaks it. The core reports OWN001 [resource: disposable field] at the field.
public sealed class ReportViewModel
{
private readonly CancellationTokenSource _cts = new();

Check failure on line 10 in frontend/roslyn/samples/DisposableFieldViewModel.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable field '_cts' (type 'CancellationTokenSource') is never disposed — its owner 'ReportViewModel' leaks it (leak) [resource: disposable field]

Check warning on line 10 in frontend/roslyn/samples/DisposableFieldViewModel.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable field '_cts' (type 'CancellationTokenSource') is never disposed — its owner 'ReportViewModel' leaks it (leak)

Check failure on line 10 in frontend/roslyn/samples/DisposableFieldViewModel.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable field '_cts' (type 'CancellationTokenSource') is never disposed — its owner 'ReportViewModel' leaks it (leak)

Check failure on line 10 in frontend/roslyn/samples/DisposableFieldViewModel.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable field '_cts' (type 'CancellationTokenSource') is never disposed — its owner 'ReportViewModel' leaks it (leak) [resource: disposable field]

Check failure on line 10 in frontend/roslyn/samples/DisposableFieldViewModel.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable field '_cts' (type 'CancellationTokenSource') is never disposed — its owner 'ReportViewModel' leaks it (leak) [resource: disposable field]

Check warning on line 10 in frontend/roslyn/samples/DisposableFieldViewModel.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable field '_cts' (type 'CancellationTokenSource') is never disposed — its owner 'ReportViewModel' leaks it (leak)

Check failure on line 10 in frontend/roslyn/samples/DisposableFieldViewModel.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable field '_cts' (type 'CancellationTokenSource') is never disposed — its owner 'ReportViewModel' leaks it (leak)

Check failure on line 10 in frontend/roslyn/samples/DisposableFieldViewModel.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable field '_cts' (type 'CancellationTokenSource') is never disposed — its owner 'ReportViewModel' leaks it (leak) [resource: disposable field]

public void Refresh()
{
Expand All @@ -30,3 +30,11 @@
_cts.Dispose(); // release
}
}

// A `static` IDisposable field has process lifetime — it is intentionally never
// disposed (a shared HttpClient, or a sentinel like Dapper's DisposedReader.Instance,
// a false positive found by mining). The detector must NOT flag it -> silent.
public sealed class SharedTokenHolder
{
public static readonly CancellationTokenSource Shared = new();
}
20 changes: 20 additions & 0 deletions frontend/roslyn/samples/FlowLocalsSample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// OWN002: used after Dispose()
public void UseAfterDispose()
{
var uad = new MemoryStream();

Check failure on line 14 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN002

[OWN002] IDisposable local 'uad' is used after it is disposed [resource: disposable]

Check warning on line 14 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'uad' is used after it is disposed

Check failure on line 14 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'uad' is used after it is disposed

Check failure on line 14 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN002

[OWN002] IDisposable local 'uad' is used after it is disposed [resource: disposable]

Check failure on line 14 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN002

[OWN002] IDisposable local 'uad' is used after it is disposed [resource: disposable]

Check warning on line 14 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'uad' is used after it is disposed

Check failure on line 14 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'uad' is used after it is disposed

Check failure on line 14 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN002

[OWN002] IDisposable local 'uad' is used after it is disposed [resource: disposable]
uad.WriteByte(1);
uad.Dispose();
uad.WriteByte(2);
Expand All @@ -20,7 +20,7 @@
// OWN001: disposed only on the `then` path -> leaks on the else path
public void LeakOnElse(bool c)
{
var leak = new MemoryStream();

Check failure on line 23 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'leak' may not be disposed on every path (leak) [resource: disposable]

Check warning on line 23 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'leak' may not be disposed on every path (leak)

Check failure on line 23 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'leak' may not be disposed on every path (leak)

Check failure on line 23 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'leak' may not be disposed on every path (leak) [resource: disposable]

Check failure on line 23 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'leak' may not be disposed on every path (leak) [resource: disposable]

Check warning on line 23 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'leak' may not be disposed on every path (leak)

Check failure on line 23 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'leak' may not be disposed on every path (leak)

Check failure on line 23 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'leak' may not be disposed on every path (leak) [resource: disposable]
if (c)
{
leak.Dispose();
Expand All @@ -30,7 +30,7 @@
// OWN003: disposed twice
public void DoubleDispose()
{
var dbl = new MemoryStream();

Check failure on line 33 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN003

[OWN003] IDisposable local 'dbl' is disposed more than once [resource: disposable]

Check warning on line 33 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'dbl' is disposed more than once

Check failure on line 33 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'dbl' is disposed more than once

Check failure on line 33 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN003

[OWN003] IDisposable local 'dbl' is disposed more than once [resource: disposable]

Check failure on line 33 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN003

[OWN003] IDisposable local 'dbl' is disposed more than once [resource: disposable]

Check warning on line 33 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'dbl' is disposed more than once

Check failure on line 33 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'dbl' is disposed more than once

Check failure on line 33 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN003

[OWN003] IDisposable local 'dbl' is disposed more than once [resource: disposable]
dbl.Dispose();
dbl.Dispose();
}
Expand Down Expand Up @@ -60,7 +60,7 @@
{
while (n > 0)
{
var whileLeak = new MemoryStream();

Check failure on line 63 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'whileLeak' is never disposed (leak) [resource: disposable]

Check warning on line 63 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'whileLeak' is never disposed (leak)

Check failure on line 63 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'whileLeak' is never disposed (leak)

Check failure on line 63 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'whileLeak' is never disposed (leak) [resource: disposable]

Check failure on line 63 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'whileLeak' is never disposed (leak) [resource: disposable]

Check warning on line 63 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'whileLeak' is never disposed (leak)

Check failure on line 63 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'whileLeak' is never disposed (leak)

Check failure on line 63 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'whileLeak' is never disposed (leak) [resource: disposable]
whileLeak.WriteByte(1);
n = n - 1;
}
Expand All @@ -71,7 +71,7 @@
{
foreach (var it in items)
{
var foreachLeak = new MemoryStream();

Check failure on line 74 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'foreachLeak' is never disposed (leak) [resource: disposable]

Check warning on line 74 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'foreachLeak' is never disposed (leak)

Check failure on line 74 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'foreachLeak' is never disposed (leak)

Check failure on line 74 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'foreachLeak' is never disposed (leak) [resource: disposable]

Check failure on line 74 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'foreachLeak' is never disposed (leak) [resource: disposable]

Check warning on line 74 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'foreachLeak' is never disposed (leak)

Check failure on line 74 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'foreachLeak' is never disposed (leak)

Check failure on line 74 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'foreachLeak' is never disposed (leak) [resource: disposable]
foreachLeak.WriteByte((byte)it);
}
}
Expand Down Expand Up @@ -110,7 +110,27 @@
// catches it.
public void TimerLeaks()
{
var realTimer = new Timer(_ => { });

Check failure on line 113 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'realTimer' is never disposed (leak) [resource: disposable]

Check warning on line 113 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'realTimer' is never disposed (leak)

Check failure on line 113 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'realTimer' is never disposed (leak)

Check failure on line 113 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'realTimer' is never disposed (leak) [resource: disposable]

Check failure on line 113 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'realTimer' is never disposed (leak) [resource: disposable]

Check warning on line 113 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'realTimer' is never disposed (leak)

Check failure on line 113 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

IDisposable local 'realTimer' is never disposed (leak)

Check failure on line 113 in frontend/roslyn/samples/FlowLocalsSample.cs

View workflow job for this annotation

GitHub Actions / own-check repo scan (github + msbuild) + composite action

OWN001

[OWN001] IDisposable local 'realTimer' is never disposed (leak) [resource: disposable]
realTimer.Change(0, 1000);
}

// `await x.DisposeAsync()` is the IAsyncDisposable release and must count as
// disposal, not a leak. Reduced from Dapper's WrappedReaderTests
// (DbWrappedReader_DisposeAsync_DoesNotThrow), a false positive found by mining.
// Silent.
public async Task DisposedAsync()
{
var asyncDisposed = new MemoryStream();
asyncDisposed.WriteByte(1);
await asyncDisposed.DisposeAsync();
}

// the library-idiomatic chained form `await x.DisposeAsync().ConfigureAwait(false)`
// is also disposal, not a leak (CodeRabbit caught this gap). Silent.
public async Task DisposedAsyncConfigured()
{
var asyncDisposedCfg = new MemoryStream();
asyncDisposedCfg.WriteByte(1);
await asyncDisposedCfg.DisposeAsync().ConfigureAwait(false);
}
}
Loading