mirror of
https://github.com/github/codeql.git
synced 2025-12-20 10:46:30 +01:00
Python: Support named imports as attribute reads
Required a small change in `DataFlow::importModule` to get the desired behaviour (cf. the type trackers defined in `moduleattr.ql`, but this should be harmless. The node that is added doesn't have any flow anywhere.
This commit is contained in:
@@ -218,3 +218,31 @@ private class GetAttrCallAsAttrRead extends AttrRead, CfgNode {
|
||||
result = this.getAttributeNameExpr().asExpr().(StrConst).getText()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience class for embedding `ImportMemberNode` into `DataFlowCfgNode`, as the former is not
|
||||
* obviously a subtype of the latter.
|
||||
*/
|
||||
private class DataFlowImportMemberNode extends ImportMemberNode, DataFlowCfgNode { }
|
||||
|
||||
/**
|
||||
* Represents a named import as an attribute read. That is,
|
||||
* ```python
|
||||
* from module import attr as attr_ref
|
||||
* ```
|
||||
* is treated as if it is a read of the attribute `module.attr`, even if `module` is not imported directly.
|
||||
*/
|
||||
private class ModuleAttributeImportAsAttrRead extends AttrRead, CfgNode {
|
||||
override DataFlowImportMemberNode node;
|
||||
|
||||
override Node getObject() { result.asCfgNode() = node.getModule(_) }
|
||||
|
||||
override ExprNode getAttributeNameExpr() {
|
||||
// The name of an imported attribute doesn't exist as a `Node` in the control flow graph, as it
|
||||
// can only ever be an identifier, and is therefore represented directly as a string.
|
||||
// Use `getAttributeName` to access the name of the attribute.
|
||||
none()
|
||||
}
|
||||
|
||||
override string getAttributeName() { exists(node.getModule(result)) }
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
|
||||
*
|
||||
* Also see `DataFlow::importMember`
|
||||
*/
|
||||
EssaNode importModule(string name) {
|
||||
Node importModule(string name) {
|
||||
exists(Variable var, Import imp, Alias alias |
|
||||
alias = imp.getAName() and
|
||||
alias.getAsname() = var.getAStore() and
|
||||
@@ -45,8 +45,14 @@ EssaNode importModule(string name) {
|
||||
or
|
||||
name = alias.getValue().(ImportExpr).getImportedModuleName()
|
||||
) and
|
||||
result.getVar().(AssignmentDefinition).getSourceVariable() = var
|
||||
result.(EssaNode).getVar().(AssignmentDefinition).getSourceVariable() = var
|
||||
)
|
||||
or
|
||||
// In `from module import attr`, we want to consider `module` to be an expression that refers to a
|
||||
// module of that name, as this allows us to refer to attributes of this module, even if it's
|
||||
// never imported directly. Note that there crucially isn't any _flow_ from `module` to references
|
||||
// to that same identifier.
|
||||
result.asCfgNode().getNode() = any(ImportExpr i | i.getAnImportedModuleName() = name)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user