Python: Start of tests for captured variables

This commit is contained in:
Rasmus Lerchedahl Petersen
2020-11-16 17:25:39 +01:00
parent 8bb9e8a4af
commit 27b4c67b9f
6 changed files with 110 additions and 4 deletions

View File

@@ -112,7 +112,7 @@ def with_multiple_kw_args(a, b, c):
SINK3(c)
@expects(9)
@expects(12)
def test_multiple_kw_args():
with_multiple_kw_args(b=arg2, c=arg3, a=arg1)
with_multiple_kw_args(arg1, *(arg2,), arg3)

View File

@@ -50,6 +50,7 @@ def check_tests_valid(testFile):
if __name__ == "__main__":
check_tests_valid("classes")
check_tests_valid("test")
check_tests_valid("argumentPassing")
check_tests_valid("coverage.classes")
check_tests_valid("coverage.test")
check_tests_valid("coverage.argumentPassing")
check_tests_valid("variable-capture.test")

View File

@@ -0,0 +1,21 @@
import python
import semmle.python.dataflow.new.DataFlow
import TestUtilities.InlineExpectationsTest
import experimental.dataflow.testConfig
class CaptureTest extends InlineExpectationsTest {
CaptureTest() { this = "CaptureTest" }
override string getARelevantTag() { result = "captured" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlow::Node source, DataFlow::Node sink |
exists(TestConfiguration cfg | cfg.hasFlow(source, sink))
|
location = sink.getLocation() and
tag = "captured" and
value = "" and
element = sink.toString()
)
}
}

View File

@@ -0,0 +1,84 @@
# All functions starting with "test_" should run and execute `print("OK")` exactly once.
# This can be checked by running validTest.py.
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname((__file__))))
from testlib import *
# These are defined so that we can evaluate the test code.
NONSOURCE = "not a source"
SOURCE = "source"
def is_source(x):
return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j
def SINK(x):
if is_source(x):
print("OK")
else:
print("Unexpected flow", x)
def SINK_F(x):
if is_source(x):
print("Unexpected flow", x)
else:
print("OK")
def In(tainted):
def captureIn1():
sinkI1 = tainted
SINK(sinkI1) #$ MISSING:captured
captureIn1()
def captureIn2():
def m():
sinkI2 = tainted
SINK(sinkI2) #$ MISSING:captured
m()
captureIn2()
# captureIn3 = lambda arg:(
# sinkI3 = tainted;
# check(sinkI3);
# return arg)
# [ captureIn3(x) for x in " " ]
def captureIn1NotCalled():
nonSink0 = tainted
SINK_F(nonSink0)
def captureIn2NotCalled():
def m():
nonSink0 = tainted
SINK_F(nonSink0)
captureIn2NotCalled()
@expects(2)
def test_In():
In(SOURCE)
def Out():
sinkO1 = ""
def captureOut1():
nonlocal sinkO1
sinkO1 = "source"
captureOut1()
SINK(sinkO1) #$ MISSING:captured
sinkO2 = ""
def captureOut2():
def m():
nonlocal sinkO2
sinkO2 = "source"
m()
captureOut2()
SINK(sinkO2) #$ MISSING:captured
@expects(2)
def test_Out():
Out()