Skip to content

Commit 378484e

Browse files
authored
Merge pull request github#12149 from MathiasVP/fewer-flowthroughs
C++: Fix spurious flow-through
2 parents 7bd2818 + 168202d commit 378484e

File tree

12 files changed

+132
-35
lines changed

12 files changed

+132
-35
lines changed

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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,29 @@ private newtype TIRDataFlowNode =
5252
TFinalParameterNode(Parameter p, int indirectionIndex) {
5353
exists(Ssa::FinalParameterUse use |
5454
use.getParameter() = p and
55-
use.getIndirectionIndex() = indirectionIndex
55+
use.getIndirectionIndex() = indirectionIndex and
56+
parameterIsRedefined(p)
5657
)
5758
} or
5859
TFinalGlobalValue(Ssa::GlobalUse globalUse) or
5960
TInitialGlobalValue(Ssa::GlobalDef globalUse)
6061

62+
/**
63+
* Holds if the value of `*p` (or `**p`, `***p`, etc.) is redefined somewhere in the body
64+
* of the enclosing function of `p`.
65+
*
66+
* Only parameters satisfying this predicate will generate a `FinalParameterNode` transferring
67+
* flow out of the function.
68+
*/
69+
private predicate parameterIsRedefined(Parameter p) {
70+
exists(Ssa::Def def |
71+
def.getSourceVariable().getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst() = p and
72+
def.getIndirectionIndex() = 0 and
73+
def.getIndirection() > 1 and
74+
not def.getValue().asInstruction() instanceof InitializeParameterInstruction
75+
)
76+
}
77+
6178
/**
6279
* An operand that is defined by a `FieldAddressInstruction`.
6380
*/

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -918,6 +918,8 @@ class Def extends DefOrUse {
918918
Instruction getAddress() { result = this.getAddressOperand().getDef() }
919919

920920
/**
921+
* Gets the indirection index of this definition.
922+
*
921923
* This predicate ensures that joins go from `defOrUse` to the result
922924
* instead of the other way around.
923925
*/
@@ -926,6 +928,19 @@ class Def extends DefOrUse {
926928
pragma[only_bind_into](result) = pragma[only_bind_out](defOrUse).getIndirectionIndex()
927929
}
928930

931+
/**
932+
* Gets the indirection level that this definition is writing to.
933+
* For instance, `x = y` is a definition of `x` at indirection level 1 and
934+
* `*x = y` is a definition of `x` at indirection level 2.
935+
*
936+
* This predicate ensures that joins go from `defOrUse` to the result
937+
* instead of the other way around.
938+
*/
939+
pragma[inline]
940+
int getIndirection() {
941+
pragma[only_bind_into](result) = pragma[only_bind_out](defOrUse).getIndirection()
942+
}
943+
929944
Node0Impl getValue() { result = defOrUse.getValue() }
930945

931946
predicate isCertain() { defOrUse.isCertain() }

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ void bg_stackstruct(XY s1, XY s2) {
5656
}
5757
}
5858

