44 * to the possible objects it points-to the inferred types of those objects and the 'origin'
55 * of those objects. The 'origin' is the point in source code that the object can be traced
66 * back to.
7- *
7+ *
88 * This file contains non-layered parts of the points-to analysis.
99 */
10+
1011import python
1112import semmle.python.essa.SsaDefinitions
1213private import semmle.python.types.Builtins
1314
1415module BasePointsTo {
1516 /** INTERNAL -- Use n.refersTo(value, _, origin) instead */
16- pragma [ noinline]
17+ pragma [ noinline]
1718 predicate points_to ( ControlFlowNode f , Object value , ControlFlowNode origin ) {
18- (
19+ (
1920 f .isLiteral ( ) and value = f and not f .getNode ( ) instanceof ImmutableLiteral
2021 or
2122 f .isFunction ( ) and value = f
22- ) and origin = f
23+ ) and
24+ origin = f
2325 }
2426}
2527
@@ -35,12 +37,13 @@ predicate varargs_points_to(ControlFlowNode f, ClassObject cls) {
3537 cls = theTupleType ( )
3638}
3739
38- /** Gets the class of the object for simple cases, namely constants, functions,
40+ /**
41+ * Gets the class of the object for simple cases, namely constants, functions,
3942 * comprehensions and built-in objects.
4043 *
4144 * This exists primarily for internal use. Use getAnInferredType() instead.
4245 */
43- pragma [ noinline]
46+ pragma [ noinline]
4447ClassObject simple_types ( Object obj ) {
4548 result = comprehension ( obj .getOrigin ( ) )
4649 or
@@ -79,37 +82,42 @@ private int tuple_index_value(Object t, int i) {
7982 result = t .( TupleNode ) .getElement ( i ) .getNode ( ) .( Num ) .getN ( ) .toInt ( )
8083 or
8184 exists ( Object item |
82- py_citems ( t , i , item ) and
85+ py_citems ( t , i , item ) and
8386 result = item .( NumericObject ) .intValue ( )
8487 )
8588}
8689
87- pragma [ noinline]
90+ pragma [ noinline]
8891int version_tuple_value ( Object t ) {
89- not exists ( tuple_index_value ( t , 1 ) ) and result = tuple_index_value ( t , 0 ) * 10
92+ not exists ( tuple_index_value ( t , 1 ) ) and result = tuple_index_value ( t , 0 ) * 10
9093 or
91- not exists ( tuple_index_value ( t , 2 ) ) and result = tuple_index_value ( t , 0 ) * 10 + tuple_index_value ( t , 1 )
94+ not exists ( tuple_index_value ( t , 2 ) ) and
95+ result = tuple_index_value ( t , 0 ) * 10 + tuple_index_value ( t , 1 )
9296 or
93- tuple_index_value ( t , 2 ) = 0 and result = tuple_index_value ( t , 0 ) * 10 + tuple_index_value ( t , 1 )
97+ tuple_index_value ( t , 2 ) = 0 and result = tuple_index_value ( t , 0 ) * 10 + tuple_index_value ( t , 1 )
9498 or
95- tuple_index_value ( t , 2 ) > 0 and result = tuple_index_value ( t , 0 ) * 10 + tuple_index_value ( t , 1 ) + 1
99+ tuple_index_value ( t , 2 ) > 0 and
100+ result = tuple_index_value ( t , 0 ) * 10 + tuple_index_value ( t , 1 ) + 1
96101}
97102
98103/** Choose a version numbers that represent the extreme of supported versions. */
99104private int major_minor ( ) {
100- if major_version ( ) = 3 then
101- ( result = 33 or result = 37 ) // 3.3 to 3.7
102- else
103- ( result = 25 or result = 27 ) // 2.5 to 2.7
105+ if major_version ( ) = 3
106+ then (
107+ result = 33 or result = 37
108+ ) else (
109+ // 3.3 to 3.7
110+ result = 25 or result = 27
111+ ) // 2.5 to 2.7
104112}
105113
106114/** Compares the given tuple object to both the maximum and minimum possible sys.version_info values */
107115int version_tuple_compare ( Object t ) {
108- version_tuple_value ( t ) < major_minor ( ) and result = - 1
116+ version_tuple_value ( t ) < major_minor ( ) and result = - 1
109117 or
110- version_tuple_value ( t ) = major_minor ( ) and result = 0
118+ version_tuple_value ( t ) = major_minor ( ) and result = 0
111119 or
112- version_tuple_value ( t ) > major_minor ( ) and result = 1
120+ version_tuple_value ( t ) > major_minor ( ) and result = 1
113121}
114122
115123/* Holds if `cls` is a new-style class if it were to have no explicit base classes */
@@ -121,22 +129,23 @@ predicate baseless_is_new_style(ClassObject cls) {
121129 exists ( cls .declaredMetaClass ( ) )
122130}
123131
124- /* The following predicates exist in order to provide
132+ /*
133+ * The following predicates exist in order to provide
125134 * more precise type information than the underlying
126135 * database relations. This help to optimise the points-to
127136 * analysis.
128137 */
129138
130139/** Holds if this class (not on a super-class) declares name */
131- pragma [ noinline]
140+ pragma [ noinline]
132141predicate class_declares_attribute ( ClassObject cls , string name ) {
133142 exists ( Class defn |
134143 defn = cls .getPyClass ( ) and
135144 class_defines_name ( defn , name )
136145 )
137146 or
138147 exists ( Builtin o |
139- o = cls .asBuiltin ( ) .getMember ( name ) and
148+ o = cls .asBuiltin ( ) .getMember ( name ) and
140149 not exists ( Builtin sup |
141150 sup = cls .asBuiltin ( ) .getBaseClass ( ) and
142151 o = sup .getMember ( name )
@@ -151,9 +160,9 @@ private predicate class_defines_name(Class cls, string name) {
151160
152161/** Gets a return value CFG node, provided that is safe to track across returns */
153162ControlFlowNode safe_return_node ( PyFunctionObject func ) {
154- result = func .getAReturnedNode ( )
163+ result = func .getAReturnedNode ( ) and
155164 // Not a parameter
156- and not exists ( Parameter p , SsaVariable pvar |
165+ not exists ( Parameter p , SsaVariable pvar |
157166 p .asName ( ) .getAFlowNode ( ) = pvar .getDefinition ( ) and
158167 result = pvar .getAUse ( )
159168 ) and
@@ -163,9 +172,11 @@ ControlFlowNode safe_return_node(PyFunctionObject func) {
163172
164173/** Holds if it can be determined from the control flow graph alone that this function can never return */
165174predicate function_can_never_return ( FunctionObject func ) {
166- /* A Python function never returns if it has no normal exits that are not dominated by a
175+ /*
176+ * A Python function never returns if it has no normal exits that are not dominated by a
167177 * call to a function which itself never returns.
168178 */
179+
169180 exists ( Function f |
170181 f = func .getFunction ( ) and
171182 not exists ( f .getAnExitNode ( ) )
@@ -174,35 +185,30 @@ predicate function_can_never_return(FunctionObject func) {
174185 func = ModuleObject:: named ( "sys" ) .attr ( "exit" )
175186}
176187
177-
178- private newtype TIterationDefinition =
188+ private newtype TIterationDefinition =
179189 TIterationDefinition_ ( SsaSourceVariable var , ControlFlowNode def , ControlFlowNode sequence ) {
180190 SsaSource:: iteration_defined_variable ( var , def , sequence )
181191 }
182192
183- /** DEPRECATED. For backwards compatibility only.
184- * A definition of a variable in a for loop `for v in ...:` */
193+ /**
194+ * DEPRECATED. For backwards compatibility only.
195+ * A definition of a variable in a for loop `for v in ...:`
196+ */
185197deprecated class IterationDefinition extends TIterationDefinition {
198+ string toString ( ) { result = "IterationDefinition" }
186199
187- string toString ( ) {
188- result = "IterationDefinition"
189- }
190-
191- ControlFlowNode getSequence ( ) {
192- this = TIterationDefinition_ ( _, _, result )
193- }
194-
200+ ControlFlowNode getSequence ( ) { this = TIterationDefinition_ ( _, _, result ) }
195201}
196202
197-
198203/** Hold if outer contains inner, both are contained within a test and inner is a use is a plain use or an attribute lookup */
199204pragma [ noinline]
200205predicate contains_interesting_expression_within_test ( ControlFlowNode outer , ControlFlowNode inner ) {
201206 inner .isLoad ( ) and
202207 exists ( ControlFlowNode test |
203208 outer .getAChild * ( ) = inner and
204209 test_contains ( test , outer ) and
205- test_contains ( test , inner ) |
210+ test_contains ( test , inner )
211+ |
206212 inner instanceof NameNode or
207213 inner instanceof AttrNode
208214 )
@@ -216,22 +222,27 @@ predicate test_contains(ControlFlowNode expr, ControlFlowNode use) {
216222}
217223
218224/** Holds if `test` is a test (a branch), `use` is within that test and `def` is an edge from that test with `sense` */
219- predicate refinement_test ( ControlFlowNode test , ControlFlowNode use , boolean sense , PyEdgeRefinement def ) {
220- /* Because calls such as `len` may create a new variable, we need to go via the source variable
225+ predicate refinement_test (
226+ ControlFlowNode test , ControlFlowNode use , boolean sense , PyEdgeRefinement def
227+ ) {
228+ /*
229+ * Because calls such as `len` may create a new variable, we need to go via the source variable
221230 * That is perfectly safe as we are only dealing with calls that do not mutate their arguments.
222231 */
232+
223233 use = def .getInput ( ) .getSourceVariable ( ) .( Variable ) .getAUse ( ) and
224234 test = def .getPredecessor ( ) .getLastNode ( ) and
225235 test_contains ( test , use ) and
226236 sense = def .getSense ( )
227237}
228238
229239/** Holds if `f` is an import of the form `from .[...] import name` and the enclosing scope is an __init__ module */
230- pragma [ noinline]
240+ pragma [ noinline]
231241predicate live_import_from_dot_in_init ( ImportMemberNode f , EssaVariable var ) {
232242 exists ( string name |
233243 import_from_dot_in_init ( f .getModule ( name ) ) and
234- var .getSourceVariable ( ) .getName ( ) = name and var .getAUse ( ) = f
244+ var .getSourceVariable ( ) .getName ( ) = name and
245+ var .getAUse ( ) = f
235246 )
236247}
237248
@@ -247,60 +258,65 @@ predicate import_from_dot_in_init(ImportExprNode f) {
247258}
248259
249260/** Gets the pseudo-object representing the value referred to by an undefined variable */
250- Object undefinedVariable ( ) {
251- py_special_objects ( result , "_semmle_undefined_value" )
252- }
261+ Object undefinedVariable ( ) { py_special_objects ( result , "_semmle_undefined_value" ) }
253262
254263/** Gets the pseudo-object representing an unknown value */
255- Object unknownValue ( ) {
256- result .asBuiltin ( ) = Builtin:: unknown ( )
257- }
264+ Object unknownValue ( ) { result .asBuiltin ( ) = Builtin:: unknown ( ) }
258265
259266BuiltinCallable theTypeNewMethod ( ) {
260267 result .asBuiltin ( ) = theTypeType ( ) .asBuiltin ( ) .getMember ( "__new__" )
261268}
262269
263270/** Gets the `value, cls, origin` that `f` would refer to if it has not been assigned some other value */
264- pragma [ noinline]
265- predicate potential_builtin_points_to ( NameNode f , Object value , ClassObject cls , ControlFlowNode origin ) {
266- f .isGlobal ( ) and f .isLoad ( ) and origin = f and
271+ pragma [ noinline]
272+ predicate potential_builtin_points_to (
273+ NameNode f , Object value , ClassObject cls , ControlFlowNode origin
274+ ) {
275+ f .isGlobal ( ) and
276+ f .isLoad ( ) and
277+ origin = f and
267278 (
268279 builtin_name_points_to ( f .getId ( ) , value , cls )
269280 or
270281 not exists ( Object:: builtin ( f .getId ( ) ) ) and value = unknownValue ( ) and cls = theUnknownType ( )
271282 )
272283}
273284
274- pragma [ noinline]
285+ pragma [ noinline]
275286predicate builtin_name_points_to ( string name , Object value , ClassObject cls ) {
276287 value = Object:: builtin ( name ) and cls .asBuiltin ( ) = value .asBuiltin ( ) .getClass ( )
277288}
278289
279290module BaseFlow {
280-
281- predicate reaches_exit ( EssaVariable var ) {
282- var .getAUse ( ) = var .getScope ( ) .getANormalExit ( )
283- }
291+ predicate reaches_exit ( EssaVariable var ) { var .getAUse ( ) = var .getScope ( ) .getANormalExit ( ) }
284292
285293 /* Helper for this_scope_entry_value_transfer(...). Transfer of values from earlier scope to later on */
286- cached predicate scope_entry_value_transfer_from_earlier ( EssaVariable pred_var , Scope pred_scope , ScopeEntryDefinition succ_def , Scope succ_scope ) {
294+ cached
295+ predicate scope_entry_value_transfer_from_earlier (
296+ EssaVariable pred_var , Scope pred_scope , ScopeEntryDefinition succ_def , Scope succ_scope
297+ ) {
287298 exists ( SsaSourceVariable var |
288299 reaches_exit ( pred_var ) and
289300 pred_var .getScope ( ) = pred_scope and
290301 var = pred_var .getSourceVariable ( ) and
291302 var = succ_def .getSourceVariable ( ) and
292303 succ_def .getScope ( ) = succ_scope
293- |
304+ |
294305 pred_scope .precedes ( succ_scope )
295306 or
296- /* If an `__init__` method does not modify the global variable, then
307+ /*
308+ * If an `__init__` method does not modify the global variable, then
297309 * we can skip it and take the value directly from the module.
298310 */
311+
299312 exists ( Scope init |
300- init .getName ( ) = "__init__" and init .precedes ( succ_scope ) and pred_scope .precedes ( init ) and
301- not var .( Variable ) .getAStore ( ) .getScope ( ) = init and var instanceof GlobalVariable
313+ init .getName ( ) = "__init__" and
314+ init .precedes ( succ_scope ) and
315+ pred_scope .precedes ( init ) and
316+ not var .( Variable ) .getAStore ( ) .getScope ( ) = init and
317+ var instanceof GlobalVariable
302318 )
303- )
319+ )
304320 }
305321}
306322
@@ -312,15 +328,17 @@ predicate simple_points_to(ControlFlowNode f, Object value, ClassObject cls, Con
312328 or
313329 BasePointsTo:: points_to ( f , value , origin ) and cls = simple_types ( value )
314330 or
315- value = f .getNode ( ) .( ImmutableLiteral ) .getLiteralObject ( ) and cls = simple_types ( value ) and origin = f
331+ value = f .getNode ( ) .( ImmutableLiteral ) .getLiteralObject ( ) and
332+ cls = simple_types ( value ) and
333+ origin = f
316334}
317335
318- /** Holds if `bit` is a binary expression node with a bitwise operator.
336+ /**
337+ * Holds if `bit` is a binary expression node with a bitwise operator.
319338 * Helper for `this_binary_expr_points_to`.
320339 */
321340predicate bitwise_expression_node ( BinaryExprNode bit , ControlFlowNode left , ControlFlowNode right ) {
322- exists ( Operator op |
323- op = bit .getNode ( ) .getOp ( ) |
341+ exists ( Operator op | op = bit .getNode ( ) .getOp ( ) |
324342 op instanceof BitAnd or
325343 op instanceof BitOr or
326344 op instanceof BitXor
@@ -329,16 +347,14 @@ predicate bitwise_expression_node(BinaryExprNode bit, ControlFlowNode left, Cont
329347 right = bit .getRight ( )
330348}
331349
332-
333- private
334- Module theCollectionsAbcModule ( ) {
350+ private Module theCollectionsAbcModule ( ) {
335351 result .getName ( ) = "_abcoll"
336352 or
337353 result .getName ( ) = "_collections_abc"
338354}
339355
340356ClassObject collectionsAbcClass ( string name ) {
341- exists ( Class cls |
357+ exists ( Class cls |
342358 result .getPyClass ( ) = cls and
343359 cls .getName ( ) = name and
344360 cls .getScope ( ) = theCollectionsAbcModule ( )
0 commit comments