Skip to content

Commit 0a9515d

Browse files
committed
python: add tests for built-in collections
- constructors: list, tuple, set, dict - methods: - general: copy, pop - list: append - set: add - dict: keys, values, items, get, popitem - functions: sorted, reversed, iter, next
1 parent f62bbf2 commit 0a9515d

File tree

3 files changed

+380
-0
lines changed

3 files changed

+380
-0
lines changed
Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
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(2)
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", SOURCE)
223+
SINK(v1) #$ flow="SOURCE, l:-4 -> v1"
224+
225+
@expects(2)
226+
def test_dict_get():
227+
d = {'k': SOURCE}
228+
v = d.get("k")
229+
SINK(v) #$ flow="SOURCE, l:-2 -> v"
230+
v1 = d.get("k", SOURCE)
231+
SINK(v1) #$ flow="SOURCE, l:-4 -> v1"
232+
233+
@expects(2)
234+
def test_dict_popitem():
235+
d = {'k': SOURCE}
236+
t = d.popitem() # could be any pair (before 3.7), but we only have one
237+
SINK_F(t[0])
238+
SINK(t[1]) #$ MISSING: flow="SOURCE, l:-3 -> t[1]"
239+
240+
@expects(2)
241+
def test_dict_copy():
242+
d = {'k': SOURCE, 'k1': NONSOURCE}
243+
d1 = d.copy()
244+
SINK(d1["k"]) #$ MISSING: flow="SOURCE, l:-2 -> d[k]"
245+
SINK_F(d1["k1"])
246+
247+
248+
## Functions on containers
249+
250+
### sorted
251+
252+
def test_sorted_list():
253+
l0 = [SOURCE]
254+
l = sorted(l0)
255+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
256+
257+
def test_sorted_tuple():
258+
t = (SOURCE,)
259+
l = sorted(t)
260+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
261+
262+
def test_sorted_set():
263+
s = {SOURCE}
264+
l = sorted(s)
265+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
266+
267+
def test_sorted_dict():
268+
d = {SOURCE: "val"}
269+
l = sorted(d)
270+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-2 -> l[0]"
271+
272+
### reversed
273+
274+
@expects(2)
275+
def test_reversed_list():
276+
l0 = [SOURCE, NONSOURCE]
277+
r = reversed(l0)
278+
l = list(r)
279+
SINK_F(l[0])
280+
SINK(l[1]) #$ MISSING: flow="SOURCE, l:-4 -> l[1]"
281+
282+
@expects(2)
283+
def test_reversed_tuple():
284+
t = (SOURCE, NONSOURCE)
285+
r = reversed(t)
286+
l = list(r)
287+
SINK_F(l[0])
288+
SINK(l[1]) #$ MISSING: flow="SOURCE, l:-4 -> l[1]"
289+
290+
@expects(2)
291+
def test_reversed_dict():
292+
d = {SOURCE: "v1", NONSOURCE: "v2"}
293+
r = reversed(d)
294+
l = list(r)
295+
SINK_F(l[0])
296+
SINK(l[1]) #$ MISSING: flow="SOURCE, l:-4 -> l[1]"
297+
298+
### iter
299+
300+
def test_iter_list():
301+
l0 = [SOURCE]
302+
i = iter(l0)
303+
l = list(i)
304+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-3 -> l[0]"
305+
306+
def test_iter_tuple():
307+
t = (SOURCE,)
308+
i = iter(t)
309+
l = list(i)
310+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-3 -> l[0]"
311+
312+
def test_iter_set():
313+
t = {SOURCE}
314+
i = iter(t)
315+
l = list(i)
316+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-3 -> l[0]"
317+
318+
def test_iter_dict():
319+
d = {SOURCE: "val"}
320+
i = iter(d)
321+
l = list(i)
322+
SINK(l[0]) #$ MISSING: flow="SOURCE, l:-3 -> l[0]"
323+
324+
### next
325+
326+
def test_next_list():
327+
l = [SOURCE]
328+
i = iter(l)
329+
n = next(i)
330+
SINK(n) #$ MISSING: flow="SOURCE, l:-3 -> n"
331+
332+
def test_next_tuple():
333+
t = (SOURCE,)
334+
i = iter(t)
335+
n = next(i)
336+
SINK(n) #$ MISSING: flow="SOURCE, l:-3 -> n"
337+
338+
def test_next_set():
339+
s = {SOURCE}
340+
i = iter(s)
341+
n = next(i)
342+
SINK(n) #$ MISSING: flow="SOURCE, l:-3 -> n"
343+
344+
def test_next_dict():
345+
d = {SOURCE: "val"}
346+
i = iter(d)
347+
n = next(i)
348+
SINK(n) #$ MISSING: flow="SOURCE, l:-3 -> n"

python/ql/test/experimental/dataflow/tainttracking/defaultAdditionalTaintStep/test_collections.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ def test_construction():
3737
tuple(tainted_list), # $ tainted
3838
set(tainted_list), # $ tainted
3939
frozenset(tainted_list), # $ tainted
40+
dict(tainted_dict), # $ tainted
41+
dict(k = tainted_string)["k"], # $ MISSING: tainted
42+
dict(dict(k = tainted_string))["k"], # $ MISSING: tainted
43+
dict(["k", tainted_string]), # $ tainted
44+
)
45+
46+
ensure_not_tainted(
47+
dict(k = tainted_string)["k1"]
4048
)
4149

4250

@@ -64,6 +72,29 @@ def test_access(x, y, z):
6472
for i in reversed(tainted_list):
6573
ensure_tainted(i) # $ tainted
6674

75+
def test_access_explicit(x, y, z):
76+
tainted_list = [TAINTED_STRING]
77+
78+
ensure_tainted(
79+
tainted_list[0], # $ tainted
80+
tainted_list[x], # $ tainted
81+
tainted_list[y:z], # $ tainted
82+
83+
sorted(tainted_list)[0], # $ tainted
84+
reversed(tainted_list)[0], # $ tainted
85+
iter(tainted_list), # $ tainted
86+
next(iter(tainted_list)), # $ tainted
87+
[i for i in tainted_list], # $ tainted
88+
[tainted_list for _i in [1,2,3]], # $ MISSING: tainted
89+
)
90+
91+
a, b, c = tainted_list[0:3]
92+
ensure_tainted(a, b, c) # $ tainted
93+
94+
for h in tainted_list:
95+
ensure_tainted(h) # $ tainted
96+
for i in reversed(tainted_list):
97+
ensure_tainted(i) # $ tainted
6798

6899
def test_dict_access(x):
69100
tainted_dict = TAINTED_DICT

0 commit comments

Comments
 (0)