Skip to content

Commit 4be226f

Browse files
authored
Merge pull request #13113 from yoff/python/test-container-steps
python: Add tests for container steps
2 parents 20e8ee8 + 81adf5a commit 4be226f

File tree

4 files changed

+403
-8
lines changed

4 files changed

+403
-8
lines changed
Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
# This tests some of the common built-in functions and methods.
2+
# We need a decent model of data flow through these in order to
3+
# analyse most programs.
4+
#
5+
# All functions starting with "test_" should run and execute `print("OK")` exactly once.
6+
# This can be checked by running validTest.py.
7+
8+
import sys
9+
import os
10+
11+
sys.path.append(os.path.dirname(os.path.dirname((__file__))))
12+
from testlib import expects
13+
14+
# These are defined so that we can evaluate the test code.
15+
NONSOURCE = "not a source"
16+
SOURCE = "source"
17+
18+
def is_source(x):
19+
return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j
20+
21+
def SINK(x):
22+
if is_source(x):
23+
print("OK")
24+
else:
25+
print("Unexpected flow", x)
26+
27+
def SINK_F(x):
28+
if is_source(x):
29+
print("Unexpected flow", x)
30+
else:
31+
print("OK")
32+
33+
34+
# Actual tests
35+
36+
## Container constructors
37+
38+
### List
39+
40+
@expects(2)
41+
def test_list_from_list():
42+
l1 = [SOURCE, NONSOURCE]
43+
l2 = list(l1)
44+
SINK(l2[0]) #$ MISSING: flow="SOURCE, l:-2 -> l2[0]"
45+
SINK_F(l2[1]) # expecting FP due to imprecise flow
46+
47+
# -- skip list_from_string
48+
49+
@expects(2)
50+
def test_list_from_tuple():
51+
t = (SOURCE, NONSOURCE)
52+
l = list(t)
53+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
54+
SINK_F(l[1]) # expecting FP due to imprecise flow
55+
56+
def test_list_from_set():
57+
s = {SOURCE}
58+
l = list(s)
59+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
60+
61+
@expects(2)
62+
def test_list_from_dict():
63+
d = {SOURCE: 'v', NONSOURCE: 'v2'}
64+
l = list(d)
65+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
66+
SINK_F(l[1]) # expecting FP due to imprecise flow
67+
68+
### Tuple
69+
70+
@expects(2)
71+
def test_tuple_from_list():
72+
l = [SOURCE, NONSOURCE]
73+
t = tuple(l)
74+
SINK(t[0]) #$ MISSING: flow="SOURCE, l:-2 -> t[0]"
75+
SINK_F(t[1])
76+
77+
@expects(2)
78+
def test_tuple_from_tuple():
79+
t0 = (SOURCE, NONSOURCE)
80+
t = tuple(t0)
81+
SINK(t[0]) #$ MISSING: flow="SOURCE, l:-2 -> t[0]"
82+
SINK_F(t[1])
83+
84+
def test_tuple_from_set():
85+
s = {SOURCE}
86+
t = tuple(s)
87+
SINK(t[0]) #$ MISSING: flow="SOURCE, l:-2 -> t[0]"
88+
89+
@expects(2)
90+
def test_tuple_from_dict():
91+
d = {SOURCE: "v1", NONSOURCE: "v2"}
92+
t = tuple(d)
93+
SINK(t[0]) #$ MISSING: flow="SOURCE, l:-2 -> t[0]"
94+
SINK_F(t[1])
95+
96+
97+
### Set
98+
99+
def test_set_from_list():
100+
l = [SOURCE]
101+
s = set(l)
102+
v = s.pop()
103+
SINK(v) #$ MISSING: flow="SOURCE, l:-3 -> v"
104+
105+
def test_set_from_tuple():
106+
t = (SOURCE,)
107+
s = set(t)
108+
v = s.pop()
109+
SINK(v) #$ MISSING: flow="SOURCE, l:-3 -> v"
110+
111+
def test_set_from_set():
112+
s0 = {SOURCE}
113+
s = set(s0)
114+
v = s.pop()
115+
SINK(v) #$ MISSING: flow="SOURCE, l:-3 -> v"
116+
117+
def test_set_from_dict():
118+
d = {SOURCE: "val"}
119+
s = set(d)
120+
v = s.pop()
121+
SINK(v) #$ MISSING: flow="SOURCE, l:-3 -> v"
122+
123+
124+
### Dict
125+
126+
@expects(2)
127+
def test_dict_from_keyword():
128+
d = dict(k = SOURCE, k1 = NONSOURCE)
129+
SINK(d["k"]) #$ MISSING: flow="SOURCE, l:-1 -> d[k]"
130+
SINK_F(d["k1"])
131+
132+
@expects(2)
133+
def test_dict_from_list():
134+
d = dict([("k", SOURCE), ("k1", NONSOURCE)])
135+
SINK(d["k"]) #$ MISSING: flow="SOURCE, l:-1 -> d[k]"
136+
SINK_F(d["k1"])
137+
138+
@expects(2)
139+
def test_dict_from_dict():
140+
d1 = {'k': SOURCE, 'k1': NONSOURCE}
141+
d2 = dict(d1)
142+
SINK(d2["k"]) #$ MISSING: flow="SOURCE, l:-2 -> d[k]"
143+
SINK_F(d2["k1"])
144+
145+
## Container methods
146+
147+
### List
148+
149+
def test_list_pop():
150+
l = [SOURCE]
151+
v = l.pop()
152+
SINK(v) #$ flow="SOURCE, l:-2 -> v"
153+
154+
def test_list_pop_index():
155+
l = [SOURCE]
156+
v = l.pop(0)
157+
SINK(v) #$ MISSING: flow="SOURCE, l:-2 -> v"
158+
159+
def test_list_pop_index_imprecise():
160+
l = [SOURCE, NONSOURCE]
161+
v = l.pop(1)
162+
SINK_F(v)
163+
164+
@expects(2)
165+
def test_list_copy():
166+
l0 = [SOURCE, NONSOURCE]
167+
l = l0.copy()
168+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
169+
SINK_F(l[1])
170+
171+
def test_list_append():
172+
l = [NONSOURCE]
173+
l.append(SOURCE)
174+
SINK(l[1]) #$ MISSING: flow="SOURCE, l:-1 -> l[1]"
175+
176+
### Set
177+
178+
def test_set_pop():
179+
s = {SOURCE}
180+
v = s.pop()
181+
SINK(v) #$ flow="SOURCE, l:-2 -> v"
182+
183+
def test_set_copy():
184+
s0 = {SOURCE}
185+
s = s0.copy()
186+
SINK(s.pop()) #$ MISSING: flow="SOURCE, l:-2 -> s.pop()"
187+
188+
def test_set_add():
189+
s = set([])
190+
s.add(SOURCE)
191+
SINK(s.pop()) #$ MISSING: flow="SOURCE, l:-2 -> s.pop()"
192+
193+
### Dict
194+
195+
def test_dict_keys():
196+
d = {SOURCE: "value"}
197+
keys = d.keys()
198+
key_list = list(keys)
199+
SINK(key_list[0]) #$ MISSING: flow="SOURCE, l:-3 -> key_list[0]"
200+
201+
def test_dict_values():
202+
d = {'k': SOURCE}
203+
vals = d.values()
204+
val_list = list(vals)
205+
SINK(val_list[0]) #$ MISSING: flow="SOURCE, l:-3 -> val_list[0]"
206+
207+
@expects(4)
208+
def test_dict_items():
209+
d = {'k': SOURCE, SOURCE: "value"}
210+
items = d.items()
211+
item_list = list(items)
212+
SINK_F(item_list[0][0]) # expecting FP due to imprecise flow
213+
SINK(item_list[0][1]) #$ MISSING: flow="SOURCE, l:-4 -> item_list[0][1]"
214+
SINK(item_list[1][0]) #$ MISSING: flow="SOURCE, l:-5 -> item_list[1][0]"
215+
SINK_F(item_list[1][1]) # expecting FP due to imprecise flow
216+
217+
@expects(3)
218+
def test_dict_pop():
219+
d = {'k': SOURCE}
220+
v = d.pop("k")
221+
SINK(v) #$ flow="SOURCE, l:-2 -> v"
222+
v1 = d.pop("k", NONSOURCE)
223+
SINK_F(v1) #$ SPURIOUS: flow="SOURCE, l:-4 -> v1"
224+
v2 = d.pop("non-existing", SOURCE)
225+
SINK(v2) #$ MISSING: flow="SOURCE, l:-1 -> v2"
226+
227+
@expects(2)
228+
def test_dict_get():
229+
d = {'k': SOURCE}
230+
v = d.get("k")
231+
SINK(v) #$ flow="SOURCE, l:-2 -> v"
232+
v1 = d.get("non-existing", SOURCE)
233+
SINK(v1) #$ MISSING: flow="SOURCE, l:-1 -> v1"
234+
235+
@expects(2)
236+
def test_dict_popitem():
237+
d = {'k': SOURCE}
238+
t = d.popitem() # could be any pair (before 3.7), but we only have one
239+
SINK_F(t[0])
240+
SINK(t[1]) #$ MISSING: flow="SOURCE, l:-3 -> t[1]"
241+
242+
@expects(2)
243+
def test_dict_copy():
244+
d = {'k': SOURCE, 'k1': NONSOURCE}
245+
d1 = d.copy()
246+
SINK(d1["k"]) #$ MISSING: flow="SOURCE, l:-2 -> d[k]"
247+
SINK_F(d1["k1"])
248+
249+
250+
## Functions on containers
251+
252+
### sorted
253+
254+
def test_sorted_list():
255+
l0 = [SOURCE]
256+
l = sorted(l0)
257+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
258+
259+
def test_sorted_tuple():
260+
t = (SOURCE,)
261+
l = sorted(t)
262+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
263+
264+
def test_sorted_set():
265+
s = {SOURCE}
266+
l = sorted(s)
267+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
268+
269+
def test_sorted_dict():
270+
d = {SOURCE: "val"}
271+
l = sorted(d)
272+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
273+
274+
### reversed
275+
276+
@expects(2)
277+
def test_reversed_list():
278+
l0 = [SOURCE, NONSOURCE]
279+
r = reversed(l0)
280+
l = list(r)
281+
SINK_F(l[0])
282+
SINK(l[1]) #$ MISSING: flow="SOURCE, l:-4 -> l[1]"
283+
284+
@expects(2)
285+
def test_reversed_tuple():
286+
t = (SOURCE, NONSOURCE)
287+
r = reversed(t)
288+
l = list(r)
289+
SINK_F(l[0])
290+
SINK(l[1]) #$ MISSING: flow="SOURCE, l:-4 -> l[1]"
291+
292+
@expects(2)
293+
def test_reversed_dict():
294+
d = {SOURCE: "v1", NONSOURCE: "v2"}
295+
r = reversed(d)
296+
l = list(r)
297+
SINK_F(l[0])
298+
SINK(l[1]) #$ MISSING: flow="SOURCE, l:-4 -> l[1]"
299+
300+
### iter
301+
302+
def test_iter_list():
303+
l0 = [SOURCE]
304+
i = iter(l0)
305+
l = list(i)
306+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-3 -> l[0]"
307+
308+
def test_iter_tuple():
309+
t = (SOURCE,)
310+
i = iter(t)
311+
l = list(i)
312+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-3 -> l[0]"
313+
314+
def test_iter_set():
315+
t = {SOURCE}
316+
i = iter(t)
317+
l = list(i)
318+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-3 -> l[0]"
319+
320+
def test_iter_dict():
321+
d = {SOURCE: "val"}
322+
i = iter(d)
323+
l = list(i)
324+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-3 -> l[0]"
325+
326+
def test_iter_iter():
327+
# applying iter() to the result of iter() is basically a no-op
328+
l0 = [SOURCE]
329+
i = iter(iter(l0))
330+
l = list(i)
331+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-3 -> l[0]"
332+
333+
### next
334+
335+
def test_next_list():
336+
l = [SOURCE]
337+
i = iter(l)
338+
n = next(i)
339+
SINK(n) #$ MISSING: flow="SOURCE, l:-3 -> n"
340+
341+
def test_next_tuple():
342+
t = (SOURCE,)
343+
i = iter(t)
344+
n = next(i)
345+
SINK(n) #$ MISSING: flow="SOURCE, l:-3 -> n"
346+
347+
def test_next_set():
348+
s = {SOURCE}
349+
i = iter(s)
350+
n = next(i)
351+
SINK(n) #$ MISSING: flow="SOURCE, l:-3 -> n"
352+
353+
def test_next_dict():
354+
d = {SOURCE: "val"}
355+
i = iter(d)
356+
n = next(i)
357+
SINK(n) #$ MISSING: flow="SOURCE, l:-3 -> n"

