Skip to content

Commit d876acd

Browse files
committed
Python: Fix SINK/SINK_F usage for crosstalk tests
As discussed in PR review #11208 (comment)
1 parent e886b53 commit d876acd

File tree

3 files changed

+25
-10
lines changed

3 files changed

+25
-10
lines changed

python/ql/test/experimental/dataflow/TestUtil/NormalDataflowTest.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ class DataFlowTest extends FlowTest {
1616
query predicate missingAnnotationOnSink(Location location, string error, string element) {
1717
error = "ERROR, you should add `# $ MISSING: flow` annotation" and
1818
exists(DataFlow::Node sink |
19+
any(TestConfiguration config).isSink(sink) and
20+
// note: we only care about `SINK` and not `SINK_F`, so we have to reconstruct manually.
1921
exists(DataFlow::CallCfgNode call |
20-
// note: we only care about `SINK` and not `SINK_F`, so we have to reconstruct manually.
2122
call.getFunction().asCfgNode().(NameNode).getId() = "SINK" and
2223
(sink = call.getArg(_) or sink = call.getArgByName(_))
2324
) and

python/ql/test/experimental/dataflow/fieldflow/test.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,17 @@ def is_source(x):
1313
return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j
1414

1515

16-
def SINK(x):
16+
def SINK(x, *, not_present_at_runtime=False):
17+
# not_present_at_runtime supports use-cases where we want flow from data-flow layer
18+
# (so we want to use SINK), but we end up in a siaution where it's not possible to
19+
# actually get flow from a source at runtime. The only use-case is for the
20+
# cross-talk tests, where our ability to use if-then-else is limited because doing
21+
# so would make cfg-splitting kick in, and that would solve the problem trivially
22+
# (by the splitting).
23+
if not_present_at_runtime:
24+
print("OK")
25+
return
26+
1727
if is_source(x):
1828
print("OK")
1929
else:
@@ -186,6 +196,9 @@ def test_nested_obj_method():
186196
# ------------------------------------------------------------------------------
187197
# Crosstalk test -- using different function based on conditional
188198
# ------------------------------------------------------------------------------
199+
# NOTE: These tests use `SINK(objy.y, not_present_at_runtime=True)` since it's not
200+
# possible to use if-then-else statements, since that would make cfg-splitting kick in,
201+
# and that would solve the problem trivially (by the splitting).
189202

190203
class CrosstalkTestX:
191204
def __init__(self):
@@ -229,7 +242,7 @@ def test_no_crosstalk_reference(cond=True):
229242
SINK(objx.x) # $ flow="SOURCE, l:-4 -> objx.x"
230243
SINK_F(objx.y)
231244
SINK_F(objy.x)
232-
SINK_F(objy.y) # $ flow="SOURCE, l:-5 -> objy.y"
245+
SINK(objy.y, not_present_at_runtime=True) # $ flow="SOURCE, l:-5 -> objy.y"
233246

234247

235248
@expects(8) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
@@ -252,7 +265,7 @@ def test_potential_crosstalk_different_name(cond=True):
252265
SINK(objx.x) # $ MISSING: flow="SOURCE, l:-2 -> objx.x"
253266
SINK_F(objx.y)
254267
SINK_F(objy.x)
255-
SINK_F(objy.y) # $ MISSING: flow="SOURCE, l:-5 -> objy.y"
268+
SINK(objy.y, not_present_at_runtime=True) # $ MISSING: flow="SOURCE, l:-5 -> objy.y"
256269

257270

258271
@expects(8) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
@@ -275,7 +288,7 @@ def test_potential_crosstalk_same_name(cond=True):
275288
SINK(objx.x) # $ MISSING: flow="SOURCE, l:-2 -> objx.x"
276289
SINK_F(objx.y)
277290
SINK_F(objy.x)
278-
SINK_F(objy.y) # $ MISSING: flow="SOURCE, l:-5 -> objy.y"
291+
SINK(objy.y, not_present_at_runtime=True) # $ MISSING: flow="SOURCE, l:-5 -> objy.y"
279292

280293

281294
@expects(10) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
@@ -298,10 +311,10 @@ def test_potential_crosstalk_same_name_object_reference(cond=True):
298311
SINK(objx.x) # $ MISSING: flow="SOURCE, l:-2 -> objx.x"
299312
SINK_F(objx.y)
300313
SINK_F(objy.x)
301-
SINK_F(objy.y) # $ MISSING: flow="SOURCE, l:-5 -> objy.y"
314+
SINK(objy.y, not_present_at_runtime=True) # $ MISSING: flow="SOURCE, l:-5 -> objy.y"
302315

303316
SINK(obj.x) # $ flow="SOURCE, l:-7 -> obj.x"
304-
SINK_F(obj.y) # $ flow="SOURCE, l:-8 -> obj.y"
317+
SINK(obj.y, not_present_at_runtime=True) # $ flow="SOURCE, l:-8 -> obj.y"
305318

306319

307320
# ------------------------------------------------------------------------------

python/ql/test/experimental/dataflow/testConfig.qll

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ class TestConfiguration extends DataFlow::Configuration {
3838
}
3939

4040
override predicate isSink(DataFlow::Node node) {
41-
exists(CallNode call |
42-
call.getFunction().(NameNode).getId() in ["SINK", "SINK_F"] and
43-
node.(DataFlow::CfgNode).getNode() = call.getAnArg()
41+
exists(DataFlow::CallCfgNode call |
42+
call.getFunction().asCfgNode().(NameNode).getId() in ["SINK", "SINK_F"] and
43+
(node = call.getArg(_) or node = call.getArgByName(_)) and
44+
not node = call.getArgByName("not_present_at_runtime")
4445
)
4546
}
4647

0 commit comments

Comments
 (0)