Skip to content

Commit 02e9795

Browse files
committed
Rust: Take prelude into account when resolving paths
1 parent ac24ef6 commit 02e9795

File tree

19 files changed

+237
-172
lines changed

19 files changed

+237
-172
lines changed

Diff for: rust/ql/integration-tests/hello-project/summary.expected

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
| Macro calls - resolved | 2 |
1616
| Macro calls - total | 2 |
1717
| Macro calls - unresolved | 0 |
18-
| Taint edges - number of edges | 1674 |
18+
| Taint edges - number of edges | 1691 |
1919
| Taint reach - nodes tainted | 0 |
2020
| Taint reach - per million nodes | 0 |
2121
| Taint sinks - cryptographic operations | 0 |

Diff for: rust/ql/integration-tests/hello-workspace/summary.cargo.expected

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
| Macro calls - resolved | 2 |
1616
| Macro calls - total | 2 |
1717
| Macro calls - unresolved | 0 |
18-
| Taint edges - number of edges | 1674 |
18+
| Taint edges - number of edges | 1691 |
1919
| Taint reach - nodes tainted | 0 |
2020
| Taint reach - per million nodes | 0 |
2121
| Taint sinks - cryptographic operations | 0 |

Diff for: rust/ql/integration-tests/hello-workspace/summary.rust-project.expected

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
| Macro calls - resolved | 2 |
1616
| Macro calls - total | 2 |
1717
| Macro calls - unresolved | 0 |
18-
| Taint edges - number of edges | 1674 |
18+
| Taint edges - number of edges | 1691 |
1919
| Taint reach - nodes tainted | 0 |
2020
| Taint reach - per million nodes | 0 |
2121
| Taint sinks - cryptographic operations | 0 |

Diff for: rust/ql/lib/codeql/rust/dataflow/internal/Content.qll

-2
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,6 @@ cached
255255
newtype TContent =
256256
TTupleFieldContent(TupleField field) { Stages::DataFlowStage::ref() } or
257257
TStructFieldContent(StructField field) or
258-
// TODO: Remove once library types are extracted
259-
TVariantInLibTupleFieldContent(VariantInLib::VariantInLib v, int pos) { pos = v.getAPosition() } or
260258
TElementContent() or
261259
TFutureContent() or
262260
TTuplePositionContent(int pos) {

Diff for: rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll

+5-129
Original file line numberDiff line numberDiff line change
@@ -296,125 +296,6 @@ module LocalFlow {
296296
}
297297
}
298298

