Skip to content

Commit ae7e15d

Browse files
authored
Merge pull request #18754 from paldepind/rust-ref-pattern
Rust ref pattern
2 parents ebd6fd4 + faef735 commit ae7e15d

File tree

22 files changed

+867
-296
lines changed

22 files changed

+867
-296
lines changed

rust/ql/.generated.list

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/controlflow/internal/ControlFlowGraphImpl.qll

+15-3
Original file line numberDiff line numberDiff line change
@@ -648,8 +648,12 @@ module PatternTrees {
648648

649649
abstract class PostOrderPatTree extends StandardPatTree, StandardPostOrderTree { }
650650

651-
class IdentPatTree extends PostOrderPatTree, IdentPat {
652-
override Pat getPat(int i) { i = 0 and result = this.getPat() }
651+
class IdentPatTree extends PostOrderTree, IdentPat {
652+
override predicate first(AstNode node) {
653+
first(this.getPat(), node)
654+
or
655+
not this.hasPat() and node = this.getName()
656+
}
653657

654658
override predicate last(AstNode node, Completion c) {
655659
super.last(node, c)
@@ -658,8 +662,16 @@ module PatternTrees {
658662
}
659663

660664
override predicate succ(AstNode pred, AstNode succ, Completion c) {
661-
super.succ(pred, succ, c) and c.(MatchCompletion).succeeded()
665+
// Edge from successful subpattern to name
666+
last(this.getPat(), pred, c) and
667+
first(this.getName(), succ) and
668+
c.(MatchCompletion).succeeded()
669+
or
670+
// Edge from name to the identifier pattern itself
671+
last(this.getName(), pred, c) and succ = this and completionIsNormal(c)
662672
}
673+
674+
override predicate propagatesAbnormal(AstNode child) { child = this.getPat() }
663675
}
664676

665677
class BoxPatTree extends PreOrderPatTree, BoxPat {

rust/ql/lib/codeql/rust/controlflow/internal/generated/CfgNodes.qll

+83-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/lib/codeql/rust/dataflow/Ssa.qll

+1-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ module Ssa {
195195
)
196196
or
197197
exists(LetStmtCfgNode ls |
198-
ls.getPat() = write and
198+
ls.getPat().(IdentPatCfgNode).getName() = write and
199199
ls.getInitializer() = value
200200
)
201201
}

rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll

+30
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,15 @@ module Node {
292292
override PatCfgNode asPat() { result = n }
293293
}
294294

295+
/** A data flow node that corresponds to a name node in the CFG. */
296+
final class NameNode extends AstCfgFlowNode, TNameNode {
297+
override NameCfgNode n;
298+
299+
NameNode() { this = TNameNode(n) }
300+
301+
NameCfgNode asName() { result = n }
302+
}
303+
295304
/**
296305
* The value of a parameter at function entry, viewed as a node in a data
297306
* flow graph.
@@ -603,11 +612,23 @@ module LocalFlow {
603612
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
604613
nodeFrom.getCfgNode() = getALastEvalNode(nodeTo.getCfgNode())
605614
or
615+
// An edge from the right-hand side of a let statement to the left-hand side.
606616
exists(LetStmtCfgNode s |
607617
nodeFrom.getCfgNode() = s.getInitializer() and
608618
nodeTo.getCfgNode() = s.getPat()
609619
)
610620
or
621+
exists(IdentPatCfgNode p |
622+
not p.isRef() and
623+
nodeFrom.getCfgNode() = p and
624+
nodeTo.getCfgNode() = p.getName()
625+
)
626+
or
627+
exists(SelfParamCfgNode self |
628+
nodeFrom.getCfgNode() = self and
629+
nodeTo.getCfgNode() = self.getName()
630+
)
631+
or
611632
// An edge from a pattern/expression to its corresponding SSA definition.
612633
nodeFrom.(Node::AstCfgFlowNode).getCfgNode() =
613634
nodeTo.(Node::SsaNode).getDefinitionExt().(Ssa::WriteDefinition).getControlFlowNode()
@@ -1285,6 +1306,14 @@ module RustDataFlow implements InputSig<Location> {
12851306
node2.asExpr().(ArrayListExprCfgNode).getAnExpr()
12861307
]
12871308
or
1309+
// Store from a `ref` identifier pattern into the contained name.
1310+
exists(IdentPatCfgNode p |
1311+
c instanceof ReferenceContent and
1312+
p.isRef() and
1313+
node1.asPat() = p and
1314+
node2.(Node::NameNode).asName() = p.getName()
1315+
)
1316+
or
12881317
fieldAssignment(node1, node2.(PostUpdateNode).getPreUpdateNode(), c)
12891318
or
12901319
referenceAssignment(node1, node2.(PostUpdateNode).getPreUpdateNode(), c)
@@ -1579,6 +1608,7 @@ private module Cached {
15791608
TExprNode(ExprCfgNode n) { Stages::DataFlowStage::ref() } or
15801609
TSourceParameterNode(ParamBaseCfgNode p) or
15811610
TPatNode(PatCfgNode p) or
1611+
TNameNode(NameCfgNode n) { n.getName() = any(Variable v).getName() } or
15821612
TExprPostUpdateNode(ExprCfgNode e) {
15831613
isArgumentForCall(e, _, _) or
15841614
lambdaCallExpr(_, _, e) or

rust/ql/lib/codeql/rust/dataflow/internal/SsaImpl.qll

+10-10
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,25 @@ private import Cfg
77
private import codeql.rust.controlflow.internal.ControlFlowGraphImpl as ControlFlowGraphImpl
88
private import codeql.ssa.Ssa as SsaImplCommon
99

10-
/** Holds if `v` is introduced like `let v : i64;`. */
11-
private predicate isUnitializedLet(IdentPat pat, Variable v) {
12-
pat = v.getPat() and
10+
/**
11+
* Holds if `name` occurs in the left-hand side of an uninitialized let
12+
* statement such as in `let name : i64;`.
13+
*/
14+
private predicate isInUninitializedLet(Name name) {
1315
exists(LetStmt let |
14-
let = v.getLetStmt() and
16+
let.getPat().(IdentPat).getName() = name and
1517
not let.hasInitializer()
1618
)
1719
}
1820

1921
/** Holds if `write` writes to variable `v`. */
2022
predicate variableWrite(AstNode write, Variable v) {
21-
exists(IdentPat pat |
22-
pat = write and
23-
pat = v.getPat() and
24-
not isUnitializedLet(pat, v)
23+
exists(Name name |
24+
name = write and
25+
name = v.getName() and
26+
not isInUninitializedLet(name)
2527
)
2628
or
27-
exists(SelfParam self | self = write and self = v.getSelfParam())
28-
or
2929
exists(VariableAccess access |
3030
access = write and
3131
access.getVariable() = v

0 commit comments

Comments
 (0)