Skip to content

Commit 3c64414

Browse files
committed
Rust: Extract data flow node and content into separate files
1 parent 72c7024 commit 3c64414

File tree

14 files changed

+800
-761
lines changed

14 files changed

+800
-761
lines changed

rust/ql/lib/codeql/rust/dataflow/DataFlow.qll

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
private import rust
77
private import codeql.dataflow.DataFlow
88
private import internal.DataFlowImpl as DataFlowImpl
9-
private import DataFlowImpl::Node as Node
9+
private import internal.Node as Node
10+
private import internal.Content as Content
1011

1112
/**
1213
* Provides classes for performing local (intra-procedural) and global
@@ -23,9 +24,9 @@ module DataFlow {
2324

2425
final class PostUpdateNode = Node::PostUpdateNodePublic;
2526

26-
final class Content = DataFlowImpl::Content;
27+
final class Content = Content::Content;
2728

28-
final class ContentSet = DataFlowImpl::ContentSet;
29+
final class ContentSet = Content::ContentSet;
2930

3031
/**
3132
* Holds if data flows from `nodeFrom` to `nodeTo` in exactly one local
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
/**
2+
* Provides the `Content` class and subclasses thereof.
3+
*/
4+
5+
private import rust
6+
private import codeql.rust.controlflow.CfgNodes
7+
private import DataFlowImpl
8+
9+
/**
10+
* A path to a value contained in an object. For example a field name of a struct.
11+
*/
12+
abstract class Content extends TContent {
13+
/** Gets a textual representation of this content. */
14+
abstract string toString();
15+
16+
/** Gets the location of this content. */
17+
abstract Location getLocation();
18+
}
19+
20+
/** A field belonging to either a variant or a struct. */
21+
abstract class FieldContent extends Content {
22+
/** Gets an access to this field. */
23+
pragma[nomagic]
24+
abstract FieldExprCfgNode getAnAccess();
25+
}
26+
27+
/** A tuple field belonging to either a variant or a struct. */
28+
class TupleFieldContent extends FieldContent, TTupleFieldContent {
29+
private TupleField field;
30+
31+
TupleFieldContent() { this = TTupleFieldContent(field) }
32+
33+
predicate isVariantField(Variant v, int pos) { field.isVariantField(v, pos) }
34+
35+
predicate isStructField(Struct s, int pos) { field.isStructField(s, pos) }
36+
37+
override FieldExprCfgNode getAnAccess() { none() } // TODO
38+
39+
final override string toString() {
40+
exists(Variant v, int pos, string vname |
41+
this.isVariantField(v, pos) and
42+
vname = v.getName().getText() and
43+
// only print indices when the arity is > 1
44+
if exists(v.getTupleField(1)) then result = vname + "(" + pos + ")" else result = vname
45+
)
46+
or
47+
exists(Struct s, int pos, string sname |
48+
this.isStructField(s, pos) and
49+
sname = s.getName().getText() and
50+
// only print indices when the arity is > 1
51+
if exists(s.getTupleField(1)) then result = sname + "(" + pos + ")" else result = sname
52+
)
53+
}
54+
55+
final override Location getLocation() { result = field.getLocation() }
56+
}
57+
58+
/** A record field belonging to either a variant or a struct. */
59+
class RecordFieldContent extends FieldContent, TRecordFieldContent {
60+
private RecordField field;
61+
62+
RecordFieldContent() { this = TRecordFieldContent(field) }
63+
64+
predicate isVariantField(Variant v, string name) { field.isVariantField(v, name) }
65+
66+
predicate isStructField(Struct s, string name) { field.isStructField(s, name) }
67+
68+
override FieldExprCfgNode getAnAccess() { none() } // TODO
69+
70+
final override string toString() {
71+
exists(Variant v, string name, string vname |
72+
this.isVariantField(v, name) and
73+
vname = v.getName().getText() and
74+
// only print field when the arity is > 1
75+
if strictcount(v.getRecordField(_)) > 1 then result = vname + "." + name else result = vname
76+
)
77+
or
78+
exists(Struct s, string name, string sname |
79+
this.isStructField(s, name) and
80+
sname = s.getName().getText() and
81+
// only print field when the arity is > 1
82+
if strictcount(s.getRecordField(_)) > 1 then result = sname + "." + name else result = sname
83+
)
84+
}
85+
86+
final override Location getLocation() { result = field.getLocation() }
87+
}
88+
89+
/** A captured variable. */
90+
final class CapturedVariableContent extends Content, TCapturedVariableContent {
91+
private Variable v;
92+
93+
CapturedVariableContent() { this = TCapturedVariableContent(v) }
94+
95+
/** Gets the captured variable. */
96+
Variable getVariable() { result = v }
97+
98+
override string toString() { result = "captured " + v }
99+
100+
override Location getLocation() { result = v.getLocation() }
101+
}
102+
103+
/** A value referred to by a reference. */
104+
final class ReferenceContent extends Content, TReferenceContent {
105+
override string toString() { result = "&ref" }
106+
107+
override Location getLocation() { result instanceof EmptyLocation }
108+
}
109+
110+
/**
111+
* An element in a collection where we do not track the specific collection
112+
* type nor the placement of the element in the collection. Therefore the
113+
* collection should be one where the elements are reasonably homogeneous,
114+
* i.e., if one is tainted all elements are considered tainted.
115+
*
116+
* Examples include the elements of a set, array, vector, or stack.
117+
*/
118+
final class ElementContent extends Content, TElementContent {
119+
override string toString() { result = "element" }
120+
121+
override Location getLocation() { result instanceof EmptyLocation }
122+
}
123+
124+
/**
125+
* A value that a future resolves to.
126+
*/
127+
final class FutureContent extends Content, TFutureContent {
128+
override string toString() { result = "future" }
129+
130+
override Location getLocation() { result instanceof EmptyLocation }
131+
}
132+
133+
/**
134+
* Content stored at a position in a tuple.
135+
*
136+
* NOTE: Unlike `struct`s and `enum`s tuples are structural and not nominal,
137+
* hence we don't store a canonical path for them.
138+
*/
139+
final class TuplePositionContent extends FieldContent, TTuplePositionContent {
140+
private int pos;
141+
142+
TuplePositionContent() { this = TTuplePositionContent(pos) }
143+
144+
int getPosition() { result = pos }
145+
146+
override FieldExprCfgNode getAnAccess() {
147+
// TODO: limit to tuple types
148+
result.getNameRef().getText().toInt() = pos
149+
}
150+
151+
override string toString() { result = "tuple." + pos.toString() }
152+
153+
override Location getLocation() { result instanceof EmptyLocation }
154+
}
155+
156+
/**
157+
* A content for the index of an argument to at function call.
158+
*
159+
* Used by the model generator to create flow summaries for higher-order
160+
* functions.
161+
*/
162+
final class FunctionCallArgumentContent extends Content, TFunctionCallArgumentContent {
163+
private int pos;
164+
165+
FunctionCallArgumentContent() { this = TFunctionCallArgumentContent(pos) }
166+
167+
int getPosition() { result = pos }
168+
169+
override string toString() { result = "function argument at " + pos }
170+
171+
override Location getLocation() { result instanceof EmptyLocation }
172+
}
173+
174+
/**
175+
* A content for the return value of function call.
176+
*
177+
* Used by the model generator to create flow summaries for higher-order
178+
* functions.
179+
*/
180+
final class FunctionCallReturnContent extends Content, TFunctionCallReturnContent {
181+
override string toString() { result = "function return" }
182+
183+
override Location getLocation() { result instanceof EmptyLocation }
184+
}
185+
186+
/** A value that represents a set of `Content`s. */
187+
abstract class ContentSet extends TContentSet {
188+
/** Gets a textual representation of this element. */
189+
abstract string toString();
190+
191+
/** Gets a content that may be stored into when storing into this set. */
192+
abstract Content getAStoreContent();
193+
194+
/** Gets a content that may be read from when reading from this set. */
195+
abstract Content getAReadContent();
196+
}
197+
198+
final class SingletonContentSet extends ContentSet, TSingletonContentSet {
199+
private Content c;
200+
201+
SingletonContentSet() { this = TSingletonContentSet(c) }
202+
203+
Content getContent() { result = c }
204+
205+
override string toString() { result = c.toString() }
206+
207+
override Content getAStoreContent() { result = c }
208+
209+
override Content getAReadContent() { result = c }
210+
}
211+
212+
/** A collection of cached types and predicates to be evaluated in the same stage. */
213+
cached
214+
private module Cached {
215+
private import codeql.rust.internal.CachedStages
216+
217+
cached
218+
newtype TContent =
219+
TTupleFieldContent(TupleField field) { Stages::DataFlowStage::ref() } or
220+
TRecordFieldContent(RecordField field) or
221+
// TODO: Remove once library types are extracted
222+
TVariantInLibTupleFieldContent(VariantInLib::VariantInLib v, int pos) { pos = v.getAPosition() } or
223+
TElementContent() or
224+
TFutureContent() or
225+
TTuplePositionContent(int pos) {
226+
pos in [0 .. max([
227+
any(TuplePat pat).getNumberOfFields(),
228+
any(FieldExpr access).getNameRef().getText().toInt()
229+
]
230+
)]
231+
} or
232+
TFunctionCallReturnContent() or
233+
TFunctionCallArgumentContent(int pos) {
234+
pos in [0 .. any(CallExpr c).getArgList().getNumberOfArgs() - 1]
235+
} or
236+
TCapturedVariableContent(VariableCapture::CapturedVariable v) or
237+
TReferenceContent()
238+
}
239+
240+
import Cached

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import codeql.rust.dataflow.DataFlow::DataFlow as DataFlow
22
private import rust
33
private import codeql.rust.dataflow.internal.DataFlowImpl
4+
private import codeql.rust.dataflow.internal.Node as Node
45
private import codeql.rust.dataflow.internal.TaintTrackingImpl
56
private import codeql.dataflow.internal.DataFlowImplConsistency
67

0 commit comments

Comments
 (0)