299-
/**
300-
* Provides temporary modeling of built-in variants, for which no source code
301-
* `Item`s are available.
302-
*
303-
* TODO: Remove once library code is extracted.
304-
*/
305-
module VariantInLib {
306-
private import codeql.util.Option
307-
308-
private class CrateOrigin extends string {
309-
CrateOrigin() { this = any(Resolvable r).getResolvedCrateOrigin() }
310-
}
311-
312-
private class CrateOriginOption = Option<CrateOrigin>::Option;
313-
314-
private CrateOriginOption langCoreCrate() { result.asSome() = "lang:core" }
315-
316-
private newtype TVariantInLib =
317-
MkVariantInLib(CrateOriginOption crate, string path, string name) {
318-
crate = langCoreCrate() and
319-
(
320-
path = "crate::option::Option" and
321-
name = "Some"
322-
or
323-
path = "crate::result::Result" and
324-
name = ["Ok", "Err"]
325-
)
326-
}
327-
328-
/** An enum variant from library code, represented by the enum's canonical path and the variant's name. */
329-
class VariantInLib extends MkVariantInLib {
330-
CrateOriginOption crate;
331-
string path;
332-
string name;
333-
334-
VariantInLib() { this = MkVariantInLib(crate, path, name) }
335-
336-
int getAPosition() {
337-
this = MkVariantInLib(langCoreCrate(), "crate::option::Option", "Some") and
338-
result = 0
339-
or
340-
this = MkVariantInLib(langCoreCrate(), "crate::result::Result", ["Ok", "Err"]) and
341-
result = 0
342-
}
343-
344-
string getExtendedCanonicalPath() { result = path + "::" + name }
345-
346-
string toString() { result = name }
347-
}
348-
349-
/** A tuple variant from library code. */
350-
class VariantInLibTupleFieldContent extends Content, TVariantInLibTupleFieldContent {
351-
private VariantInLib::VariantInLib v;
352-
private int pos_;
353-
354-
VariantInLibTupleFieldContent() { this = TVariantInLibTupleFieldContent(v, pos_) }
355-
356-
VariantInLib::VariantInLib getVariantInLib(int pos) { result = v and pos = pos_ }
357-
358-
string getExtendedCanonicalPath() { result = v.getExtendedCanonicalPath() }
359-
360-
int getPosition() { result = pos_ }
361-
362-
final override string toString() {
363-
// only print indices when the arity is > 1
364-
if exists(TVariantInLibTupleFieldContent(v, 1))
365-
then result = v.toString() + "(" + pos_ + ")"
366-
else result = v.toString()
367-
}
368-
369-
final override Location getLocation() { result instanceof EmptyLocation }
370-
}
371-
372-
pragma[nomagic]
373-
private predicate resolveExtendedCanonicalPath(Resolvable r, CrateOriginOption crate, string path) {
374-
path = r.getResolvedPath() and
375-
(
376-
crate.asSome() = r.getResolvedCrateOrigin()
377-
or
378-
crate.isNone() and
379-
not r.hasResolvedCrateOrigin()
380-
)
381-
}
382-
383-
/** Holds if path `p` resolves to variant `v`. */
384-
private predicate pathResolveToVariantInLib(PathAstNode p, VariantInLib v) {
385-
exists(CrateOriginOption crate, string path, string name |
386-
resolveExtendedCanonicalPath(p, pragma[only_bind_into](crate), path + "::" + name) and
387-
v = MkVariantInLib(pragma[only_bind_into](crate), path, name)
388-
)
389-
}
390-
391-
/** Holds if `p` destructs an enum variant `v`. */
392-
pragma[nomagic]
393-
private predicate tupleVariantCanonicalDestruction(TupleStructPat p, VariantInLib v) {
394-
pathResolveToVariantInLib(p, v)
395-
}
396-
397-
bindingset[pos]
398-
predicate tupleVariantCanonicalDestruction(
399-
TupleStructPat pat, VariantInLibTupleFieldContent c, int pos
400-
) {
401-
tupleVariantCanonicalDestruction(pat, c.getVariantInLib(pos))
402-
}
403-
404-
/** Holds if `ce` constructs an enum value of type `v`. */
405-
pragma[nomagic]
406-
private predicate tupleVariantCanonicalConstruction(CallExpr ce, VariantInLib v) {
407-
pathResolveToVariantInLib(ce.getFunction().(PathExpr), v)
408-
}
409-
410-
bindingset[pos]
411-
predicate tupleVariantCanonicalConstruction(CallExpr ce, VariantInLibTupleFieldContent c, int pos) {
412-
tupleVariantCanonicalConstruction(ce, c.getVariantInLib(pos))
413-
}
414-
}
415-
416-
class VariantInLibTupleFieldContent = VariantInLib::VariantInLibTupleFieldContent;
417-
418299
class LambdaCallKind = Unit;
419300

