mirror of
https://github.com/github/codeql.git
synced 2026-04-28 18:25:24 +02:00
Python: Require MISSING: flow annotations for normal data-flow tests
I had to rewrite the SINK1-SINK7 definitions, since this new requirement complained that we had to add this `MISSING: flow` annotation :D Doing this implementation also revealed that there was a bug, since I did not compare files when checking for these `MISSING:` annotations. So fixed that up in the implementation for inline taint tests as well. (extra whitespace in argumentPassing.py to avoid changing line numbers for other tests)
This commit is contained in:
@@ -16,3 +16,22 @@ class DataFlowTest extends FlowTest {
|
||||
super.hasActualResult(location, element, tag, value)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate missingAnnotationOnSINK(Location location, string error, string element) {
|
||||
error = "ERROR, you should add `# $ MISSING: flow` annotation" and
|
||||
exists(DataFlow::Node sink |
|
||||
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
|
||||
(sink = call.getArg(_) or sink = call.getArgByName(_))
|
||||
) and
|
||||
location = sink.getLocation() and
|
||||
element = prettyExpr(sink.asExpr()) and
|
||||
not any(TestConfiguration config).hasFlow(_, sink) and
|
||||
not exists(FalseNegativeExpectation missingResult |
|
||||
missingResult.getTag() = "flow" and
|
||||
missingResult.getLocation().getFile() = location.getFile() and
|
||||
missingResult.getLocation().getStartLine() = location.getStartLine()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
missingAnnotationOnSINK
|
||||
failures
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import sys
|
||||
import os
|
||||
import functools
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.dirname((__file__))))
|
||||
from testlib import *
|
||||
@@ -29,36 +30,35 @@ def SINK_F(x, unexpected=arg):
|
||||
SINK_TEST(x, test=lambda x: x != unexpected)
|
||||
|
||||
|
||||
def SINK1(x):
|
||||
SINK(x, expected=arg1)
|
||||
SINK1 = functools.partial(SINK, expected=arg1)
|
||||
SINK2 = functools.partial(SINK, expected=arg2)
|
||||
SINK3 = functools.partial(SINK, expected=arg3)
|
||||
SINK4 = functools.partial(SINK, expected=arg4)
|
||||
SINK5 = functools.partial(SINK, expected=arg5)
|
||||
SINK6 = functools.partial(SINK, expected=arg6)
|
||||
SINK7 = functools.partial(SINK, expected=arg7)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def SINK2(x):
|
||||
SINK(x, expected=arg2)
|
||||
|
||||
|
||||
def SINK2_F(x):
|
||||
SINK_F(x, unexpected=arg2)
|
||||
|
||||
|
||||
def SINK3(x):
|
||||
SINK(x, expected=arg3)
|
||||
|
||||
|
||||
def SINK4(x):
|
||||
SINK(x, expected=arg4)
|
||||
|
||||
|
||||
def SINK5(x):
|
||||
SINK(x, expected=arg5)
|
||||
|
||||
|
||||
def SINK6(x):
|
||||
SINK(x, expected=arg6)
|
||||
|
||||
|
||||
def SINK7(x):
|
||||
SINK(x, expected=arg7)
|
||||
|
||||
|
||||
def argument_passing(
|
||||
|
||||
@@ -90,11 +90,11 @@ def gen(x, count):
|
||||
n -= 1
|
||||
|
||||
iter = gen(SOURCE, 1)
|
||||
SINK(iter.__next__())
|
||||
SINK(iter.__next__()) # $ MISSING: flow
|
||||
# SINK_F(iter.__next__()) # throws StopIteration, FP
|
||||
|
||||
oiter = c.gen(SOURCE, 1)
|
||||
SINK(oiter.__next__())
|
||||
SINK(oiter.__next__()) # $ MISSING: flow
|
||||
# SINK_F(oiter.__next__()) # throws StopIteration, FP
|
||||
|
||||
# Coroutine functions
|
||||
@@ -103,8 +103,8 @@ async def coro(x):
|
||||
return x
|
||||
|
||||
import asyncio
|
||||
SINK(asyncio.run(coro(SOURCE)))
|
||||
SINK(asyncio.run(c.coro(SOURCE)))
|
||||
SINK(asyncio.run(coro(SOURCE))) # $ MISSING: flow
|
||||
SINK(asyncio.run(c.coro(SOURCE))) # $ MISSING: flow
|
||||
|
||||
class A:
|
||||
|
||||
@@ -116,7 +116,7 @@ async def agen(x):
|
||||
a = A()
|
||||
return await a
|
||||
|
||||
SINK(asyncio.run(agen(SOURCE)))
|
||||
SINK(asyncio.run(agen(SOURCE))) # $ MISSING: flow
|
||||
|
||||
# Asynchronous generator functions
|
||||
# A function or method which is defined using async def and which uses the yield statement is called a asynchronous generator function. Such a function, when called, returns an asynchronous iterator object which can be used in an async for statement to execute the body of the function.
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
missingAnnotationOnSINK
|
||||
failures
|
||||
|
||||
@@ -61,7 +61,7 @@ def test_example1_method():
|
||||
myobj = MyObj("OK")
|
||||
|
||||
myobj.setFoo(SOURCE)
|
||||
SINK(myobj.foo)
|
||||
SINK(myobj.foo) # $ MISSING: flow
|
||||
|
||||
|
||||
def test_example2():
|
||||
@@ -81,7 +81,7 @@ def test_example2_method():
|
||||
|
||||
a.getObj().foo = x
|
||||
|
||||
SINK(a.obj.foo)
|
||||
SINK(a.obj.foo) # $ MISSING: flow
|
||||
|
||||
|
||||
def test_example3():
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
missingAnnotationOnSINK
|
||||
failures
|
||||
|
||||
@@ -100,6 +100,8 @@ query predicate untaintedArgumentToEnsureTaintedNotMarkedAsMissing(
|
||||
not any(TestTaintTrackingConfiguration config).hasFlow(_, sink) and
|
||||
location = sink.getLocation() and
|
||||
not exists(FalseNegativeExpectation missingResult |
|
||||
missingResult.getTag() = "tainted" and
|
||||
missingResult.getLocation().getFile() = location.getFile() and
|
||||
missingResult.getLocation().getStartLine() = location.getStartLine()
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user