Skip to content

Commit ab62606

Browse files
authored
Merge pull request #14822 from MathiasVP/fix-global-variable-flow-for-arrays
C++: Fix global-variable flow for array types
2 parents 9bdc2d1 + dcba8e5 commit ab62606

File tree

7 files changed

+130
-7
lines changed

7 files changed

+130
-7
lines changed

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,24 @@ class GlobalLikeVariable extends Variable {
645645
}
646646
}
647647

648+
/**
649+
* Returns the smallest indirection for the type `t`.
650+
*
651+
* For most types this is `1`, but for `ArrayType`s (which are allocated on
652+
* the stack) this is `0`
653+
*/
654+
int getMinIndirectionsForType(Type t) {
655+
if t.getUnspecifiedType() instanceof Cpp::ArrayType then result = 0 else result = 1
656+
}
657+
658+
private int getMinIndirectionForGlobalUse(Ssa::GlobalUse use) {
659+
result = getMinIndirectionsForType(use.getUnspecifiedType())
660+
}
661+
662+
private int getMinIndirectionForGlobalDef(Ssa::GlobalDef def) {
663+
result = getMinIndirectionsForType(def.getUnspecifiedType())
664+
}
665+
648666
/**
649667
* Holds if data can flow from `node1` to `node2` in a way that loses the
650668
* calling context. For example, this would happen with flow through a
@@ -656,7 +674,7 @@ predicate jumpStep(Node n1, Node n2) {
656674
v = globalUse.getVariable() and
657675
n1.(FinalGlobalValue).getGlobalUse() = globalUse
658676
|
659-
globalUse.getIndirection() = 1 and
677+
globalUse.getIndirection() = getMinIndirectionForGlobalUse(globalUse) and
660678
v = n2.asVariable()
661679
or
662680
v = n2.asIndirectVariable(globalUse.getIndirection())
@@ -666,7 +684,7 @@ predicate jumpStep(Node n1, Node n2) {
666684
v = globalDef.getVariable() and
667685
n2.(InitialGlobalValue).getGlobalDef() = globalDef
668686
|
669-
globalDef.getIndirection() = 1 and
687+
globalDef.getIndirection() = getMinIndirectionForGlobalDef(globalDef) and
670688
v = n1.asVariable()
671689
or
672690
v = n1.asIndirectVariable(globalDef.getIndirection())

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ cached
3434
private newtype TIRDataFlowNode =
3535
TNode0(Node0Impl node) { DataFlowImplCommon::forceCachingInSameStage() } or
3636
TVariableNode(Variable var, int indirectionIndex) {
37-
indirectionIndex = [1 .. Ssa::getMaxIndirectionsForType(var.getUnspecifiedType())]
37+
indirectionIndex =
38+
[getMinIndirectionsForType(var.getUnspecifiedType()) .. Ssa::getMaxIndirectionsForType(var.getUnspecifiedType())]
3839
} or
3940
TPostFieldUpdateNode(FieldAddress operand, int indirectionIndex) {
4041
indirectionIndex =
@@ -346,15 +347,17 @@ class Node extends TIRDataFlowNode {
346347
* Gets the variable corresponding to this node, if any. This can be used for
347348
* modeling flow in and out of global variables.
348349
*/
349-
Variable asVariable() { this = TVariableNode(result, 1) }
350+
Variable asVariable() {
351+
this = TVariableNode(result, getMinIndirectionsForType(result.getUnspecifiedType()))
352+
}
350353

351354
/**
352355
* Gets the `indirectionIndex`'th indirection of this node's underlying variable, if any.
353356
*
354357
* This can be used for modeling flow in and out of global variables.
355358
*/
356359
Variable asIndirectVariable(int indirectionIndex) {
357-
indirectionIndex > 1 and
360+
indirectionIndex > getMinIndirectionsForType(result.getUnspecifiedType()) and
358361
this = TVariableNode(result, indirectionIndex)
359362
}
360363

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternalsCommon.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -872,7 +872,7 @@ private module Cached {
872872
upper = countIndirectionsForCppType(type) and
873873
ind = ind0 + [lower .. upper] and
874874
indirectionIndex = ind - (ind0 + lower) and
875-
(if type.hasType(any(Cpp::ArrayType arrayType), true) then lower = 0 else lower = 1)
875+
lower = getMinIndirectionsForType(any(Type t | type.hasUnspecifiedType(t, _)))
876876
)
877877
}
878878

