Skip to content

Commit 2927d7d

Browse files
committed
special
1 parent 85b5638 commit 2927d7d

File tree

5 files changed

+141
-23
lines changed

5 files changed

+141
-23
lines changed

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

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

38+
TupleField getField() { result = field }
39+
3840
/** Holds if this field belongs to an enum variant. */
3941
predicate isVariantField(Variant v, int pos) { field.isVariantField(v, pos) }
4042

@@ -68,6 +70,8 @@ class StructFieldContent extends FieldContent, TStructFieldContent {
6870

6971
StructFieldContent() { this = TStructFieldContent(field) }
7072

73+
StructField getField() { result = field }
74+
7175
/** Holds if this field belongs to an enum variant. */
7276
predicate isVariantField(Variant v, string name) { field.isVariantField(v, name) }
7377

@@ -275,3 +279,65 @@ newtype TContent =
275279
} or
276280
TCapturedVariableContent(VariableCapture::CapturedVariable v) or
277281
TReferenceContent()
282+
283+
string tupleFieldApprox(TupleField field) {
284+
exists(Variant v, int pos |
285+
field.isVariantField(v, pos) and
286+
result = v.getName().getText().charAt(0)
287+
)
288+
or
289+
exists(Struct s, int pos |
290+
field.isStructField(s, pos) and
291+
result = s.getName().getText().charAt(0)
292+
)
293+
}
294+
295+
string structFieldApprox(StructField field) {
296+
exists(Variant v, string name |
297+
field.isVariantField(v, name) and
298+
result = v.getName().getText().charAt(0) + "." + name
299+
)
300+
or
301+
exists(Struct s, string name |
302+
field.isStructField(s, name) and
303+
result = s.getName().getText().charAt(0) + "." + name
304+
)
305+
}
306+
307+
cached
308+
newtype TContentApprox =
309+
TTupleFieldContentApprox(string s) { Stages::DataFlowStage::ref() and s = tupleFieldApprox(_) } or
310+
TStructFieldContentApprox(string s) { s = structFieldApprox(_) } or
311+
TElementContentApprox() or
312+
TFutureContentApprox() or
313+
TTuplePositionContentApprox() or
314+
TFunctionCallReturnContentApprox() or
315+
TFunctionCallArgumentContentApprox() or
316+
TCapturedVariableContentApprox() or
317+
TReferenceContentApprox()
318+
319+
final class ContentApprox extends TContentApprox {
320+
/** Gets a textual representation of this element. */
321+
string toString() {
322+
exists(string s |
323+
this = TTupleFieldContentApprox(s) or
324+
this = TStructFieldContentApprox(s)
325+
|
326+
result = s
327+
)
328+
or
329+
this = TElementContentApprox() and result = "element"
330+
or
331+
this = TFutureContentApprox() and result = "future"
332+
or
333+
this = TTuplePositionContentApprox() and result = "tuple.position"
334+
or
335+
this = TFunctionCallReturnContentApprox() and result = "function.return"
336+
or
337+
this = TFunctionCallArgumentContentApprox() and result = "function.argument"
338+
or
339+
this = TCapturedVariableContentApprox() and result = "captured.variable"
340+
or
341+
this = TReferenceContentApprox() and result = "&ref"
342+
}
343+
}

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+
specialDeref(nodeFrom, nodeTo)
547+
or
526548
VariableCapture::localFlowStep(nodeFrom, nodeTo)
527549
) and
528550
model = ""

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

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,12 @@ class ImplicitDerefNodeState extends TImplicitDerefNodeState {
263263
}
264264
}
265265

