Skip to content

Commit ab67103

Browse files
authored
Merge pull request github#12966 from MathiasVP/dataflow-for-static-vars
C++: Dataflow for static local variables
2 parents 51c08f1 + fbc872c commit ab67103

File tree

8 files changed

+101
-13
lines changed

8 files changed

+101
-13
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -607,13 +607,21 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
607607
result.getReturnKind() = kind
608608
}
609609

610+
/** A variable that behaves like a global variable. */
611+
class GlobalLikeVariable extends Variable {
612+
GlobalLikeVariable() {
613+
this instanceof Cpp::GlobalOrNamespaceVariable or
614+
this instanceof Cpp::StaticLocalVariable
615+
}
616+
}
617+
610618
/**
611619
* Holds if data can flow from `node1` to `node2` in a way that loses the
612620
* calling context. For example, this would happen with flow through a
613621
* global or static variable.
614622
*/
615623
predicate jumpStep(Node n1, Node n2) {
616-
exists(Cpp::GlobalOrNamespaceVariable v |
624+
exists(GlobalLikeVariable v |
617625
exists(Ssa::GlobalUse globalUse |
618626
v = globalUse.getVariable() and
619627
n1.(FinalGlobalValue).getGlobalUse() = globalUse

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

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -145,14 +145,14 @@ private newtype TDefOrUseImpl =
145145
or
146146
// Since the pruning stage doesn't know about global variables we can't use the above check to
147147
// rule out dead assignments to globals.
148-
base.(VariableAddressInstruction).getAstVariable() instanceof Cpp::GlobalOrNamespaceVariable
148+
base.(VariableAddressInstruction).getAstVariable() instanceof GlobalLikeVariable
149149
)
150150
} or
151151
TUseImpl(Operand operand, int indirectionIndex) {
152152
isUse(_, operand, _, _, indirectionIndex) and
153153
not isDef(_, _, operand, _, _, _)
154154
} or
155-
TGlobalUse(Cpp::GlobalOrNamespaceVariable v, IRFunction f, int indirectionIndex) {
155+
TGlobalUse(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
156156
// Represents a final "use" of a global variable to ensure that
157157
// the assignment to a global variable isn't ruled out as dead.
158158
exists(VariableAddressInstruction vai, int defIndex |
@@ -162,7 +162,7 @@ private newtype TDefOrUseImpl =
162162
indirectionIndex = [0 .. defIndex] + 1
163163
)
164164
} or
165-
TGlobalDefImpl(Cpp::GlobalOrNamespaceVariable v, IRFunction f, int indirectionIndex) {
165+
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
166166
// Represents the initial "definition" of a global variable when entering
167167
// a function body.
168168
exists(VariableAddressInstruction vai |
@@ -458,7 +458,7 @@ class FinalParameterUse extends UseImpl, TFinalParameterUse {
458458
}
459459

460460
class GlobalUse extends UseImpl, TGlobalUse {
461-
Cpp::GlobalOrNamespaceVariable global;
461+
GlobalLikeVariable global;
462462
IRFunction f;
463463

464464
GlobalUse() { this = TGlobalUse(global, f, ind) }
@@ -468,7 +468,7 @@ class GlobalUse extends UseImpl, TGlobalUse {
468468
override int getIndirection() { result = ind + 1 }
469469

470470
/** Gets the global variable associated with this use. */
471-
Cpp::GlobalOrNamespaceVariable getVariable() { result = global }
471+
GlobalLikeVariable getVariable() { result = global }
472472

473473
/** Gets the `IRFunction` whose body is exited from after this use. */
474474
IRFunction getIRFunction() { result = f }
@@ -496,14 +496,14 @@ class GlobalUse extends UseImpl, TGlobalUse {
496496
}
497497

498498
class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
499-
Cpp::GlobalOrNamespaceVariable global;
499+
GlobalLikeVariable global;
500500
IRFunction f;
501501
int indirectionIndex;
502502

503503
GlobalDefImpl() { this = TGlobalDefImpl(global, f, indirectionIndex) }
504504

505505
/** Gets the global variable associated with this definition. */
506-
Cpp::GlobalOrNamespaceVariable getVariable() { result = global }
506+
GlobalLikeVariable getVariable() { result = global }
507507

508508
/** Gets the `IRFunction` whose body is evaluated after this definition. */
509509
IRFunction getIRFunction() { result = f }
@@ -760,13 +760,14 @@ private predicate variableWriteCand(IRBlock bb, int i, SourceVariable v) {
760760
}
761761

762762
private predicate sourceVariableIsGlobal(
763-
SourceVariable sv, Cpp::GlobalOrNamespaceVariable global, IRFunction func, int indirectionIndex
763+
SourceVariable sv, GlobalLikeVariable global, IRFunction func, int indirectionIndex
764764
) {
765765
exists(IRVariable irVar, BaseIRVariable base |
766766
sourceVariableHasBaseAndIndex(sv, base, indirectionIndex) and
767767
irVar = base.getIRVariable() and
768768
irVar.getEnclosingIRFunction() = func and
769-
global = irVar.getAst()
769+
global = irVar.getAst() and
770+
not irVar instanceof IRDynamicInitializationFlag
770771
)
771772
}
772773

@@ -919,7 +920,7 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
919920
IRFunction getIRFunction() { result = global.getIRFunction() }
920921

921922
/** Gets the global variable associated with this definition. */
922-
Cpp::GlobalOrNamespaceVariable getVariable() { result = global.getVariable() }
923+
GlobalLikeVariable getVariable() { result = global.getVariable() }
923924
}
924925

925926
class Phi extends TPhi, SsaDefOrUse {

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,16 @@ postWithInFlow
115115
| test.cpp:602:3:602:7 | access to array [post update] | PostUpdateNode should not be the target of local flow. |
116116
| test.cpp:608:3:608:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
117117
| test.cpp:608:4:608:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
118+
| test.cpp:639:3:639:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
119+
| test.cpp:646:3:646:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
120+
| test.cpp:652:3:652:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
121+
| test.cpp:653:3:653:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
122+
| test.cpp:659:3:659:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
123+
| test.cpp:660:3:660:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
124+
| test.cpp:671:3:671:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
125+
| test.cpp:681:3:681:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
126+
| test.cpp:689:3:689:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
127+
| test.cpp:690:3:690:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
118128
viableImplInCallContextTooLarge
119129
uniqueParameterNodeAtPosition
120130
uniqueParameterNodePosition

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

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,4 +627,66 @@ void test_def_via_phi_read(bool b)
627627
}
628628
intPointerSource(buffer);
629629
sink(buffer); // $ ast,ir
630-
}
630+
}
631+
632+
void test_static_local_1() {
633+
static int x = source();
634+
sink(x); // $ ast,ir
635+
}
636+
637+
void test_static_local_2() {
638+
static int x = source();
639+
x = 0;
640+
sink(x); // clean
641+
}
642+
643+
void test_static_local_3() {
644+
static int x = 0;
645+
sink(x); // $ ir MISSING: ast
646+
x = source();
647+
}
648+
649+
void test_static_local_4() {
650+
static int x = 0;
651+
sink(x); // clean
652+
x = source();
653+
x = 0;
654+
}
655+
656+
void test_static_local_5() {
657+
static int x = 0;
658+
sink(x); // $ ir MISSING: ast
659+
x = 0;
660+
x = source();
661+
}
662+
663+
void test_static_local_6() {
664+
static int s = source();
665+
static int* ptr_to_s = &s;
666+
sink(*ptr_to_s); // $ ir MISSING: ast
667+
}
668+
669+
void test_static_local_7() {
670+
static int s = source();
671+
s = 0;
672+
static int* ptr_to_s = &s;
673+
sink(*ptr_to_s); // clean
674+
}
675+
676+
void test_static_local_8() {
677+
static int s;
678+
static int* ptr_to_s = &s;
679+
sink(*ptr_to_s); // $ ir MISSING: ast
680+
681+
s = source();
682+
}
683+
684+
void test_static_local_9() {
685+
static int s;
686+
static int* ptr_to_s = &s;
687+
sink(*ptr_to_s); // clean
688+
689+
s = source();
690+
s = 0;
691+
}
692+

cpp/ql/test/library-tests/syntax-zoo/dataflow-ir-consistency.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ uniqueType
44
uniqueNodeLocation
55
missingLocation
66
uniqueNodeToString
7+
| cpp11.cpp:50:15:50:16 | (no string representation) | Node should have one toString but has 0. |
78
missingToString
9+
| Nodes without toString: 1 |
810
parameterCallable
911
localFlowIsLocal
1012
readStepIsLocal

cpp/ql/test/query-tests/Likely Bugs/Format/NonConstantFormat/NonConstantFormat.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
| nested.cpp:21:23:21:26 | fmt0 | The format string argument to snprintf should be constant to prevent security issues and other potential errors. |
44
| nested.cpp:79:32:79:38 | call to get_fmt | The format string argument to diagnostic should be constant to prevent security issues and other potential errors. |
55
| nested.cpp:87:18:87:20 | fmt | The format string argument to diagnostic should be constant to prevent security issues and other potential errors. |
6+
| test.cpp:51:10:51:21 | call to make_message | The format string argument to printf should be constant to prevent security issues and other potential errors. |
67
| test.cpp:57:12:57:16 | hello | The format string argument to printf should be constant to prevent security issues and other potential errors. |
78
| test.cpp:60:12:60:21 | call to const_wash | The format string argument to printf should be constant to prevent security issues and other potential errors. |
89
| test.cpp:61:12:61:26 | ... + ... | The format string argument to printf should be constant to prevent security issues and other potential errors. |

cpp/ql/test/query-tests/Likely Bugs/Format/NonConstantFormat/test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ int main(int argc, char **argv) {
4848
printf(choose_message(argc - 1), argc - 1); // GOOD
4949
printf(messages[1]); // GOOD
5050
printf(message); // GOOD
51-
printf(make_message(argc - 1)); // BAD [NOT DETECTED]
51+
printf(make_message(argc - 1)); // BAD
5252
printf("Hello, World\n"); // GOOD
5353
printf(_("Hello, World\n")); // GOOD
5454
{

0 commit comments

Comments
 (0)