Skip to content

Commit d3541b8

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

File tree

4 files changed

+58
-23
lines changed

4 files changed

+58
-23
lines changed

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

Lines changed: 50 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,41 @@ private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind ki
130130
result = item
131131
}
132132

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

135170
private class UseOption = UseOption::Option;
@@ -288,10 +323,6 @@ abstract class ItemNode extends Locatable {
288323
cached
289324
ItemNode getASuccessor(string name, SuccessorKind kind, UseOption useOpt) {
290325
Stages::PathResolutionStage::ref() and
291-
sourceFileEdge(this, name, result) and
292-
kind.isBoth() and
293-
useOpt.isNone()
294-
or
295326
result = getAChildSuccessor(this, name, kind) and
296327
useOpt.isNone()
297328
or
@@ -471,6 +502,8 @@ abstract class ItemNode extends Locatable {
471502
Location getLocation() { result = super.getLocation() }
472503
}
473504

505+
abstract class NamedItemNode extends ItemNode { }
506+
474507
abstract class TypeItemNode extends ItemNode { }
475508

476509
/** A module or a source file. */
@@ -509,7 +542,7 @@ private class SourceFileItemNode extends ModuleLikeNode instanceof SourceFile {
509542
override string getCanonicalPath(Crate c) { none() }
510543
}
511544

512-
class CrateItemNode extends ItemNode instanceof Crate {
545+
class CrateItemNode extends NamedItemNode instanceof Crate {
513546
/**
514547
* Gets the source file that defines this crate.
515548
*/
@@ -565,15 +598,15 @@ class CrateItemNode extends ItemNode instanceof Crate {
565598
override string getCanonicalPath(Crate c) { c = this and result = Crate.super.getName() }
566599
}
567600

568-
class ExternCrateItemNode extends ItemNode instanceof ExternCrate {
601+
class ExternCrateItemNode extends NamedItemNode instanceof ExternCrate {
569602
override string getName() {
570603
result = super.getRename().getName().getText()
571604
or
572605
not super.hasRename() and
573606
result = super.getIdentifier().getText()
574607
}
575608

576-
override Namespace getNamespace() { none() }
609+
override Namespace getNamespace() { result.isType() }
577610

578611
override Visibility getVisibility() { result = ExternCrate.super.getVisibility() }
579612

@@ -587,7 +620,7 @@ class ExternCrateItemNode extends ItemNode instanceof ExternCrate {
587620
}
588621

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

@@ -626,7 +659,7 @@ private class ConstItemNode extends AssocItemNode instanceof Const {
626659
override TypeParam getTypeParam(int i) { none() }
627660
}
628661

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

632665
override Namespace getNamespace() { result.isType() }
@@ -659,7 +692,7 @@ private class TypeItemTypeItemNode extends TypeItemNode instanceof TypeItem {
659692
}
660693

661694
/** An item that can be referenced with arguments. */
662-
abstract class ParameterizableItemNode extends ItemNode {
695+
abstract class ParameterizableItemNode extends NamedItemNode {
663696
/** Gets the arity this item. */
664697
abstract int getArity();
665698
}
@@ -911,7 +944,7 @@ private class ImplTraitTypeReprItemNodeImpl extends ImplTraitTypeReprItemNode {
911944
ItemNode resolveABoundCand() { result = resolvePathCand(this.getABoundPath()) }
912945
}
913946

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

917950
override Namespace getNamespace() { result.isType() }
@@ -929,7 +962,7 @@ private class ModuleItemNode extends ModuleLikeNode instanceof Module {
929962
(
930963
exists(SourceFile f |
931964
fileImport(this, f) and
932-
sourceFileEdge(f, _, child)
965+
child = getAChildSuccessor(f, _, _)
933966
)
934967
or
935968
this = child.getImmediateParent()
@@ -1001,7 +1034,7 @@ private class StructItemNode extends TypeItemTypeItemNode, ParameterizableItemNo
10011034
}
10021035
}
10031036

1004-
final class TraitItemNode extends ImplOrTraitItemNode, TypeItemNode instanceof Trait {
1037+
final class TraitItemNode extends ImplOrTraitItemNode, NamedItemNode, TypeItemNode instanceof Trait {
10051038
pragma[nomagic]
10061039
Path getABoundPath() { result = super.getATypeBound().getTypeRepr().(PathTypeRepr).getPath() }
10071040

@@ -1126,7 +1159,7 @@ private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
11261159
pragma[nomagic]
11271160
private Path getWherePredPath(WherePred wp) { result = wp.getTypeRepr().(PathTypeRepr).getPath() }
11281161

1129-
final class TypeParamItemNode extends TypeItemNode instanceof TypeParam {
1162+
final class TypeParamItemNode extends NamedItemNode, TypeItemNode instanceof TypeParam {
11301163
/** Gets a where predicate for this type parameter, if any */
11311164
pragma[nomagic]
11321165
private WherePred getAWherePred() {
@@ -1214,7 +1247,7 @@ final private class TypeParamItemNodeImpl extends TypeParamItemNode instanceof T
12141247
ItemNode resolveABoundCand() { result = resolvePathCand(this.getABoundPathCand()) }
12151248
}
12161249

1217-
abstract private class MacroItemNode extends ItemNode {
1250+
abstract private class MacroItemNode extends NamedItemNode {
12181251
override Namespace getNamespace() { result.isMacro() }
12191252

12201253
override TypeParam getTypeParam(int i) { none() }
@@ -1256,12 +1289,6 @@ private class MacroDefItemNode extends MacroItemNode instanceof MacroDef {
12561289
override Attr getAnAttr() { result = MacroDef.super.getAnAttr() }
12571290
}
12581291

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-
12651292
/** Holds if `f` is available as `mod name;` inside `folder`. */
12661293
pragma[nomagic]
12671294
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)