Skip to content

Commit 1b67b30

Browse files
committed
Rust: Refine visibility check in path resolution
1 parent 394a1eb commit 1b67b30

3 files changed

Lines changed: 111 additions & 17 deletions

File tree

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

Lines changed: 109 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -87,10 +87,32 @@ abstract class ItemNode extends Locatable {
8787
/** Gets the `i`th type parameter of this item, if any. */
8888
abstract TypeParam getTypeParam(int i);
8989

90+
/** Gets the parent item from which this node inherits visibility, if any. */
91+
abstract ItemNode getVisibilityParent();
92+
93+
/** Holds if this item has a visibility parent. */
94+
// Cannot be defined as `exists(this.getVisibilityParent())` because of non-monotonicity
95+
abstract predicate hasVisibilityParent();
96+
9097
/** Holds if this item is declared as `pub`. */
91-
bindingset[this]
92-
pragma[inline_late]
93-
predicate isPublic() { exists(this.getVisibility()) }
98+
pragma[nomagic]
99+
predicate isPublic() {
100+
exists(this.getVisibility())
101+
or
102+
this.getVisibilityParent().isPublic()
103+
}
104+
105+
/** Holds if this item is not declared as `pub`. */
106+
pragma[nomagic]
107+
predicate isPrivate() {
108+
// Cannot be defined as `not this.isPublic()` because of non-monotonicity
109+
not exists(this.getVisibility()) and
110+
(
111+
not this.hasVisibilityParent()
112+
or
113+
this.getVisibilityParent().isPrivate()
114+
)
115+
}
94116

95117
/** Gets an element that has this item as immediately enclosing item. */
96118
pragma[nomagic]
@@ -243,10 +265,16 @@ private class SourceFileItemNode extends ModuleLikeNode, SourceFile {
243265
result.isType() // can be referenced with `super`
244266
}
245267

268+
override ItemNode getVisibilityParent() { none() }
269+
270+
override predicate hasVisibilityParent() { none() }
271+
246272
override Visibility getVisibility() { none() }
247273

248274
override predicate isPublic() { any() }
249275

276+
override predicate isPrivate() { none() }
277+
250278
override TypeParam getTypeParam(int i) { none() }
251279
}
252280

@@ -307,17 +335,45 @@ class CrateItemNode extends ItemNode instanceof Crate {
307335
result.isType() // can be referenced with `crate`
308336
}
309337

338+
override ItemNode getVisibilityParent() { none() }
339+
340+
override predicate hasVisibilityParent() { none() }
341+
310342
override Visibility getVisibility() { none() }
311343

312344
override predicate isPublic() { any() }
313345

346+
override predicate isPrivate() { none() }
347+
314348
override TypeParam getTypeParam(int i) { none() }
315349
}
316350

317351
/** An item that can occur in a trait or an `impl` block. */
318352
abstract private class AssocItemNode extends ItemNode, AssocItem {
319353
/** Holds if this associated item has an implementation. */
320354
abstract predicate hasImplementation();
355+
356+
override ItemNode getVisibilityParent() {
357+
exists(ImplItemNode i | this = i.getAnAssocItem() |
358+
// trait implementations inherit visibility from the trait
359+
result = i.resolveTraitTy()
360+
or
361+
// for inherent implementations that are not explicitly marked as
362+
// `pub`, the `impl` block itself must be visible
363+
not i.(Impl).hasTrait() and
364+
not exists(this.getVisibility()) and
365+
result = i
366+
)
367+
}
368+
369+
override predicate hasVisibilityParent() {
370+
exists(ImplItemNode i | this = i.getAnAssocItem() |
371+
i.(Impl).hasTrait()
372+
or
373+
not i.(Impl).hasTrait() and
374+
not exists(this.getVisibility())
375+
)
376+
}
321377
}
322378

