Skip to content

Commit 4e532e1

Browse files
committed
codeql: add query to check for wrong pool ele_acquire null check
pool ele_acquire can never return NULL (even when the pool is empty) so checking for that is likely to be a misunderstanding or superflous.
1 parent d2fd47d commit 4e532e1

File tree

4 files changed

+75
-27
lines changed

4 files changed

+75
-27
lines changed

contrib/codeql/dev/MissingPoolFreeCheck.ql

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,10 @@
1010
*/
1111

1212
import cpp
13-
14-
class PoolAcquire extends FunctionCall {
15-
PoolAcquire() {
16-
(this.getTarget().getName().matches("%_idx_acquire") or this.getTarget().getName().matches("%_ele_acquire")) and
17-
this.getTarget().getLocation().getFile().getBaseName().matches("fd_pool.c") and
18-
not this.getLocation().getFile().getAbsolutePath().matches("%/tmpl/%")
19-
}
20-
string getPoolName() {
21-
result = this.getTarget().getName().replaceAll("_idx_acquire", "").replaceAll("_ele_acquire", "")
22-
}
23-
}
24-
25-
26-
class PoolFree extends FunctionCall {
27-
PoolFree() {
28-
(this.getTarget().getName().matches("%_free") or this.getTarget().getName().matches("%_used")) and
29-
this.getTarget().getLocation().getFile().getBaseName().matches("fd_pool.c") and
30-
not this.getLocation().getFile().getAbsolutePath().matches("%/tmpl/%")
31-
}
32-
33-
string getPoolName() {
34-
result = this.getTarget().getName().replaceAll("_free", "").replaceAll("_used", "")
35-
}
36-
}
37-
13+
import fdpool
3814

3915
from PoolAcquire acq
4016
where
41-
not exists(PoolFree free | dominates(free, acq) and free.getPoolName() = acq.getPoolName()) and
42-
not acq.getLocation().getFile().getBaseName() = "fd_types.c"
17+
not exists(PoolFree free | dominates(free, acq) and free.getPoolName() = acq.getPoolName()) and
18+
not acq.getLocation().getFile().getBaseName() = "fd_types.c"
4319
select acq, acq.getPoolName()

contrib/codeql/dev/fdpool.qll

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import cpp
2+
3+
class PoolAcquire extends FunctionCall {
4+
PoolAcquire() {
5+
(
6+
this.getTarget().getName().matches("%_idx_acquire") or
7+
this.getTarget().getName().matches("%_ele_acquire")
8+
) and
9+
this.getTarget().getLocation().getFile().getBaseName().matches("fd_pool.c") and
10+
not this.getLocation().getFile().getAbsolutePath().matches("%/tmpl/%")
11+
}
12+
13+
string getPoolName() {
14+
result =
15+
this.getTarget().getName().replaceAll("_idx_acquire", "").replaceAll("_ele_acquire", "")
16+
}
17+
}
18+
19+
class PoolFree extends FunctionCall {
20+
PoolFree() {
21+
(this.getTarget().getName().matches("%_free") or this.getTarget().getName().matches("%_used")) and
22+
this.getTarget().getLocation().getFile().getBaseName().matches("fd_pool.c") and
23+
not this.getLocation().getFile().getAbsolutePath().matches("%/tmpl/%")
24+
}
25+
26+
string getPoolName() {
27+
result = this.getTarget().getName().replaceAll("_free", "").replaceAll("_used", "")
28+
}
29+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* @name Checking for null after pool ele_acquire is dubious.
3+
* @description Pool ele_acquire functions never return null even when
4+
* the pool is exhausted. Therefore, checking their return value for null
5+
* indicates a misunderstanding and is likely a bug.
6+
* @kind path-problem
7+
* @problem.severity warning
8+
* @precision high
9+
* @id asymmetric-research/fd-pool-ele-acquire-wrong-null-check
10+
*/
11+
12+
import cpp
13+
import semmle.code.cpp.dataflow.new.DataFlow
14+
import fdpool
15+
import semmle.code.cpp.ir.IR
16+
import semmle.code.cpp.controlflow.IRGuards
17+
18+
module AcquireToNullCheck implements DataFlow::ConfigSig {
19+
predicate isSource(DataFlow::Node source) {
20+
exists(PoolAcquire pa | pa.isEleAcquire() | source.asExpr() = pa)
21+
}
22+
23+
predicate isSink(DataFlow::Node sink) {
24+
exists(IRGuardCondition g |
25+
g.comparesEq(sink.asInstruction().getAUse(),
26+
any(ConstantValueInstruction const | const.getValue() = "0").getAUse(), 0, false, _)
27+
)
28+
}
29+
}
30+
31+
module Flow = DataFlow::Global<AcquireToNullCheck>;
32+
33+
import Flow::PathGraph
34+
35+
from Flow::PathNode sourceNode, Flow::PathNode sinkNode
36+
where
37+
// only intra-procedural flow to reduce FPs
38+
sourceNode.getNode().getEnclosingCallable() = sinkNode.getNode().getEnclosingCallable() and
39+
Flow::flowPath(sourceNode, sinkNode)
40+
select sinkNode, sourceNode, sinkNode,
41+
"Result of $@ cannot be null; checking it indicates a misunderstanding.", sourceNode,
42+
"pool ele_acquire"

contrib/codeql/nightly/qlpack.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ extractor: cpp
44
warnOnImplicitThis: true
55
dependencies:
66
codeql/cpp-all: "*"
7+
asymmetric-research/fd-dev-queries: "*"

0 commit comments

Comments
 (0)