Skip to content

Commit d69e84a

Browse files
committed
Rust: Type inference and path resolution for builtins
1 parent 8ac7503 commit d69e84a

File tree

14 files changed

+656
-274
lines changed

14 files changed

+656
-274
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* Provides classes for builtins.
3+
*/
4+
5+
private import rust
6+
7+
/** The folder containing builtins. */
8+
class BuiltinsFolder extends Folder {
9+
BuiltinsFolder() {
10+
this.getBaseName() = "builtins" and
11+
this.getParentContainer().getBaseName() = "tools"
12+
}
13+
}
14+
15+
private class BuiltinsTypesFile extends File {
16+
BuiltinsTypesFile() {
17+
this.getBaseName() = "types.rs" and
18+
this.getParentContainer() instanceof BuiltinsFolder
19+
}
20+
}
21+
22+
private class BuiltinType extends Struct {
23+
BuiltinType() { this.getFile() instanceof BuiltinsTypesFile }
24+
}
25+
26+
/** The builtin `bool` type. */
27+
class Bool extends BuiltinType {
28+
Bool() { this.getName().getText() = "bool" }
29+
}
30+
31+
/** The builtin `char` type. */
32+
class Char extends BuiltinType {
33+
Char() { this.getName().getText() = "char" }
34+
}
35+
36+
/** The builtin `str` type. */
37+
class Str extends BuiltinType {
38+
Str() { this.getName().getText() = "str" }
39+
}
40+
41+
/** The builtin `i8` type. */
42+
class I8 extends BuiltinType {
43+
I8() { this.getName().getText() = "i8" }
44+
}
45+
46+
/** The builtin `i16` type. */
47+
class I16 extends BuiltinType {
48+
I16() { this.getName().getText() = "i16" }
49+
}
50+
51+
/** The builtin `i32` type. */
52+
class I32 extends BuiltinType {
53+
I32() { this.getName().getText() = "i32" }
54+
}
55+
56+
/** The builtin `i64` type. */
57+
class I64 extends BuiltinType {
58+
I64() { this.getName().getText() = "i64" }
59+
}
60+
61+
/** The builtin `i128` type. */
62+
class I128 extends BuiltinType {
63+
I128() { this.getName().getText() = "i128" }
64+
}
65+
66+
/** The builtin `u8` type. */
67+
class U8 extends BuiltinType {
68+
U8() { this.getName().getText() = "u8" }
69+
}
70+
71+
/** The builtin `u16` type. */
72+
class U16 extends BuiltinType {
73+
U16() { this.getName().getText() = "u16" }
74+
}
75+
76+
/** The builtin `u32` type. */
77+
class U32 extends BuiltinType {
78+
U32() { this.getName().getText() = "u32" }
79+
}
80+
81+
/** The builtin `u64` type. */
82+
class U64 extends BuiltinType {
83+
U64() { this.getName().getText() = "u64" }
84+
}
85+
86+
/** The builtin `u128` type. */
87+
class U128 extends BuiltinType {
88+
U128() { this.getName().getText() = "u128" }
89+
}
90+
91+
/** The builtin `usize` type. */
92+
class USize extends BuiltinType {
93+
USize() { this.getName().getText() = "usize" }
94+
}
95+
96+
/** The builtin `isize` type. */
97+
class ISize extends BuiltinType {
98+
ISize() { this.getName().getText() = "isize" }
99+
}
100+
101+
/** The builtin `f32` type. */
102+
class F32 extends BuiltinType {
103+
F32() { this.getName().getText() = "f32" }
104+
}
105+
106+
/** The builtin `f64` type. */
107+
class F64 extends BuiltinType {
108+
F64() { this.getName().getText() = "f64" }
109+
}

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ abstract class ItemNode extends Locatable {
180180
or
181181
preludeEdge(this, name, result) and not declares(this, _, name)
182182
or
183+
builtinEdge(this, name, result)
184+
or
183185
name = "super" and
184186
if this instanceof Module or this instanceof SourceFile
185187
then result = this.getImmediateParentModule()
@@ -1184,6 +1186,21 @@ private predicate preludeEdge(SourceFile f, string name, ItemNode i) {
11841186
)
11851187
}
11861188

