@@ -18,36 +18,6 @@ import csharp
18
18
import Dispose
19
19
import semmle.code.csharp.frameworks.System
20
20
21
- /**
22
- * Gets an exception type that may be thrown during the execution of method `m`.
23
- * Assumes any exception may be thrown by library types.
24
- */
25
- Class getAThrownException ( Method m ) {
26
- m .fromLibrary ( ) and
27
- result = any ( SystemExceptionClass sc )
28
- or
29
- exists ( ControlFlowElement cfe |
30
- cfe = any ( ThrowElement te | result = te .getExpr ( ) .getType ( ) ) or
31
- cfe = any ( MethodCall mc | result = getAThrownException ( mc .getARuntimeTarget ( ) ) )
32
- |
33
- cfe .getEnclosingCallable ( ) = m and
34
- not isTriedAgainstException ( cfe , result )
35
- )
36
- }
37
-
38
- /**
39
- * Holds if control flow element is tried against throwing an exception of type
40
- * `ec`.
41
- */
42
- pragma [ noinline]
43
- predicate isTriedAgainstException ( ControlFlowElement cfe , ExceptionClass ec ) {
44
- ( cfe instanceof ThrowElement or cfe instanceof MethodCall ) and
45
- exists ( TryStmt ts |
46
- ts .getATriedElement ( ) = cfe and
47
- exists ( ts .getAnExceptionHandler ( ec ) )
48
- )
49
- }
50
-
51
21
private class DisposeCall extends MethodCall {
52
22
DisposeCall ( ) { this .getTarget ( ) instanceof DisposeMethod }
53
23
}
@@ -78,8 +48,17 @@ predicate disposeReachableFromDisposableCreation(DisposeCall disposeCall, Expr d
78
48
reachesDisposeCall ( disposeCall , DataFlow:: exprNode ( disposableCreation ) )
79
49
}
80
50
81
- class MethodCallThatMayThrow extends MethodCall {
82
- MethodCallThatMayThrow ( ) { exists ( getAThrownException ( this .getARuntimeTarget ( ) ) ) }
51
+ /**
52
+ * Holds if control flow element is tried against throwing an exception of type
53
+ * `ec`.
54
+ */
55
+ pragma [ noinline]
56
+ predicate isTriedAgainstException ( ControlFlowElement cfe , ExceptionClass ec ) {
57
+ ( cfe instanceof ThrowElement or cfe instanceof MethodCall ) and
58
+ exists ( TryStmt ts |
59
+ ts .getATriedElement ( ) = cfe and
60
+ exists ( ts .getAnExceptionHandler ( ec ) )
61
+ )
83
62
}
84
63
85
64
ControlFlowElement getACatchOrFinallyClauseChild ( ) {
@@ -88,15 +67,71 @@ ControlFlowElement getACatchOrFinallyClauseChild() {
88
67
result = getACatchOrFinallyClauseChild ( ) .getAChild ( )
89
68
}
90
69
91
- from DisposeCall disposeCall , Expr disposableCreation , MethodCallThatMayThrow callThatThrows
92
- where
70
+ private predicate candidate ( DisposeCall disposeCall , Call call , Expr disposableCreation ) {
93
71
disposeReachableFromDisposableCreation ( disposeCall , disposableCreation ) and
94
72
// The dispose call is not, itself, within a dispose method.
95
73
not disposeCall .getEnclosingCallable ( ) instanceof DisposeMethod and
96
74
// Dispose call not within a finally or catch block
97
75
not getACatchOrFinallyClauseChild ( ) = disposeCall and
98
76
// At least one method call exists between the allocation and disposal that could throw
99
- disposableCreation .getAReachableElement ( ) = callThatThrows and
100
- callThatThrows .getAReachableElement ( ) = disposeCall
77
+ disposableCreation .getAReachableElement ( ) = call and
78
+ call .getAReachableElement ( ) = disposeCall
79
+ }
80
+
81
+ private class RelevantMethod extends Method {
82
+ RelevantMethod ( ) {
83
+ exists ( Call call |
84
+ candidate ( _, call , _) and
85
+ this = call .getARuntimeTarget ( )
86
+ )
87
+ or
88
+ exists ( RelevantMethod other | other .calls ( this ) )
89
+ }
90
+
91
+ pragma [ noinline]
92
+ private RelevantMethod callsNoTry ( ) {
93
+ exists ( MethodCall mc |
94
+ result = mc .getARuntimeTarget ( ) and
95
+ not isTriedAgainstException ( mc , _) and
96
+ mc .getEnclosingCallable ( ) = this
97
+ )
98
+ }
99
+
100
+ pragma [ noinline]
101
+ private RelevantMethod callsInTry ( MethodCall mc ) {
102
+ result = mc .getARuntimeTarget ( ) and
103
+ isTriedAgainstException ( mc , _) and
104
+ mc .getEnclosingCallable ( ) = this
105
+ }
106
+
107
+ /**
108
+ * Gets an exception type that may be thrown during the execution of this method.
109
+ * Assumes any exception may be thrown by library types.
110
+ */
111
+ Class getAThrownException ( ) {
112
+ this .fromLibrary ( ) and
113
+ result instanceof SystemExceptionClass
114
+ or
115
+ exists ( ControlFlowElement cfe |
116
+ result = cfe .( ThrowElement ) .getExpr ( ) .getType ( ) and
117
+ cfe .getEnclosingCallable ( ) = this
118
+ or
119
+ result = this .callsInTry ( cfe ) .getAThrownException ( )
120
+ |
121
+ not isTriedAgainstException ( cfe , result )
122
+ )
123
+ or
124
+ result = this .callsNoTry ( ) .getAThrownException ( )
125
+ }
126
+ }
127
+
128
+ class MethodCallThatMayThrow extends MethodCall {
129
+ MethodCallThatMayThrow ( ) {
130
+ exists ( this .getARuntimeTarget ( ) .( RelevantMethod ) .getAThrownException ( ) )
131
+ }
132
+ }
133
+
134
+ from DisposeCall disposeCall , Expr disposableCreation , MethodCallThatMayThrow callThatThrows
135
+ where candidate ( disposeCall , callThatThrows , disposableCreation )
101
136
select disposeCall , "Dispose missed if exception is thrown by $@." , callThatThrows ,
102
137
callThatThrows .toString ( )
0 commit comments