Skip to content

Commit 6f3cb67

Browse files
committed
Python: Model parameter with default value as DefinitionNode
1 parent cfd2d09 commit 6f3cb67

File tree

4 files changed

+17
-2
lines changed

4 files changed

+17
-2
lines changed

python/ql/lib/semmle/python/Flow.qll

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -640,12 +640,23 @@ class DefinitionNode extends ControlFlowNode {
640640
exists(Assign a | list_or_tuple_nested_element(a.getATarget()).getAFlowNode() = this)
641641
or
642642
exists(For for | for.getTarget().getAFlowNode() = this)
643+
or
644+
exists(Parameter param | this = param.asName().getAFlowNode() and exists(param.getDefault()))
643645
}
644646

645647
/** flow node corresponding to the value assigned for the definition corresponding to this flow node */
646648
ControlFlowNode getValue() {
647649
result = assigned_value(this.getNode()).getAFlowNode() and
648-
(result.getBasicBlock().dominates(this.getBasicBlock()) or result.isImport())
650+
(
651+
result.getBasicBlock().dominates(this.getBasicBlock())
652+
or
653+
result.isImport()
654+
or
655+
// since the default value for a parameter is evaluated in the same basic block as
656+
// the function definition, but the parameter belongs to the basic block of the function,
657+
// there is no dominance relationship between the two.
658+
exists(Parameter param | this = param.asName().getAFlowNode())
659+
)
649660
}
650661
}
651662

@@ -795,6 +806,8 @@ private AstNode assigned_value(Expr lhs) {
795806
or
796807
/* for lhs in seq: => `result` is the `for` node, representing the `iter(next(seq))` operation. */
797808
result.(For).getTarget() = lhs
809+
or
810+
exists(Parameter param | lhs = param.asName() and result = param.getDefault())
798811
}
799812

800813
predicate nested_sequence_assign(

python/ql/test/experimental/dataflow/typetracking/test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def from_parameter_default():
7171
def outer(x=tracked): # $tracked
7272
print(x) # $tracked
7373
def inner():
74-
print(x) # $ MISSING: tracked
74+
print(x) # $ tracked
7575
print(x_alias) # $tracked
7676
return x # $tracked
7777
also_x = outer() # $tracked
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
| test.py:3:5:3:9 | ControlFlowNode for fail5 | test.py:3:1:3:13 | ControlFlowNode for FunctionExpr |
22
| test.py:4:5:4:8 | ControlFlowNode for Tuple | test.py:4:12:4:12 | ControlFlowNode for t |
33
| test.py:7:5:7:26 | ControlFlowNode for default_value_in_param | test.py:7:1:7:33 | ControlFlowNode for FunctionExpr |
4+
| test.py:7:28:7:28 | ControlFlowNode for x | test.py:7:30:7:31 | ControlFlowNode for IntegerLiteral |

python/ql/test/library-tests/variables/definitions/test.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
| 4 | 5 | ControlFlowNode for x |
44
| 4 | 8 | ControlFlowNode for y |
55
| 7 | 5 | ControlFlowNode for default_value_in_param |
6+
| 7 | 28 | ControlFlowNode for x |

0 commit comments

Comments
 (0)