420301
/** Holds if `creation` is an expression that creates a lambda of kind `kind`. */
@@ -480,6 +361,7 @@ module RustDataFlow implements InputSig<Location> {
480361
private import Aliases
481362
private import codeql.rust.dataflow.DataFlow
482363
private import Node as Node
364+
private import codeql.rust.frameworks.stdlib.Stdlib
483365

484366
/**
485367
* An element, viewed as a node in a data flow graph. Either an expression
@@ -665,11 +547,8 @@ module RustDataFlow implements InputSig<Location> {
665547
exists(Content c | c = cs.(SingletonContentSet).getContent() |
666548
exists(TupleStructPatCfgNode pat, int pos |
667549
pat = node1.asPat() and
668-
node2.asPat() = pat.getField(pos)
669-
|
550+
node2.asPat() = pat.getField(pos) and
670551
c = TTupleFieldContent(pat.getTupleStructPat().getTupleField(pos))
671-
or
672-
VariantInLib::tupleVariantCanonicalDestruction(pat.getPat(), c, pos)
673552
)
674553
or
675554
exists(TuplePatCfgNode pat, int pos |
@@ -714,8 +593,8 @@ module RustDataFlow implements InputSig<Location> {
714593
exists(TryExprCfgNode try |
715594
node1.asExpr() = try.getExpr() and
716595
node2.asExpr() = try and
717-
c.(VariantInLibTupleFieldContent).getVariantInLib(0).getExtendedCanonicalPath() =
718-
["crate::option::Option::Some", "crate::result::Result::Ok"]
596+
c.(TupleFieldContent)
597+
.isVariantField([any(OptionEnum o).getSome(), any(ResultEnum r).getOk()], 0)
719598
)
720599
or
721600
exists(PrefixExprCfgNode deref |
@@ -791,11 +670,8 @@ module RustDataFlow implements InputSig<Location> {
791670
private predicate storeContentStep(Node node1, Content c, Node node2) {
792671
exists(CallExprCfgNode call, int pos |
793672
node1.asExpr() = call.getArgument(pragma[only_bind_into](pos)) and
794-
node2.asExpr() = call
795-
|
673+
node2.asExpr() = call and
796674
c = TTupleFieldContent(call.getCallExpr().getTupleField(pragma[only_bind_into](pos)))
797-
or
798-
VariantInLib::tupleVariantCanonicalConstruction(call.getCallExpr(), c, pos)
799675
)
800676
or
801677
exists(StructExprCfgNode re, string field |

Diff for: rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll

+14-7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ private import Content
1111

1212
module Input implements InputSig<Location, RustDataFlow> {
1313
private import codeql.rust.elements.internal.CallExprBaseImpl::Impl as CallExprBaseImpl
14+
private import codeql.rust.frameworks.stdlib.Stdlib
1415

1516
class SummarizedCallableBase = string;
1617

@@ -66,9 +67,20 @@ module Input implements InputSig<Location, RustDataFlow> {
6667
exists(Content c | cs = TSingletonContentSet(c) |
6768
result = "Field" and
6869
(
69-
exists(Addressable a, int pos |
70+
exists(Addressable a, int pos, string prefix |
7071
// TODO: calculate in QL
71-
arg = a.getExtendedCanonicalPath() + "(" + pos + ")"
72+
arg = prefix + "(" + pos + ")" and
73+
(
74+
prefix = a.getExtendedCanonicalPath()
75+
or
76+
a = any(OptionEnum o).getSome() and
77+
prefix = "crate::option::Option::Some"
78+
or
79+
exists(string name |
80+
a = any(ResultEnum r).getVariant(name) and
81+
prefix = "crate::result::Result::" + name
82+
)
83+
)
7284
|
7385
c.(TupleFieldContent).isStructField(a, pos)
7486
or
@@ -84,11 +96,6 @@ module Input implements InputSig<Location, RustDataFlow> {
8496
c.(StructFieldContent).isVariantField(a, field)
8597
)
8698
or
87-
c =
88-
any(VariantInLibTupleFieldContent v |
89-
arg = v.getExtendedCanonicalPath() + "(" + v.getPosition() + ")"
90-
)
91-
or
9299
exists(int pos |
93100
c = TTuplePositionContent(pos) and
94101
arg = pos.toString()

Diff for: rust/ql/lib/codeql/rust/elements/internal/EnumImpl.qll

+9
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ private import codeql.rust.elements.internal.generated.Enum
1111
* be referenced directly.
1212
*/
1313
module Impl {
14+
private import rust
15+
1416
// the following QLdoc is generated: if you need to edit it, do it in the schema file
1517
/**
1618
* A Enum. For example:
@@ -20,5 +22,12 @@ module Impl {
2022
*/
2123
class Enum extends Generated::Enum {
2224
override string toStringImpl() { result = "enum " + this.getName().getText() }
25+
26+
/** Gets the variant named `name`, if any. */
27+
pragma[nomagic]
28+
Variant getVariant(string name) {
29+
result = this.getVariantList().getAVariant() and
30+
result.getName().getText() = name
31+
}
2332
}
2433
}

Diff for: rust/ql/lib/codeql/rust/elements/internal/PathImpl.qll

+12
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,18 @@ module Impl {
4040
*/
4141
pragma[nomagic]
4242
string getText() { result = this.getSegment().getIdentifier().getText() }
43+
44+
/**
45+
* Gets the full text of this path, including the qualifier.
46+
*
47+
* Should only be used for debugging purposes.
48+
*/
49+
string toStringDebug() {
50+
not this.hasQualifier() and
51+
result = this.getText()
52+
or
53+
result = this.getQualifier().toStringDebug() + "::" + this.getText()
54+
}
4355
}
4456

4557
/** A simple identifier path. */

Diff for: rust/ql/lib/codeql/rust/frameworks/stdlib/Stdlib.qll

+45
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,48 @@ private class StartswithCall extends Path::SafeAccessCheck::Range, CfgNodes::Met
2121
branch = true
2222
}
2323
}
24+
25+
/**
26+
* The [`Option` enum][1].
27+
*
28+
* [1]: https://doc.rust-lang.org/std/option/enum.Option.html
29+
*/
30+
class OptionEnum extends Enum {
31+
OptionEnum() {
32+
// todo: replace with canonical path, once calculated in QL
33+
exists(Crate core, Module m |
34+
core.getName() = "core" and
35+
m = core.getModule().getItemList().getAnItem() and
36+
m.getName().getText() = "option" and
37+
this = m.getItemList().getAnItem() and
38+
this.getName().getText() = "Option"
39+
)
40+
}
41+
42+
/** Gets the `Some` variant. */
43+
Variant getSome() { result = this.getVariant("Some") }
44+
}
45+
46+
/**
47+
* The [`Result` enum][1].
48+
*
49+
* [1]: https://doc.rust-lang.org/stable/std/result/enum.Result.html
50+
*/
51+
class ResultEnum extends Enum {
52+
ResultEnum() {
53+
// todo: replace with canonical path, once calculated in QL
54+
exists(Crate core, Module m |
55+
core.getName() = "core" and
56+
m = core.getModule().getItemList().getAnItem() and
57+
m.getName().getText() = "result" and
58+
this = m.getItemList().getAnItem() and
59+
this.getName().getText() = "Result"
60+
)
61+
}
62+
63+
/** Gets the `Ok` variant. */
64+
Variant getOk() { result = this.getVariant("Ok") }
65+
66+
/** Gets the `Err` variant. */
67+
Variant getErr() { result = this.getVariant("Err") }
68+
}