cpp/ql/test/library-tests/dataflow/dataflow-tests/TestBase.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ module IRTest {
7171
or
7272
source.asIndirectExpr(1).(FunctionCall).getTarget().getName() = "indirect_source"
7373
or
74+
source.asExpr().(StringLiteral).getValue() = "source"
75+
or
76+
// indirect_source(n) gives the dataflow node representing the indirect node after n dereferences.
77+
exists(int n, string s |
78+
n = s.regexpCapture("indirect_source\\((\\d)\\)", 1).toInt() and
79+
source.asIndirectExpr(n).(StringLiteral).getValue() = s
80+
)
81+
or
7482
source.asParameter().getName().matches("source%")
7583
or
7684
source.(DataFlow::DefinitionByReferenceNode).getParameter().getName().matches("ref_source%")

cpp/ql/test/library-tests/dataflow/dataflow-tests/dataflow-consistency.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
uniqueEnclosingCallable
2+
| test.cpp:864:44:864:58 | {...} | Node should have one enclosing callable but has 0. |
3+
| test.cpp:864:47:864:54 | call to source | Node should have one enclosing callable but has 0. |
4+
| test.cpp:872:46:872:51 | call to source | Node should have one enclosing callable but has 0. |
5+
| test.cpp:872:53:872:56 | 1 | Node should have one enclosing callable but has 0. |
26
uniqueCallEnclosingCallable
7+
| test.cpp:864:47:864:54 | call to source | Call should have one enclosing callable but has 0. |
8+
| test.cpp:872:46:872:51 | call to source | Call should have one enclosing callable but has 0. |
39
uniqueType
410
uniqueNodeLocation
511
missingLocation

cpp/ql/test/library-tests/dataflow/dataflow-tests/test-source-sink.expected

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ astFlow
120120
| test.cpp:797:22:797:28 | ref arg content | test.cpp:798:19:798:25 | content |
121121
| test.cpp:842:11:842:16 | call to source | test.cpp:844:8:844:8 | y |
122122
| test.cpp:846:13:846:27 | call to indirect_source | test.cpp:848:23:848:25 | rpx |
123+
| test.cpp:860:54:860:59 | call to source | test.cpp:861:10:861:37 | static_local_pointer_dynamic |
123124
| true_upon_entry.cpp:17:11:17:16 | call to source | true_upon_entry.cpp:21:8:21:8 | x |
124125
| true_upon_entry.cpp:27:9:27:14 | call to source | true_upon_entry.cpp:29:8:29:8 | x |
125126
| true_upon_entry.cpp:33:11:33:16 | call to source | true_upon_entry.cpp:39:8:39:8 | x |
@@ -282,6 +283,17 @@ irFlow
282283
| test.cpp:832:21:832:26 | call to source | test.cpp:836:10:836:22 | global_direct |
283284
| test.cpp:842:11:842:16 | call to source | test.cpp:844:8:844:8 | y |
284285
| test.cpp:846:13:846:27 | call to indirect_source indirection | test.cpp:848:17:848:25 | rpx indirection |
286+
| test.cpp:853:55:853:62 | call to source | test.cpp:854:10:854:36 | * ... |
287+
| test.cpp:860:54:860:59 | call to source | test.cpp:861:10:861:37 | static_local_pointer_dynamic |
288+
| test.cpp:872:46:872:51 | call to source | test.cpp:875:10:875:31 | global_pointer_dynamic |
289+
| test.cpp:880:64:880:83 | indirect_source(1) indirection | test.cpp:883:10:883:45 | static_local_array_static_indirect_1 |
290+
| test.cpp:881:64:881:83 | indirect_source(2) indirection | test.cpp:886:19:886:54 | static_local_array_static_indirect_2 indirection |
291+
| test.cpp:890:54:890:61 | source | test.cpp:893:10:893:36 | static_local_pointer_static |
292+
| test.cpp:891:65:891:84 | indirect_source(1) indirection | test.cpp:895:19:895:56 | static_local_pointer_static_indirect_1 indirection |
293+
| test.cpp:901:56:901:75 | indirect_source(1) indirection | test.cpp:907:10:907:39 | global_array_static_indirect_1 |
294+
| test.cpp:902:56:902:75 | indirect_source(2) indirection | test.cpp:911:19:911:48 | global_array_static_indirect_2 indirection |
295+
| test.cpp:914:46:914:53 | source | test.cpp:919:10:919:30 | global_pointer_static |
296+
| test.cpp:915:57:915:76 | indirect_source(1) indirection | test.cpp:921:19:921:50 | global_pointer_static_indirect_1 indirection |
285297
| true_upon_entry.cpp:9:11:9:16 | call to source | true_upon_entry.cpp:13:8:13:8 | x |
286298
| true_upon_entry.cpp:17:11:17:16 | call to source | true_upon_entry.cpp:21:8:21:8 | x |
287299
| true_upon_entry.cpp:27:9:27:14 | call to source | true_upon_entry.cpp:29:8:29:8 | x |

cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
int source();
2-
void sink(int); void sink(const int *); void sink(int **); void indirect_sink(...);
2+
void sink(...); void indirect_sink(...);
33

44
void intraprocedural_with_local_flow() {
55
int t2;
@@ -846,4 +846,80 @@ void test_references() {
846846
int* px = indirect_source();
847847
int*& rpx = px;
848848
indirect_sink((int*)rpx); // $ ast,ir
849+
}
850+
851+
namespace GlobalArrays {
852+
void test1() {
853+
static const int static_local_array_dynamic[] = { ::source() };
854+
sink(*static_local_array_dynamic); // $ ir MISSING: ast
855+
}
856+
857+
const int* source(bool);
858+
859+
void test2() {
860+
static const int* static_local_pointer_dynamic = source(true);
861+
sink(static_local_pointer_dynamic); // $ ast,ir
862+
}
863+
864+
static const int global_array_dynamic[] = { ::source() };
865+
866+
void test3() {
867+
sink(*global_array_dynamic); // $ MISSING: ir,ast // Missing in IR because no 'IRFunction' for global_array is generated because the type of global_array_dynamic is "deeply const".
868+
}
869+
870+
const int* source(bool);
871+
872+
static const int* global_pointer_dynamic = source(true);
873+
874+
void test4() {
875+
sink(global_pointer_dynamic); // $ ir MISSING: ast
876+
}
877+
878+
void test5() {
879+
static const char static_local_array_static[] = "source";
880+
static const char static_local_array_static_indirect_1[] = "indirect_source(1)";
881+
static const char static_local_array_static_indirect_2[] = "indirect_source(2)";
882+
sink(static_local_array_static); // clean
883+
sink(static_local_array_static_indirect_1); // $ ir MISSING: ast
884+
indirect_sink(static_local_array_static_indirect_1); // clean
885+
sink(static_local_array_static_indirect_2); // clean
886+
indirect_sink(static_local_array_static_indirect_2); // $ ir MISSING: ast
887+
}
888+
889+
void test6() {
890+
static const char* static_local_pointer_static = "source";
891+
static const char* static_local_pointer_static_indirect_1 = "indirect_source(1)";
892+
static const char* static_local_pointer_static_indirect_2 = "indirect_source(2)";
893+
sink(static_local_pointer_static); // $ ir MISSING: ast
894+
sink(static_local_pointer_static_indirect_1); // clean
895+
indirect_sink(static_local_pointer_static_indirect_1); // $ ir MISSING: ast
896+
sink(static_local_pointer_static_indirect_2); // clean: static_local_pointer_static_indirect_2 does not have 2 indirections
897+
indirect_sink(static_local_pointer_static_indirect_2); // clean: static_local_pointer_static_indirect_2 does not have 2 indirections
898+
}
899+
900+
static const char global_array_static[] = "source";
901+
static const char global_array_static_indirect_1[] = "indirect_source(1)";
902+
static const char global_array_static_indirect_2[] = "indirect_source(2)";
903+
904+
void test7() {
905+
sink(global_array_static); // clean
906+
sink(*global_array_static); // clean
907+
sink(global_array_static_indirect_1); // $ ir MISSING: ast
908+
sink(*global_array_static_indirect_1); // clean
909+
indirect_sink(global_array_static); // clean
910+
indirect_sink(global_array_static_indirect_1); // clean
911+
indirect_sink(global_array_static_indirect_2); // $ ir MISSING: ast
912+
}
913+
914+
static const char* global_pointer_static = "source";
915+
static const char* global_pointer_static_indirect_1 = "indirect_source(1)";
916+
static const char* global_pointer_static_indirect_2 = "indirect_source(2)";
917+
918+
void test8() {
919+
sink(global_pointer_static); // $ ir MISSING: ast
920+
sink(global_pointer_static_indirect_1); // clean
921+
indirect_sink(global_pointer_static_indirect_1); // $ ir MISSING: ast
922+
sink(global_pointer_static_indirect_2); // clean: global_pointer_static_indirect_2 does not have 2 indirections
923+
indirect_sink(global_pointer_static_indirect_2); // clean: global_pointer_static_indirect_2 does not have 2 indirections
924+
}
849925
}

0 commit comments

Comments
 (0)