mirror of
https://github.com/github/codeql.git
synced 2025-12-21 19:26:31 +01:00
Python: Fix SINK/SINK_F usage for crosstalk tests
As discussed in PR review https://github.com/github/codeql/pull/11208#discussion_r1022473421
This commit is contained in:
@@ -16,8 +16,9 @@ class DataFlowTest extends FlowTest {
|
|||||||
query predicate missingAnnotationOnSink(Location location, string error, string element) {
|
query predicate missingAnnotationOnSink(Location location, string error, string element) {
|
||||||
error = "ERROR, you should add `# $ MISSING: flow` annotation" and
|
error = "ERROR, you should add `# $ MISSING: flow` annotation" and
|
||||||
exists(DataFlow::Node sink |
|
exists(DataFlow::Node sink |
|
||||||
|
any(TestConfiguration config).isSink(sink) and
|
||||||
|
// note: we only care about `SINK` and not `SINK_F`, so we have to reconstruct manually.
|
||||||
exists(DataFlow::CallCfgNode call |
|
exists(DataFlow::CallCfgNode call |
|
||||||
// note: we only care about `SINK` and not `SINK_F`, so we have to reconstruct manually.
|
|
||||||
call.getFunction().asCfgNode().(NameNode).getId() = "SINK" and
|
call.getFunction().asCfgNode().(NameNode).getId() = "SINK" and
|
||||||
(sink = call.getArg(_) or sink = call.getArgByName(_))
|
(sink = call.getArg(_) or sink = call.getArgByName(_))
|
||||||
) and
|
) and
|
||||||
|
|||||||
@@ -13,7 +13,17 @@ def is_source(x):
|
|||||||
return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j
|
return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j
|
||||||
|
|
||||||
|
|
||||||
def SINK(x):
|
def SINK(x, *, not_present_at_runtime=False):
|
||||||
|
# not_present_at_runtime supports use-cases where we want flow from data-flow layer
|
||||||
|
# (so we want to use SINK), but we end up in a siaution where it's not possible to
|
||||||
|
# actually get flow from a source at runtime. The only use-case is for the
|
||||||
|
# cross-talk tests, where our ability to use if-then-else is limited because doing
|
||||||
|
# so would make cfg-splitting kick in, and that would solve the problem trivially
|
||||||
|
# (by the splitting).
|
||||||
|
if not_present_at_runtime:
|
||||||
|
print("OK")
|
||||||
|
return
|
||||||
|
|
||||||
if is_source(x):
|
if is_source(x):
|
||||||
print("OK")
|
print("OK")
|
||||||
else:
|
else:
|
||||||
@@ -186,6 +196,9 @@ def test_nested_obj_method():
|
|||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Crosstalk test -- using different function based on conditional
|
# Crosstalk test -- using different function based on conditional
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
# NOTE: These tests use `SINK(objy.y, not_present_at_runtime=True)` since it's not
|
||||||
|
# possible to use if-then-else statements, since that would make cfg-splitting kick in,
|
||||||
|
# and that would solve the problem trivially (by the splitting).
|
||||||
|
|
||||||
class CrosstalkTestX:
|
class CrosstalkTestX:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -229,7 +242,7 @@ def test_no_crosstalk_reference(cond=True):
|
|||||||
SINK(objx.x) # $ flow="SOURCE, l:-4 -> objx.x"
|
SINK(objx.x) # $ flow="SOURCE, l:-4 -> objx.x"
|
||||||
SINK_F(objx.y)
|
SINK_F(objx.y)
|
||||||
SINK_F(objy.x)
|
SINK_F(objy.x)
|
||||||
SINK_F(objy.y) # $ flow="SOURCE, l:-5 -> objy.y"
|
SINK(objy.y, not_present_at_runtime=True) # $ flow="SOURCE, l:-5 -> objy.y"
|
||||||
|
|
||||||
|
|
||||||
@expects(8) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
|
@expects(8) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
|
||||||
@@ -252,7 +265,7 @@ def test_potential_crosstalk_different_name(cond=True):
|
|||||||
SINK(objx.x) # $ MISSING: flow="SOURCE, l:-2 -> objx.x"
|
SINK(objx.x) # $ MISSING: flow="SOURCE, l:-2 -> objx.x"
|
||||||
SINK_F(objx.y)
|
SINK_F(objx.y)
|
||||||
SINK_F(objy.x)
|
SINK_F(objy.x)
|
||||||
SINK_F(objy.y) # $ MISSING: flow="SOURCE, l:-5 -> objy.y"
|
SINK(objy.y, not_present_at_runtime=True) # $ MISSING: flow="SOURCE, l:-5 -> objy.y"
|
||||||
|
|
||||||
|
|
||||||
@expects(8) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
|
@expects(8) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
|
||||||
@@ -275,7 +288,7 @@ def test_potential_crosstalk_same_name(cond=True):
|
|||||||
SINK(objx.x) # $ MISSING: flow="SOURCE, l:-2 -> objx.x"
|
SINK(objx.x) # $ MISSING: flow="SOURCE, l:-2 -> objx.x"
|
||||||
SINK_F(objx.y)
|
SINK_F(objx.y)
|
||||||
SINK_F(objy.x)
|
SINK_F(objy.x)
|
||||||
SINK_F(objy.y) # $ MISSING: flow="SOURCE, l:-5 -> objy.y"
|
SINK(objy.y, not_present_at_runtime=True) # $ MISSING: flow="SOURCE, l:-5 -> objy.y"
|
||||||
|
|
||||||
|
|
||||||
@expects(10) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
|
@expects(10) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
|
||||||
@@ -298,10 +311,10 @@ def test_potential_crosstalk_same_name_object_reference(cond=True):
|
|||||||
SINK(objx.x) # $ MISSING: flow="SOURCE, l:-2 -> objx.x"
|
SINK(objx.x) # $ MISSING: flow="SOURCE, l:-2 -> objx.x"
|
||||||
SINK_F(objx.y)
|
SINK_F(objx.y)
|
||||||
SINK_F(objy.x)
|
SINK_F(objy.x)
|
||||||
SINK_F(objy.y) # $ MISSING: flow="SOURCE, l:-5 -> objy.y"
|
SINK(objy.y, not_present_at_runtime=True) # $ MISSING: flow="SOURCE, l:-5 -> objy.y"
|
||||||
|
|
||||||
SINK(obj.x) # $ flow="SOURCE, l:-7 -> obj.x"
|
SINK(obj.x) # $ flow="SOURCE, l:-7 -> obj.x"
|
||||||
SINK_F(obj.y) # $ flow="SOURCE, l:-8 -> obj.y"
|
SINK(obj.y, not_present_at_runtime=True) # $ flow="SOURCE, l:-8 -> obj.y"
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -38,9 +38,10 @@ class TestConfiguration extends DataFlow::Configuration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override predicate isSink(DataFlow::Node node) {
|
override predicate isSink(DataFlow::Node node) {
|
||||||
exists(CallNode call |
|
exists(DataFlow::CallCfgNode call |
|
||||||
call.getFunction().(NameNode).getId() in ["SINK", "SINK_F"] and
|
call.getFunction().asCfgNode().(NameNode).getId() in ["SINK", "SINK_F"] and
|
||||||
node.(DataFlow::CfgNode).getNode() = call.getAnArg()
|
(node = call.getArg(_) or node = call.getArgByName(_)) and
|
||||||
|
not node = call.getArgByName("not_present_at_runtime")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user