diff --git a/csharp/ql/src/API Abuse/DisposeNotCalledOnException.ql b/csharp/ql/src/API Abuse/DisposeNotCalledOnException.ql index ec3db37f8bba..6b4ba7519e48 100644 --- a/csharp/ql/src/API Abuse/DisposeNotCalledOnException.ql +++ b/csharp/ql/src/API Abuse/DisposeNotCalledOnException.ql @@ -49,18 +49,28 @@ predicate isTriedAgainstException(ControlFlowElement cfe, ExceptionClass ec) { ) } +private class DisposeCall extends MethodCall { + DisposeCall() { this.getTarget() instanceof DisposeMethod } +} + +private predicate reachesDisposeCall(DisposeCall disposeCall, DataFlow::Node node) { + DataFlow::localFlowStep(node, DataFlow::exprNode(disposeCall.getQualifier())) + or + exists(DataFlow::Node mid | reachesDisposeCall(disposeCall, mid) | + DataFlow::localFlowStep(node, mid) + ) +} + /** * Holds if `disposeCall` disposes the object created by `disposableCreation`. */ -predicate disposeReachableFromDisposableCreation(MethodCall disposeCall, Expr disposableCreation) { +predicate disposeReachableFromDisposableCreation(DisposeCall disposeCall, Expr disposableCreation) { // The qualifier of the Dispose call flows from something that introduced a disposable into scope ( disposableCreation instanceof LocalScopeDisposableCreation or disposableCreation instanceof MethodCall ) and - DataFlow::localFlowStep+(DataFlow::exprNode(disposableCreation), - DataFlow::exprNode(disposeCall.getQualifier())) and - disposeCall.getTarget() instanceof DisposeMethod + reachesDisposeCall(disposeCall, DataFlow::exprNode(disposableCreation)) } class MethodCallThatMayThrow extends MethodCall { @@ -73,7 +83,7 @@ ControlFlowElement getACatchOrFinallyClauseChild() { result = getACatchOrFinallyClauseChild().getAChild() } -from MethodCall disposeCall, Expr disposableCreation, MethodCallThatMayThrow callThatThrows +from DisposeCall disposeCall, Expr disposableCreation, MethodCallThatMayThrow callThatThrows where disposeReachableFromDisposableCreation(disposeCall, disposableCreation) and // The dispose call is not, itself, within a dispose method. diff --git a/csharp/ql/src/semmle/code/csharp/Assignable.qll b/csharp/ql/src/semmle/code/csharp/Assignable.qll index 9783418475b4..14318ac37b15 100644 --- a/csharp/ql/src/semmle/code/csharp/Assignable.qll +++ b/csharp/ql/src/semmle/code/csharp/Assignable.qll @@ -76,6 +76,11 @@ class AssignableRead extends AssignableAccess { not nameOfChild(_, this) } + pragma[noinline] + private ControlFlow::Node getAnAdjacentReadSameVar() { + Ssa::Internal::adjacentReadPairSameVar(this.getAControlFlowNode(), result) + } + /** * Gets a next read of the same underlying assignable. That is, a read * that can be reached from this read without passing through any other reads, @@ -102,7 +107,7 @@ class AssignableRead extends AssignableAccess { */ AssignableRead getANextRead() { forex(ControlFlow::Node cfn | cfn = result.getAControlFlowNode() | - Ssa::Internal::adjacentReadPairSameVar(this.getAControlFlowNode(), cfn) + cfn = this.getAnAdjacentReadSameVar() ) } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll b/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll index f66876653d35..fd749c55f7c9 100755 --- a/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll @@ -704,6 +704,7 @@ module DataFlow { ) } + pragma[nomagic] private ControlFlowElement getANonExactScopeChild(ControlFlowElement scope) { scope = getAScope(false) and result = scope