Skip to content

Commit 721ffb1

Browse files
committed
Rust: Path resolution for extern crates
1 parent 4fb4bfd commit 721ffb1

File tree

16 files changed

+1040
-529
lines changed

16 files changed

+1040
-529
lines changed

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

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,12 +127,25 @@ abstract class ItemNode extends Locatable {
127127
or
128128
crateDependencyEdge(this, name, result)
129129
or
130+
externCrateEdge(this, name, result)
131+
or
130132
// items made available through `use` are available to nodes that contain the `use`
131133
exists(UseItemNode use |
132134
use = this.getASuccessorRec(_) and
133135
result = use.(ItemNode).getASuccessorRec(name)
134136
)
135137
or
138+
exists(ExternCrateItemNode ec | result = ec.(ItemNode).getASuccessorRec(name) |
139+
ec = this.getASuccessorRec(_)
140+
or
141+
// if the extern crate appears in the crate root, then the crate name is also added
142+
// to the 'extern prelude', see https://doc.rust-lang.org/reference/items/extern-crates.html
143+
exists(Crate c |
144+
ec = c.getSourceFile().(ItemNode).getASuccessorRec(_) and
145+
this = c.getASourceFile()
146+
)
147+
)
148+
or
136149
// items made available through macro calls are available to nodes that contain the macro call
137150
exists(MacroCallItemNode call |
138151
call = this.getASuccessorRec(_) and
@@ -353,16 +366,30 @@ class CrateItemNode extends ItemNode instanceof Crate {
353366

354367
override predicate providesCanonicalPathPrefixFor(Crate c, ItemNode child) {
355368
this.hasCanonicalPath(c) and
356-
exists(ModuleLikeNode m |
357-
child.getImmediateParent() = m and
358-
not m = child.(SourceFileItemNode).getSuper() and
359-
m = super.getSourceFile()
369+
exists(SourceFileItemNode file |
370+
child.getImmediateParent() = file and
371+
not file = child.(SourceFileItemNode).getSuper() and
372+
file = super.getSourceFile()
360373
)
361374
}
362375

363376
override string getCanonicalPath(Crate c) { c = this and result = Crate.super.getName() }
364377
}
365378

379+
class ExternCrateItemNode extends ItemNode instanceof ExternCrate {
380+
override string getName() { result = super.getRename().getName().getText() }
381+
382+
override Namespace getNamespace() { none() }
383+
384+
override Visibility getVisibility() { none() }
385+
386+
override TypeParam getTypeParam(int i) { none() }
387+
388+
override predicate hasCanonicalPath(Crate c) { none() }
389+
390+
override string getCanonicalPath(Crate c) { none() }
391+
}
392+
366393
/** An item that can occur in a trait or an `impl` block. */
367394
abstract private class AssocItemNode extends ItemNode, AssocItem {
368395
/** Holds if this associated item has an implementation. */
@@ -793,6 +820,10 @@ class TypeAliasItemNode extends AssocItemNode instanceof TypeAlias {
793820
override Visibility getVisibility() { result = TypeAlias.super.getVisibility() }
794821

795822
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
823+
824+
override predicate hasCanonicalPath(Crate c) { none() }
825+
826+
override string getCanonicalPath(Crate c) { none() }
796827
}
797828

798829
private class UnionItemNode extends ItemNode instanceof Union {
@@ -1063,12 +1094,12 @@ private predicate crateDefEdge(CrateItemNode c, string name, ItemNode i) {
10631094
}
10641095

10651096
/**
1066-
* Holds if `m` depends on crate `dep` named `name`.
1097+
* Holds if `file` depends on crate `dep` named `name`.
10671098
*/
1068-
private predicate crateDependencyEdge(ModuleLikeNode m, string name, CrateItemNode dep) {
1099+
private predicate crateDependencyEdge(SourceFileItemNode file, string name, CrateItemNode dep) {
10691100
exists(CrateItemNode c |
10701101
dep = c.(Crate).getDependency(name) and
1071-
m = c.getASourceFile()
1102+
file = c.getASourceFile()
10721103
)
10731104
}
10741105

@@ -1404,6 +1435,22 @@ private predicate useImportEdge(Use use, string name, ItemNode item) {
14041435
)
14051436
}
14061437

1438+
/** Holds if `ec` imports `crate` as `name`. */
1439+
pragma[nomagic]
1440+
private predicate externCrateEdge(ExternCrateItemNode ec, string name, CrateItemNode crate) {
1441+
name = ec.getName() and
1442+
exists(SourceFile f, string s |
1443+
ec.getFile() = f.getFile() and
1444+
s = ec.(ExternCrate).getIdentifier().getText()
1445+
|
1446+
crateDependencyEdge(f, s, crate)
1447+
or
1448+
// `extern crate` is used to import the current crate
1449+
s = "self" and
1450+
ec.getFile() = crate.getASourceFile().getFile()
1451+
)
1452+
}
1453+
14071454
/**
14081455
* Holds if `i` is available inside `f` because it is reexported in
14091456
* [the `core` prelude][1] or [the `std` prelude][2].

rust/ql/test/library-tests/dataflow/sources/CONSISTENCY/PathResolutionConsistency.expected

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,64 @@
1+
multiplePathResolutions
2+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
3+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
4+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
5+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
6+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
7+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
8+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
9+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
10+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
11+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
12+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
13+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
14+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
15+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
16+
| test.rs:112:62:112:73 | ...::from | file://:0:0:0:0 | fn from |
17+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
18+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
19+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
20+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
21+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
22+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
23+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
24+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
25+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
26+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
27+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
28+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
29+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
30+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
31+
| test.rs:119:58:119:69 | ...::from | file://:0:0:0:0 | fn from |
32+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
33+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
34+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
35+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
36+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
37+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
38+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
39+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
40+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
41+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
42+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
43+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
44+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
45+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
46+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
47+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
48+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
49+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
50+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
51+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
52+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
53+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
54+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
55+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
56+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
57+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
58+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
59+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
60+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
61+
| test.rs:775:50:775:61 | ...::from | file://:0:0:0:0 | fn from |
162
multipleCanonicalPaths
263
| file://:0:0:0:0 | fn to_ordering | file://:0:0:0:0 | Crate(typenum@1.18.0) | <typenum::Equal as core::cmp::Ord>::to_ordering |
364
| file://:0:0:0:0 | fn to_ordering | file://:0:0:0:0 | Crate(typenum@1.18.0) | <typenum::Equal as typenum::marker_traits::Ord>::to_ordering |
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
multiplePathResolutions
2+
| main.rs:52:11:52:22 | ...::from | file://:0:0:0:0 | fn from |
3+
| main.rs:52:11:52:22 | ...::from | file://:0:0:0:0 | fn from |
4+
| main.rs:52:11:52:22 | ...::from | file://:0:0:0:0 | fn from |
5+
| main.rs:52:11:52:22 | ...::from | file://:0:0:0:0 | fn from |
6+
| main.rs:52:11:52:22 | ...::from | file://:0:0:0:0 | fn from |
7+
| main.rs:52:11:52:22 | ...::from | file://:0:0:0:0 | fn from |

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@ edges
2222
| main.rs:57:11:57:26 | source_slice(...) | main.rs:57:6:57:7 | s1 | provenance | |
2323
| main.rs:58:6:58:7 | s2 | main.rs:59:7:59:8 | s2 | provenance | |
2424
| main.rs:58:11:58:24 | s1.to_string() | main.rs:58:6:58:7 | s2 | provenance | |
25+
| main.rs:63:9:63:9 | s | main.rs:64:16:64:16 | s | provenance | |
2526
| main.rs:63:9:63:9 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:3 |
2627
| main.rs:63:13:63:22 | source(...) | main.rs:63:9:63:9 | s | provenance | |
28+
| main.rs:64:16:64:16 | s | main.rs:64:16:64:25 | s.as_str() | provenance | MaD:3 |
2729
| main.rs:68:9:68:9 | s | main.rs:70:34:70:61 | MacroExpr | provenance | |
2830
| main.rs:68:9:68:9 | s | main.rs:73:34:73:59 | MacroExpr | provenance | |
2931
| main.rs:68:13:68:22 | source(...) | main.rs:68:9:68:9 | s | provenance | |
@@ -75,6 +77,7 @@ nodes
7577
| main.rs:59:7:59:8 | s2 | semmle.label | s2 |
7678
| main.rs:63:9:63:9 | s | semmle.label | s |
7779
| main.rs:63:13:63:22 | source(...) | semmle.label | source(...) |
80+
| main.rs:64:16:64:16 | s | semmle.label | s |
7881
| main.rs:64:16:64:25 | s.as_str() | semmle.label | s.as_str() |
7982
| main.rs:68:9:68:9 | s | semmle.label | s |
8083
| main.rs:68:13:68:22 | source(...) | semmle.label | source(...) |

rust/ql/test/library-tests/path-resolution/my.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ type Result<
2121
T, // T
2222
> = ::std::result::Result<
2323
T, // $ item=T
24-
String,> // $ item=Result
24+
String,> // $ item=Result $ item=String
2525
; // my::Result
2626

2727
fn int_div(

rust/ql/test/library-tests/path-resolution/path-resolution.expected

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,13 @@ resolvePath
145145
| main.rs:278:16:278:16 | T | main.rs:272:7:272:7 | T |
146146
| main.rs:279:14:279:17 | Self | main.rs:270:5:280:5 | trait MyParamTrait |
147147
| main.rs:279:14:279:33 | ...::AssociatedType | main.rs:274:9:274:28 | type AssociatedType |
148+
| main.rs:288:13:288:16 | zelf | main.rs:0:0:0:0 | Crate(main@0.0.1) |
149+
| main.rs:288:13:288:21 | ...::m13 | main.rs:283:1:296:1 | mod m13 |
150+
| main.rs:288:13:288:24 | ...::f | main.rs:284:5:284:17 | fn f |
151+
| main.rs:288:13:288:24 | ...::f | main.rs:284:19:285:19 | struct f |
152+
| main.rs:291:17:291:17 | f | main.rs:284:19:285:19 | struct f |
153+
| main.rs:292:21:292:21 | f | main.rs:284:19:285:19 | struct f |
154+
| main.rs:293:13:293:13 | f | main.rs:284:5:284:17 | fn f |
148155
| main.rs:307:9:307:14 | Trait1 | main.rs:299:5:303:5 | trait Trait1 |
149156
| main.rs:310:13:310:16 | Self | main.rs:305:5:313:5 | trait Trait2 |
150157
| main.rs:310:13:310:19 | ...::g | main.rs:302:9:302:20 | fn g |
@@ -318,6 +325,8 @@ resolvePath
318325
| main.rs:653:5:653:10 | ...::f | main.rs:547:5:551:5 | fn f |
319326
| main.rs:654:5:654:7 | m24 | main.rs:554:1:622:1 | mod m24 |
320327
| main.rs:654:5:654:10 | ...::f | main.rs:608:5:621:5 | fn f |
328+
| main.rs:655:5:655:8 | zelf | main.rs:0:0:0:0 | Crate(main@0.0.1) |
329+
| main.rs:655:5:655:11 | ...::h | main.rs:50:1:69:1 | fn h |
321330
| my2/mod.rs:5:5:5:11 | nested2 | my2/mod.rs:1:1:1:16 | mod nested2 |
322331
| my2/mod.rs:5:5:5:20 | ...::nested3 | my2/nested2.rs:1:1:11:1 | mod nested3 |
323332
| my2/mod.rs:5:5:5:29 | ...::nested4 | my2/nested2.rs:2:5:10:5 | mod nested4 |
@@ -347,6 +356,7 @@ resolvePath
347356
| my.rs:22:5:22:17 | ...::result | {EXTERNAL LOCATION} | mod result |
348357
| my.rs:22:5:24:12 | ...::Result::<...> | {EXTERNAL LOCATION} | enum Result |
349358
| my.rs:23:5:23:5 | T | my.rs:21:5:21:5 | T |
359+
| my.rs:24:5:24:10 | String | {EXTERNAL LOCATION} | struct String |
350360
| my.rs:28:8:28:10 | i32 | {EXTERNAL LOCATION} | struct i32 |
351361
| my.rs:29:8:29:10 | i32 | {EXTERNAL LOCATION} | struct i32 |
352362
| my.rs:30:6:30:16 | Result::<...> | my.rs:18:34:25:1 | type Result<...> |
@@ -360,9 +370,3 @@ resolvePath
360370
| my/nested.rs:21:5:21:20 | ...::nested2 | my/nested.rs:2:5:11:5 | mod nested2 |
361371
| my/nested.rs:21:5:21:23 | ...::f | my/nested.rs:3:9:5:9 | fn f |
362372
testFailures
363-
| main.rs:288:27:288:48 | //... | Missing result: item=I71 |
364-
| main.rs:288:27:288:48 | //... | Missing result: item=I72 |
365-
| main.rs:291:22:291:34 | //... | Missing result: item=I72 |
366-
| main.rs:292:27:292:39 | //... | Missing result: item=I72 |
367-
| main.rs:293:18:293:30 | //... | Missing result: item=I71 |
368-
| main.rs:655:16:655:28 | //... | Missing result: item=I25 |

rust/ql/test/library-tests/variables/CONSISTENCY/PathResolutionConsistency.expected

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,16 @@ multipleMethodCallTargets
77
| main.rs:459:9:459:23 | z.add_assign(...) | file://:0:0:0:0 | fn add_assign |
88
| main.rs:459:9:459:23 | z.add_assign(...) | file://:0:0:0:0 | fn add_assign |
99
| main.rs:459:9:459:23 | z.add_assign(...) | file://:0:0:0:0 | fn add_assign |
10+
multiplePathResolutions
11+
| main.rs:85:19:85:30 | ...::from | file://:0:0:0:0 | fn from |
12+
| main.rs:85:19:85:30 | ...::from | file://:0:0:0:0 | fn from |
13+
| main.rs:85:19:85:30 | ...::from | file://:0:0:0:0 | fn from |
14+
| main.rs:85:19:85:30 | ...::from | file://:0:0:0:0 | fn from |
15+
| main.rs:85:19:85:30 | ...::from | file://:0:0:0:0 | fn from |
16+
| main.rs:85:19:85:30 | ...::from | file://:0:0:0:0 | fn from |
17+
| main.rs:102:19:102:30 | ...::from | file://:0:0:0:0 | fn from |
18+
| main.rs:102:19:102:30 | ...::from | file://:0:0:0:0 | fn from |
19+
| main.rs:102:19:102:30 | ...::from | file://:0:0:0:0 | fn from |
20+
| main.rs:102:19:102:30 | ...::from | file://:0:0:0:0 | fn from |
21+
| main.rs:102:19:102:30 | ...::from | file://:0:0:0:0 | fn from |
22+
| main.rs:102:19:102:30 | ...::from | file://:0:0:0:0 | fn from |
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
multiplePathResolutions
2+
| my_struct.rs:25:19:25:30 | ...::from | file://:0:0:0:0 | fn from |
3+
| my_struct.rs:25:19:25:30 | ...::from | file://:0:0:0:0 | fn from |
4+
| my_struct.rs:25:19:25:30 | ...::from | file://:0:0:0:0 | fn from |
5+
| my_struct.rs:25:19:25:30 | ...::from | file://:0:0:0:0 | fn from |
6+
| my_struct.rs:25:19:25:30 | ...::from | file://:0:0:0:0 | fn from |
7+
| my_struct.rs:25:19:25:30 | ...::from | file://:0:0:0:0 | fn from |

rust/ql/test/query-tests/diagnostics/SummaryStatsReduced.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
| Files extracted - without errors % | 57 |
77
| Inconsistencies - AST | 0 |
88
| Inconsistencies - CFG | 0 |
9-
| Inconsistencies - Path resolution | 0 |
9+
| Inconsistencies - Path resolution | 1 |
1010
| Inconsistencies - SSA | 0 |
1111
| Inconsistencies - data flow | 0 |
1212
| Lines of code extracted | 60 |

0 commit comments

Comments
 (0)