Skip to content

Commit 003fece

Browse files
committed
python: add test for capturing via global
1 parent 4d95b20 commit 003fece

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ def check_tests_valid_after_version(testFile, version):
6868
check_tests_valid("coverage-py3.classes")
6969
check_tests_valid("variable-capture.in")
7070
check_tests_valid("variable-capture.nonlocal")
71+
check_tests_valid("variable-capture.global")
7172
check_tests_valid("variable-capture.dict")
7273
check_tests_valid("variable-capture.test_collections")
7374
check_tests_valid("module-initialization.multiphase")
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Here we test writing to a captured variable via the `nonlocal` keyword (see `out`).
2+
# We also test reading one captured variable and writing the value to another (see `through`).
3+
4+
# All functions starting with "test_" should run and execute `print("OK")` exactly once.
5+
# This can be checked by running validTest.py.
6+
7+
import sys
8+
import os
9+
10+
sys.path.append(os.path.dirname(os.path.dirname((__file__))))
11+
from testlib import expects
12+
13+
# These are defined so that we can evaluate the test code.
14+
NONSOURCE = "not a source"
15+
SOURCE = "source"
16+
17+
def is_source(x):
18+
return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j
19+
20+
21+
def SINK(x):
22+
if is_source(x):
23+
print("OK")
24+
else:
25+
print("Unexpected flow", x)
26+
27+
28+
def SINK_F(x):
29+
if is_source(x):
30+
print("Unexpected flow", x)
31+
else:
32+
print("OK")
33+
34+
35+
sinkO1 = ""
36+
sinkO2 = ""
37+
nonSink0 = ""
38+
39+
def out():
40+
def captureOut1():
41+
global sinkO1
42+
sinkO1 = SOURCE
43+
captureOut1()
44+
SINK(sinkO1) #$ captured
45+
46+
def captureOut2():
47+
def m():
48+
global sinkO2
49+
sinkO2 = SOURCE
50+
m()
51+
captureOut2()
52+
SINK(sinkO2) #$ captured
53+
54+
def captureOut1NotCalled():
55+
global nonSink0
56+
nonSink0 = SOURCE
57+
SINK_F(nonSink0) #$ SPURIOUS: captured
58+
59+
def captureOut2NotCalled():
60+
def m():
61+
global nonSink0
62+
nonSink0 = SOURCE
63+
captureOut2NotCalled()
64+
SINK_F(nonSink0) #$ SPURIOUS: captured
65+
66+
@expects(4)
67+
def test_out():
68+
out()
69+
70+
sinkT1 = ""
71+
sinkT2 = ""
72+
nonSinkT0 = ""
73+
def through(tainted):
74+
def captureOut1():
75+
global sinkT1
76+
sinkT1 = tainted
77+
captureOut1()
78+
SINK(sinkT1) #$ MISSING:captured
79+
80+
def captureOut2():
81+
def m():
82+
global sinkT2
83+
sinkT2 = tainted
84+
m()
85+
captureOut2()
86+
SINK(sinkT2) #$ MISSING:captured
87+
88+
def captureOut1NotCalled():
89+
global nonSinkT0
90+
nonSinkT0 = tainted
91+
SINK_F(nonSinkT0)
92+
93+
def captureOut2NotCalled():
94+
def m():
95+
global nonSinkT0
96+
nonSinkT0 = tainted
97+
captureOut2NotCalled()
98+
SINK_F(nonSinkT0)
99+
100+
@expects(4)
101+
def test_through():
102+
through(SOURCE)

0 commit comments

Comments
 (0)