C#: Exclude case from cs/dispose-not-called-on-throw where the disposable is disposed by a UsingStmt, even when explicitly disposed.

This commit is contained in:
Calum Grant
2019-06-05 12:07:56 +01:00
parent 7790ac45bd
commit d055c85ff0
2 changed files with 22 additions and 2 deletions

View File

@@ -52,11 +52,19 @@ private class DisposeCall extends MethodCall {
DisposeCall() { this.getTarget() instanceof DisposeMethod }
}
private predicate localFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
DataFlow::localFlowStep(nodeFrom, nodeTo) and
not exists(AssignableDefinition def, UsingStmt uds |
nodeTo.asExpr() = def.getAReachableRead() and
def.getTargetAccess() = uds.getAVariableDeclExpr().getAccess()
)
}
private predicate reachesDisposeCall(DisposeCall disposeCall, DataFlow::Node node) {
DataFlow::localFlowStep(node, DataFlow::exprNode(disposeCall.getQualifier()))
localFlowStep(node, DataFlow::exprNode(disposeCall.getQualifier()))
or
exists(DataFlow::Node mid | reachesDisposeCall(disposeCall, mid) |
DataFlow::localFlowStep(node, mid)
localFlowStep(node, mid)
)
}

View File

@@ -62,6 +62,18 @@ class Test
// GOOD: using declaration
using SqlConnection c2 = new SqlConnection("");
c2.Open();
// GOOD: Always disposed
using SqlConnection c3 = new SqlConnection("");
Throw2(c3);
c3.Dispose();
// GOOD: Disposed automatically
using (SqlConnection c4 = new SqlConnection(""))
{
Throw2(c4);
c4.Dispose();
}
}
void Throw1(SqlConnection sc)