Skip to content

Commit 2397376

Browse files
authored
Merge pull request #862 from github/michaelrfairhurst/fix-resource-leak-analysis-qll-performance-issue
Fix performance issue in ResourceLeakAnalysis.qll
2 parents 7317d11 + dd86a4e commit 2397376

File tree

4 files changed

+16
-16
lines changed

4 files changed

+16
-16
lines changed

c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected

+1
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ WARNING: module 'DataFlow' has been deprecated and may be removed in future (Mut
77
| test.c:72:3:72:10 | call to mtx_lock | Mutex 'g1' is locked here and may not always be subsequently unlocked. |
88
| test.c:79:3:79:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. |
99
| test.c:101:5:101:12 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. |
10+
| test.c:113:3:113:10 | call to mtx_lock | Mutex 'ptr_m1' is locked here and may not always be subsequently unlocked. |

c/misra/test/rules/RULE-22-16/test.c

+8
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,12 @@ void f15(int p) {
104104
}
105105
mtx_unlock(&m);
106106
}
107+
}
108+
109+
void f16(int p) {
110+
mtx_t *ptr;
111+
mtx_t *ptr_m1 = ptr;
112+
mtx_t *ptr_m2 = ptr;
113+
mtx_lock(ptr_m1); // COMPLIANT[FALSE_POSITIVE]
114+
mtx_unlock(ptr_m2);
107115
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- `RULE-22-16`, `ERR57-CPP`, `A15-1-4` - `MutexObjectsNotAlwaysUnlocked.ql`, `DoNotLeakResourcesWhenHandlingExceptions.ql`, `ValidResourcesStateBeforeThrow.ql`:
2+
- Shared module `ResourceLeakAnalysis.qll` changed to not get aliases recursively for simplicity and improved performance. The recent update to these queries had logic intending to handle the case where an allocation node is an alias of a parent node, and the free operation releases that parent node. However, the behavior was incorrectly defined and not working, and in the presence of performance issues this behavior has been removed.
3+
- (`RULE-22-16` only) The alias behavior has been updated to compare expressions with `HashCons` instead of `GlobalValueNumbering` for higher performance. GVN is more expensive generally, seemed to introduce low performance joins secondarily, and is stricter than `HashCons` in a contravening position, meaning a stricter analysis introduces a higher likelihood of false positives.

cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll

+4-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import cpp
22
import semmle.code.cpp.dataflow.DataFlow
3-
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
3+
import semmle.code.cpp.valuenumbering.HashCons
44
import semmle.code.cpp.controlflow.Dominance
55
import codeql.util.Boolean
66

@@ -40,13 +40,14 @@ signature module ResourceLeakConfigSig {
4040

4141
predicate isFree(ControlFlowNode node, DataFlow::Node resource);
4242

43+
bindingset[node]
4344
default DataFlow::Node getAnAlias(DataFlow::Node node) {
4445
DataFlow::localFlow(node, result)
4546
or
4647
exists(Expr current, Expr after |
4748
current in [node.asExpr(), node.asDefiningArgument()] and
4849
after in [result.asExpr(), result.asDefiningArgument()] and
49-
globalValueNumber(current) = globalValueNumber(after) and
50+
hashCons(current) = hashCons(after) and
5051
strictlyDominates(current, after)
5152
)
5253
}
@@ -63,19 +64,6 @@ module ResourceLeak<ResourceLeakConfigSig Config> {
6364
Config::isAllocate(cfgNode, resource)
6465
}
6566

66-
/**
67-
* Get an alias of a resource, and aliases of nodes that are aliased by a resource.
68-
*/
69-
private DataFlow::Node getAnAliasRecursive(DataFlow::Node node) {
70-
result = Config::getAnAlias(node) and
71-
Config::isAllocate(_, node)
72-
or
73-
exists(DataFlow::Node parent |
74-
node = getAnAliasRecursive(parent) and
75-
result = Config::getAnAlias(parent)
76-
)
77-
}
78-
7967
private predicate isLeakedAtControlPoint(TResource resource, ControlFlowNode cfgNode) {
8068
// Holds if this control point is where the resource was allocated (and therefore not freed).
8169
resource = TJustResource(_, cfgNode)
@@ -85,7 +73,7 @@ module ResourceLeak<ResourceLeakConfigSig Config> {
8573
isLeakedAtControlPoint(resource, cfgNode.getAPredecessor()) and
8674
not exists(DataFlow::Node freed, DataFlow::Node resourceNode |
8775
Config::isFree(cfgNode, freed) and
88-
freed = getAnAliasRecursive(resourceNode) and
76+
freed = Config::getAnAlias(resourceNode) and
8977
resource = TJustResource(resourceNode, _)
9078
)
9179
}

0 commit comments

Comments
 (0)