mirror of
https://github.com/github/codeql.git
synced 2026-05-27 17:41:24 +02:00
In the legacy CFG the same Python 'Name' that is the target of an
augmented assignment has two distinct CFG nodes — a load node (context
3) earlier in the basic block and a store node (context 5) later.
'augstore(load, store)' relates the pair via dominance.
The new (shared) CFG canonicalises each AST expression to a single
CFG node, so 'load' and 'store' collapse to one. The dominance-based
'augstore' from the legacy implementation no longer holds (it would
require 'load.strictlyDominates(load)'), so 'isAugLoad' / 'isAugStore'
never fired and 'isStore' missed the AugAssign target entirely.
Redefines 'augstore' as reflexive on the AugAssign target's canonical
CFG node. With this change:
* isAugLoad / isAugStore both fire on the single canonical node.
* isStore fires (via 'or augstore(_, this)') — matching the legacy
classification that an augmented-assignment target is a store.
* isLoad does not fire (excluded by 'not augstore(_, this)').
Adds 'python/ql/test/library-tests/ControlFlow/store-load/' covering
plain load/store/delete, parameters, augmented assignment, tuple
unpacking, attribute and subscript stores. The test asserts the
classification directly on the new-CFG facade.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
46 lines
1.4 KiB
Plaintext
46 lines
1.4 KiB
Plaintext
/**
|
|
* Inline-expectations test for the store/load/delete/parameter
|
|
* classification predicates on the new-CFG facade.
|
|
*
|
|
* Each tag fires when the corresponding predicate (`isLoad`,
|
|
* `isStore`, `isDelete`, `isParameter`, `isAugLoad`, `isAugStore`)
|
|
* holds on the canonical CFG node wrapping a `Py::Name` with the
|
|
* given identifier.
|
|
*
|
|
* For subscript / attribute stores the tag fires on the Subscript /
|
|
* Attribute node itself, with `value` set to the rightmost identifier
|
|
* (the attribute name for `Attribute`, the index expression's textual
|
|
* form for `Subscript`).
|
|
*/
|
|
|
|
import python
|
|
import semmle.python.controlflow.internal.Cfg as Cfg
|
|
import utils.test.InlineExpectationsTest
|
|
|
|
module StoreLoadTest implements TestSig {
|
|
string getARelevantTag() { result = ["load", "store", "delete", "param", "augload", "augstore"] }
|
|
|
|
predicate hasActualResult(Location location, string element, string tag, string value) {
|
|
exists(Cfg::NameNode n |
|
|
location = n.getLocation() and
|
|
element = n.toString() and
|
|
value = n.getId() and
|
|
(
|
|
n.isLoad() and tag = "load"
|
|
or
|
|
n.isStore() and not n.isAugStore() and tag = "store"
|
|
or
|
|
n.isDelete() and tag = "delete"
|
|
or
|
|
n.isParameter() and tag = "param"
|
|
or
|
|
n.isAugLoad() and tag = "augload"
|
|
or
|
|
n.isAugStore() and tag = "augstore"
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
import MakeTest<StoreLoadTest>
|