Skip to content

Commit de3a73e

Browse files
committed
special
1 parent 85b5638 commit de3a73e

File tree

9 files changed

+220
-95
lines changed

9 files changed

+220
-95
lines changed

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

Lines changed: 73 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

@@ -256,10 +262,37 @@ final class OptionalBarrier extends ContentSet, TOptionalBarrier {
256262

257263
private import codeql.rust.internal.CachedStages
258264

265+
string tupleFieldApprox(TupleField field) {
266+
exists(Variant v, int pos |
267+
field.isVariantField(v, pos) and
268+
result = v.getName().getText().charAt(0)
269+
)
270+
or
271+
exists(Struct s, int pos |
272+
field.isStructField(s, pos) and
273+
result = s.getName().getText().charAt(0)
274+
)
275+
}
276+
277+
string structFieldApprox(StructField field) {
278+
exists(Variant v, string name |
279+
field.isVariantField(v, name) and
280+
result = v.getName().getText().charAt(0) + "." + name
281+
)
282+
or
283+
exists(Struct s, string name |
284+
field.isStructField(s, name) and
285+
result = s.getName().getText().charAt(0) + "." + name
286+
)
287+
}
288+
259289
cached
260290
newtype TContent =
261-
TTupleFieldContent(TupleField field) { Stages::DataFlowStage::ref() } or
262-
TStructFieldContent(StructField field) or
291+
TTupleFieldContent(TupleField field) {
292+
Stages::DataFlowStage::ref() and
293+
exists(tupleFieldApprox(field))
294+
} or
295+
TStructFieldContent(StructField field) { exists(structFieldApprox(field)) } or
263296
TElementContent() or
264297
TFutureContent() or
265298
TTuplePositionContent(int pos) {
@@ -275,3 +308,41 @@ newtype TContent =
275308
} or
276309
TCapturedVariableContent(VariableCapture::CapturedVariable v) or
277310
TReferenceContent()
311+
312+
cached
313+
newtype TContentApprox =
314+
TTupleFieldContentApprox(string s) { Stages::DataFlowStage::ref() and s = tupleFieldApprox(_) } or
315+
TStructFieldContentApprox(string s) { s = structFieldApprox(_) } or
316+
TElementContentApprox() or
317+
TFutureContentApprox() or
318+
TTuplePositionContentApprox() or
319+
TFunctionCallReturnContentApprox() or
320+
TFunctionCallArgumentContentApprox() or
321+
TCapturedVariableContentApprox() or
322+
TReferenceContentApprox()
323+
324+
final class ContentApprox extends TContentApprox {
325+
/** Gets a textual representation of this element. */
326+
string toString() {
327+
exists(string s |
328+
this = TTupleFieldContentApprox(s) or
329+
this = TStructFieldContentApprox(s)
330+
|
331+
result = s
332+
)
333+
or
334+
this = TElementContentApprox() and result = "element"
335+
or
336+
this = TFutureContentApprox() and result = "future"
337+
or
338+
this = TTuplePositionContentApprox() and result = "tuple.position"
339+
or
340+
this = TFunctionCallReturnContentApprox() and result = "function.return"
341+
or
342+
this = TFunctionCallArgumentContentApprox() and result = "function.argument"
343+
or
344+
this = TCapturedVariableContentApprox() and result = "captured.variable"
345+
or
346+
this = TReferenceContentApprox() and result = "&ref"
347+
}
348+
}

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

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,8 @@ private module Aliases {
274274

275275
class ContentAlias = Content;
276276

277+
class ContentApproxAlias = ContentApprox;
278+
277279
class ContentSetAlias = ContentSet;
278280

279281
class LambdaCallKindAlias = LambdaCallKind;
@@ -495,9 +497,27 @@ module RustDataFlow implements InputSig<Location> {
495497

496498
predicate forceHighPrecision(Content c) { none() }
497499

498-
final class ContentApprox = Content; // TODO: Implement if needed
500+
class ContentApprox = ContentApproxAlias;
499501

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

502522
/**
503523
* Holds if the parameter position `ppos` matches the argument position
@@ -523,6 +543,8 @@ module RustDataFlow implements InputSig<Location> {
523543
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
524544
)
525545
or
546+
nodeFrom = nodeTo.(ImplicitDerefNode).getLocalInputNode()
547+
or
526548
VariableCapture::localFlowStep(nodeFrom, nodeTo)
527549
) and
528550
model = ""

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,10 @@ private newtype TImplicitDerefNodeState =
252252
* - `TImplicitDerefNodeBorrowState` represents the `&x` part,
253253
* - `TImplicitDerefNodeBeforeDerefState` represents the `Deref::deref(&x)` part, and
254254
* - `TImplicitDerefNodeAfterDerefState` represents the entire `*Deref::deref(&x)` part.
255+
*
256+
* When the targeted `deref` function is a no-op, we optimize away the call, skipping
257+
* the `TImplicitDerefNodeBorrowState` state, and instead add a local step directly from
258+
* `x` to the `TImplicitDerefNodeBeforeDerefState` state.
255259
*/
256260
class ImplicitDerefNodeState extends TImplicitDerefNodeState {
257261
string toString() {
@@ -265,6 +269,8 @@ class ImplicitDerefNodeState extends TImplicitDerefNodeState {
265269

266270
/**
267271
* A node used to represent implicit dereferencing.
272+
*
273+
* TODO: Special case `&` and `&mut` implementations.
268274
*/
269275
class ImplicitDerefNode extends Node, TImplicitDerefNode {
270276
AstNode n;
@@ -274,11 +280,21 @@ class ImplicitDerefNode extends Node, TImplicitDerefNode {
274280

275281
ImplicitDerefNode() { this = TImplicitDerefNode(n, derefChain, state, i, false) }
276282

283+
predicate isNoOp() { derefChain.isNoOp(i) }
284+
285+
AstNodeNode getLocalInputNode() {
286+
result.getAstNode() = n and
287+
state = TImplicitDerefNodeBorrowState() and
288+
i = 0 and
289+
derefChain.isNoOp(0)
290+
}
291+
277292
/**
278293
* Gets the node that should the predecessor in a reference store-step into this
279294
* node, if any.
280295
*/
281296
Node getBorrowInputNode() {
297+
not this.isNoOp() and
282298
state = TImplicitDerefNodeBorrowState() and
283299
(
284300
i = 0 and
@@ -293,7 +309,11 @@ class ImplicitDerefNode extends Node, TImplicitDerefNode {
293309
* node, if any.
294310
*/
295311
Node getDerefOutputNode() {
296-
state = TImplicitDerefNodeBeforeDerefState() and
312+
(
313+
if this.isNoOp()
314+
then state = TImplicitDerefNodeBorrowState()
315+
else state = TImplicitDerefNodeBeforeDerefState()
316+
) and
297317
result = TImplicitDerefNode(n, derefChain, TImplicitDerefNodeAfterDerefState(), i, false)
298318
}
299319

@@ -315,6 +335,7 @@ final class ImplicitDerefArgNode extends ImplicitDerefNode, ArgumentNode {
315335
private RustDataFlow::ArgumentPosition pos_;
316336

317337
ImplicitDerefArgNode() {
338+
not derefChain.isNoOp(i) and
318339
state = TImplicitDerefNodeBorrowState() and
319340
call_ = TImplicitDerefCall(n, derefChain, i, _) and
320341
pos_.isSelf()
@@ -332,7 +353,10 @@ final class ImplicitDerefArgNode extends ImplicitDerefNode, ArgumentNode {
332353
private class ImplicitDerefOutNode extends ImplicitDerefNode, OutNode {
333354
private DataFlowCall call;
334355

335-
ImplicitDerefOutNode() { state = TImplicitDerefNodeBeforeDerefState() }
356+
ImplicitDerefOutNode() {
357+
not derefChain.getElement(i).isNoOp() and
358+
state = TImplicitDerefNodeBeforeDerefState()
359+
}
336360

337361
override DataFlowCall getCall(ReturnKind kind) {
338362
result = TImplicitDerefCall(n, derefChain, i, _) and

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3235,7 +3235,7 @@ private Type getFieldExprLookupType(FieldExpr fe, string name, DerefChain derefC
32353235
derefChain = DerefChain::nil()
32363236
or
32373237
exists(DerefImplItemNode impl, TypeParamTypeParameter tp |
3238-
tp.getTypeParam() = impl.resolveSelfTy().getTypeParam(0) and
3238+
tp = impl.getFirstSelfTypeParameter() and
32393239
path.getHead() = tp and
32403240
derefChain = DerefChain::singleton(impl)
32413241
)

rust/ql/lib/codeql/rust/internal/typeinference/DerefChain.qll

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,25 @@ class DerefImplItemNode extends ImplItemNode {
4141
path0.isCons(getRefTypeParameter(false), path)
4242
)
4343
}
44+
45+
/** Gets the first type parameter of the type being implemented, if any. */
46+
pragma[nomagic]
47+
TypeParamTypeParameter getFirstSelfTypeParameter() {
48+
result.getTypeParam() = this.resolveSelfTy().getTypeParam(0)
49+
}
50+
51+
/**
52+
* Holds if this `Deref` implementation is a no-op.
53+
*
54+
* That is, either it is
55+
*
56+
* [`impl<T> Deref for &T`](https://doc.rust-lang.org/std/ops/trait.Deref.html#impl-Deref-for-%26T)
57+
*
58+
* or
59+
*
60+
* [`impl<T> Deref for &mut T`](https://doc.rust-lang.org/std/ops/trait.Deref.html#impl-Deref-for-%26mut+T).
61+
*/
62+
predicate isNoOp() { this.resolveSelfTyBuiltin() instanceof Builtins::RefType }
4463
}
4564

4665
private module UnboundListInput implements UnboundListImpl::InputSig<Location> {
@@ -70,7 +89,13 @@ private import UnboundListImpl::Make<Location, UnboundListInput>
7089
* A sequence of `Deref` impl blocks representing a chain of implicit dereferences,
7190
* encoded as a string.
7291
*/
73-
class DerefChain = UnboundList;
92+
class DerefChain extends UnboundList {
93+
bindingset[this]
94+
DerefChain() { exists(this) }
95+
96+
bindingset[this]
97+
predicate isNoOp(int i) { this.getElement(i).isNoOp() }
98+
}
7499

75100
/** Provides predicates for constructing `DerefChain`s. */
76101
module DerefChain = UnboundList;

rust/ql/test/library-tests/dataflow/collections/inline-flow.expected

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,8 @@ edges
3737
| main.rs:47:14:47:16 | arr | main.rs:47:14:47:19 | arr[0] | provenance | MaD:4 |
3838
| main.rs:63:18:63:22 | SelfParam [&ref, S] | main.rs:63:56:65:9 | { ... } [&ref, S] | provenance | |
3939
| main.rs:76:34:76:44 | ...: Self [S] | main.rs:77:23:77:27 | other [S] | provenance | |
40-
| main.rs:77:13:77:16 | [post] self [&ref, S] | main.rs:76:23:76:31 | SelfParam [Return] [&ref, S] | provenance | |
41-
| main.rs:77:13:77:16 | [post] self [&ref, tuple.0] | main.rs:76:23:76:31 | SelfParam [Return] [&ref, tuple.0] | provenance | |
42-
| main.rs:77:13:77:18 | [post] self.0 | main.rs:77:13:77:16 | [post] self [&ref, S] | provenance | |
43-
| main.rs:77:13:77:18 | [post] self.0 | main.rs:77:13:77:16 | [post] self [&ref, tuple.0] | provenance | |
40+
| main.rs:77:13:77:18 | [post] self.0 | main.rs:76:23:76:31 | SelfParam [Return] [&ref, S] | provenance | |
41+
| main.rs:77:13:77:18 | [post] self.0 | main.rs:76:23:76:31 | SelfParam [Return] [&ref, tuple.0] | provenance | |
4442
| main.rs:77:23:77:27 | other [S] | main.rs:77:23:77:29 | other.0 | provenance | |
4543
| main.rs:77:23:77:29 | other.0 | main.rs:77:13:77:18 | [post] self.0 | provenance | MaD:2 |
4644
| main.rs:77:23:77:29 | other.0 | main.rs:77:13:77:18 | [post] self.0 | provenance | MaD:3 |
@@ -158,8 +156,6 @@ nodes
158156
| main.rs:76:23:76:31 | SelfParam [Return] [&ref, S] | semmle.label | SelfParam [Return] [&ref, S] |
159157
| main.rs:76:23:76:31 | SelfParam [Return] [&ref, tuple.0] | semmle.label | SelfParam [Return] [&ref, tuple.0] |
160158
| main.rs:76:34:76:44 | ...: Self [S] | semmle.label | ...: Self [S] |
161-
| main.rs:77:13:77:16 | [post] self [&ref, S] | semmle.label | [post] self [&ref, S] |
162-
| main.rs:77:13:77:16 | [post] self [&ref, tuple.0] | semmle.label | [post] self [&ref, tuple.0] |
163159
| main.rs:77:13:77:18 | [post] self.0 | semmle.label | [post] self.0 |
164160
| main.rs:77:23:77:27 | other [S] | semmle.label | other [S] |
165161
| main.rs:77:23:77:29 | other.0 | semmle.label | other.0 |

rust/ql/test/library-tests/dataflow/global/inline-flow.expected

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,20 @@ edges
88
| main.rs:17:9:17:9 | a | main.rs:18:10:18:10 | a | provenance | |
99
| main.rs:17:13:17:23 | get_data(...) | main.rs:17:9:17:9 | a | provenance | |
1010
| main.rs:26:28:26:33 | ...: i64 | main.rs:27:21:27:21 | n | provenance | |
11-
| main.rs:27:9:27:12 | [post] self [&ref, MyStruct] | main.rs:26:17:26:25 | SelfParam [Return] [&ref, MyStruct] | provenance | |
12-
| main.rs:27:21:27:21 | n | main.rs:27:9:27:12 | [post] self [&ref, MyStruct] | provenance | |
13-
| main.rs:30:17:30:21 | SelfParam [&ref, MyStruct] | main.rs:31:9:31:12 | self [&ref, MyStruct] | provenance | |
14-
| main.rs:31:9:31:12 | self [&ref, MyStruct] | main.rs:31:9:31:17 | self.data | provenance | MaD:1 |
11+
| main.rs:27:21:27:21 | n | main.rs:26:17:26:25 | SelfParam [Return] [&ref, MyStruct] | provenance | |
12+
| main.rs:30:17:30:21 | SelfParam [&ref, MyStruct] | main.rs:31:9:31:17 | self.data | provenance | |
1513
| main.rs:31:9:31:17 | self.data | main.rs:30:31:32:5 | { ... } | provenance | |
1614
| main.rs:38:5:38:5 | [post] a [MyStruct] | main.rs:39:10:39:10 | a [MyStruct] | provenance | |
1715
| main.rs:38:16:38:24 | source(...) | main.rs:26:28:26:33 | ...: i64 | provenance | |
1816
| main.rs:38:16:38:24 | source(...) | main.rs:38:5:38:5 | [post] a [MyStruct] | provenance | |
1917
| main.rs:39:10:39:10 | a [MyStruct] | main.rs:30:17:30:21 | SelfParam [&ref, MyStruct] | provenance | |
20-
| main.rs:39:10:39:10 | a [MyStruct] | main.rs:39:10:39:21 | a.get_data() | provenance | MaD:1 |
18+
| main.rs:39:10:39:10 | a [MyStruct] | main.rs:39:10:39:21 | a.get_data() | provenance | |
2119
| main.rs:46:9:46:14 | [post] &mut a [&ref, MyStruct] | main.rs:46:14:46:14 | [post] a [MyStruct] | provenance | |
2220
| main.rs:46:14:46:14 | [post] a [MyStruct] | main.rs:49:10:49:10 | a [MyStruct] | provenance | |
2321
| main.rs:48:15:48:23 | source(...) | main.rs:26:28:26:33 | ...: i64 | provenance | |
2422
| main.rs:48:15:48:23 | source(...) | main.rs:46:9:46:14 | [post] &mut a [&ref, MyStruct] | provenance | |
2523
| main.rs:49:10:49:10 | a [MyStruct] | main.rs:30:17:30:21 | SelfParam [&ref, MyStruct] | provenance | |
26-
| main.rs:49:10:49:10 | a [MyStruct] | main.rs:49:10:49:21 | a.get_data() | provenance | MaD:1 |
24+
| main.rs:49:10:49:10 | a [MyStruct] | main.rs:49:10:49:21 | a.get_data() | provenance | |
2725
| main.rs:52:12:52:17 | ...: i64 | main.rs:53:10:53:10 | n | provenance | |
2826
| main.rs:57:9:57:9 | a | main.rs:58:13:58:13 | a | provenance | |
2927
| main.rs:57:13:57:21 | source(...) | main.rs:57:9:57:9 | a | provenance | |
@@ -112,9 +110,8 @@ edges
112110
| main.rs:238:24:238:27 | self [MyInt] | main.rs:238:24:238:33 | self.value | provenance | |
113111
| main.rs:238:24:238:33 | self.value | main.rs:238:9:238:35 | MyInt {...} [MyInt] | provenance | |
114112
| main.rs:243:30:243:39 | ...: MyInt [MyInt] | main.rs:244:22:244:24 | rhs [MyInt] | provenance | |
115-
| main.rs:244:9:244:12 | [post] self [&ref, MyInt] | main.rs:243:19:243:27 | SelfParam [Return] [&ref, MyInt] | provenance | |
116113
| main.rs:244:22:244:24 | rhs [MyInt] | main.rs:244:22:244:30 | rhs.value | provenance | |
117-
| main.rs:244:22:244:30 | rhs.value | main.rs:244:9:244:12 | [post] self [&ref, MyInt] | provenance | |
114+
| main.rs:244:22:244:30 | rhs.value | main.rs:243:19:243:27 | SelfParam [Return] [&ref, MyInt] | provenance | |
118115
| main.rs:251:14:251:18 | SelfParam [&ref, MyInt] | main.rs:252:12:252:15 | self [&ref, MyInt] | provenance | |
119116
| main.rs:252:9:252:22 | &... [&ref] | main.rs:251:38:253:5 | { ... } [&ref] | provenance | |
120117
| main.rs:252:10:252:22 | ... .value | main.rs:252:9:252:22 | &... [&ref] | provenance | |
@@ -233,11 +230,9 @@ nodes
233230
| main.rs:18:10:18:10 | a | semmle.label | a |
234231
| main.rs:26:17:26:25 | SelfParam [Return] [&ref, MyStruct] | semmle.label | SelfParam [Return] [&ref, MyStruct] |
235232
| main.rs:26:28:26:33 | ...: i64 | semmle.label | ...: i64 |
236-
| main.rs:27:9:27:12 | [post] self [&ref, MyStruct] | semmle.label | [post] self [&ref, MyStruct] |
237233
| main.rs:27:21:27:21 | n | semmle.label | n |
238234
| main.rs:30:17:30:21 | SelfParam [&ref, MyStruct] | semmle.label | SelfParam [&ref, MyStruct] |
239235
| main.rs:30:31:32:5 | { ... } | semmle.label | { ... } |
240-
| main.rs:31:9:31:12 | self [&ref, MyStruct] | semmle.label | self [&ref, MyStruct] |
241236
| main.rs:31:9:31:17 | self.data | semmle.label | self.data |
242237
| main.rs:38:5:38:5 | [post] a [MyStruct] | semmle.label | [post] a [MyStruct] |
243238
| main.rs:38:16:38:24 | source(...) | semmle.label | source(...) |
@@ -348,7 +343,6 @@ nodes
348343
| main.rs:238:24:238:33 | self.value | semmle.label | self.value |
349344
| main.rs:243:19:243:27 | SelfParam [Return] [&ref, MyInt] | semmle.label | SelfParam [Return] [&ref, MyInt] |
350345
| main.rs:243:30:243:39 | ...: MyInt [MyInt] | semmle.label | ...: MyInt [MyInt] |
351-
| main.rs:244:9:244:12 | [post] self [&ref, MyInt] | semmle.label | [post] self [&ref, MyInt] |
352346
| main.rs:244:22:244:24 | rhs [MyInt] | semmle.label | rhs [MyInt] |
353347
| main.rs:244:22:244:30 | rhs.value | semmle.label | rhs.value |
354348
| main.rs:251:14:251:18 | SelfParam [&ref, MyInt] | semmle.label | SelfParam [&ref, MyInt] |

0 commit comments

Comments
 (0)