Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rust: Limit TypePaths to at most length 10 #19035

Merged
merged 1 commit into from
Mar 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
extractionWarning
| loop/main.rs:1:1:1:1 | semantic analyzer unavailable (not included as a module) |
14 changes: 14 additions & 0 deletions rust/ql/test/library-tests/type-inference/loop/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// The code in this file is not valid Rust code, but it is used to test that
// our type inference implementation does not run into an infinite loop.

struct S<T>(T);

trait T1<T>: T2<S<T>> {
fn foo(self) {}
}

trait T2<T>: T1<S<T>> {
fn bar(self) {
self.foo()
}
}
1 change: 1 addition & 0 deletions rust/ql/test/library-tests/type-inference/loop/options.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
qltest_cargo_check: false
39 changes: 39 additions & 0 deletions rust/ql/test/library-tests/type-inference/type-inference.expected
Original file line number Diff line number Diff line change
@@ -1,4 +1,42 @@
inferType
| loop/main.rs:7:12:7:15 | SelfParam | | loop/main.rs:6:1:8:1 | trait T1 |
| loop/main.rs:7:12:7:15 | SelfParam | T | loop/main.rs:6:10:6:10 | T |
| loop/main.rs:11:12:11:15 | SelfParam | | loop/main.rs:6:1:8:1 | trait T1 |
| loop/main.rs:11:12:11:15 | SelfParam | | loop/main.rs:10:1:14:1 | trait T2 |
| loop/main.rs:11:12:11:15 | SelfParam | T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:11:12:11:15 | SelfParam | T | loop/main.rs:10:10:10:10 | T |
| loop/main.rs:11:12:11:15 | SelfParam | T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:11:12:11:15 | SelfParam | T.T | loop/main.rs:10:10:10:10 | T |
| loop/main.rs:11:12:11:15 | SelfParam | T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:11:12:11:15 | SelfParam | T.T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:11:12:11:15 | SelfParam | T.T.T.T | loop/main.rs:10:10:10:10 | T |
| loop/main.rs:11:12:11:15 | SelfParam | T.T.T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:11:12:11:15 | SelfParam | T.T.T.T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:11:12:11:15 | SelfParam | T.T.T.T.T.T | loop/main.rs:10:10:10:10 | T |
| loop/main.rs:11:12:11:15 | SelfParam | T.T.T.T.T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:11:12:11:15 | SelfParam | T.T.T.T.T.T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:11:12:11:15 | SelfParam | T.T.T.T.T.T.T.T | loop/main.rs:10:10:10:10 | T |
| loop/main.rs:11:12:11:15 | SelfParam | T.T.T.T.T.T.T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:11:12:11:15 | SelfParam | T.T.T.T.T.T.T.T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:11:12:11:15 | SelfParam | T.T.T.T.T.T.T.T.T.T | loop/main.rs:10:10:10:10 | T |
| loop/main.rs:12:9:12:12 | self | | loop/main.rs:6:1:8:1 | trait T1 |
| loop/main.rs:12:9:12:12 | self | | loop/main.rs:10:1:14:1 | trait T2 |
| loop/main.rs:12:9:12:12 | self | T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:12:9:12:12 | self | T | loop/main.rs:10:10:10:10 | T |
| loop/main.rs:12:9:12:12 | self | T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:12:9:12:12 | self | T.T | loop/main.rs:10:10:10:10 | T |
| loop/main.rs:12:9:12:12 | self | T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:12:9:12:12 | self | T.T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:12:9:12:12 | self | T.T.T.T | loop/main.rs:10:10:10:10 | T |
| loop/main.rs:12:9:12:12 | self | T.T.T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:12:9:12:12 | self | T.T.T.T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:12:9:12:12 | self | T.T.T.T.T.T | loop/main.rs:10:10:10:10 | T |
| loop/main.rs:12:9:12:12 | self | T.T.T.T.T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:12:9:12:12 | self | T.T.T.T.T.T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:12:9:12:12 | self | T.T.T.T.T.T.T.T | loop/main.rs:10:10:10:10 | T |
| loop/main.rs:12:9:12:12 | self | T.T.T.T.T.T.T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:12:9:12:12 | self | T.T.T.T.T.T.T.T.T.T | loop/main.rs:4:1:4:15 | struct S |
| loop/main.rs:12:9:12:12 | self | T.T.T.T.T.T.T.T.T.T | loop/main.rs:10:10:10:10 | T |
| main.rs:5:19:5:22 | SelfParam | | main.rs:2:5:2:21 | struct Foo |
| main.rs:5:33:7:9 | { ... } | | main.rs:2:5:2:21 | struct Foo |
| main.rs:6:13:6:16 | self | | main.rs:2:5:2:21 | struct Foo |
Expand Down Expand Up @@ -783,6 +821,7 @@ inferType
| main.rs:582:11:582:20 | ...::Foo {...} | | main.rs:2:5:2:21 | struct Foo |
| main.rs:582:23:582:32 | ...::Foo {...} | | main.rs:2:5:2:21 | struct Foo |
resolveMethodCallExpr
| loop/main.rs:12:9:12:18 | self.foo(...) | loop/main.rs:7:5:7:19 | fn foo |
| main.rs:23:9:23:14 | x.m1(...) | main.rs:5:9:7:9 | fn m1 |
| main.rs:24:9:24:14 | y.m2(...) | main.rs:9:9:11:9 | fn m2 |
| main.rs:67:26:67:31 | x.m2(...) | main.rs:52:9:54:9 | fn m2 |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,15 @@ signature module InputSig1<LocationSig Location> {
predicate typeArgumentParameterPositionMatch(
TypeArgumentPosition tapos, TypeParameterPosition tppos
);

/**
* Gets the limit on the length of type paths. Set to `none()` if there should
* be no limit.
*
* Having a limit can be useful to avoid inifinite recursion on malformed
* programs.
*/
default int getTypePathLimit() { result = 10 }
}

module Make1<LocationSig Location, InputSig1<Location> Input1> {
Expand Down Expand Up @@ -143,6 +152,15 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
/** Holds if this type path is empty. */
predicate isEmpty() { this = "" }

/** Gets the length of this path. */
bindingset[this]
pragma[inline_late]
int length() {
this.isEmpty() and result = 0
or
result = strictcount(this.indexOf(".")) + 1
}

/** Gets the path obtained by appending `suffix` onto this path. */
bindingset[suffix, result]
bindingset[this, result]
Expand All @@ -153,7 +171,10 @@ module Make1<LocationSig Location, InputSig1<Location> Input1> {
else
if suffix.isEmpty()
then result = this
else result = this + "." + suffix
else (
result = this + "." + suffix and
not result.length() > getTypePathLimit()
)
}

/** Holds if this path starts with `tp`, followed by `suffix`. */
Expand Down
Loading