Skip to content

Commit 3288cf1

Browse files
committed
Python: Hopefully final changes to documentation.
1 parent b07c7ab commit 3288cf1

File tree

2 files changed

+26
-8
lines changed

2 files changed

+26
-8
lines changed

python/ql/src/experimental/dataflow/internal/Attributes.qll

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ abstract class AttrRef extends Node {
3737
}
3838

3939
/**
40-
* Gets the name of the attribute being read or written. Only holds if the attribute name has
41-
* been uniquely determined statically. For attributes that are computed dynamically,
42-
* consider using `mayHaveAttributeName` instead.
40+
* Gets the name of the attribute being read or written. For dynamic attribute accesses, this
41+
* method is not guaranteed to return a result. For such cases, using `mayHaveAttributeName` may yield
42+
* better results.
4343
*/
4444
abstract string getAttributeName();
4545
}

python/ql/src/experimental/dataflow/internal/DataFlowUtil.qll

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ predicate localFlowStep(Node nodeFrom, Node nodeTo) { simpleLocalFlowStep(nodeFr
1818
predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
1919

2020
/**
21-
* Gets an EssaNode that holds the module imported by `name`.
21+
* Gets a `Node` that refers to the module referenced by `name`.
2222
* Note that for the statement `import pkg.mod`, the new variable introduced is `pkg` that is a
2323
* reference to the module `pkg`.
2424
*
@@ -27,6 +27,9 @@ predicate localFlow(Node source, Node sink) { localFlowStep*(source, sink) }
2727
* 2. `from <package> import <module>` when `<name> = <package> + "." + <module>`
2828
* 3. `from <module> import <member>` when `<name> = <module> + "." + <member>`
2929
*
30+
* Finally, in `from <module> import <member>` we consider the `ImportExpr` corresponding to
31+
* `<module>` to be a reference to that module.
32+
*
3033
* Note:
3134
* While it is technically possible that `import mypkg.foo` and `from mypkg import foo` can give different values,
3235
* it's highly unlikely that this will be a problem in production level code.
@@ -48,10 +51,25 @@ Node importModule(string name) {
4851
result.(EssaNode).getVar().(AssignmentDefinition).getSourceVariable() = var
4952
)
5053
or
51-
// In `from module import attr`, we want to consider `module` to be an expression that refers to a
52-
// module of that name, as this allows us to refer to attributes of this module, even if it's
53-
// never imported directly. Note that there crucially isn't any _flow_ from `module` to references
54-
// to that same identifier.
54+
// Although it may seem superfluous to consider the `foo` part of `from foo import bar as baz` to
55+
// be a reference to a module (since that reference only makes sense locally within the `import`
56+
// statement), it's important for our use of type trackers to consider this local reference to
57+
// also refer to the `foo` module. That way, if one wants to track references to the `bar`
58+
// attribute using a type tracker, one can simply write
59+
//
60+
// ```ql
61+
// DataFlow::Node bar_attr_tracker(TypeTracker t) {
62+
// t.startInAttr("bar") and
63+
// result = foo_module_tracker()
64+
// or
65+
// exists(TypeTracker t2 | result = bar_attr_tracker(t2).track(t2, t))
66+
// }
67+
// ```
68+
//
69+
// Where `foo_module_tracker` is a type tracker that tracks references to the `foo` module.
70+
// Because named imports are modelled as `AttrRead`s, the statement `from foo import bar as baz`
71+
// is interpreted as if it was an assignment `baz = foo.bar`, which means `baz` gets tracked as a
72+
// reference to `foo.bar`, as desired.
5573
result.asCfgNode().getNode() = any(ImportExpr i | i.getAnImportedModuleName() = name)
5674
}
5775

0 commit comments

Comments
 (0)