mirror of
https://github.com/github/codeql.git
synced 2025-12-21 03:06:31 +01:00
Python: Add missing flow for AssignmentExpr nodes
Also extend the tests surrounding this construct to be a bit more comprehensive. Co-authored-by: Rasmus Lerchedahl Petersen <yoff@github.com>
This commit is contained in:
@@ -547,6 +547,31 @@ class IfExprNode extends ControlFlowNode {
|
|||||||
override IfExp getNode() { result = super.getNode() }
|
override IfExp getNode() { result = super.getNode() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** A control flow node corresponding to an assignment expression such as `lhs := rhs`. */
|
||||||
|
class AssignmentExprNode extends ControlFlowNode {
|
||||||
|
AssignmentExprNode() { toAst(this) instanceof AssignExpr }
|
||||||
|
|
||||||
|
/** Gets the flow node corresponding to the left-hand side of the assignment expression */
|
||||||
|
ControlFlowNode getTarget() {
|
||||||
|
exists(AssignExpr a |
|
||||||
|
this.getNode() = a and
|
||||||
|
a.getTarget() = result.getNode() and
|
||||||
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Gets the flow node corresponding to the right-hand side of the assignment expression */
|
||||||
|
ControlFlowNode getValue() {
|
||||||
|
exists(AssignExpr a |
|
||||||
|
this.getNode() = a and
|
||||||
|
a.getValue() = result.getNode() and
|
||||||
|
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override AssignExpr getNode() { result = super.getNode() }
|
||||||
|
}
|
||||||
|
|
||||||
/** A control flow node corresponding to a binary expression, such as `x + y` */
|
/** A control flow node corresponding to a binary expression, such as `x + y` */
|
||||||
class BinaryExprNode extends ControlFlowNode {
|
class BinaryExprNode extends ControlFlowNode {
|
||||||
BinaryExprNode() { toAst(this) instanceof BinaryExpr }
|
BinaryExprNode() { toAst(this) instanceof BinaryExpr }
|
||||||
@@ -630,6 +655,8 @@ class DefinitionNode extends ControlFlowNode {
|
|||||||
Stages::AST::ref() and
|
Stages::AST::ref() and
|
||||||
exists(Assign a | a.getATarget().getAFlowNode() = this)
|
exists(Assign a | a.getATarget().getAFlowNode() = this)
|
||||||
or
|
or
|
||||||
|
exists(AssignExpr a | a.getTarget().getAFlowNode() = this)
|
||||||
|
or
|
||||||
exists(AnnAssign a | a.getTarget().getAFlowNode() = this and exists(a.getValue()))
|
exists(AnnAssign a | a.getTarget().getAFlowNode() = this and exists(a.getValue()))
|
||||||
or
|
or
|
||||||
exists(Alias a | a.getAsname().getAFlowNode() = this)
|
exists(Alias a | a.getAsname().getAFlowNode() = this)
|
||||||
@@ -787,6 +814,9 @@ private AstNode assigned_value(Expr lhs) {
|
|||||||
/* lhs = result */
|
/* lhs = result */
|
||||||
exists(Assign a | a.getATarget() = lhs and result = a.getValue())
|
exists(Assign a | a.getATarget() = lhs and result = a.getValue())
|
||||||
or
|
or
|
||||||
|
/* lhs := result */
|
||||||
|
exists(AssignExpr a | a.getTarget() = lhs and result = a.getValue())
|
||||||
|
or
|
||||||
/* lhs : annotation = result */
|
/* lhs : annotation = result */
|
||||||
exists(AnnAssign a | a.getTarget() = lhs and result = a.getValue())
|
exists(AnnAssign a | a.getTarget() = lhs and result = a.getValue())
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -357,6 +357,9 @@ module EssaFlow {
|
|||||||
// If expressions
|
// If expressions
|
||||||
nodeFrom.asCfgNode() = nodeTo.asCfgNode().(IfExprNode).getAnOperand()
|
nodeFrom.asCfgNode() = nodeTo.asCfgNode().(IfExprNode).getAnOperand()
|
||||||
or
|
or
|
||||||
|
// Assignment expressions
|
||||||
|
nodeFrom.asCfgNode() = nodeTo.asCfgNode().(AssignmentExprNode).getValue()
|
||||||
|
or
|
||||||
// boolean inline expressions such as `x or y` or `x and y`
|
// boolean inline expressions such as `x or y` or `x and y`
|
||||||
nodeFrom.asCfgNode() = nodeTo.asCfgNode().(BoolExprNode).getAnOperand()
|
nodeFrom.asCfgNode() = nodeTo.asCfgNode().(BoolExprNode).getAnOperand()
|
||||||
or
|
or
|
||||||
|
|||||||
@@ -435,10 +435,14 @@ def test_and(x = True):
|
|||||||
|
|
||||||
|
|
||||||
# 6.12. Assignment expressions
|
# 6.12. Assignment expressions
|
||||||
def test_assignment_expression():
|
def test_assignment_expression_flow_lhs():
|
||||||
x = NONSOURCE
|
x = NONSOURCE
|
||||||
SINK(x := SOURCE) #$ MISSING:flow="SOURCE -> x"
|
if x := SOURCE:
|
||||||
|
SINK(x) #$ flow="SOURCE, l:-1 -> x"
|
||||||
|
|
||||||
|
def test_assignment_expression_flow_out():
|
||||||
|
x = NONSOURCE
|
||||||
|
SINK(x := SOURCE) #$ flow="SOURCE -> AssignExpr"
|
||||||
|
|
||||||
# 6.13. Conditional expressions
|
# 6.13. Conditional expressions
|
||||||
def test_conditional_true():
|
def test_conditional_true():
|
||||||
@@ -460,13 +464,13 @@ def test_conditional_false_guards():
|
|||||||
# Condition is evaluated first, so x is SOURCE once chosen
|
# Condition is evaluated first, so x is SOURCE once chosen
|
||||||
def test_conditional_evaluation_true():
|
def test_conditional_evaluation_true():
|
||||||
x = NONSOURCE
|
x = NONSOURCE
|
||||||
SINK(x if (SOURCE == (x := SOURCE)) else NONSOURCE) #$ MISSING:flow="SOURCE -> IfExp"
|
SINK(x if (SOURCE == (x := SOURCE)) else NONSOURCE) #$ flow="SOURCE -> IfExp"
|
||||||
|
|
||||||
|
|
||||||
# Condition is evaluated first, so x is SOURCE once chosen
|
# Condition is evaluated first, so x is SOURCE once chosen
|
||||||
def test_conditional_evaluation_false():
|
def test_conditional_evaluation_false():
|
||||||
x = NONSOURCE
|
x = NONSOURCE
|
||||||
SINK(NONSOURCE if (NONSOURCE == (x := SOURCE)) else x) #$ MISSING:flow="SOURCE -> IfExp"
|
SINK(NONSOURCE if (NONSOURCE == (x := SOURCE)) else x) #$ flow="SOURCE -> IfExp"
|
||||||
|
|
||||||
|
|
||||||
# 6.14. Lambdas
|
# 6.14. Lambdas
|
||||||
|
|||||||
Reference in New Issue
Block a user