Skip to content

Commit 6c50c2b

Browse files
committed
Python: Highlight missing flow for class attributes
1 parent a0e73ea commit 6c50c2b

File tree

1 file changed

+98
-0
lines changed
  • python/ql/test/experimental/dataflow/fieldflow

1 file changed

+98
-0
lines changed

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

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,104 @@ def set_attr(obj):
237237
SINK(y.attr) # $ MISSING: flow
238238
SINK_F(z.attr) # $ MISSING: flow
239239

240+
# ------------------------------------------------------------------------------
241+
# Content in class attribute
242+
# ------------------------------------------------------------------------------
243+
244+
class WithTuple:
245+
my_tuple = (SOURCE, NONSOURCE)
246+
247+
def test_inst(self):
248+
SINK(self.my_tuple[0]) # $ MISSING: flow
249+
SINK_F(self.my_tuple[1])
250+
251+
@classmethod
252+
def test_cm(cls):
253+
SINK(cls.my_tuple[0]) # $ MISSING: flow
254+
SINK_F(cls.my_tuple[1])
255+
256+
257+
@expects(2*4) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
258+
def test_WithTuple():
259+
SINK(WithTuple.my_tuple[0]) # $ MISSING: flow="SOURCE, l:-7 -> WithTuple.my_tuple[0]"
260+
SINK_F(WithTuple.my_tuple[1])
261+
262+
WithTuple.test_cm()
263+
264+
inst = WithTuple()
265+
inst.test_inst()
266+
267+
SINK(inst.my_tuple[0]) # $ MISSING: flow="SOURCE, l:-18 -> inst.my_tuple[0]"
268+
SINK_F(inst.my_tuple[1])
269+
270+
271+
@expects(4) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
272+
def test_inst_override():
273+
inst = WithTuple()
274+
275+
# setting attribute on instance does not override class attribute, it's only on the
276+
# instance!
277+
inst.my_tuple = (NONSOURCE, SOURCE)
278+
279+
SINK_F(inst.my_tuple[0])
280+
SINK(inst.my_tuple[1]) # $ flow="SOURCE, l:-3 -> inst.my_tuple[1]"
281+
282+
SINK(WithTuple.my_tuple[0]) # $ MISSING: flow="SOURCE, l:-27 -> WithTuple.my_tuple[0]"
283+
SINK_F(WithTuple.my_tuple[1])
284+
285+
286+
class WithTuple2:
287+
my_tuple = (NONSOURCE,)
288+
289+
def set_to_source():
290+
WithTuple2.my_tuple = (SOURCE,)
291+
292+
@expects(4) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
293+
def test_class_override():
294+
inst = WithTuple2()
295+
SINK_F(WithTuple2.my_tuple[0])
296+
SINK_F(inst.my_tuple[0])
297+
298+
set_to_source()
299+
300+
SINK(WithTuple2.my_tuple[0]) # $ MISSING: flow="SOURCE, l:-10 -> WithTuple2.my_tuple[0]"
301+
SINK(inst.my_tuple[0]) # $ MISSING: flow="SOURCE, l:-11 -> inst.my_tuple[0]"
302+
303+
# --------------------------------------
304+
# unique classes from functions
305+
# --------------------------------------
306+
def make_class():
307+
# a fresh class is returned each time this function is called
308+
class C:
309+
my_tuple = (NONSOURCE,)
310+
return C
311+
312+
@expects(8) # $ unresolved_call=expects(..) unresolved_call=expects(..)(..)
313+
def test_unique_class():
314+
# This test highlights that if we use the _ClassExpr_ itself as the target/source
315+
# for jumpsteps, we will end up with spurious flow (that is, we will think that
316+
# x_cls and y_cls are the same, so by updating .my_tuple on x_cls we might propagate
317+
# that to y_cls as well -- it might not matter too much in reality, but certainly an
318+
# interesting corner case)
319+
x_cls = make_class()
320+
y_cls = make_class()
321+
322+
assert x_cls != y_cls
323+
324+
x_inst = x_cls()
325+
y_inst = y_cls()
326+
327+
SINK_F(x_cls.my_tuple[0])
328+
SINK_F(x_inst.my_tuple[0])
329+
SINK_F(y_cls.my_tuple[0])
330+
SINK_F(y_inst.my_tuple[0])
331+
332+
x_cls.my_tuple = (SOURCE,)
333+
SINK(x_cls.my_tuple[0]) # $ flow="SOURCE, l:-1 -> x_cls.my_tuple[0]"
334+
SINK(x_inst.my_tuple[0]) # $ MISSING: flow="SOURCE, l:-2 -> x_inst.my_tuple[0]"
335+
SINK_F(y_cls.my_tuple[0])
336+
SINK_F(y_inst.my_tuple[0])
337+
240338
# ------------------------------------------------------------------------------
241339
# Crosstalk test -- using different function based on conditional
242340
# ------------------------------------------------------------------------------

0 commit comments

Comments
 (0)