1189+
private import codeql.rust.frameworks.stdlib.Bultins as Builtins
1190+
1191+
pragma[nomagic]
1192+
private predicate builtinEdge(ModuleLikeNode m, string name, ItemNode i) {
1193+
(
1194+
m instanceof SourceFile
1195+
or
1196+
m = any(CrateItemNode c).getModuleNode()
1197+
) and
1198+
exists(SourceFileItemNode builtins |
1199+
builtins.getFile().getParentContainer() instanceof Builtins::BuiltinsFolder and
1200+
i = builtins.getASuccessorRec(name)
1201+
)
1202+
}
1203+
11871204
/** Provides predicates for debugging the path resolution implementation. */
11881205
private module Debug {
11891206
private Locatable getRelevantLocatable() {

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

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,80 @@ private Type inferTryExprType(TryExpr te, TypePath path) {
885885
)
886886
}
887887

888+
private import codeql.rust.frameworks.stdlib.Bultins as Builtins
889+
890+
pragma[nomagic]
891+
private StructType inferLiteralType(LiteralExpr le) {
892+
le instanceof CharLiteralExpr and
893+
result = TStruct(any(Builtins::Char t))
894+
or
895+
le instanceof StringLiteralExpr and
896+
result = TStruct(any(Builtins::Str t))
897+
or
898+
le =
899+
any(IntegerLiteralExpr n |
900+
not exists(n.getSuffix()) and
901+
result = TStruct(any(Builtins::I32 t))
902+
or
903+
n.getSuffix() =
904+
any(string suffix |
905+
suffix = "u8" and
906+
result = TStruct(any(Builtins::U8 t))
907+
or
908+
suffix = "i8" and
909+
result = TStruct(any(Builtins::I8 t))
910+
or
911+
suffix = "u16" and
912+
result = TStruct(any(Builtins::U16 t))
913+
or
914+
suffix = "i16" and
915+
result = TStruct(any(Builtins::I16 t))
916+
or
917+
suffix = "u32" and
918+
result = TStruct(any(Builtins::U32 t))
919+
or
920+
suffix = "i32" and
921+
result = TStruct(any(Builtins::I32 t))
922+
or
923+
suffix = "u64" and
924+
result = TStruct(any(Builtins::U64 t))
925+
or
926+
suffix = "i64" and
927+
result = TStruct(any(Builtins::I64 t))
928+
or
929+
suffix = "u128" and
930+
result = TStruct(any(Builtins::U128 t))
931+
or
932+
suffix = "i128" and
933+
result = TStruct(any(Builtins::I128 t))
934+
or
935+
suffix = "usize" and
936+
result = TStruct(any(Builtins::USize t))
937+
or
938+
suffix = "isize" and
939+
result = TStruct(any(Builtins::ISize t))
940+
)
941+
)
942+
or
943+
le =
944+
any(FloatLiteralExpr n |
945+
not exists(n.getSuffix()) and
946+
result = TStruct(any(Builtins::F32 t))
947+
or
948+
n.getSuffix() =
949+
any(string suffix |
950+
suffix = "f32" and
951+
result = TStruct(any(Builtins::F32 t))
952+
or
953+
suffix = "f64" and
954+
result = TStruct(any(Builtins::F64 t))
955+
)
956+
)
957+
or
958+
le instanceof BooleanLiteralExpr and
959+
result = TStruct(any(Builtins::Bool t))
960+
}
961+
888962
cached
889963
private module Cached {
890964
private import codeql.rust.internal.CachedStages
@@ -1026,6 +1100,9 @@ private module Cached {
10261100
result = inferRefExprType(n, path)
10271101
or
10281102
result = inferTryExprType(n, path)
1103+
or
1104+
result = inferLiteralType(n) and
1105+
path.isEmpty()
10291106
}
10301107
}
10311108

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
multiplePathResolutions
2+
| main.rs:532:10:532:18 | ...::from | file://:0:0:0:0 | fn from |
3+
| main.rs:532:10:532:18 | ...::from | file://:0:0:0:0 | fn from |
4+
| main.rs:532:10:532:18 | ...::from | file://:0:0:0:0 | fn from |
5+
| main.rs:532:10:532:18 | ...::from | file://:0:0:0:0 | fn from |
6+
| main.rs:532:10:532:18 | ...::from | file://:0:0:0:0 | fn from |
7+
| main.rs:532:10:532:18 | ...::from | file://:0:0:0:0 | fn from |
8+
| main.rs:532:10:532:18 | ...::from | file://:0:0:0:0 | fn from |
9+
| main.rs:538:10:538:18 | ...::from | file://:0:0:0:0 | fn from |
10+
| main.rs:538:10:538:18 | ...::from | file://:0:0:0:0 | fn from |
11+
| main.rs:538:10:538:18 | ...::from | file://:0:0:0:0 | fn from |
12+
| main.rs:538:10:538:18 | ...::from | file://:0:0:0:0 | fn from |
13+
| main.rs:538:10:538:18 | ...::from | file://:0:0:0:0 | fn from |
14+
| main.rs:538:10:538:18 | ...::from | file://:0:0:0:0 | fn from |
15+
| main.rs:538:10:538:18 | ...::from | file://:0:0:0:0 | fn from |

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ models
33
| 2 | Summary: lang:core; <crate::option::Option>::unwrap; Argument[self].Field[crate::option::Option::Some(0)]; ReturnValue; value |
44
| 3 | Summary: lang:core; <crate::option::Option>::zip; Argument[0].Field[crate::option::Option::Some(0)]; ReturnValue.Field[crate::option::Option::Some(0)].Field[1]; value |
55
| 4 | Summary: lang:core; <crate::result::Result>::unwrap; Argument[self].Field[crate::result::Result::Ok(0)]; ReturnValue; value |
6-
| 5 | Summary: lang:core; crate::ptr::read; Argument[0].Reference; ReturnValue; value |
7-
| 6 | Summary: lang:core; crate::ptr::write; Argument[1]; Argument[0].Reference; value |
6+
| 5 | Summary: lang:core; <i64 as crate::clone::Clone>::clone; Argument[self].Reference; ReturnValue; value |
7+
| 6 | Summary: lang:core; crate::ptr::read; Argument[0].Reference; ReturnValue; value |
8+
| 7 | Summary: lang:core; crate::ptr::write; Argument[1]; Argument[0].Reference; value |
89
edges
910
| main.rs:12:9:12:9 | a [Some] | main.rs:13:10:13:19 | a.unwrap() | provenance | MaD:2 |
1011
| main.rs:12:9:12:9 | a [Some] | main.rs:14:13:14:13 | a [Some] | provenance | |
@@ -22,7 +23,12 @@ edges
2223
| main.rs:21:13:21:13 | a [Ok] | main.rs:21:13:21:21 | a.clone() [Ok] | provenance | generated |
2324
| main.rs:21:13:21:21 | a.clone() [Ok] | main.rs:21:9:21:9 | b [Ok] | provenance | |
2425
| main.rs:26:9:26:9 | a | main.rs:27:10:27:10 | a | provenance | |
26+
| main.rs:26:9:26:9 | a | main.rs:28:13:28:13 | a | provenance | |
2527
| main.rs:26:13:26:22 | source(...) | main.rs:26:9:26:9 | a | provenance | |
28+
| main.rs:28:9:28:9 | b | main.rs:29:10:29:10 | b | provenance | |
29+
| main.rs:28:13:28:13 | a | main.rs:28:13:28:21 | a.clone() | provenance | MaD:5 |
30+
| main.rs:28:13:28:13 | a | main.rs:28:13:28:21 | a.clone() | provenance | generated |
31+
| main.rs:28:13:28:21 | a.clone() | main.rs:28:9:28:9 | b | provenance | |
2632
| main.rs:41:13:41:13 | w [Wrapper] | main.rs:42:15:42:15 | w [Wrapper] | provenance | |
2733
| main.rs:41:17:41:41 | Wrapper {...} [Wrapper] | main.rs:41:13:41:13 | w [Wrapper] | provenance | |
2834
| main.rs:41:30:41:39 | source(...) | main.rs:41:17:41:41 | Wrapper {...} [Wrapper] | provenance | |
@@ -47,8 +53,8 @@ edges
4753
| main.rs:61:18:61:23 | TuplePat [tuple.1] | main.rs:61:22:61:22 | m | provenance | |
4854
| main.rs:61:22:61:22 | m | main.rs:63:22:63:22 | m | provenance | |
4955
| main.rs:84:29:84:29 | [post] y [&ref] | main.rs:85:33:85:33 | y [&ref] | provenance | |
50-
| main.rs:84:32:84:41 | source(...) | main.rs:84:29:84:29 | [post] y [&ref] | provenance | MaD:6 |
51-
| main.rs:85:33:85:33 | y [&ref] | main.rs:85:18:85:34 | ...::read(...) | provenance | MaD:5 |
56+
| main.rs:84:32:84:41 | source(...) | main.rs:84:29:84:29 | [post] y [&ref] | provenance | MaD:7 |
57+
| main.rs:85:33:85:33 | y [&ref] | main.rs:85:18:85:34 | ...::read(...) | provenance | MaD:6 |
5258
nodes
5359
| main.rs:12:9:12:9 | a [Some] | semmle.label | a [Some] |
5460
| main.rs:12:13:12:28 | Some(...) [Some] | semmle.label | Some(...) [Some] |
@@ -69,6 +75,10 @@ nodes
6975
| main.rs:26:9:26:9 | a | semmle.label | a |
7076
| main.rs:26:13:26:22 | source(...) | semmle.label | source(...) |
7177
| main.rs:27:10:27:10 | a | semmle.label | a |
78+
| main.rs:28:9:28:9 | b | semmle.label | b |
79+
| main.rs:28:13:28:13 | a | semmle.label | a |
80+
| main.rs:28:13:28:21 | a.clone() | semmle.label | a.clone() |
81+
| main.rs:29:10:29:10 | b | semmle.label | b |
7282
| main.rs:41:13:41:13 | w [Wrapper] | semmle.label | w [Wrapper] |
7383
| main.rs:41:17:41:41 | Wrapper {...} [Wrapper] | semmle.label | Wrapper {...} [Wrapper] |
7484
| main.rs:41:30:41:39 | source(...) | semmle.label | source(...) |
@@ -106,6 +116,7 @@ testFailures
106116
| main.rs:20:10:20:19 | a.unwrap() | main.rs:19:34:19:43 | source(...) | main.rs:20:10:20:19 | a.unwrap() | $@ | main.rs:19:34:19:43 | source(...) | source(...) |
107117
| main.rs:22:10:22:19 | b.unwrap() | main.rs:19:34:19:43 | source(...) | main.rs:22:10:22:19 | b.unwrap() | $@ | main.rs:19:34:19:43 | source(...) | source(...) |
108118
| main.rs:27:10:27:10 | a | main.rs:26:13:26:22 | source(...) | main.rs:27:10:27:10 | a | $@ | main.rs:26:13:26:22 | source(...) | source(...) |
119+
| main.rs:29:10:29:10 | b | main.rs:26:13:26:22 | source(...) | main.rs:29:10:29:10 | b | $@ | main.rs:26:13:26:22 | source(...) | source(...) |
109120
| main.rs:43:38:43:38 | n | main.rs:41:30:41:39 | source(...) | main.rs:43:38:43:38 | n | $@ | main.rs:41:30:41:39 | source(...) | source(...) |
110121
| main.rs:47:38:47:38 | n | main.rs:41:30:41:39 | source(...) | main.rs:47:38:47:38 | n | $@ | main.rs:41:30:41:39 | source(...) | source(...) |
111122
| main.rs:63:22:63:22 | m | main.rs:58:22:58:31 | source(...) | main.rs:63:22:63:22 | m | $@ | main.rs:58:22:58:31 | source(...) | source(...) |

rust/ql/test/library-tests/dataflow/modeled/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ fn i64_clone() {
2626
let a = source(12);
2727
sink(a); // $ hasValueFlow=12
2828
let b = a.clone();
29-
sink(b); // $ MISSING: hasValueFlow=12 - lack of builtins means that we cannot resolve clone call above, and hence not insert implicit borrow
29+
sink(b); // $ hasValueFlow=12
3030
}
3131

3232
mod my_clone {

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ fn i() {
7575

7676
{
7777
struct Foo {
78-
x: i32,
78+
x: i32, // $ item=i32
7979
} // I30
8080

8181
let _ = Foo { x: 0 }; // $ item=I30
@@ -121,9 +121,13 @@ mod m6 {
121121

122122
mod m7 {
123123
pub enum MyEnum {
124-
A(i32), // I42
125-
B { x: i32 }, // I43
126-
C, // I44
124+
A(
125+
i32, // $ item=i32
126+
), // I42
127+
B {
128+
x: i32, // $ item=i32
129+
}, // I43
130+
C, // I44
127131
} // I41
128132

129133
#[rustfmt::skip]

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ type Result<
2525
>; // my::Result
2626

2727
fn int_div(
28-
x: i32, //
29-
y: i32,
30-
) -> Result<i32> // $ item=my::Result
28+
x: i32, // $ item=i32
29+
y: i32, // $ item=i32
30+
) -> Result<i32> // $ item=my::Result $ item=i32
3131
{
3232
if y == 0 {
3333
return Err("Div by zero".to_string());

0 commit comments

Comments
 (0)