Skip to content

Commit f28f42b

Browse files
authored
Merge pull request #17049 from aschackmull/dataflow/bugfix-flowfeature-sinkctx
Dataflow: Fix bug causing spurious flow for FeatureHasSinkCallContext
2 parents c514d36 + 86c63db commit f28f42b

File tree

2 files changed

+85
-18
lines changed

2 files changed

+85
-18
lines changed

java/ql/test/library-tests/dataflow/flowfeature/A.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,50 @@ static void test6() {
4646
Object x = source("6");
4747
test6sink(x);
4848
}
49+
50+
Object getSrc() {
51+
return source("get");
52+
}
53+
54+
void srcField() {
55+
foo = source("field");
56+
}
57+
58+
static Object foo = null;
59+
60+
void srcCall(int i) {
61+
test7(source("call"), i);
62+
}
63+
64+
Object test7(Object x, int i) {
65+
Object src = null;
66+
if (i == 0) {
67+
src = getSrc();
68+
} else if (i == 1) {
69+
src = foo;
70+
} else if (i == 2) {
71+
src = x;
72+
} else if (i == 3) {
73+
src = source("direct");
74+
}
75+
76+
sinkPut(src);
77+
foo2 = src;
78+
sink(src); // $ EqCc="direct" SrcCc="field" SrcCc="call" SrcCc="direct" SinkCc="get" SinkCc="field" SinkCc="direct"
79+
return src;
80+
}
81+
82+
static Object foo2 = null;
83+
84+
void sinkPut(Object x) {
85+
sink(x); // $ SrcCc="field" SrcCc="call" SrcCc="direct"
86+
}
87+
88+
void sinkField() {
89+
sink(foo2); // $ SrcCc="field" SrcCc="call" SrcCc="direct" SinkCc="get" SinkCc="field" SinkCc="call" SinkCc="direct"
90+
}
91+
92+
void sinkReturn(int i) {
93+
sink(test7(null, i)); // $ SrcCc="field" SinkCc="get" SinkCc="field" SinkCc="direct"
94+
}
4995
}

shared/dataflow/codeql/dataflow/internal/DataFlowImpl.qll

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,7 +1560,13 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
15601560
argT = TypOption::some(t) and
15611561
argAp = apSome(ap)
15621562
) else (
1563-
summaryCtx = TParamNodeNone() and argT instanceof TypOption::None and argAp = apNone()
1563+
summaryCtx = TParamNodeNone() and
1564+
argT instanceof TypOption::None and
1565+
argAp = apNone() and
1566+
// When the call contexts of source and sink needs to match then there's
1567+
// never any reason to enter a callable except to find a summary. See also
1568+
// the comment in `PathNodeMid::isAtSink`.
1569+
not Config::getAFeature() instanceof FeatureEqualSourceSinkCallContext
15641570
)
15651571
)
15661572
or
@@ -2598,8 +2604,23 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
25982604

25992605
override predicate isSink() {
26002606
sinkNode(node, state) and
2601-
(if hasSinkCallCtx() then instanceofCcNoCall(cc) else any()) and
2602-
ap instanceof ApNil
2607+
ap instanceof ApNil and
2608+
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
2609+
// is exactly what we need to check.
2610+
// For `FeatureEqualSourceSinkCallContext` the initial call
2611+
// context was set to `CallContextSomeCall` and jumps are
2612+
// disallowed, so `cc instanceof CallContextNoCall` never holds.
2613+
// On the other hand, in this case there's never any need to
2614+
// enter a call except to identify a summary, so the condition in
2615+
// conjunction with setting the summary context enforces this,
2616+
// which means that the summary context being empty holds if and
2617+
// only if we are in the call context of the source.
2618+
if Config::getAFeature() instanceof FeatureEqualSourceSinkCallContext
2619+
then summaryCtx = TParamNodeNone()
2620+
else
2621+
if Config::getAFeature() instanceof FeatureHasSinkCallContext
2622+
then instanceofCcNoCall(cc)
2623+
else any()
26032624
}
26042625
}
26052626

@@ -4320,21 +4341,21 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
43204341
sinkNode(node, state) and
43214342
sinkModel(node, model) and
43224343
ap instanceof AccessPathNil and
4323-
if hasSinkCallCtx()
4324-
then
4325-
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
4326-
// is exactly what we need to check. This also implies
4327-
// `sc instanceof SummaryCtxNone`.
4328-
// For `FeatureEqualSourceSinkCallContext` the initial call context was
4329-
// set to `CallContextSomeCall` and jumps are disallowed, so
4330-
// `cc instanceof CallContextNoCall` never holds. On the other hand,
4331-
// in this case there's never any need to enter a call except to identify
4332-
// a summary, so the condition in `pathIntoCallable` enforces this, which
4333-
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
4334-
// in the call context of the source.
4335-
sc instanceof SummaryCtxNone or
4336-
cc instanceof CallContextNoCall
4337-
else any()
4344+
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
4345+
// is exactly what we need to check.
4346+
// For `FeatureEqualSourceSinkCallContext` the initial call context was
4347+
// set to `CallContextSomeCall` and jumps are disallowed, so
4348+
// `cc instanceof CallContextNoCall` never holds. On the other hand,
4349+
// in this case there's never any need to enter a call except to identify
4350+
// a summary, so the condition in `pathIntoCallable` enforces this, which
4351+
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
4352+
// in the call context of the source.
4353+
if Config::getAFeature() instanceof FeatureEqualSourceSinkCallContext
4354+
then sc instanceof SummaryCtxNone
4355+
else
4356+
if Config::getAFeature() instanceof FeatureHasSinkCallContext
4357+
then cc instanceof CallContextNoCall
4358+
else any()
43384359
}
43394360

43404361
PathNodeSink projectToSink(string model) {

0 commit comments

Comments
 (0)