266+
private import codeql.rust.frameworks.stdlib.Builtins as Builtins
267+
266268
/**
267269
* A node used to represent implicit dereferencing.
270+
*
271+
* TODO: Special case `&` and `&mut` implementations.
268272
*/
269273
class ImplicitDerefNode extends Node, TImplicitDerefNode {
270274
AstNode n;
@@ -274,11 +278,14 @@ class ImplicitDerefNode extends Node, TImplicitDerefNode {
274278

275279
ImplicitDerefNode() { this = TImplicitDerefNode(n, derefChain, state, i, false) }
276280

281+
predicate isSpecial() { derefChain.isSpecial(i) }
282+
277283
/**
278284
* Gets the node that should the predecessor in a reference store-step into this
279285
* node, if any.
280286
*/
281287
Node getBorrowInputNode() {
288+
not this.isSpecial() and
282289
state = TImplicitDerefNodeBorrowState() and
283290
(
284291
i = 0 and
@@ -293,7 +300,11 @@ class ImplicitDerefNode extends Node, TImplicitDerefNode {
293300
* node, if any.
294301
*/
295302
Node getDerefOutputNode() {
296-
state = TImplicitDerefNodeBeforeDerefState() and
303+
(
304+
if this.isSpecial()
305+
then state = TImplicitDerefNodeBorrowState()
306+
else state = TImplicitDerefNodeBeforeDerefState()
307+
) and
297308
result = TImplicitDerefNode(n, derefChain, TImplicitDerefNodeAfterDerefState(), i, false)
298309
}
299310

@@ -310,18 +321,31 @@ class ImplicitDerefNode extends Node, TImplicitDerefNode {
310321
override string toString() { result = n + " [implicit deref " + i + " in state " + state + "]" }
311322
}
312323

324+
predicate specialDeref(AstNodeNode node1, Node node2) {
325+
exists(DerefChain derefChain |
326+
node2 =
327+
TImplicitDerefNode(node1.getAstNode(), derefChain, TImplicitDerefNodeBorrowState(), 0, false) and
328+
derefChain.isSpecial(0)
329+
)
330+
}
331+
313332
final class ImplicitDerefArgNode extends ImplicitDerefNode, ArgumentNode {
314333
private DataFlowCall call_;
315334
private RustDataFlow::ArgumentPosition pos_;
316335

317336
ImplicitDerefArgNode() {
318-
state = TImplicitDerefNodeBorrowState() and
319-
call_ = TImplicitDerefCall(n, derefChain, i, _) and
320-
pos_.isSelf()
321-
or
322-
this.isLast(_) and
323-
TypeInference::implicitDerefChainBorrow(n, derefChain, false) and
324-
isArgumentForCall(n, call_.asCall(), pos_)
337+
// negative recursion
338+
not derefChain.isSpecial(i) and
339+
// not this.isSpecial() and
340+
(
341+
state = TImplicitDerefNodeBorrowState() and
342+
call_ = TImplicitDerefCall(n, derefChain, i, _) and
343+
pos_.isSelf()
344+
or
345+
this.isLast(_) and
346+
TypeInference::implicitDerefChainBorrow(n, derefChain, false) and
347+
isArgumentForCall(n, call_.asCall(), pos_)
348+
)
325349
}
326350

327351
override predicate isArgumentOf(DataFlowCall call, RustDataFlow::ArgumentPosition pos) {
@@ -332,7 +356,11 @@ final class ImplicitDerefArgNode extends ImplicitDerefNode, ArgumentNode {
332356
private class ImplicitDerefOutNode extends ImplicitDerefNode, OutNode {
333357
private DataFlowCall call;
334358

335-
ImplicitDerefOutNode() { state = TImplicitDerefNodeBeforeDerefState() }
359+
ImplicitDerefOutNode() {
360+
// not this.isSpecial() and
361+
not derefChain.getElement(i).resolveSelfTyBuiltin() instanceof Builtins::RefType and
362+
state = TImplicitDerefNodeBeforeDerefState()
363+
}
336364

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

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,15 @@ private import UnboundListImpl::Make<Location, UnboundListInput>
7070
* A sequence of `Deref` impl blocks representing a chain of implicit dereferences,
7171
* encoded as a string.
7272
*/
73-
class DerefChain = UnboundList;
73+
class DerefChain extends UnboundList {
74+
bindingset[this]
75+
DerefChain() { exists(this) }
76+
77+
bindingset[this]
78+
predicate isSpecial(int i) {
79+
this.getElement(i).resolveSelfTyBuiltin() instanceof Builtins::RefType
80+
}
81+
}
7482

7583
/** Provides predicates for constructing `DerefChain`s. */
7684
module DerefChain = UnboundList;

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)