@@ -18,36 +18,6 @@ import csharp
1818import Dispose
1919import semmle.code.csharp.frameworks.System
2020
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-
5121private class DisposeCall extends MethodCall {
5222 DisposeCall ( ) { this .getTarget ( ) instanceof DisposeMethod }
5323}
@@ -78,8 +48,17 @@ predicate disposeReachableFromDisposableCreation(DisposeCall disposeCall, Expr d
7848 reachesDisposeCall ( disposeCall , DataFlow:: exprNode ( disposableCreation ) )
7949}
8050
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+ )
8362}
8463
8564ControlFlowElement getACatchOrFinallyClauseChild ( ) {
@@ -88,15 +67,71 @@ ControlFlowElement getACatchOrFinallyClauseChild() {
8867 result = getACatchOrFinallyClauseChild ( ) .getAChild ( )
8968}
9069
91- from DisposeCall disposeCall , Expr disposableCreation , MethodCallThatMayThrow callThatThrows
92- where
70+ private predicate candidate ( DisposeCall disposeCall , Call call , Expr disposableCreation ) {
9371 disposeReachableFromDisposableCreation ( disposeCall , disposableCreation ) and
9472 // The dispose call is not, itself, within a dispose method.
9573 not disposeCall .getEnclosingCallable ( ) instanceof DisposeMethod and
9674 // Dispose call not within a finally or catch block
9775 not getACatchOrFinallyClauseChild ( ) = disposeCall and
9876 // 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 )
101136select disposeCall , "Dispose missed if exception is thrown by $@." , callThatThrows ,
102137 callThatThrows .toString ( )
0 commit comments