Skip to content

Commit 00b243a

Browse files
committed
Rust: Model implicit Deref trait calls in data flow
1 parent 42c8ca6 commit 00b243a

File tree

22 files changed

+756
-435
lines changed

22 files changed

+756
-435
lines changed

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

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ class TupleFieldContent extends FieldContent, TTupleFieldContent {
3535
not field = any(TupleType tt).getATupleField()
3636
}
3737

38+
/** Gets the tuple field. */
39+
TupleField getField() { result = field }
40+
3841
/** Holds if this field belongs to an enum variant. */
3942
predicate isVariantField(Variant v, int pos) { field.isVariantField(v, pos) }
4043

@@ -68,6 +71,9 @@ class StructFieldContent extends FieldContent, TStructFieldContent {
6871

6972
StructFieldContent() { this = TStructFieldContent(field) }
7073

74+
/** Gets the struct field. */
75+
StructField getField() { result = field }
76+
7177
/** Holds if this field belongs to an enum variant. */
7278
predicate isVariantField(Variant v, string name) { field.isVariantField(v, name) }
7379

@@ -253,10 +259,32 @@ final class OptionalBarrier extends ContentSet, TOptionalBarrier {
253259

254260
private import codeql.rust.internal.CachedStages
255261

262+
string tupleFieldApprox(TupleField field) {
263+
exists(Name name |
264+
name = any(Variant v | field.isVariantField(v, _)).getName()
265+
or
266+
name = any(Struct s | field.isStructField(s, _)).getName()
267+
|
268+
result = name.getText().charAt(0)
269+
)
270+
}
271+
272+
string structFieldApprox(StructField field) {
273+
exists(string name |
274+
field.isVariantField(_, name) or
275+
field.isStructField(_, name)
276+
|
277+
result = name.charAt(0)
278+
)
279+
}
280+
256281
cached
257282
newtype TContent =
258-
TTupleFieldContent(TupleField field) { Stages::DataFlowStage::ref() } or
259-
TStructFieldContent(StructField field) or
283+
TTupleFieldContent(TupleField field) {
284+
Stages::DataFlowStage::ref() and
285+
exists(tupleFieldApprox(field))
286+
} or
287+
TStructFieldContent(StructField field) { exists(structFieldApprox(field)) } or
260288
TElementContent() or
261289
TFutureContent() or
262290
TTuplePositionContent(int pos) {
@@ -272,3 +300,41 @@ newtype TContent =
272300
} or
273301
TCapturedVariableContent(VariableCapture::CapturedVariable v) or
274302
TReferenceContent()
303+
304+
cached
305+
newtype TContentApprox =
306+
TTupleFieldContentApprox(string s) { Stages::DataFlowStage::ref() and s = tupleFieldApprox(_) } or
307+
TStructFieldContentApprox(string s) { s = structFieldApprox(_) } or
308+
TElementContentApprox() or
309+
TFutureContentApprox() or
310+
TTuplePositionContentApprox() or
311+
TFunctionCallReturnContentApprox() or
312+
TFunctionCallArgumentContentApprox() or
313+
TCapturedVariableContentApprox() or
314+
TReferenceContentApprox()
315+
316+
final class ContentApprox extends TContentApprox {
317+
/** Gets a textual representation of this element. */
318+
string toString() {
319+
exists(string s |
320+
this = TTupleFieldContentApprox(s) or
321+
this = TStructFieldContentApprox(s)
322+
|
323+
result = s
324+
)
325+
or
326+
this = TElementContentApprox() and result = "element"
327+
or
328+
this = TFutureContentApprox() and result = "future"
329+
or
330+
this = TTuplePositionContentApprox() and result = "tuple.position"
331+
or
332+
this = TFunctionCallReturnContentApprox() and result = "function.return"
333+
or
334+
this = TFunctionCallArgumentContentApprox() and result = "function.argument"
335+
or
336+
this = TCapturedVariableContentApprox() and result = "captured.variable"
337+
or
338+
this = TReferenceContentApprox() and result = "&ref"
339+
}
340+
}

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

Lines changed: 61 additions & 12 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 isImplicitDerefCall(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,20 @@ final class DataFlowCall extends TDataFlowCall {
6975
DataFlowCallable getEnclosingCallable() {
7076
result.asCfgScope() = this.asCall().getEnclosingCfgScope()
7177
or
78+
result.asCfgScope() =
79+
any(AstNode n | this.isImplicitDerefCall(n, _, _, _)).getEnclosingCfgScope()
80+
or
7281
this.isSummaryCall(result.asSummarizedCallable(), _)
7382
}
7483

7584
string toString() {
7685
result = this.asCall().toString()
7786
or
87+
exists(AstNode n, DerefChain derefChain, int i, Function target |
88+
this.isImplicitDerefCall(n, derefChain, i, target) and
89+
result = "[implicit deref call " + i + " in " + derefChain.toString() + "] " + n
90+
)
91+
or
7892
exists(
7993
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
8094
|
@@ -83,7 +97,11 @@ final class DataFlowCall extends TDataFlowCall {
8397
)
8498
}
8599

86-
Location getLocation() { result = this.asCall().getLocation() }
100+
Location getLocation() {
101+
result = this.asCall().getLocation()
102+
or
103+
result = any(AstNode n | this.isImplicitDerefCall(n, _, _, _)).getLocation()
104+
}
87105
}
88106

89107
/**
@@ -257,6 +275,8 @@ private module Aliases {
257275

258276
class ContentAlias = Content;
259277

278+
class ContentApproxAlias = ContentApprox;
279+
260280
class ContentSetAlias = ContentSet;
261281

262282
class LambdaCallKindAlias = LambdaCallKind;
@@ -383,7 +403,8 @@ module RustDataFlow implements InputSig<Location> {
383403
node.(FlowSummaryNode).getSummaryNode().isHidden() or
384404
node instanceof CaptureNode or
385405
node instanceof ClosureParameterNode or
386-
node instanceof DerefBorrowNode or
406+
node instanceof ImplicitDerefNode or
407+
node instanceof ImplicitBorrowNode or
387408
node instanceof DerefOutNode or
388409
node instanceof IndexOutNode or
389410
node.asExpr() instanceof ParenExpr or
@@ -445,6 +466,12 @@ module RustDataFlow implements InputSig<Location> {
445466
or
446467
result.asSummarizedCallable() = getStaticTargetExt(c)
447468
)
469+
or
470+
exists(Function f | call = TImplicitDerefCall(_, _, _, f) |
471+
result.asCfgScope() = f
472+
or
473+
result.asSummarizedCallable() = f
474+
)
448475
}
449476

450477
/**
@@ -471,9 +498,27 @@ module RustDataFlow implements InputSig<Location> {
471498

472499
predicate forceHighPrecision(Content c) { none() }
473500

474-
final class ContentApprox = Content; // TODO: Implement if needed
501+
class ContentApprox = ContentApproxAlias;
475502

476-
ContentApprox getContentApprox(Content c) { result = c }
503+
ContentApprox getContentApprox(Content c) {
504+
result = TTupleFieldContentApprox(tupleFieldApprox(c.(TupleFieldContent).getField()))
505+
or
506+
result = TStructFieldContentApprox(structFieldApprox(c.(StructFieldContent).getField()))
507+
or
508+
result = TElementContentApprox() and c instanceof ElementContent
509+
or
510+
result = TFutureContentApprox() and c instanceof FutureContent
511+
or
512+
result = TTuplePositionContentApprox() and c instanceof TuplePositionContent
513+
or
514+
result = TFunctionCallArgumentContentApprox() and c instanceof FunctionCallArgumentContent
515+
or
516+
result = TFunctionCallReturnContentApprox() and c instanceof FunctionCallReturnContent
517+
or
518+
result = TCapturedVariableContentApprox() and c instanceof CapturedVariableContent
519+
or
520+
result = TReferenceContentApprox() and c instanceof ReferenceContent
521+
}
477522

478523
/**
479524
* Holds if the parameter position `ppos` matches the argument position
@@ -499,6 +544,8 @@ module RustDataFlow implements InputSig<Location> {
499544
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
500545
)
501546
or
547+
nodeFrom = nodeTo.(ImplicitDerefNode).getLocalInputNode()
548+
or
502549
VariableCapture::localFlowStep(nodeFrom, nodeTo)
503550
) and
504551
model = ""
@@ -524,16 +571,14 @@ module RustDataFlow implements InputSig<Location> {
524571
}
525572

526573
pragma[nomagic]
527-
private predicate implicitDeref(Node node1, DerefBorrowNode node2, ReferenceContent c) {
528-
not node2.isBorrow() and
529-
node1.asExpr() = node2.getNode() and
574+
private predicate implicitDeref(ImplicitDerefNode node1, Node node2, ReferenceContent c) {
575+
node2 = node1.getDerefOutputNode() and
530576
exists(c)
531577
}
532578

533579
pragma[nomagic]
534-
private predicate implicitBorrow(Node node1, DerefBorrowNode node2, ReferenceContent c) {
535-
node2.isBorrow() and
536-
node1.asExpr() = node2.getNode() and
580+
private predicate implicitBorrow(Node node1, ImplicitDerefBorrowNode node2, ReferenceContent c) {
581+
node1 = node2.getBorrowInputNode() and
537582
exists(c)
538583
}
539584

@@ -545,10 +590,10 @@ module RustDataFlow implements InputSig<Location> {
545590

546591
private Node getFieldExprContainerNode(FieldExpr fe) {
547592
exists(Expr container | container = fe.getContainer() |
548-
not any(DerefBorrowNode n).getNode() = container and
593+
not TypeInference::implicitDerefChainBorrow(container, _, _) and
549594
result.asExpr() = container
550595
or
551-
result.(DerefBorrowNode).getNode() = container
596+
result.(ImplicitDerefNode).isLast(container)
552597
)
553598
}
554599

@@ -1037,6 +1082,10 @@ private module Cached {
10371082
Stages::DataFlowStage::ref() and
10381083
call.hasEnclosingCfgScope()
10391084
} or
1085+
TImplicitDerefCall(AstNode n, DerefChain derefChain, int i, Function target) {
1086+
TypeInference::implicitDerefChainBorrow(n, derefChain, _) and
1087+
target = derefChain.getElement(i).getDerefFunction()
1088+
} or
10401089
TSummaryCall(
10411090
FlowSummaryImpl::Public::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver
10421091
) {

0 commit comments

Comments
 (0)