Skip to content

Commit dd62164

Browse files
committed
wip
1 parent adcbfc8 commit dd62164

File tree

4 files changed

+181
-61
lines changed

4 files changed

+181
-61
lines changed

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

Lines changed: 37 additions & 11 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 + "] " + 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,8 @@ module RustDataFlow implements InputSig<Location> {
463481
not staticTarget.fromSource()
464482
)
465483
)
484+
or
485+
call = TImplicitDerefCall(_, _, _, result.asCfgScope())
466486
}
467487

468488
/**
@@ -542,16 +562,18 @@ module RustDataFlow implements InputSig<Location> {
542562
}
543563

544564
pragma[nomagic]
545-
private predicate implicitDeref(Node node1, DerefBorrowNode node2, ReferenceContent c) {
546-
not node2.isBorrow() and
547-
node1.asExpr() = node2.getNode() and
565+
private predicate implicitDeref(ImplicitDerefNode node1, Node node2, ReferenceContent c) {
566+
node2 = node1.getDerefOutputNode() and
548567
exists(c)
549568
}
550569

551570
pragma[nomagic]
552-
private predicate implicitBorrow(Node node1, DerefBorrowNode node2, ReferenceContent c) {
553-
node2.isBorrow() and
554-
node1.asExpr() = node2.getNode() and
571+
private predicate implicitBorrow(Node node1, Node node2, ReferenceContent c) {
572+
(
573+
node1 = node2.(ImplicitDerefNode).getBorrowInputNode()
574+
or
575+
node1 = node2.(ImplicitBorrowNode).getBorrowInputNode()
576+
) and
555577
exists(c)
556578
}
557579

@@ -563,10 +585,10 @@ module RustDataFlow implements InputSig<Location> {
563585

564586
private Node getFieldExprContainerNode(FieldExpr fe) {
565587
exists(Expr container | container = fe.getContainer() |
566-
not any(DerefBorrowNode n).getNode() = container and
588+
// not any(DerefBorrowNode n).getNode() = container and
567589
result.asExpr() = container
568-
or
569-
result.(DerefBorrowNode).getNode() = container
590+
// or
591+
// result.(DerefBorrowNode).getNode() = container
570592
)
571593
}
572594

@@ -1055,6 +1077,10 @@ private module Cached {
10551077
Stages::DataFlowStage::ref() and
10561078
call.hasEnclosingCfgScope()
10571079
} or
1080+
TImplicitDerefCall(AstNode n, DerefChain derefChain, int i, Function target) {
1081+
TypeInference::implicitDerefChainBorrow(n, derefChain, _) and
1082+
target = derefChain.getElement(i).getDerefFunction()
1083+
} or
10581084
TSummaryCall(
10591085
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
10601086
) {

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

Lines changed: 129 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,103 @@ 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+
// i = derefChain.length() - 1 and
268+
// result.(AstNodeNode).getAstNode() = n
269+
// or
270+
// result = TImplicitDerefNode(n, derefChain, TImplicitDerefNodeAfterDerefState(), i - 1, false)
271+
// )
272+
}
254273

274+
// AstNode getNode() { result = n }
255275
override CfgScope getCfgScope() { result = n.getEnclosingCfgScope() }
256276

257277
override Location getLocation() { result = n.getLocation() }
258278

259-
override string toString() {
260-
if isBorrow = true then result = n + " [borrowed]" else result = n + " [dereferenced]"
279+
override string toString() { result = n + " [implicit deref " + i + " in state " + state + "]" }
280+
}
281+
282+
/**
283+
* A node that represents the value of an argument of a call _after_ implicit
284+
* dereferencing or borrowing.
285+
*/
286+
final class ImplicitDerefArgNode extends ImplicitDerefNode, ArgumentNode {
287+
private DataFlowCall call_;
288+
private RustDataFlow::ArgumentPosition pos_;
289+
290+
ImplicitDerefArgNode() {
291+
state = TImplicitDerefNodeBorrowState() and
292+
call_ = TImplicitDerefCall(n, derefChain, i, _) and
293+
pos_.isSelf()
294+
or
295+
state = TImplicitDerefNodeAfterDerefState() and
296+
i = derefChain.length() - 1 and
297+
TypeInference::implicitDerefChainBorrow(n, derefChain, false) and
298+
isArgumentForCall(n, call_.asCall(), pos_)
299+
}
300+
301+
override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) {
302+
call = call_ and pos = pos_
303+
}
304+
}
305+
306+
/**
307+
* A node that represents the value of an expression _after_ implicit dereferencing
308+
* or borrowing.
309+
*/
310+
class ImplicitBorrowNode extends Node, TImplicitBorrowNode {
311+
AstNode n;
312+
DerefChain derefChain;
313+
314+
ImplicitBorrowNode() { this = TImplicitBorrowNode(n, derefChain, false) }
315+
316+
Node getBorrowInputNode() {
317+
result =
318+
TImplicitDerefNode(n, derefChain, TImplicitDerefNodeAfterDerefState(),
319+
derefChain.length() - 1, false)
320+
or
321+
derefChain.isEmpty() and
322+
result.(AstNodeNode).getAstNode() = n
261323
}
324+
325+
// AstNode getNode() { result = n }
326+
override CfgScope getCfgScope() { result = n.getEnclosingCfgScope() }
327+
328+
override Location getLocation() { result = n.getLocation() }
329+
330+
override string toString() { result = n + " [implicit borrow]" }
262331
}
263332

