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
27 changes: 20 additions & 7 deletions csharp/ql/src/API Abuse/NoDisposeCallOnLocalIDisposable.ql
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import csharp
import Dispose
import semmle.code.csharp.frameworks.System
import semmle.code.csharp.frameworks.system.threading.Tasks
import semmle.code.csharp.commons.Disposal

private class ReturnNode extends DataFlow::ExprNode {
Expand All @@ -24,15 +25,27 @@ private class ReturnNode extends DataFlow::ExprNode {
}
}

private class Task extends Type {
Task() {
this instanceof SystemThreadingTasksTaskClass or
this instanceof SystemThreadingTasksTaskTClass
}
}

module DisposeCallOnLocalIDisposableConfig implements DataFlow::ConfigSig {
predicate isSource(DataFlow::Node node) {
node.asExpr() =
any(LocalScopeDisposableCreation disposable |
// Only care about library types - user types often have spurious IDisposable declarations
disposable.getType().fromLibrary() and
// WebControls are usually disposed automatically
not disposable.getType() instanceof WebControl
)
exists(LocalScopeDisposableCreation disposable, Type t |
node.asExpr() = disposable and
t = disposable.getType()
|
// Only care about library types - user types often have spurious IDisposable declarations
t.fromLibrary() and
// WebControls are usually disposed automatically
not t instanceof WebControl and
// It is typically not nessesary to dispose tasks
// https://devblogs.microsoft.com/pfxteam/do-i-need-to-dispose-of-tasks/
not t instanceof Task
)
}

predicate isSink(DataFlow::Node node) {
Expand Down
4 changes: 4 additions & 0 deletions csharp/ql/src/change-notes/2025-03-10-task-not-disposed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `cs/local-not-disposed` query no longer flags un-disposed tasks as this is often not needed (explained [here](https://devblogs.microsoft.com/pfxteam/do-i-need-to-dispose-of-tasks/)).
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.IO.Compression;
using System.Xml;
using System.Threading;
using System.Threading.Tasks;

class Test
{
Expand Down Expand Up @@ -86,6 +87,13 @@ public IDisposable Method()
using (XmlReader.Create(source ?? new StringReader("xml"), null))
;

// GOOD: Flagging these generates too much noise and there is a general
// acceptance that Tasks are not disposed.
// https://devblogs.microsoft.com/pfxteam/do-i-need-to-dispose-of-tasks/
Task t = new Task(() => { });
t.Start();
t.Wait();

return null;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
| NoDisposeCallOnLocalIDisposable.cs:50:19:50:38 | object creation of type Timer | Disposable 'Timer' is created but not disposed. |
| NoDisposeCallOnLocalIDisposable.cs:51:18:51:73 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. |
| NoDisposeCallOnLocalIDisposable.cs:52:9:52:64 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. |
| NoDisposeCallOnLocalIDisposable.cs:74:25:74:71 | call to method Create | Disposable 'XmlReader' is created but not disposed. |
| NoDisposeCallOnLocalIDisposable.cs:74:42:74:64 | object creation of type StringReader | Disposable 'StringReader' is created but not disposed. |
| NoDisposeCallOnLocalIDisposable.cs:79:38:79:67 | object creation of type StreamWriter | Disposable 'StreamWriter' is created but not disposed. |
| NoDisposeCallOnLocalIDisposable.cs:51:19:51:38 | object creation of type Timer | Disposable 'Timer' is created but not disposed. |
| NoDisposeCallOnLocalIDisposable.cs:52:18:52:73 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. |
| NoDisposeCallOnLocalIDisposable.cs:53:9:53:64 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. |
| NoDisposeCallOnLocalIDisposable.cs:75:25:75:71 | call to method Create | Disposable 'XmlReader' is created but not disposed. |
| NoDisposeCallOnLocalIDisposable.cs:75:42:75:64 | object creation of type StringReader | Disposable 'StringReader' is created but not disposed. |
| NoDisposeCallOnLocalIDisposable.cs:80:38:80:67 | object creation of type StreamWriter | Disposable 'StreamWriter' is created but not disposed. |
| NoDisposeCallOnLocalIDisposableBad.cs:8:22:8:56 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. |