-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathNoDisposeCallOnLocalIDisposable.ql
More file actions
78 lines (74 loc) · 2.77 KB
/
NoDisposeCallOnLocalIDisposable.ql
File metadata and controls
78 lines (74 loc) · 2.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/**
* @name Missing Dispose call on local IDisposable
* @description Methods that create objects of type 'IDisposable' should call 'Dispose' on those
* objects, otherwise unmanaged resources may not be released.
* @kind problem
* @problem.severity warning
* @precision high
* @id cs/local-not-disposed
* @tags efficiency
* maintainability
* security
* external/cwe/cwe-404
* external/cwe/cwe-459
* external/cwe/cwe-460
*/
import csharp
import Dispose
import semmle.code.csharp.frameworks.System
import semmle.code.csharp.commons.Disposal
/** Holds if expression `e` escapes the local method scope. */
predicate escapes(Expr e) {
// Things that return escape
exists(Callable c | c.canReturn(e) or c.canYieldReturn(e))
or
// Things that are assigned to fields, properties, or indexers escape the scope
exists(AssignableDefinition def, Assignable a |
def.getSource() = e and
a = def.getTarget()
|
a instanceof Field or
a instanceof Property or
a instanceof Indexer
)
or
// Things that are added to a collection of some kind are likely to escape the scope
exists(MethodCall mc | mc.getTarget().hasName("Add") | mc.getAnArgument() = e)
}
/** Holds if the `disposable` is a whitelisted result. */
predicate isWhitelisted(LocalScopeDisposableCreation disposable) {
exists(MethodCall mc |
// Close can often be used instead of Dispose
mc.getTarget().hasName("Close")
or
// Used as an alias for Dispose
mc.getTarget().hasName("Clear")
|
mc.getQualifier() = disposable.getADisposeTarget()
)
or
// WebControls are usually disposed automatically
disposable.getType() instanceof WebControl
}
from LocalScopeDisposableCreation disposable
// The disposable is local scope - the lifetime is the execution of this method
where
not escapes(disposable.getADisposeTarget()) and
// Only care about library types - user types often have spurious IDisposable declarations
disposable.getType().fromLibrary() and
// Disposables constructed in the initializer of a `using` are safe
not exists(UsingStmt us | us.getAnExpr() = disposable.getADisposeTarget()) and
// Foreach calls Dispose
not exists(ForeachStmt fs | fs.getIterableExpr() = disposable.getADisposeTarget()) and
// As are disposables on which the Dispose method is called explicitly
not exists(MethodCall mc |
mc.getTarget() instanceof DisposeMethod and
mc.getQualifier() = disposable.getADisposeTarget()
) and
// Ignore whitelisted results
not isWhitelisted(disposable) and
// Not passed to a disposing method
not exists(Call c, Parameter p | disposable.getADisposeTarget() = c.getArgumentForParameter(p) |
mayBeDisposed(p)
)
select disposable, "Disposable '" + disposable.getType() + "' is created here but is not disposed."