Skip to content

Commit dc0c45b

Browse files
committed
wip
1 parent 78a69b4 commit dc0c45b

File tree

7 files changed

+232
-75
lines changed

7 files changed

+232
-75
lines changed

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

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ private import codeql.rust.internal.PathResolution
1515
private import codeql.rust.controlflow.ControlFlowGraph
1616
private import codeql.rust.dataflow.Ssa
1717
private import codeql.rust.dataflow.FlowSummary
18+
private import codeql.rust.internal.TypeInference as TypeInference
19+
private import codeql.rust.internal.typeinference.DerefChain
1820
private import Node
1921
private import Content
2022
private import FlowSummaryImpl as FlowSummaryImpl
@@ -60,6 +62,10 @@ final class DataFlowCall extends TDataFlowCall {
6062
/** Gets the underlying call, if any. */
6163
Call asCall() { this = TCall(result) }
6264

65+
predicate isImplicitDeref(AstNode n, DerefChain derefChain, int i, Function target) {
66+
this = TImplicitDerefCall(n, derefChain, i, target)
67+
}
68+
6369
predicate isSummaryCall(
6470
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
6571
) {
@@ -69,12 +75,19 @@ final class DataFlowCall extends TDataFlowCall {
6975
DataFlowCallable getEnclosingCallable() {
7076
result.asCfgScope() = this.asCall().getEnclosingCfgScope()
7177
or
78+
result.asCfgScope() = any(AstNode n | this.isImplicitDeref(n, _, _, _)).getEnclosingCfgScope()
79+
or
7280
this.isSummaryCall(result.asSummarizedCallable(), _)
7381
}
7482

7583
string toString() {
7684
result = this.asCall().toString()
7785
or
86+
exists(AstNode n, DerefChain derefChain, int i, Function target |
87+
this.isImplicitDeref(n, derefChain, i, target) and
88+
result = "[implicit deref call " + i + " in " + derefChain.toString() + "] " + n
89+
)
90+
or
7891
exists(
7992
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
8093
|
@@ -83,7 +96,11 @@ final class DataFlowCall extends TDataFlowCall {
8396
)
8497
}
8598

86-
Location getLocation() { result = this.asCall().getLocation() }
99+
Location getLocation() {
100+
result = this.asCall().getLocation()
101+
or
102+
result = any(AstNode n | this.isImplicitDeref(n, _, _, _)).getLocation()
103+
}
87104
}
88105

89106
/**
@@ -383,7 +400,8 @@ module RustDataFlow implements InputSig<Location> {
383400
node.(FlowSummaryNode).getSummaryNode().isHidden() or
384401
node instanceof CaptureNode or
385402
node instanceof ClosureParameterNode or
386-
node instanceof DerefBorrowNode or
403+
node instanceof ImplicitDerefNode or
404+
node instanceof ImplicitBorrowNode or
387405
node instanceof DerefOutNode or
388406
node instanceof IndexOutNode or
389407
node.asExpr() instanceof ParenExpr or
@@ -463,6 +481,12 @@ module RustDataFlow implements InputSig<Location> {
463481
not staticTarget.fromSource()
464482
)
465483
)
484+
or
485+
exists(Function f | call = TImplicitDerefCall(_, _, _, f) |
486+
result.asCfgScope() = f
487+
or
488+
result.asSummarizedCallable() = f
489+
)
466490
}
467491

468492
/**
@@ -542,16 +566,18 @@ module RustDataFlow implements InputSig<Location> {
542566
}
543567

544568
pragma[nomagic]
545-
private predicate implicitDeref(Node node1, DerefBorrowNode node2, ReferenceContent c) {
546-
not node2.isBorrow() and
547-
node1.asExpr() = node2.getNode() and
569+
private predicate implicitDeref(ImplicitDerefNode node1, Node node2, ReferenceContent c) {
570+
node2 = node1.getDerefOutputNode() and
548571
exists(c)
549572
}
550573

551574
pragma[nomagic]
552-
private predicate implicitBorrow(Node node1, DerefBorrowNode node2, ReferenceContent c) {
553-
node2.isBorrow() and
554-
node1.asExpr() = node2.getNode() and
575+
private predicate implicitBorrow(Node node1, Node node2, ReferenceContent c) {
576+
(
577+
node1 = node2.(ImplicitDerefNode).getBorrowInputNode()
578+
or
579+
node1 = node2.(ImplicitBorrowNode).getBorrowInputNode()
580+
) and
555581
exists(c)
556582
}
557583

@@ -563,10 +589,12 @@ module RustDataFlow implements InputSig<Location> {
563589

564590
private Node getFieldExprContainerNode(FieldExpr fe) {
565591
exists(Expr container | container = fe.getContainer() |
566-
not any(DerefBorrowNode n).getNode() = container and
592+
not TypeInference::implicitDerefChainBorrow(container, _, _) and
567593
result.asExpr() = container
568594
or
569-
result.(DerefBorrowNode).getNode() = container
595+
result.(ImplicitBorrowNode).getNode() = container
596+
or
597+
result.(ImplicitDerefNode).isLast(container)
570598
)
571599
}
572600

@@ -1055,6 +1083,10 @@ private module Cached {
10551083
Stages::DataFlowStage::ref() and
10561084
call.hasEnclosingCfgScope()
10571085
} or
1086+
TImplicitDerefCall(AstNode n, DerefChain derefChain, int i, Function target) {
1087+
TypeInference::implicitDerefChainBorrow(n, derefChain, _) and
1088+
target = derefChain.getElement(i).getDerefFunction()
1089+
} or
10581090
TSummaryCall(
10591091
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
10601092
) {

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

Lines changed: 141 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ private import codeql.rust.controlflow.CfgNodes
1515
private import codeql.rust.dataflow.Ssa
1616
private import codeql.rust.dataflow.FlowSummary
1717
private import codeql.rust.internal.TypeInference as TypeInference
18+
private import codeql.rust.internal.typeinference.DerefChain
1819
private import Node as Node
1920
private import DataFlowImpl
2021
private import FlowSummaryImpl as FlowSummaryImpl
@@ -229,8 +230,7 @@ final class ExprArgumentNode extends ArgumentNode, ExprNode {
229230

230231
ExprArgumentNode() {
231232
isArgumentForCall(n, call_, pos_) and
232-
not TypeInference::implicitDeref(n) and
233-
not TypeInference::implicitBorrow(n, _)
233+
not TypeInference::implicitDerefChainBorrow(n, _, _)
234234
}
235235

236236
override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) {
@@ -242,34 +242,115 @@ final class ExprArgumentNode extends ArgumentNode, ExprNode {
242242
* A node that represents the value of an expression _after_ implicit dereferencing
243243
* or borrowing.
244244
*/
245-
class DerefBorrowNode extends Node, TDerefBorrowNode {
245+
class ImplicitDerefNode extends Node, TImplicitDerefNode {
246246
AstNode n;
247-
boolean isBorrow;
247+
DerefChain derefChain;
248+
ImplicitDerefNodeState state;
249+
int i;
248250

249-
DerefBorrowNode() { this = TDerefBorrowNode(n, isBorrow, false) }
251+
ImplicitDerefNode() { this = TImplicitDerefNode(n, derefChain, state, i, false) }
250252

251-
AstNode getNode() { result = n }
253+
Node getBorrowInputNode() {
254+
state = TImplicitDerefNodeBorrowState() and
255+
(
256+
i = 0 and
257+
result.(AstNodeNode).getAstNode() = n
258+
or
259+
result = TImplicitDerefNode(n, derefChain, TImplicitDerefNodeAfterDerefState(), i - 1, false)
260+
)
261+
}
252262

253-
predicate isBorrow() { isBorrow = true }
263+
Node getDerefOutputNode() {
264+
state = TImplicitDerefNodeBeforeDerefState() and
265+
result = TImplicitDerefNode(n, derefChain, TImplicitDerefNodeAfterDerefState(), i, false)
266+
}
267+
268+
predicate isLast(AstNode node) {
269+
this =
270+
TImplicitDerefNode(node, derefChain, TImplicitDerefNodeAfterDerefState(),
271+
derefChain.length() - 1, false)
272+
}
254273

255274
override CfgScope getCfgScope() { result = n.getEnclosingCfgScope() }
256275

257276
override Location getLocation() { result = n.getLocation() }
258277

259-
override string toString() {
260-
if isBorrow = true then result = n + " [borrowed]" else result = n + " [dereferenced]"
278+
override string toString() { result = n + " [implicit deref " + i + " in state " + state + "]" }
279+
}
280+
281+
/**
282+
* A node that represents the value of an argument of a call _after_ implicit
283+
* dereferencing or borrowing.
284+
*/
285+
final class ImplicitDerefArgNode extends ImplicitDerefNode, ArgumentNode {
286+
private DataFlowCall call_;
287+
private RustDataFlow::ArgumentPosition pos_;
288+
289+
ImplicitDerefArgNode() {
290+
state = TImplicitDerefNodeBorrowState() and
291+
call_ = TImplicitDerefCall(n, derefChain, i, _) and
292+
pos_.isSelf()
293+
or
294+
state = TImplicitDerefNodeAfterDerefState() and
295+
i = derefChain.length() - 1 and
296+
TypeInference::implicitDerefChainBorrow(n, derefChain, false) and
297+
isArgumentForCall(n, call_.asCall(), pos_)
298+
}
299+
300+
override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) {
301+
call = call_ and pos = pos_
302+
}
303+
}
304+
305+
private class ImplicitDerefOutNode extends ImplicitDerefNode, OutNode {
306+
private DataFlowCall call;
307+
308+
ImplicitDerefOutNode() { state = TImplicitDerefNodeBeforeDerefState() }
309+
310+
override DataFlowCall getCall(ReturnKind kind) {
311+
result = TImplicitDerefCall(n, derefChain, i, _) and
312+
kind = TNormalReturnKind()
261313
}
262314
}
263315

316+
/**
317+
* A node that represents the value of an expression _after_ implicit dereferencing
318+
* or borrowing.
319+
*/
320+
class ImplicitBorrowNode extends Node, TImplicitBorrowNode {
321+
AstNode n;
322+
DerefChain derefChain;
323+
324+
ImplicitBorrowNode() { this = TImplicitBorrowNode(n, derefChain, false) }
325+
326+
AstNode getNode() { result = n }
327+
328+
Node getBorrowInputNode() {
329+
result =
330+
TImplicitDerefNode(n, derefChain, TImplicitDerefNodeAfterDerefState(),
331+
derefChain.length() - 1, false)
332+
or
333+
derefChain.isEmpty() and
334+
result.(AstNodeNode).getAstNode() = n
335+
}
336+
337+
// AstNode getNode() { result = n }
338+
override CfgScope getCfgScope() { result = n.getEnclosingCfgScope() }
339+
340+
override Location getLocation() { result = n.getLocation() }
341+
342+
override string toString() { result = n + " [implicit borrow]" }
343+
}
344+
264345
/**
265346
* A node that represents the value of an argument of a call _after_ implicit
266347
* dereferencing or borrowing.
267348
*/
268-
final class DerefBorrowArgNode extends DerefBorrowNode, ArgumentNode {
349+
final class ImplicitBorrowArgNode extends ImplicitBorrowNode, ArgumentNode {
269350
private DataFlowCall call_;
270351
private RustDataFlow::ArgumentPosition pos_;
271352

272-
DerefBorrowArgNode() { isArgumentForCall(n, call_.asCall(), pos_) }
353+
ImplicitBorrowArgNode() { isArgumentForCall(n, call_.asCall(), pos_) }
273354

274355
override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) {
275356
call = call_ and pos = pos_
@@ -478,17 +559,36 @@ final class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode {
478559
override Location getLocation() { result = e.getLocation() }
479560
}
480561

481-
final class DerefBorrowPostUpdateNode extends PostUpdateNode, TDerefBorrowNode {
482-
private Expr arg;
483-
private boolean isBorrow;
562+
final class ImplicitDerefPostUpdateNode extends PostUpdateNode, TImplicitDerefNode {
563+
AstNode n;
564+
DerefChain derefChain;
565+
ImplicitDerefNodeState state;
566+
int i;
484567

485-
DerefBorrowPostUpdateNode() { this = TDerefBorrowNode(arg, isBorrow, true) }
568+
ImplicitDerefPostUpdateNode() { this = TImplicitDerefNode(n, derefChain, state, i, true) }
486569

487-
override DerefBorrowNode getPreUpdateNode() { result = TDerefBorrowNode(arg, isBorrow, false) }
570+
override ImplicitDerefNode getPreUpdateNode() {
571+
result = TImplicitDerefNode(n, derefChain, state, i, false)
572+
}
488573

489-
override CfgScope getCfgScope() { result = arg.getEnclosingCfgScope() }
574+
override CfgScope getCfgScope() { result = n.getEnclosingCfgScope() }
490575

491-
override Location getLocation() { result = arg.getLocation() }
576+
override Location getLocation() { result = n.getLocation() }
577+
}
578+
579+
final class ImplicitBorrowPostUpdateNode extends PostUpdateNode, TImplicitBorrowNode {
580+
AstNode n;
581+
DerefChain derefChain;
582+
583+
ImplicitBorrowPostUpdateNode() { this = TImplicitBorrowNode(n, derefChain, true) }
584+
585+
override ImplicitBorrowNode getPreUpdateNode() {
586+
result = TImplicitBorrowNode(n, derefChain, false)
587+
}
588+
589+
override CfgScope getCfgScope() { result = n.getEnclosingCfgScope() }
590+
591+
override Location getLocation() { result = n.getLocation() }
492592
}
493593

494594
class DerefOutPostUpdateNode extends PostUpdateNode, TDerefOutNode {
@@ -544,6 +644,21 @@ final class CastNode extends ExprNode {
544644
CastNode() { none() }
545645
}
546646

647+
newtype TImplicitDerefNodeState =
648+
TImplicitDerefNodeBorrowState() or
649+
TImplicitDerefNodeBeforeDerefState() or
650+
TImplicitDerefNodeAfterDerefState()
651+
652+
class ImplicitDerefNodeState extends TImplicitDerefNodeState {
653+
string toString() {
654+
this = TImplicitDerefNodeBorrowState() and result = "borrow"
655+
or
656+
this = TImplicitDerefNodeBeforeDerefState() and result = "before deref"
657+
or
658+
this = TImplicitDerefNodeAfterDerefState() and result = "after deref"
659+
}
660+
}
661+
547662
cached
548663
newtype TNode =
549664
TExprNode(Expr e) { e.hasEnclosingCfgScope() and Stages::DataFlowStage::ref() } or
@@ -575,12 +690,14 @@ newtype TNode =
575690
]
576691
)
577692
} or
578-
TDerefBorrowNode(AstNode n, boolean borrow, Boolean isPost) {
579-
TypeInference::implicitDeref(n) and
580-
borrow = false
581-
or
582-
TypeInference::implicitBorrow(n, _) and
583-
borrow = true
693+
TImplicitDerefNode(
694+
AstNode n, DerefChain derefChain, ImplicitDerefNodeState state, int i, Boolean isPost
695+
) {
696+
TypeInference::implicitDerefChainBorrow(n, derefChain, _) and
697+
i in [0 .. derefChain.length() - 1]
698+
} or
699+
TImplicitBorrowNode(AstNode n, DerefChain derefChain, Boolean isPost) {
700+
TypeInference::implicitDerefChainBorrow(n, derefChain, true)
584701
} or
585702
TDerefOutNode(DerefExpr de, Boolean isPost) or
586703
TIndexOutNode(IndexExpr ie, Boolean isPost) or

0 commit comments

Comments
 (0)