59-
void bg_structptr(XY *p1, XY *p2) {
59+
void bg_structptr(XY *p1, XY *p2) { // $ ast-def=p1 ast-def=p2
6060
p1->x = source();
6161
if (guarded(p1->x)) {
6262
sink(p1->x); // $ SPURIOUS: ast

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ struct twoIntFields {
88
int getFirst() { return m1; }
99
};
1010

11-
void following_pointers(
11+
void following_pointers( // $ ast-def=sourceStruct1_ptr
1212
int sourceArray1[],
1313
int cleanArray1[],
1414
twoIntFields sourceStruct1,

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ postWithInFlow
107107
| test.cpp:552:25:552:25 | y [inner post update] | PostUpdateNode should not be the target of local flow. |
108108
| test.cpp:562:5:562:13 | globalInt [post update] | PostUpdateNode should not be the target of local flow. |
109109
| test.cpp:576:5:576:13 | globalInt [post update] | PostUpdateNode should not be the target of local flow. |
110+
| test.cpp:589:19:589:19 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
110111
viableImplInCallContextTooLarge
111112
uniqueParameterNodeAtPosition
112113
uniqueParameterNodePosition

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ struct Bottom : Middle {
2525
void notSink(int x) override { }
2626
};
2727

28-
void VirtualDispatch(Bottom *bottomPtr, Bottom &bottomRef) {
28+
void VirtualDispatch(Bottom *bottomPtr, Bottom &bottomRef) { // $ ast-def=bottomPtr ast-def=bottomRef
2929
Top *topPtr = bottomPtr, &topRef = bottomRef;
3030

3131
sink(topPtr->isSource1()); // $ ir MISSING: ast
@@ -65,11 +65,11 @@ Top *allocateBottom() {
6565
return new Bottom();
6666
}
6767

68-
void callSinkByPointer(Top *top) {
68+
void callSinkByPointer(Top *top) { // $ ast-def=top
6969
top->isSink(source()); // leads to MISSING from ast
7070
}
7171

72-
void callSinkByReference(Top &top) {
72+
void callSinkByReference(Top &top) { // $ ast-def=top
7373
top.isSink(source()); // leads to MISSING from ast
7474
}
7575

@@ -81,11 +81,11 @@ void globalVirtualDispatch() {
8181
x->isSink(source()); // $ MISSING: ast,ir
8282
}
8383

84-
Top *identity(Top *top) {
84+
Top *identity(Top *top) { // $ ast-def=top
8585
return top;
8686
}
8787

88-
void callIdentityFunctions(Top *top, Bottom *bottom) {
88+
void callIdentityFunctions(Top *top, Bottom *bottom) { // $ ast-def=bottom ast-def=top
8989
identity(bottom)->isSink(source()); // $ MISSING: ast,ir
9090
identity(top)->isSink(source()); // no flow
9191
}
@@ -120,7 +120,7 @@ namespace virtual_inheritance {
120120
struct Bottom : Middle {
121121
};
122122

123-
void VirtualDispatch(Bottom *bottomPtr, Bottom &bottomRef) {
123+
void VirtualDispatch(Bottom *bottomPtr, Bottom &bottomRef) { // $ ast-def=bottomPtr ast-def=bottomRef
124124
// Because the inheritance from `Top` is virtual, the following casts go
125125
// directly from `Bottom` to `Top`, skipping `Middle`. That means we don't
126126
// get flow from a `Middle` value to the call qualifier.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ typedef struct
1212
char isTrue;
1313
} MyBool;
1414

15-
void myTest_with_local_flow(MyBool *b, int pos)
15+
void myTest_with_local_flow(MyBool *b, int pos) // $ ast-def=b
1616
{
1717
MyCoords coords = {0};
1818

cpp/ql/test/library-tests/dataflow/dataflow-tests/has-parameter-flow-out.expected

Whitespace-only changes.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import TestUtilities.InlineExpectationsTest
2+
import cpp
3+
4+
module AstTest {
5+
private import semmle.code.cpp.dataflow.DataFlow::DataFlow
6+
private import semmle.code.cpp.dataflow.internal.DataFlowPrivate
7+
8+
class ASTParameterDefTest extends InlineExpectationsTest {
9+
ASTParameterDefTest() { this = "ASTParameterDefTest" }
10+
11+
override string getARelevantTag() { result = "ast-def" }
12+
13+
override predicate hasActualResult(Location location, string element, string tag, string value) {
14+
exists(Function f, Parameter p, RefParameterFinalValueNode n |
15+
p.isNamed() and
16+
n.getParameter() = p and
17+
n.getFunction() = f and
18+
location = f.getLocation() and
19+
element = p.toString() and
20+
tag = "ast-def" and
21+
value = p.getName()
22+
)
23+
}
24+
}
25+
}
26+
27+
module IRTest {
28+
private import semmle.code.cpp.ir.dataflow.DataFlow
29+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
30+
31+
private string stars(int k) {
32+
k = [0 .. max(FinalParameterNode n | | n.getIndirectionIndex())] and
33+
(if k = 0 then result = "" else result = "*" + stars(k - 1))
34+
}
35+
36+
class IRParameterDefTest extends InlineExpectationsTest {
37+
IRParameterDefTest() { this = "IRParameterDefTest" }
38+
39+
override string getARelevantTag() { result = "ir-def" }
40+
41+
override predicate hasActualResult(Location location, string element, string tag, string value) {
42+
exists(Function f, Parameter p, FinalParameterNode n |
43+
p.isNamed() and
44+
n.getParameter() = p and
45+
n.getFunction() = f and
46+
location = f.getLocation() and
47+
element = p.toString() and
48+
tag = "ir-def" and
49+
value = stars(n.getIndirectionIndex()) + p.getName()
50+
)
51+
}
52+
}
53+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ void test_lambdas()
3737
};
3838
d(t, u);
3939

40-
auto e = [](int &a, int &b, int &c) {
40+
auto e = [](int &a, int &b, int &c) { // $ ast-def=a ast-def=b ast-def=c ir-def=*c
4141
sink(a); // $ ast,ir
4242
sink(b);
4343
c = source();

0 commit comments

Comments
 (0)