1
- # This should cover all the syntactical constructs that we hope to support
1
+ # This should cover all the syntactical constructs that we hope to support.
2
+ # Headings refer to https://docs.python.org/3/reference/expressions.html,
3
+ # and are selected whenever they incur dataflow.
2
4
# Intended sources should be the variable `SOURCE` and intended sinks should be
3
5
# arguments to the function `SINK` (see python/ql/test/experimental/dataflow/testConfig.qll).
4
6
#
5
7
# Functions whose name ends with "_with_local_flow" will also be tested for local flow.
8
+ #
9
+ # All functions starting with "test_" should run and print a source (sources are defined in testConfig.qll).
6
10
7
- # These are included so that we can easily evaluate the test code
11
+ # These are defined so that we can evaluate the test code.
8
12
SOURCE = "source"
9
13
def SINK (x ):
10
14
print (x )
@@ -14,7 +18,6 @@ def test_tuple_with_local_flow():
14
18
y = x [1 ]
15
19
SINK (y )
16
20
17
- # List taken from https://docs.python.org/3/reference/expressions.html
18
21
# 6.2.1. Identifiers (Names)
19
22
def test_names ():
20
23
x = SOURCE
@@ -90,42 +93,188 @@ def test_generator():
90
93
x = (SOURCE for y in [3 ])
91
94
SINK ([* x ][0 ])
92
95
93
- # List taken from https://docs.python.org/3/reference/expressions.html
94
- # 6. Expressions
95
- # 6.1. Arithmetic conversions
96
- # 6.2. Atoms
97
- # 6.2.1. Identifiers (Names)
98
- # 6.2.2. Literals
99
- # 6.2.3. Parenthesized forms
100
- # 6.2.4. Displays for lists, sets and dictionaries
101
- # 6.2.5. List displays
102
- # 6.2.6. Set displays
103
- # 6.2.7. Dictionary displays
104
- # 6.2.8. Generator expressions
105
96
# 6.2.9. Yield expressions
97
+ def gen (x ):
98
+ yield x
99
+
100
+ def test_yield ():
101
+ g = gen (SOURCE )
102
+ SINK (next (g ))
103
+
104
+ def gen_from (x ):
105
+ yield from gen (x )
106
+
107
+ def test_yield_from ():
108
+ g = gen_from (SOURCE )
109
+ SINK (next (g ))
110
+
111
+ # a statement rather than an expression, but related to generators
112
+ def test_for ():
113
+ for x in gen (SOURCE ):
114
+ SINK (x )
115
+
106
116
# 6.2.9.1. Generator-iterator methods
107
- # 6.2.9.2. Examples
117
+ def test___next__ ():
118
+ g = gen (SOURCE )
119
+ SINK (g .__next__ ())
120
+
121
+ def gen2 (x ):
122
+ m = yield x # argument of `send` has to flow to value of `yield x` (and so to `m`)
123
+ yield m
124
+
125
+ def test_send ():
126
+ g = gen2 (3 )
127
+ n = next (g )
128
+ SINK (g .send (SOURCE ))
129
+
130
+ def gen_ex (x ):
131
+ try :
132
+ yield 3
133
+ except :
134
+ yield x # `x` has to flow to call to `throw`
135
+
136
+ def test_throw ():
137
+ g = gen_ex (SOURCE )
138
+ n = next (g )
139
+ SINK (g .throw (TypeError ))
140
+
141
+ # no `test_close` as `close` involves no data flow
142
+
108
143
# 6.2.9.3. Asynchronous generator functions
144
+ async def agen (x ):
145
+ yield x
146
+
109
147
# 6.2.9.4. Asynchronous generator-iterator methods
110
- # 6.3. Primaries
148
+
149
+ # helper to run async test functions
150
+ def runa (a ):
151
+ import asyncio
152
+ asyncio .run (a )
153
+
154
+ async def atest___anext__ ():
155
+ g = agen (SOURCE )
156
+ SINK (await g .__anext__ ())
157
+
158
+ def test___anext__ ():
159
+ runa (atest___anext__ ())
160
+
161
+ async def agen2 (x ):
162
+ m = yield x # argument of `send` has to flow to value of `yield x` (and so to `m`)
163
+ yield m
164
+
165
+ async def atest_asend ():
166
+ g = agen2 (3 )
167
+ n = await g .__anext__ ()
168
+ SINK (await g .asend (SOURCE ))
169
+
170
+ def test_asend ():
171
+ runa (atest_asend ())
172
+
173
+ async def agen_ex (x ):
174
+ try :
175
+ yield 3
176
+ except :
177
+ yield x # `x` has to flow to call to `athrow`
178
+
179
+ async def atest_athrow ():
180
+ g = agen_ex (SOURCE )
181
+ n = await g .__anext__ ()
182
+ SINK (await g .athrow (TypeError ))
183
+
184
+ def test_athrow ():
185
+ runa (atest_athrow ())
186
+
111
187
# 6.3.1. Attribute references
188
+ class C :
189
+ a = SOURCE
190
+
191
+ def test_attribute_reference ():
192
+ SINK (C .a )
193
+
194
+ # overriding __getattr__ should be tested by the class coverage tests
195
+
112
196
# 6.3.2. Subscriptions
197
+ # This does not constitute dataflow (but could be taint flow)
198
+ def example_subscription_string ():
199
+ SINK ("source" [0 ])
200
+
201
+ def test_subscription_tuple ():
202
+ SINK ((SOURCE ,)[0 ])
203
+
204
+ def test_subscription_list ():
205
+ SINK ([SOURCE ][0 ])
206
+
207
+ def test_subscription_mapping ():
208
+ SINK ({"s" :SOURCE }["s" ])
209
+
210
+ # overriding __getitem__ should be tested by the class coverage tests
211
+
113
212
# 6.3.3. Slicings
213
+ l = [SOURCE ]
214
+
215
+ def test_slicing ():
216
+ s = l [0 :1 :1 ]
217
+ SINK (s [0 ])
218
+
219
+ # The grammar seems to allow `l[0:1:1, 0:1]`, but the interpreter does not like it
220
+
114
221
# 6.3.4. Calls
115
- # 6.4. Await expression
116
- # 6.5. The power operator
117
- # 6.6. Unary arithmetic and bitwise operations
118
- # 6.7. Binary arithmetic operations
119
- # 6.8. Shifting operations
120
- # 6.9. Binary bitwise operations
121
- # 6.10. Comparisons
122
- # 6.10.1. Value comparisons
123
- # 6.10.2. Membership test operations
124
- # 6.10.3. Identity comparisons
125
- # 6.11. Boolean operations
222
+ def f (a , b ):
223
+ return b
224
+
225
+ def test_call_positional ():
226
+ SINK (f (3 , SOURCE ))
227
+
228
+ def test_call_keyword ():
229
+ SINK (f (3 , b = SOURCE ))
230
+
231
+ def test_call_unpack_iterable ():
232
+ SINK (f (3 , * [SOURCE ]))
233
+
234
+ def test_call_unpack_mapping ():
235
+ SINK (f (3 , ** {"b" : SOURCE }))
236
+
237
+ def f_extra_pos (a , * b ):
238
+ return b [0 ]
239
+
240
+ def test_call_extra_pos ():
241
+ SINK (f_extra_pos (3 , SOURCE ))
242
+
243
+ def f_extra_keyword (a , ** b ):
244
+ return b ["b" ]
245
+
246
+ def test_call_extra_keyword ():
247
+ SINK (f_extra_keyword (3 , b = SOURCE ))
248
+
249
+ # return the name of the first extra keyword argument
250
+ def f_extra_keyword_flow (** a ):
251
+ return [* a ][0 ]
252
+
253
+ # call the function with our source as the name of the keyword arguemnt
254
+ def test_call_extra_keyword_flow ():
255
+ SINK (f_extra_keyword_flow (** {SOURCE : None }))
256
+
126
257
# 6.12. Assignment expressions
258
+ def test_assignment_expression ():
259
+ x = 3
260
+ SINK (x := SOURCE )
261
+
127
262
# 6.13. Conditional expressions
263
+ def test_conditional_true ():
264
+ SINK (SOURCE if True else 3 )
265
+
266
+ def test_conditional_false ():
267
+ SINK (3 if False else SOURCE )
268
+
269
+ def test_conditional_evaluation_true ():
270
+ x = 3
271
+ SINK (x if (SOURCE == (x := SOURCE )) else 3 ) # Condition is evaluated first, so x is SOURCE once chosen
272
+
273
+ def test_conditional_evaluation_false ():
274
+ x = 3
275
+ SINK (3 if (3 == (x := SOURCE )) else x ) # Condition is evaluated first, so x is SOURCE once chosen
276
+
128
277
# 6.14. Lambdas
129
- # 6.15. Expression lists
130
- # 6.16. Evaluation order
131
- # 6.17. Operator precedence
278
+ def test_lambda ():
279
+ f = lambda x : x
280
+ SINK ( f ( SOURCE ))
0 commit comments