Merge pull request #1404 from calumgrant/cs/dispose-not-called-on-throw

C#: Improvement to cs/dispose-not-called-on-throw
This commit is contained in:
Tom Hvitved
2019-06-17 11:25:16 +02:00
committed by GitHub
3 changed files with 35 additions and 2 deletions

View File

@@ -0,0 +1,13 @@
# Improvements to C# analysis
## Changes to existing queries
| **Query** | **Expected impact** | **Change** |
|------------------------------|------------------------|-----------------------------------|
| Dispose may not be called if an exception is thrown during execution (`cs/dispose-not-called-on-throw`) | Fewer false positive results | Results have been removed where an object is disposed both by a `using` statement and a `Dispose` call. |
## Changes to code extraction
## Changes to QL libraries
## Changes to autobuilder

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 us |
nodeTo.asExpr() = def.getAReachableRead() and
def.getTargetAccess() = us.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)