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
20 changes: 15 additions & 5 deletions csharp/ql/src/API Abuse/DisposeNotCalledOnException.ql
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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.
Expand Down
7 changes: 6 additions & 1 deletion csharp/ql/src/semmle/code/csharp/Assignable.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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()
)
}

Expand Down
1 change: 1 addition & 0 deletions csharp/ql/src/semmle/code/csharp/dataflow/DataFlow.qll
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,7 @@ module DataFlow {
)
}

pragma[nomagic]
private ControlFlowElement getANonExactScopeChild(ControlFlowElement scope) {
scope = getAScope(false) and
result = scope
Expand Down