Merge pull request #8890 from tausbn/python-add-global-attribute-writes

Python: Add support for global attribute writes
This commit is contained in:
Taus
2022-05-02 12:03:41 +02:00
committed by GitHub
2 changed files with 44 additions and 0 deletions

View File

@@ -92,6 +92,32 @@ private class AttributeAssignmentAsAttrWrite extends AttrWrite, CfgNode {
override string getAttributeName() { result = node.getName() }
}
/**
* An attribute assignment where the object is a global variable: `global_var.attr = value`.
*
* Syntactically, this is identical to the situation that is covered by
* `AttributeAssignmentAsAttrWrite`, however in this case we want to behave as if the object that is
* being written is the underlying `ModuleVariableNode`.
*/
private class GlobalAttributeAssignmentAsAttrWrite extends AttrWrite, CfgNode {
override AttributeAssignmentNode node;
override Node getValue() { result.asCfgNode() = node.getValue() }
override Node getObject() {
result.(ModuleVariableNode).getVariable() = node.getObject().getNode().(Name).getVariable()
}
override ExprNode getAttributeNameExpr() {
// Attribute names don't exist as `Node`s in the control flow graph, as they can only ever be
// identifiers, and are therefore represented directly as strings.
// Use `getAttributeName` to access the name of the attribute.
none()
}
override string getAttributeName() { result = node.getName() }
}
/** Represents `CallNode`s that may refer to calls to built-in functions or classes. */
private class BuiltInCallNode extends CallNode {
string name;

View File

@@ -49,6 +49,24 @@ def test_create_with_foo():
x = create_with_foo() # $ tracked=foo
print(x.foo) # $ tracked=foo tracked
def test_global_attribute_assignment():
global global_var
global_var.foo = tracked # $ tracked tracked=foo
def test_global_attribute_read():
x = global_var.foo # $ tracked tracked=foo
def test_local_attribute_assignment():
# Same as `test_global_attribute_assignment`, but the assigned variable is not global
# In this case, we don't want flow going to the `ModuleVariableNode` for `local_var`
# (which is referenced in `test_local_attribute_read`).
local_var = object() # $ tracked=foo
local_var.foo = tracked # $ tracked tracked=foo
def test_local_attribute_read():
x = local_var.foo
# ------------------------------------------------------------------------------
# Attributes assigned statically to a class
# ------------------------------------------------------------------------------