python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/dataflow-consistency.expected

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,17 @@ uniqueParameterNodePosition
2525
uniqueContentApprox
2626
identityLocalStep
2727
| test_async.py:48:9:48:22 | ControlFlowNode for ensure_tainted | Node steps to itself |
28-
| test_collections.py:56:10:56:21 | ControlFlowNode for tainted_list | Node steps to itself |
29-
| test_collections.py:63:9:63:22 | ControlFlowNode for ensure_tainted | Node steps to itself |
30-
| test_collections.py:65:9:65:22 | ControlFlowNode for ensure_tainted | Node steps to itself |
31-
| test_collections.py:79:9:79:22 | ControlFlowNode for ensure_tainted | Node steps to itself |
32-
| test_collections.py:81:9:81:22 | ControlFlowNode for ensure_tainted | Node steps to itself |
28+
| test_collections.py:64:10:64:21 | ControlFlowNode for tainted_list | Node steps to itself |
29+
| test_collections.py:71:9:71:22 | ControlFlowNode for ensure_tainted | Node steps to itself |
30+
| test_collections.py:73:9:73:22 | ControlFlowNode for ensure_tainted | Node steps to itself |
31+
| test_collections.py:88:10:88:21 | ControlFlowNode for tainted_list | Node steps to itself |
32+
| test_collections.py:89:10:89:23 | ControlFlowNode for TAINTED_STRING | Node steps to itself |
33+
| test_collections.py:97:9:97:22 | ControlFlowNode for ensure_tainted | Node steps to itself |
34+
| test_collections.py:99:9:99:22 | ControlFlowNode for ensure_tainted | Node steps to itself |
35+
| test_collections.py:112:9:112:22 | ControlFlowNode for ensure_tainted | Node steps to itself |
3336
| test_collections.py:114:9:114:22 | ControlFlowNode for ensure_tainted | Node steps to itself |
34-
| test_collections.py:116:9:116:22 | ControlFlowNode for ensure_tainted | Node steps to itself |
35-
| test_collections.py:213:9:213:15 | ControlFlowNode for my_dict | Node steps to itself |
36-
| test_collections.py:213:22:213:33 | ControlFlowNode for tainted_dict | Node steps to itself |
37+
| test_collections.py:147:9:147:22 | ControlFlowNode for ensure_tainted | Node steps to itself |
38+
| test_collections.py:149:9:149:22 | ControlFlowNode for ensure_tainted | Node steps to itself |
39+
| test_collections.py:246:9:246:15 | ControlFlowNode for my_dict | Node steps to itself |
40+
| test_collections.py:246:22:246:33 | ControlFlowNode for tainted_dict | Node steps to itself |
3741
| test_for.py:24:9:24:22 | ControlFlowNode for ensure_tainted | Node steps to itself |

0 commit comments

Comments
 (0)