Skip to content

Commit 27b4c67

Browse files
committed
Python: Start of tests for captured variables
1 parent 8bb9e8a commit 27b4c67

File tree

6 files changed

+110
-4
lines changed

6 files changed

+110
-4
lines changed

python/ql/test/experimental/dataflow/coverage/argumentPassing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def with_multiple_kw_args(a, b, c):
112112
SINK3(c)
113113

114114

115-
@expects(9)
115+
@expects(12)
116116
def test_multiple_kw_args():
117117
with_multiple_kw_args(b=arg2, c=arg3, a=arg1)
118118
with_multiple_kw_args(arg1, *(arg2,), arg3)
File renamed without changes.

python/ql/test/experimental/dataflow/coverage/validTest.py renamed to python/ql/test/experimental/dataflow/validTest.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ def check_tests_valid(testFile):
5050

5151

5252
if __name__ == "__main__":
53-
check_tests_valid("classes")
54-
check_tests_valid("test")
55-
check_tests_valid("argumentPassing")
53+
check_tests_valid("coverage.classes")
54+
check_tests_valid("coverage.test")
55+
check_tests_valid("coverage.argumentPassing")
56+
check_tests_valid("variable-capture.test")

python/ql/test/experimental/dataflow/variable-capture/CaptureTest.expected

Whitespace-only changes.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import python
2+
import semmle.python.dataflow.new.DataFlow
3+
import TestUtilities.InlineExpectationsTest
4+
import experimental.dataflow.testConfig
5+
6+
class CaptureTest extends InlineExpectationsTest {
7+
CaptureTest() { this = "CaptureTest" }
8+
9+
override string getARelevantTag() { result = "captured" }
10+
11+
override predicate hasActualResult(Location location, string element, string tag, string value) {
12+
exists(DataFlow::Node source, DataFlow::Node sink |
13+
exists(TestConfiguration cfg | cfg.hasFlow(source, sink))
14+
|
15+
location = sink.getLocation() and
16+
tag = "captured" and
17+
value = "" and
18+
element = sink.toString()
19+
)
20+
}
21+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
# All functions starting with "test_" should run and execute `print("OK")` exactly once.
2+
# This can be checked by running validTest.py.
3+
4+
import sys
5+
import os
6+
7+
sys.path.append(os.path.dirname(os.path.dirname((__file__))))
8+
from testlib import *
9+
10+
# These are defined so that we can evaluate the test code.
11+
NONSOURCE = "not a source"
12+
SOURCE = "source"
13+
14+
def is_source(x):
15+
return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j
16+
17+
18+
def SINK(x):
19+
if is_source(x):
20+
print("OK")
21+
else:
22+
print("Unexpected flow", x)
23+
24+
25+
def SINK_F(x):
26+
if is_source(x):
27+
print("Unexpected flow", x)
28+
else:
29+
print("OK")
30+
31+
32+
def In(tainted):
33+
def captureIn1():
34+
sinkI1 = tainted
35+
SINK(sinkI1) #$ MISSING:captured
36+
captureIn1()
37+
38+
def captureIn2():
39+
def m():
40+
sinkI2 = tainted
41+
SINK(sinkI2) #$ MISSING:captured
42+
m()
43+
captureIn2()
44+
45+
# captureIn3 = lambda arg:(
46+
# sinkI3 = tainted;
47+
# check(sinkI3);
48+
# return arg)
49+
# [ captureIn3(x) for x in " " ]
50+
51+
def captureIn1NotCalled():
52+
nonSink0 = tainted
53+
SINK_F(nonSink0)
54+
55+
def captureIn2NotCalled():
56+
def m():
57+
nonSink0 = tainted
58+
SINK_F(nonSink0)
59+
captureIn2NotCalled()
60+
61+
@expects(2)
62+
def test_In():
63+
In(SOURCE)
64+
65+
def Out():
66+
sinkO1 = ""
67+
def captureOut1():
68+
nonlocal sinkO1
69+
sinkO1 = "source"
70+
captureOut1()
71+
SINK(sinkO1) #$ MISSING:captured
72+
73+
sinkO2 = ""
74+
def captureOut2():
75+
def m():
76+
nonlocal sinkO2
77+
sinkO2 = "source"
78+
m()
79+
captureOut2()
80+
SINK(sinkO2) #$ MISSING:captured
81+
82+
@expects(2)
83+
def test_Out():
84+
Out()

0 commit comments

Comments
 (0)