Skip to content

Commit 2de5d24

Browse files
committed
Rust: Make path resolution robust against invalid code with conflicting declarations
1 parent b34777e commit 2de5d24

File tree

4 files changed

+48
-23
lines changed

4 files changed

+48
-23
lines changed

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

Lines changed: 40 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class SuccessorKind extends TSuccessorKind {
107107
}
108108

109109
pragma[nomagic]
110-
private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind kind) {
110+
private ItemNode getAChildSuccessor0(ItemNode item, string name, SuccessorKind kind) {
111111
item = result.getImmediateParent() and
112112
name = result.getName() and
113113
// Associated items in `impl` and `trait` blocks are handled elsewhere
@@ -116,7 +116,7 @@ private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind ki
116116
if result instanceof TypeParam
117117
then kind.isInternal()
118118
else
119-
if result.isPublic()
119+
if result.isPublic() or item instanceof SourceFile
120120
then kind.isBoth()
121121
else kind.isInternal()
122122
or
@@ -130,6 +130,31 @@ private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind ki
130130
result = item
131131
}
132132

133+
pragma[nomagic]
134+
private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind kind) {
135+
result = getAChildSuccessor0(item, name, kind) and
136+
// In valid Rust code, there cannot be multiple children with the same name and namespace,
137+
// but to safeguard against combinatorial explosions in invalid code, we always pick the
138+
// last child, except for modules, where we take the union.
139+
(
140+
not result instanceof NamedItemNode
141+
or
142+
result instanceof ModuleItemNode
143+
or
144+
exists(Namespace ns |
145+
result =
146+
max(NamedItemNode i, int startline, int startcolumn, int endline, int endcolumn |
147+
i.getLocation().hasLocationInfo(_, startline, startcolumn, endline, endcolumn) and
148+
i = getAChildSuccessor0(item, name, _) and
149+
ns = i.getNamespace() and
150+
not i instanceof ModuleItemNode
151+
|
152+
i order by startline, startcolumn, endline, endcolumn
153+
)
154+
)
155+
)
156+
}
157+
133158
private module UseOption = Option<Use>;
134159