264333
/**
265334
* A node that represents the value of an argument of a call _after_ implicit
266335
* dereferencing or borrowing.
267336
*/
268-
final class DerefBorrowArgNode extends DerefBorrowNode, ArgumentNode {
337+
final class ImplicitBorrowArgNode extends ImplicitBorrowNode, ArgumentNode {
269338
private DataFlowCall call_;
270339
private RustDataFlow::ArgumentPosition pos_;
271340

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

274343
override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) {
275344
call = call_ and pos = pos_
@@ -478,17 +547,36 @@ final class ExprPostUpdateNode extends PostUpdateNode, TExprPostUpdateNode {
478547
override Location getLocation() { result = e.getLocation() }
479548
}
480549

481-
final class DerefBorrowPostUpdateNode extends PostUpdateNode, TDerefBorrowNode {
482-
private Expr arg;
483-
private boolean isBorrow;
550+
final class ImplicitDerefPostUpdateNode extends PostUpdateNode, TImplicitDerefNode {
551+
AstNode n;
552+
DerefChain derefChain;
553+
ImplicitDerefNodeState state;
554+
int i;
484555

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

487-
override DerefBorrowNode getPreUpdateNode() { result = TDerefBorrowNode(arg, isBorrow, false) }
558+
override ImplicitDerefNode getPreUpdateNode() {
559+
result = TImplicitDerefNode(n, derefChain, state, i, false)
560+
}
488561

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

491-
override Location getLocation() { result = arg.getLocation() }
564+
override Location getLocation() { result = n.getLocation() }
565+
}
566+
567+
final class ImplicitBorrowPostUpdateNode extends PostUpdateNode, TImplicitBorrowNode {
568+
AstNode n;
569+
DerefChain derefChain;
570+
571+
ImplicitBorrowPostUpdateNode() { this = TImplicitBorrowNode(n, derefChain, true) }
572+
573+
override ImplicitBorrowNode getPreUpdateNode() {
574+
result = TImplicitBorrowNode(n, derefChain, false)
575+
}
576+
577+
override CfgScope getCfgScope() { result = n.getEnclosingCfgScope() }
578+
579+
override Location getLocation() { result = n.getLocation() }
492580
}
493581

494582
class DerefOutPostUpdateNode extends PostUpdateNode, TDerefOutNode {
@@ -544,6 +632,21 @@ final class CastNode extends ExprNode {
544632
CastNode() { none() }
545633
}
546634

635+
newtype TImplicitDerefNodeState =
636+
TImplicitDerefNodeBorrowState() or
637+
TImplicitDerefNodeBeforeDerefState() or
638+
TImplicitDerefNodeAfterDerefState()
639+
640+
class ImplicitDerefNodeState extends TImplicitDerefNodeState {
641+
string toString() {
642+
this = TImplicitDerefNodeBorrowState() and result = "borrow"
643+
or
644+
this = TImplicitDerefNodeBeforeDerefState() and result = "before deref"
645+
or
646+
this = TImplicitDerefNodeAfterDerefState() and result = "after deref"
647+
}
648+
}
649+
547650
cached
548651
newtype TNode =
549652
TExprNode(Expr e) { e.hasEnclosingCfgScope() and Stages::DataFlowStage::ref() } or
@@ -575,12 +678,14 @@ newtype TNode =
575678
]
576679
)
577680
} 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
681+
TImplicitDerefNode(
682+
AstNode n, DerefChain derefChain, ImplicitDerefNodeState state, int i, Boolean isPost
683+
) {
684+
TypeInference::implicitDerefChainBorrow(n, derefChain, _) and
685+
i in [0 .. derefChain.length() - 1]
686+
} or
687+
TImplicitBorrowNode(AstNode n, DerefChain derefChain, Boolean isPost) {
688+
TypeInference::implicitDerefChainBorrow(n, derefChain, true)
584689
} or
585690
TDerefOutNode(DerefExpr de, Boolean isPost) or
586691
TIndexOutNode(IndexExpr ie, Boolean isPost) or

rust/ql/lib/codeql/rust/internal/TypeInference.qll

Lines changed: 14 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3934,33 +3934,22 @@ private Type inferCastExprType(CastExpr ce, TypePath path) {
39343934

39353935
cached
39363936
private module Cached {
3937-
/** Holds if `n` is implicitly dereferenced. */
3937+
/** Holds if `n` is implicitly dereferenced and/or borrowed. */
39383938
cached
3939-
predicate implicitDeref(AstNode n) {
3940-
exists(DerefChain derefChain, DerefImplItemNode impl |
3941-
impl.resolveSelfTyBuiltin() instanceof Builtins::RefType and
3942-
derefChain = DerefChain::singleton(impl)
3943-
|
3944-
exists(BorrowKind borrow |
3945-
any(MethodResolution::MethodCall mc)
3946-
.argumentHasImplicitDerefChainBorrow(n, derefChain, borrow) and
3947-
borrow.isNoBorrow()
3948-
)
3949-
or
3950-
n =
3951-
any(FieldExpr fe |
3952-
exists(resolveStructFieldExpr(fe, derefChain))
3953-
or
3954-
exists(resolveTupleFieldExpr(fe, derefChain))
3955-
).getContainer()
3939+
predicate implicitDerefChainBorrow(AstNode n, DerefChain derefChain, boolean borrow) {
3940+
exists(BorrowKind bk |
3941+
any(MethodResolution::MethodCall mc).argumentHasImplicitDerefChainBorrow(n, derefChain, bk) and
3942+
if bk.isNoBorrow() then borrow = false else borrow = true
39563943
)
3957-
}
3958-
3959-
/** Holds if `n` is implicitly borrowed. */
3960-
cached
3961-
predicate implicitBorrow(AstNode n, boolean isMutable) {
3962-
any(MethodResolution::MethodCall mc)
3963-
.argumentHasImplicitDerefChainBorrow(n, DerefChain::nil(), TSomeBorrowKind(isMutable))
3944+
or
3945+
n =
3946+
any(FieldExpr fe |
3947+
exists(resolveStructFieldExpr(fe, derefChain))
3948+
or
3949+
exists(resolveTupleFieldExpr(fe, derefChain))
3950+
).getContainer() and
3951+
not derefChain.isEmpty() and
3952+
borrow = false
39643953
}
39653954

39663955
/**

shared/util/codeql/util/UnboundList.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ module Make<LocationSig Location, InputSig<Location> Input> {
6666

6767
/** Gets the `i`th element in this list. */
6868
bindingset[this]
69-
private Element getElement(int i) { result = decode(this.splitAt(".", i)) }
69+
Element getElement(int i) { result = decode(this.splitAt(".", i)) }
7070

7171
/** Gets a textual representation of this list. */
7272
bindingset[this]

0 commit comments

Comments
 (0)