mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Python: Add post-update nodes
This commit is contained in:
@@ -123,8 +123,18 @@ module Consistency {
|
||||
n.getEnclosingCallable() != call.getEnclosingCallable()
|
||||
}
|
||||
|
||||
// This predicate helps the compiler forget that in some languages
|
||||
// it is impossible for a result of `getPreUpdateNode` to be an
|
||||
// instance of `PostUpdateNode`.
|
||||
private Node getPre(PostUpdateNode n) {
|
||||
result = n.getPreUpdateNode()
|
||||
or
|
||||
none()
|
||||
}
|
||||
|
||||
query predicate postIsNotPre(PostUpdateNode n, string msg) {
|
||||
n.getPreUpdateNode() = n and msg = "PostUpdateNode should not equal its pre-update node."
|
||||
getPre(n) = n and
|
||||
msg = "PostUpdateNode should not equal its pre-update node."
|
||||
}
|
||||
|
||||
query predicate postHasUniquePre(PostUpdateNode n, string msg) {
|
||||
@@ -152,12 +162,6 @@ module Consistency {
|
||||
msg = "Origin of readStep is missing a PostUpdateNode."
|
||||
}
|
||||
|
||||
query predicate storeIsPostUpdate(Node n, string msg) {
|
||||
storeStep(_, _, n) and
|
||||
not n instanceof PostUpdateNode and
|
||||
msg = "Store targets should be PostUpdateNodes."
|
||||
}
|
||||
|
||||
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
|
||||
not hasPost(n) and
|
||||
not isImmutableOrUnobservable(n) and
|
||||
|
||||
@@ -15,6 +15,32 @@ class DataFlowCfgNode extends ControlFlowNode {
|
||||
DataFlowCfgNode() { isExpressionNode(this) }
|
||||
}
|
||||
|
||||
/** A data flow node which should have an associated post-update node. */
|
||||
abstract class PreUpdateNode extends Node { }
|
||||
|
||||
/** An argument might have its value changed as a result of a call. */
|
||||
class ArgumentPreUpdateNode extends PreUpdateNode, ArgumentNode { }
|
||||
|
||||
/** An object might have its value changed after a store. */
|
||||
class StorePreUpdateNode extends PreUpdateNode, CfgNode {
|
||||
StorePreUpdateNode() {
|
||||
exists(Attribute a |
|
||||
node = a.getObject().getAFlowNode() and
|
||||
a.getCtx() instanceof Store
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A node marking the state change of an object after a read */
|
||||
class ReadPreUpdateNode extends PreUpdateNode, CfgNode {
|
||||
ReadPreUpdateNode() {
|
||||
exists(Attribute a |
|
||||
node = a.getObject().getAFlowNode() and
|
||||
a.getCtx() instanceof Load
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node associated with an object after an operation that might have
|
||||
* changed its state.
|
||||
@@ -24,12 +50,21 @@ class DataFlowCfgNode extends ControlFlowNode {
|
||||
* an update to the field.
|
||||
*
|
||||
* Nodes corresponding to AST elements, for example `ExprNode`, usually refer
|
||||
* to the value before the update with the exception of `ObjectCreation`,
|
||||
* which represents the value after the constructor has run.
|
||||
* to the value before the update.
|
||||
*/
|
||||
abstract class PostUpdateNode extends Node {
|
||||
class PostUpdateNode extends Node, TPostUpdateNode {
|
||||
PreUpdateNode pre;
|
||||
|
||||
PostUpdateNode() { this = TPostUpdateNode(pre) }
|
||||
|
||||
/** Gets the node before the state update. */
|
||||
abstract Node getPreUpdateNode();
|
||||
Node getPreUpdateNode() { result = pre }
|
||||
|
||||
override string toString() { result = "[post] " + pre.toString() }
|
||||
|
||||
override Scope getScope() { result = pre.getScope() }
|
||||
|
||||
override Location getLocation() { result = pre.getLocation() }
|
||||
}
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
@@ -98,7 +133,17 @@ module EssaFlow {
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
not nodeFrom.(EssaNode).getVar() instanceof GlobalSsaVariable and
|
||||
not nodeTo.(EssaNode).getVar() instanceof GlobalSsaVariable and
|
||||
EssaFlow::essaFlowStep(nodeFrom, nodeTo)
|
||||
EssaFlow::essaFlowStep(update(nodeFrom), nodeTo)
|
||||
}
|
||||
|
||||
private Node update(Node node) {
|
||||
exists(PostUpdateNode pun |
|
||||
node = pun.getPreUpdateNode() and
|
||||
result = pun
|
||||
)
|
||||
or
|
||||
not exists(PostUpdateNode pun | node = pun.getPreUpdateNode()) and
|
||||
result = node
|
||||
}
|
||||
|
||||
// TODO: Make modules for these headings
|
||||
|
||||
@@ -20,7 +20,9 @@ newtype TNode =
|
||||
/** A node corresponding to an SSA variable. */
|
||||
TEssaNode(EssaVariable var) or
|
||||
/** A node corresponding to a control flow node. */
|
||||
TCfgNode(DataFlowCfgNode node)
|
||||
TCfgNode(DataFlowCfgNode node) or
|
||||
/** A node representing the value of an object after a state change */
|
||||
TPostUpdateNode(PreUpdateNode pre)
|
||||
|
||||
/**
|
||||
* An element, viewed as a node in a data flow graph. Either an SSA variable
|
||||
|
||||
@@ -38,3 +38,4 @@
|
||||
| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() | test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() |
|
||||
| test.py:7:5:7:20 | GSSA Variable a | test.py:7:5:7:20 | GSSA Variable a |
|
||||
| test.py:7:19:7:19 | ControlFlowNode for a | test.py:7:19:7:19 | ControlFlowNode for a |
|
||||
| test.py:7:19:7:19 | [post] ControlFlowNode for a | test.py:7:19:7:19 | [post] ControlFlowNode for a |
|
||||
|
||||
@@ -23,3 +23,4 @@
|
||||
| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() |
|
||||
| test.py:7:5:7:20 | GSSA Variable a |
|
||||
| test.py:7:19:7:19 | ControlFlowNode for a |
|
||||
| test.py:7:19:7:19 | [post] ControlFlowNode for a |
|
||||
|
||||
@@ -23,3 +23,4 @@
|
||||
| test.py:7:5:7:20 | ControlFlowNode for obfuscated_id() |
|
||||
| test.py:7:5:7:20 | GSSA Variable a |
|
||||
| test.py:7:19:7:19 | ControlFlowNode for a |
|
||||
| test.py:7:19:7:19 | [post] ControlFlowNode for a |
|
||||
|
||||
@@ -85,21 +85,4 @@ postHasUniquePre
|
||||
uniquePostUpdate
|
||||
postIsInSameCallable
|
||||
reverseRead
|
||||
storeIsPostUpdate
|
||||
| test.py:152:9:152:16 | ControlFlowNode for List | Store targets should be PostUpdateNodes. |
|
||||
| test.py:153:9:153:24 | ControlFlowNode for Dict | Store targets should be PostUpdateNodes. |
|
||||
argHasPostUpdate
|
||||
| test.py:25:10:25:10 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. |
|
||||
| test.py:29:10:29:10 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. |
|
||||
| test.py:48:19:48:21 | ControlFlowNode for arg | ArgumentNode is missing PostUpdateNode. |
|
||||
| test.py:51:10:51:12 | ControlFlowNode for arg | ArgumentNode is missing PostUpdateNode. |
|
||||
| test.py:55:14:55:16 | ControlFlowNode for arg | ArgumentNode is missing PostUpdateNode. |
|
||||
| test.py:59:11:59:11 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. |
|
||||
| test.py:67:11:67:14 | ControlFlowNode for cond | ArgumentNode is missing PostUpdateNode. |
|
||||
| test.py:67:17:67:17 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. |
|
||||
| test.py:74:11:74:14 | ControlFlowNode for cond | ArgumentNode is missing PostUpdateNode. |
|
||||
| test.py:74:17:74:17 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. |
|
||||
| test.py:81:13:81:13 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. |
|
||||
| test.py:86:13:86:13 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. |
|
||||
| test.py:158:15:158:15 | ControlFlowNode for l | ArgumentNode is missing PostUpdateNode. |
|
||||
| test.py:159:15:159:15 | ControlFlowNode for d | ArgumentNode is missing PostUpdateNode. |
|
||||
|
||||
@@ -93,7 +93,7 @@ class With_str:
|
||||
|
||||
def __str__(self):
|
||||
SINK1(self) # Flow not found
|
||||
OK() # Call not found # Call not found
|
||||
OK() # Call not found
|
||||
return "Awesome"
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ class With_bytes:
|
||||
|
||||
def __bytes__(self):
|
||||
SINK1(self) # Flow not found
|
||||
OK() # Call not found # Call not found
|
||||
OK() # Call not found
|
||||
return b"Awesome"
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ class With_format:
|
||||
def __format__(self, format_spec):
|
||||
SINK2(format_spec) # Flow not found
|
||||
SINK1(self) # Flow not found
|
||||
OK() # Call not found # Call not found
|
||||
OK() # Call not found
|
||||
return "Awesome"
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ class With_lt:
|
||||
def __lt__(self, other):
|
||||
SINK2(other) # Flow not found
|
||||
SINK1(self) # Flow not found
|
||||
OK() # Call not found # Call not found
|
||||
OK() # Call not found
|
||||
return ""
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user