135160
private class UseOption = UseOption::Option;
@@ -288,10 +313,6 @@ abstract class ItemNode extends Locatable {
288313
cached
289314
ItemNode getASuccessor(string name, SuccessorKind kind, UseOption useOpt) {
290315
Stages::PathResolutionStage::ref() and
291-
sourceFileEdge(this, name, result) and
292-
kind.isBoth() and
293-
useOpt.isNone()
294-
or
295316
result = getAChildSuccessor(this, name, kind) and
296317
useOpt.isNone()
297318
or
@@ -471,6 +492,8 @@ abstract class ItemNode extends Locatable {
471492
Location getLocation() { result = super.getLocation() }
472493
}
473494

495+
abstract class NamedItemNode extends ItemNode { }
496+
474497
abstract class TypeItemNode extends ItemNode { }
475498

476499
/** A module or a source file. */
@@ -509,7 +532,7 @@ private class SourceFileItemNode extends ModuleLikeNode instanceof SourceFile {
509532
override string getCanonicalPath(Crate c) { none() }
510533
}
511534

512-
class CrateItemNode extends ItemNode instanceof Crate {
535+
class CrateItemNode extends NamedItemNode instanceof Crate {
513536
/**
514537
* Gets the source file that defines this crate.
515538
*/
@@ -565,15 +588,15 @@ class CrateItemNode extends ItemNode instanceof Crate {
565588
override string getCanonicalPath(Crate c) { c = this and result = Crate.super.getName() }
566589
}
567590

568-
class ExternCrateItemNode extends ItemNode instanceof ExternCrate {
591+
class ExternCrateItemNode extends NamedItemNode instanceof ExternCrate {
569592
override string getName() {
570593
result = super.getRename().getName().getText()
571594
or
572595
not super.hasRename() and
573596
result = super.getIdentifier().getText()
574597
}
575598

576-
override Namespace getNamespace() { none() }
599+
override Namespace getNamespace() { result.isType() }
577600

578601
override Visibility getVisibility() { result = ExternCrate.super.getVisibility() }
579602

@@ -587,7 +610,7 @@ class ExternCrateItemNode extends ItemNode instanceof ExternCrate {
587610
}
588611

589612
/** An item that can occur in a trait or an `impl` block. */
590-
abstract private class AssocItemNode extends ItemNode instanceof AssocItem {
613+
abstract private class AssocItemNode extends NamedItemNode instanceof AssocItem {
591614
/** Holds if this associated item has an implementation. */
592615
abstract predicate hasImplementation();
593616

@@ -626,7 +649,7 @@ private class ConstItemNode extends AssocItemNode instanceof Const {
626649
override TypeParam getTypeParam(int i) { none() }
627650
}
628651

629-
private class TypeItemTypeItemNode extends TypeItemNode instanceof TypeItem {
652+
private class TypeItemTypeItemNode extends NamedItemNode, TypeItemNode instanceof TypeItem {
630653
override string getName() { result = TypeItem.super.getName().getText() }
631654

632655
override Namespace getNamespace() { result.isType() }
@@ -659,7 +682,7 @@ private class TypeItemTypeItemNode extends TypeItemNode instanceof TypeItem {
659682
}
660683

661684
/** An item that can be referenced with arguments. */
662-
abstract class ParameterizableItemNode extends ItemNode {
685+
abstract class ParameterizableItemNode extends NamedItemNode {
663686
/** Gets the arity this item. */
664687
abstract int getArity();
665688
}
@@ -911,7 +934,7 @@ private class ImplTraitTypeReprItemNodeImpl extends ImplTraitTypeReprItemNode {
911934
ItemNode resolveABoundCand() { result = resolvePathCand(this.getABoundPath()) }
912935
}
913936

914-
private class ModuleItemNode extends ModuleLikeNode instanceof Module {
937+
private class ModuleItemNode extends NamedItemNode, ModuleLikeNode instanceof Module {
915938
override string getName() { result = Module.super.getName().getText() }
916939

917940
override Namespace getNamespace() { result.isType() }
@@ -929,7 +952,7 @@ private class ModuleItemNode extends ModuleLikeNode instanceof Module {
929952
(
930953
exists(SourceFile f |
931954
fileImport(this, f) and
932-
sourceFileEdge(f, _, child)
955+
child = getAChildSuccessor(f, _, _)
933956
)
934957
or
935958
this = child.getImmediateParent()
@@ -1001,7 +1024,7 @@ private class StructItemNode extends TypeItemTypeItemNode, ParameterizableItemNo
10011024
}
10021025
}
10031026

1004-
final class TraitItemNode extends ImplOrTraitItemNode, TypeItemNode instanceof Trait {
1027+
final class TraitItemNode extends ImplOrTraitItemNode, NamedItemNode, TypeItemNode instanceof Trait {
10051028
pragma[nomagic]
10061029
Path getABoundPath() { result = super.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() }
10071030

@@ -1126,7 +1149,7 @@ private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
11261149
pragma[nomagic]
11271150
private Path getWherePredPath(WherePred wp) { result = wp.getTypeRepr().(PathTypeRepr).getPath() }
11281151

1129-
final class TypeParamItemNode extends TypeItemNode instanceof TypeParam {
1152+
final class TypeParamItemNode extends NamedItemNode, TypeItemNode instanceof TypeParam {
11301153
/** Gets a where predicate for this type parameter, if any */
11311154
pragma[nomagic]
11321155
private WherePred getAWherePred() {
@@ -1214,7 +1237,7 @@ final private class TypeParamItemNodeImpl extends TypeParamItemNode instanceof T
12141237
ItemNode resolveABoundCand() { result = resolvePathCand(this.getABoundPathCand()) }
12151238
}
12161239

1217-
abstract private class MacroItemNode extends ItemNode {
1240+
abstract private class MacroItemNode extends NamedItemNode {
12181241
override Namespace getNamespace() { result.isMacro() }
12191242

12201243
override TypeParam getTypeParam(int i) { none() }
@@ -1256,12 +1279,6 @@ private class MacroDefItemNode extends MacroItemNode instanceof MacroDef {
12561279
override Attr getAnAttr() { result = MacroDef.super.getAnAttr() }
12571280
}
12581281

1259-
/** Holds if `item` has the name `name` and is a top-level item inside `f`. */
1260-
private predicate sourceFileEdge(SourceFile f, string name, ItemNode item) {
1261-
item = f.(ItemNode).getADescendant() and
1262-
name = item.getName()
1263-
}
1264-
12651282
/** Holds if `f` is available as `mod name;` inside `folder`. */
12661283
pragma[nomagic]
12671284
private predicate fileModule(SourceFile f, string name, Folder folder) {
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// The code in this file is not valid Rust code
2+
3+
struct A; // A1
4+
struct A; // A2
5+
6+
fn f(x: A) {} // $ item=A2 (the latter occurence takes precedence)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
qltest_cargo_check: false

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ mod
5151
| my/nested.rs:1:1:17:1 | mod nested1 |
5252
| my/nested.rs:2:5:11:5 | mod nested2 |
5353
resolvePath
54+
| invalid/main.rs:6:9:6:9 | A | invalid/main.rs:3:11:4:9 | struct A |
5455
| main.rs:4:8:4:9 | my | main.rs:1:1:1:7 | mod my |
5556
| main.rs:4:14:4:17 | self | main.rs:1:1:1:7 | mod my |
5657
| main.rs:6:5:6:6 | my | main.rs:1:1:1:7 | mod my |

0 commit comments

Comments
 (0)