Diff for: rust/ql/lib/codeql/rust/internal/CachedStages.qll

+33-2
Original file line numberDiff line numberDiff line change
@@ -95,17 +95,48 @@ module Stages {
9595
}
9696
}
9797

98+
/**
99+
* The path resolution stage.
100+
*/
101+
cached
102+
module PathResolutionStage {
103+
private import codeql.rust.internal.PathResolution
104+
105+
/**
106+
* Always holds.
107+
* Ensures that a predicate is evaluated as part of the path resolution stage.
108+
*/
109+
cached
110+
predicate ref() { 1 = 1 }
111+
112+
/**
113+
* DO NOT USE!
114+
*
115+
* Contains references to each predicate that use the above `ref` predicate.
116+
*/
117+
cached
118+
predicate backref() {
119+
1 = 1
120+
or
121+
exists(resolvePath(_))
122+
or
123+
exists(any(ItemNode i).getASuccessor(_))
124+
or
125+
exists(any(ItemNode i).getASuccessorRec(_))
126+
}
127+
}
128+
98129
/**
99130
* The type inference stage.
100131
*/
101132
cached
102-
module TypeInference {
133+
module TypeInferenceStage {
103134
private import codeql.rust.internal.Type
104135
private import codeql.rust.internal.TypeInference
105136

106137
/**
107138
* Always holds.
108-
* Ensures that a predicate is evaluated as part of the CFG stage.
139+
* Ensures that a predicate is evaluated as part of the type inference stage.
109140
*/
110141
cached
111142
predicate ref() { 1 = 1 }

0 commit comments

Comments
 (0)