323379
private class ConstItemNode extends AssocItemNode instanceof Const {
@@ -337,6 +393,10 @@ private class EnumItemNode extends ItemNode instanceof Enum {
337393

338394
override Namespace getNamespace() { result.isType() }
339395

396+
override ItemNode getVisibilityParent() { none() }
397+
398+
override predicate hasVisibilityParent() { none() }
399+
340400
override Visibility getVisibility() { result = Enum.super.getVisibility() }
341401

342402
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
@@ -353,7 +413,11 @@ private class VariantItemNode extends ItemNode instanceof Variant {
353413
result = super.getEnum().getGenericParamList().getTypeParam(i)
354414
}
355415

356-
override Visibility getVisibility() { result = super.getEnum().getVisibility() }
416+
override predicate hasVisibilityParent() { any() }
417+
418+
override ItemNode getVisibilityParent() { result = super.getEnum() }
419+
420+
override Visibility getVisibility() { none() }
357421
}
358422

359423
class FunctionItemNode extends AssocItemNode instanceof Function {
@@ -478,6 +542,10 @@ class ImplItemNode extends ImplOrTraitItemNode instanceof Impl {
478542

479543
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
480544

545+
override ItemNode getVisibilityParent() { none() }
546+
547+
override predicate hasVisibilityParent() { none() }
548+
481549
override Visibility getVisibility() { result = Impl.super.getVisibility() }
482550
}
483551

@@ -498,6 +566,10 @@ private class ModuleItemNode extends ModuleLikeNode instanceof Module {
498566

499567
override Namespace getNamespace() { result.isType() }
500568

569+
override ItemNode getVisibilityParent() { none() }
570+
571+
override predicate hasVisibilityParent() { none() }
572+
501573
override Visibility getVisibility() { result = Module.super.getVisibility() }
502574

503575
override TypeParam getTypeParam(int i) { none() }
@@ -513,6 +585,10 @@ private class StructItemNode extends ItemNode instanceof Struct {
513585
result.isValue() // the constructor
514586
}
515587

588+
override ItemNode getVisibilityParent() { none() }
589+
590+
override predicate hasVisibilityParent() { none() }
591+
516592
override Visibility getVisibility() { result = Struct.super.getVisibility() }
517593

518594
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
@@ -533,6 +609,10 @@ class TraitItemNode extends ImplOrTraitItemNode instanceof Trait {
533609

534610
override Namespace getNamespace() { result.isType() }
535611

612+
override ItemNode getVisibilityParent() { none() }
613+
614+
override predicate hasVisibilityParent() { none() }
615+
536616
override Visibility getVisibility() { result = Trait.super.getVisibility() }
537617

538618
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
@@ -555,6 +635,10 @@ private class UnionItemNode extends ItemNode instanceof Union {
555635

556636
override Namespace getNamespace() { result.isType() }
557637

638+
override ItemNode getVisibilityParent() { none() }
639+
640+
override predicate hasVisibilityParent() { none() }
641+
558642
override Visibility getVisibility() { result = Union.super.getVisibility() }
559643

560644
override TypeParam getTypeParam(int i) { result = super.getGenericParamList().getTypeParam(i) }
@@ -565,6 +649,10 @@ private class UseItemNode extends ItemNode instanceof Use {
565649

566650
override Namespace getNamespace() { none() }
567651

652+
override ItemNode getVisibilityParent() { none() }
653+
654+
override predicate hasVisibilityParent() { none() }
655+
568656
override Visibility getVisibility() { result = Use.super.getVisibility() }
569657

570658
override TypeParam getTypeParam(int i) { none() }
@@ -575,6 +663,10 @@ private class BlockExprItemNode extends ItemNode instanceof BlockExpr {
575663

576664
override Namespace getNamespace() { none() }
577665

666+
override ItemNode getVisibilityParent() { none() }
667+
668+
override predicate hasVisibilityParent() { none() }
669+
578670
override Visibility getVisibility() { none() }
579671

580672
override TypeParam getTypeParam(int i) { none() }
@@ -638,6 +730,10 @@ class TypeParamItemNode extends ItemNode instanceof TypeParam {
638730

639731
override Namespace getNamespace() { result.isType() }
640732

733+
override ItemNode getVisibilityParent() { none() }
734+
735+
override predicate hasVisibilityParent() { none() }
736+
641737
override Visibility getVisibility() { none() }
642738

643739
override TypeParam getTypeParam(int i) { none() }
@@ -1030,12 +1126,17 @@ private ItemNode resolvePathPrivate(
10301126
RelevantPath path, ModuleLikeNode itemParent, ModuleLikeNode pathParent
10311127
) {
10321128
result = resolvePath1(path) and
1033-
itemParent = result.getImmediateParentModule() and
1034-
not result.isPublic() and
1129+
result.isPrivate() and
10351130
(
10361131
pathParent.getADescendant() = path
10371132
or
10381133
pathParent = any(ItemNode mid | path = mid.getADescendant()).getImmediateParentModule()
1134+
) and
1135+
(
1136+
itemParent = result.getVisibilityParent().getImmediateParentModule()
1137+
or
1138+
not result.hasVisibilityParent() and
1139+
itemParent = result.getImmediateParentModule()
10391140
)
10401141
}
10411142

@@ -1176,19 +1277,11 @@ private module Debug {
11761277
private Locatable getRelevantLocatable() {
11771278
exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
11781279
result.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) and
1179-
filepath.matches("%/test_logging.rs") and
1180-
startline = 163
1280+
filepath.matches("%/illegal/main.rs") and
1281+
startline = 51
11811282
)
11821283
}
11831284

1184-
predicate debugUnqualifiedPathLookup(
1185-
RelevantPath p, string name, Namespace ns, ItemNode encl, string path
1186-
) {
1187-
p = getRelevantLocatable() and
1188-
unqualifiedPathLookup(p, name, ns, encl) and
1189-
path = p.toStringDebug()
1190-
}
1191-
11921285
ItemNode debugResolvePath(RelevantPath path) {
11931286
path = getRelevantLocatable() and
11941287
result = resolvePath(path)

rust/ql/test/library-tests/path-resolution/illegal/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ mod m1 {
5858
);
5959
super::S(). // $ item=I1
6060
f1(); // $ item=I6
61-
super::S::f1( // $ MISSING: item=I6
61+
super::S::f1( // $ item=I6
6262
super::S() // $ item=I1
6363
);
6464
super::S(). // $ item=I1

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ resolvePath
7777
| illegal/main.rs:59:13:59:20 | ...::S | illegal/main.rs:2:5:2:15 | struct S |
7878
| illegal/main.rs:61:13:61:17 | super | illegal/main.rs:1:1:71:1 | mod m1 |
7979
| illegal/main.rs:61:13:61:20 | ...::S | illegal/main.rs:2:5:2:15 | struct S |
80+
| illegal/main.rs:61:13:61:24 | ...::f1 | illegal/main.rs:27:24:30:13 | fn f1 |
8081
| illegal/main.rs:62:17:62:21 | super | illegal/main.rs:1:1:71:1 | mod m1 |
8182
| illegal/main.rs:62:17:62:24 | ...::S | illegal/main.rs:2:5:2:15 | struct S |
8283
| illegal/main.rs:64:13:64:17 | super | illegal/main.rs:1:1:71:1 | mod m1 |

0 commit comments

Comments
 (0)