@@ -85,6 +85,12 @@ module CfgOrigin {
8585 result = unknownValue ( )
8686 }
8787
88+ CfgOrigin fromModule ( ModuleObjectInternal mod ) {
89+ mod .isBuiltin ( ) and result = unknownValue ( )
90+ or
91+ result = mod .getSourceModule ( ) .getEntryNode ( )
92+ }
93+
8894}
8995
9096module PointsTo2 {
@@ -264,14 +270,14 @@ module PointsTo2 {
264270 //// TO DO...
265271 // or
266272 // self_parameter_points_to(def, context, value, origin)
267- // or
268- // delete_points_to(def, context, value, origin)
269- // or
270- // module_name_points_to(def, context, value, origin)
273+ or
274+ delete_points_to ( def , context , value , origin )
275+ or
276+ module_name_points_to ( def , context , value , origin )
271277 or
272278 scope_entry_points_to ( def , context , value , origin )
273- // or
274- // implicit_submodule_points_to(def, context, value, origin)
279+ or
280+ InterModulePointsTo :: implicit_submodule_points_to ( def , context , value , origin )
275281 // or
276282 // iteration_definition_points_to(def, context, value, origin)
277283 /*
@@ -322,6 +328,35 @@ module PointsTo2 {
322328 points_to ( def .getValue ( ) , context , value , origin )
323329 }
324330
331+ /** Points-to for deletion: `del name`. */
332+ pragma [ noinline]
333+ private predicate delete_points_to ( DeletionDefinition def , PointsToContext2 context , ObjectInternal value , ControlFlowNode origin ) {
334+ value = ObjectInternal:: undefined ( ) and origin = def .getDefiningNode ( ) and context .appliesToScope ( def .getScope ( ) )
335+ }
336+
337+ /** Implicit "definition" of `__name__` at the start of a module. */
338+ pragma [ noinline]
339+ private predicate module_name_points_to ( ScopeEntryDefinition def , PointsToContext2 context , StringObjectInternal value , ControlFlowNode origin ) {
340+ def .getVariable ( ) .getName ( ) = "__name__" and
341+ exists ( Module m |
342+ m = def .getScope ( )
343+ |
344+ value = module_dunder_name ( m ) and context .isImport ( )
345+ or
346+ value .strValue ( ) = "__main__" and context .isMain ( ) and context .appliesToScope ( m )
347+ ) and
348+ origin = def .getDefiningNode ( )
349+ }
350+
351+ private StringObjectInternal module_dunder_name ( Module m ) {
352+ exists ( string name |
353+ result .strValue ( ) = name |
354+ if m .isPackageInit ( ) then
355+ name = m .getPackage ( ) .getName ( )
356+ else
357+ name = m .getName ( )
358+ )
359+ }
325360
326361 /** Holds if the phi-function `phi` refers to `(value, origin)` given the context `context`. */
327362 pragma [ nomagic]
@@ -566,9 +601,21 @@ module InterModulePointsTo {
566601 exists ( ModuleObjectInternal mod |
567602 mod = package .submodule ( name ) and
568603 value = mod |
569- origin = CfgOrigin:: fromCfgNode ( mod .getSourceModule ( ) .getEntryNode ( ) )
570- or
571- mod .isBuiltin ( ) and origin = CfgOrigin:: unknown ( )
604+ origin = CfgOrigin:: fromModule ( mod )
605+ )
606+ }
607+
608+ /** Implicit "definition" of the names of submodules at the start of an `__init__.py` file.
609+ *
610+ * PointsTo isn't exactly how the interpreter works, but is the best approximation we can manage statically.
611+ */
612+ pragma [ noinline]
613+ predicate implicit_submodule_points_to ( ImplicitSubModuleDefinition def , PointsToContext2 context , ModuleObjectInternal value , ControlFlowNode origin ) {
614+ exists ( PackageObjectInternal package |
615+ package .getSourceModule ( ) = def .getDefiningNode ( ) .getScope ( ) |
616+ value = package .submodule ( def .getSourceVariable ( ) .getName ( ) ) and
617+ origin = CfgOrigin:: fromModule ( value ) .fix ( def .getDefiningNode ( ) ) and
618+ context .isImport ( )
572619 )
573620 }
574621
0 commit comments