Skip to content

Commit e94b2b6

Browse files
authored
Merge pull request github#6915 from geoffw0/nullterm2
C++: Fix the two null termination queries and re-enable them.
2 parents 2096c0a + e0e18c6 commit e94b2b6

File tree

3 files changed

+68
-16
lines changed

3 files changed

+68
-16
lines changed

cpp/ql/lib/semmle/code/cpp/commons/NullTermination.qll

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,19 @@ private predicate mayAddNullTerminatorHelper(Expr e, VariableAccess va, Expr e0)
1111
)
1212
}
1313

14+
bindingset[n1, n2]
15+
private predicate controlFlowNodeSuccessorTransitive(ControlFlowNode n1, ControlFlowNode n2) {
16+
exists(BasicBlock bb1, int pos1, BasicBlock bb2, int pos2 |
17+
pragma[only_bind_into](bb1).getNode(pos1) = n1 and
18+
pragma[only_bind_into](bb2).getNode(pos2) = n2 and
19+
(
20+
bb1 = bb2 and pos1 < pos2
21+
or
22+
bb1.getASuccessor+() = bb2
23+
)
24+
)
25+
}
26+
1427
/**
1528
* Holds if the expression `e` may add a null terminator to the string in
1629
* variable `v`.
@@ -30,14 +43,9 @@ predicate mayAddNullTerminator(Expr e, VariableAccess va) {
3043
)
3144
or
3245
// Assignment to another stack variable
33-
exists(Expr e0, BasicBlock bb, int pos, BasicBlock bb0, int pos0 |
34-
mayAddNullTerminatorHelper(e, va, e0) and
35-
bb.getNode(pos) = e and
36-
bb0.getNode(pos0) = e0
37-
|
38-
bb = bb0 and pos < pos0
39-
or
40-
bb.getASuccessor+() = bb0
46+
exists(Expr e0 |
47+
mayAddNullTerminatorHelper(pragma[only_bind_into](e), va, pragma[only_bind_into](e0)) and
48+
controlFlowNodeSuccessorTransitive(e, e0)
4149
)
4250
or
4351
// Assignment to non-stack variable
@@ -119,14 +127,9 @@ predicate variableMustBeNullTerminated(VariableAccess va) {
119127
variableMustBeNullTerminated(use) and
120128
// Simplified: check that `p` may not be null terminated on *any*
121129
// path to `use` (including the one found via `parameterUsePair`)
122-
not exists(Expr e, BasicBlock bb1, int pos1, BasicBlock bb2, int pos2 |
123-
mayAddNullTerminator(e, p.getAnAccess()) and
124-
bb1.getNode(pos1) = e and
125-
bb2.getNode(pos2) = use
126-
|
127-
bb1 = bb2 and pos1 < pos2
128-
or
129-
bb1.getASuccessor+() = bb2
130+
not exists(Expr e |
131+
mayAddNullTerminator(pragma[only_bind_into](e), p.getAnAccess()) and
132+
controlFlowNodeSuccessorTransitive(e, use)
130133
)
131134
)
132135
)

cpp/ql/test/query-tests/Likely Bugs/Memory Management/ImproperNullTermination/ImproperNullTermination.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@
2727
| test.cpp:454:18:454:23 | buffer | Variable $@ may not be null terminated. | test.cpp:452:8:452:13 | buffer | buffer |
2828
| test.cpp:513:10:513:15 | buffer | Variable $@ may not be null terminated. | test.cpp:511:8:511:13 | buffer | buffer |
2929
| test.cpp:519:16:519:21 | buffer | Variable $@ may not be null terminated. | test.cpp:517:8:517:13 | buffer | buffer |
30+
| test.cpp:558:10:558:16 | buffer2 | Variable $@ may not be null terminated. | test.cpp:553:8:553:14 | buffer2 | buffer2 |

cpp/ql/test/query-tests/Likely Bugs/Memory Management/ImproperNullTermination/test.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,3 +536,51 @@ void test_printf(char *str)
536536
}
537537
}
538538

539+
void test_reassignment()
540+
{
541+
{
542+
char buffer1[1024];
543+
char buffer2[1024];
544+
char *buffer_ptr = buffer1;
545+
546+
buffer_ptr = buffer2;
547+
strcpy(buffer_ptr, "content"); // null terminates buffer2
548+
strdup(buffer2); // GOOD
549+
}
550+
551+
{
552+
char buffer1[1024];
553+
char buffer2[1024];
554+
char *buffer_ptr = buffer1;
555+
556+
strcpy(buffer_ptr, "content"); // null terminates buffer1
557+
buffer_ptr = buffer2;
558+
strdup(buffer2); // BAD
559+
}
560+
561+
{
562+
char buffer1[1024];
563+
char buffer2[1024];
564+
char *buffer_ptr = buffer1;
565+
566+
while (cond())
567+
{
568+
buffer_ptr = buffer2;
569+
strcpy(buffer_ptr, "content"); // null terminates buffer2
570+
strdup(buffer2); // GOOD
571+
}
572+
}
573+
574+
{
575+
char buffer1[1024];
576+
char buffer2[1024];
577+
char *buffer_ptr = buffer1;
578+
579+
while (cond())
580+
{
581+
strcpy(buffer_ptr, "content"); // null terminates buffer1 or buffer2
582+
buffer_ptr = buffer2;
583+
strdup(buffer2); // BAD [NOT DETECTED]
584+
}
585+
}
586+
}

0 commit comments

Comments
 (0)