Python points-to: Cache a few key predicates.

This commit is contained in:
Mark Shannon
2019-05-30 16:19:43 +01:00
parent 1de0dc9282
commit f311c2013e
5 changed files with 33 additions and 35 deletions

View File

@@ -340,8 +340,7 @@ class PhiFunction extends EssaDefinition, TPhiFunction {
}
/** Gets the input variable for this phi node on the edge `pred` -> `this.getBasicBlock()`, if any. */
pragma [noinline]
EssaVariable getInput(BasicBlock pred) {
cached EssaVariable getInput(BasicBlock pred) {
result.getDefinition() = this.reachingDefinition(pred)
or
result.getDefinition() = this.inputEdgeRefinement(pred)

View File

@@ -188,7 +188,7 @@ class CallableValue extends Value {
}
/** Gets the argument corresponding to the `n'th parameter node of this callable. */
ControlFlowNode getArgumentForCall(CallNode call, int n) {
cached ControlFlowNode getArgumentForCall(CallNode call, int n) {
exists(ObjectInternal called, int offset |
PointsToInternal::pointsTo(call.getFunction(), _, called, _) and
called.functionAndOffset(this, offset)
@@ -204,7 +204,7 @@ class CallableValue extends Value {
/** Gets the argument corresponding to the `name`d parameter node of this callable. */
ControlFlowNode getNamedArgumentForCall(CallNode call, string name) {
cached ControlFlowNode getNamedArgumentForCall(CallNode call, string name) {
exists(CallableObjectInternal called, int offset |
PointsToInternal::pointsTo(call.getFunction(), _, called, _) and
called.functionAndOffset(this, offset)

View File

@@ -589,8 +589,7 @@ module BaseFlow {
}
/* Helper for this_scope_entry_value_transfer(...). Transfer of values from earlier scope to later on */
pragma [noinline]
predicate scope_entry_value_transfer_from_earlier(EssaVariable pred_var, Scope pred_scope, ScopeEntryDefinition succ_def, Scope succ_scope) {
cached predicate scope_entry_value_transfer_from_earlier(EssaVariable pred_var, Scope pred_scope, ScopeEntryDefinition succ_def, Scope succ_scope) {
exists(SsaSourceVariable var |
reaches_exit(pred_var) and
pred_var.getScope() = pred_scope and

View File

@@ -124,7 +124,7 @@ module PointsTo {
}
/* Backwards compatibility */
deprecated predicate
deprecated cached predicate
points_to(ControlFlowNode f, PointsToContext context, Object obj, ClassObject cls, ControlFlowNode origin) {
exists(ObjectInternal value |
PointsToInternal::pointsTo(f, context, value, origin) and
@@ -568,15 +568,34 @@ cached module PointsToInternal {
pointsTo(f.getAnOperand(), context, value, origin)
}
/* Holds if `import name` will import the module `m`. */
cached predicate module_imported_as(ModuleObjectInternal m, string name) {
/* Normal imports */
m.getName() = name
or
/* sys.modules['name'] = m */
exists(ControlFlowNode sys_modules_flow, ControlFlowNode n, ControlFlowNode mod |
/* Use previous points-to here to avoid slowing down the recursion too much */
exists(SubscriptNode sub |
sub.getValue() = sys_modules_flow and
pointsTo(sys_modules_flow, _, ObjectInternal::sysModules(), _) and
sub.getIndex() = n and
n.getNode().(StrConst).getText() = name and
sub.(DefinitionNode).getValue() = mod and
pointsTo(mod, _, m, _)
)
)
}
}
module InterModulePointsTo {
private module InterModulePointsTo {
pragma [noinline]
predicate import_points_to(ControlFlowNode f, PointsToContext context, ObjectInternal value, ControlFlowNode origin) {
exists(string name, ImportExpr i |
i.getAFlowNode() = f and i.getImportedModuleName() = name and
module_imported_as(value, name) and
PointsToInternal::module_imported_as(value, name) and
origin = f and
context.appliesTo(f)
)
@@ -623,25 +642,6 @@ module InterModulePointsTo {
)
}
/* Holds if `import name` will import the module `m`. */
predicate module_imported_as(ModuleObjectInternal m, string name) {
/* Normal imports */
m.getName() = name
or
/* sys.modules['name'] = m */
exists(ControlFlowNode sys_modules_flow, ControlFlowNode n, ControlFlowNode mod |
/* Use previous points-to here to avoid slowing down the recursion too much */
exists(SubscriptNode sub |
sub.getValue() = sys_modules_flow and
PointsToInternal::pointsTo(sys_modules_flow, _, ObjectInternal::sysModules(), _) and
sub.getIndex() = n and
n.getNode().(StrConst).getText() = name and
sub.(DefinitionNode).getValue() = mod and
PointsToInternal::pointsTo(mod, _, m, _)
)
)
}
/** Implicit "definition" of the names of submodules at the start of an `__init__.py` file.
*
* PointsTo isn't exactly how the interpreter works, but is the best approximation we can manage statically.
@@ -2077,13 +2077,13 @@ module AttributePointsTo {
}
module ModuleAttributes {
cached module ModuleAttributes {
private EssaVariable varAtExit(Module mod, string name) {
result.getName() = name and result.getAUse() = mod.getANormalExit()
}
EssaVariable moduleStateVariable(ControlFlowNode use) {
private EssaVariable moduleStateVariable(ControlFlowNode use) {
result.isMetaVariable() and result.getAUse() = use
}
@@ -2091,7 +2091,7 @@ module ModuleAttributes {
result = moduleStateVariable(mod.getANormalExit())
}
predicate pointsToAtExit(Module mod, string name, ObjectInternal value, CfgOrigin origin) {
cached predicate pointsToAtExit(Module mod, string name, ObjectInternal value, CfgOrigin origin) {
if exists(varAtExit(mod, name)) then (
PointsToInternal::variablePointsTo(varAtExit(mod, name), any(Context c | c.isImport()), value, origin)
) else (
@@ -2099,7 +2099,7 @@ module ModuleAttributes {
)
}
predicate attributePointsTo(EssaVariable var, string name, ObjectInternal value, CfgOrigin origin) {
cached predicate attributePointsTo(EssaVariable var, string name, ObjectInternal value, CfgOrigin origin) {
importStarPointsTo(var.getDefinition(), name, value, origin)
or
callsitePointsTo(var.getDefinition(), name, value, origin)
@@ -2142,7 +2142,7 @@ module ModuleAttributes {
* Where var may be redefined in call to `foo` if `var` escapes (is global or non-local).
*/
pragma [noinline]
predicate callsitePointsTo(CallsiteRefinement def, string name, ObjectInternal value, CfgOrigin origin) {
private predicate callsitePointsTo(CallsiteRefinement def, string name, ObjectInternal value, CfgOrigin origin) {
def.getVariable().isMetaVariable() and
exists(EssaVariable var, Function func, PointsToContext callee |
InterProceduralPointsTo::callsite_calls_function(def.getCall(), _, func, callee, _) and
@@ -2155,7 +2155,7 @@ module ModuleAttributes {
* Since it cannot refer to any actual value, it is set to "undefined" for sub module names.
*/
pragma [noinline]
predicate scopeEntryPointsTo(ScopeEntryDefinition def, string name, ObjectInternal value, CfgOrigin origin) {
private predicate scopeEntryPointsTo(ScopeEntryDefinition def, string name, ObjectInternal value, CfgOrigin origin) {
def.getVariable().isMetaVariable() and
exists(Module m |
def.getScope() = m and

View File

@@ -95,7 +95,7 @@ abstract class ModuleObject extends Object {
/** Whether this module is imported by 'import name'. For example on a linux system,
* the module 'posixpath' is imported as 'os.path' or as 'posixpath' */
predicate importedAs(string name) {
InterModulePointsTo::module_imported_as(theModule(), name)
PointsToInternal::module_imported_as(theModule(), name)
}
ModuleObject getAnImportedModule() {