Skip to content
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
23 changes: 10 additions & 13 deletions rust/ql/lib/codeql/rust/elements/internal/LiteralExprImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,14 @@ module Impl {
/**
* A number literal.
*/
abstract class NumberLiteralExpr extends LiteralExpr { }
abstract class NumberLiteralExpr extends LiteralExpr {
/**
* Get the suffix of this number literal, if any.
*
* For example, `42u8` has the suffix `u8`.
*/
abstract string getSuffix();
}

// https://doc.rust-lang.org/reference/tokens.html#integer-literals
private module IntegerLiteralRegexs {
Expand Down Expand Up @@ -126,12 +133,7 @@ module Impl {
class IntegerLiteralExpr extends NumberLiteralExpr {
IntegerLiteralExpr() { this.getTextValue().regexpMatch(IntegerLiteralRegexs::integerLiteral()) }

/**
* Get the suffix of this integer literal, if any.
*
* For example, `42u8` has the suffix `u8`.
*/
string getSuffix() {
override string getSuffix() {
exists(string s, string reg |
s = this.getTextValue() and
reg = IntegerLiteralRegexs::integerLiteral() and
Expand Down Expand Up @@ -193,12 +195,7 @@ module Impl {
not this instanceof IntegerLiteralExpr
}

/**
* Get the suffix of this floating-point literal, if any.
*
* For example, `42.0f32` has the suffix `f32`.
*/
string getSuffix() {
override string getSuffix() {
exists(string s, string reg |
reg =
IntegerLiteralRegexs::paren(FloatLiteralRegexs::floatLiteralSuffix1()) + "|" +
Expand Down
117 changes: 117 additions & 0 deletions rust/ql/lib/codeql/rust/frameworks/stdlib/Bultins.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/**
* Provides classes for builtins.
*/

private import rust

/** The folder containing builtins. */
class BuiltinsFolder extends Folder {
BuiltinsFolder() {
this.getBaseName() = "builtins" and
this.getParentContainer().getBaseName() = "tools"
}
}

private class BuiltinsTypesFile extends File {
BuiltinsTypesFile() {
this.getBaseName() = "types.rs" and
this.getParentContainer() instanceof BuiltinsFolder
}
}

/**
* A builtin type, such as `bool` and `i32`.
*
* Builtin types are represented as structs.
*/
class BuiltinType extends Struct {
BuiltinType() { this.getFile() instanceof BuiltinsTypesFile }

/** Gets the name of this type. */
string getName() { result = super.getName().getText() }
}

/** The builtin `bool` type. */
class Bool extends BuiltinType {
Bool() { this.getName() = "bool" }
}

/** The builtin `char` type. */
class Char extends BuiltinType {
Char() { this.getName() = "char" }
}

/** The builtin `str` type. */
class Str extends BuiltinType {
Str() { this.getName() = "str" }
}

/** The builtin `i8` type. */
class I8 extends BuiltinType {
I8() { this.getName() = "i8" }
}

/** The builtin `i16` type. */
class I16 extends BuiltinType {
I16() { this.getName() = "i16" }
}

/** The builtin `i32` type. */
class I32 extends BuiltinType {
I32() { this.getName() = "i32" }
}

/** The builtin `i64` type. */
class I64 extends BuiltinType {
I64() { this.getName() = "i64" }
}

/** The builtin `i128` type. */
class I128 extends BuiltinType {
I128() { this.getName() = "i128" }
}

/** The builtin `u8` type. */
class U8 extends BuiltinType {
U8() { this.getName() = "u8" }
}

/** The builtin `u16` type. */
class U16 extends BuiltinType {
U16() { this.getName() = "u16" }
}

/** The builtin `u32` type. */
class U32 extends BuiltinType {
U32() { this.getName() = "u32" }
}

/** The builtin `u64` type. */
class U64 extends BuiltinType {
U64() { this.getName() = "u64" }
}

/** The builtin `u128` type. */
class U128 extends BuiltinType {
U128() { this.getName() = "u128" }
}

/** The builtin `usize` type. */
class Usize extends BuiltinType {
Usize() { this.getName() = "usize" }
}

/** The builtin `isize` type. */
class Isize extends BuiltinType {
Isize() { this.getName() = "isize" }
}

/** The builtin `f32` type. */
class F32 extends BuiltinType {
F32() { this.getName() = "f32" }
}

/** The builtin `f64` type. */
class F64 extends BuiltinType {
F64() { this.getName() = "f64" }
}
17 changes: 17 additions & 0 deletions rust/ql/lib/codeql/rust/internal/PathResolution.qll
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ abstract class ItemNode extends Locatable {
or
preludeEdge(this, name, result) and not declares(this, _, name)
or
builtinEdge(this, name, result)
or
name = "super" and
if this instanceof Module or this instanceof SourceFile
then result = this.getImmediateParentModule()
Expand Down Expand Up @@ -1184,6 +1186,21 @@ private predicate preludeEdge(SourceFile f, string name, ItemNode i) {
)
}

private import codeql.rust.frameworks.stdlib.Bultins as Builtins

pragma[nomagic]
private predicate builtinEdge(ModuleLikeNode m, string name, ItemNode i) {
(
m instanceof SourceFile
or
m = any(CrateItemNode c).getModuleNode()
) and
exists(SourceFileItemNode builtins |
builtins.getFile().getParentContainer() instanceof Builtins::BuiltinsFolder and
i = builtins.getASuccessorRec(name)
)
}

/** Provides predicates for debugging the path resolution implementation. */
private module Debug {
private Locatable getRelevantLocatable() {
Expand Down
33 changes: 33 additions & 0 deletions rust/ql/lib/codeql/rust/internal/TypeInference.qll
Original file line number Diff line number Diff line change
Expand Up @@ -885,6 +885,36 @@ private Type inferTryExprType(TryExpr te, TypePath path) {
)
}

private import codeql.rust.frameworks.stdlib.Bultins as Builtins

pragma[nomagic]
private StructType inferLiteralType(LiteralExpr le) {
exists(Builtins::BuiltinType t | result = TStruct(t) |
le instanceof CharLiteralExpr and
t instanceof Builtins::Char
or
le instanceof StringLiteralExpr and
t instanceof Builtins::Str
or
le =
any(NumberLiteralExpr ne |
t.getName() = ne.getSuffix()
or
not exists(ne.getSuffix()) and
(
ne instanceof IntegerLiteralExpr and
t instanceof Builtins::I32
or
ne instanceof FloatLiteralExpr and
t instanceof Builtins::F64
)
)
or
le instanceof BooleanLiteralExpr and
t instanceof Builtins::Bool
)
}

cached
private module Cached {
private import codeql.rust.internal.CachedStages
Expand Down Expand Up @@ -1026,6 +1056,9 @@ private module Cached {
result = inferRefExprType(n, path)
or
result = inferTryExprType(n, path)
or
result = inferLiteralType(n) and
path.isEmpty()
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
multiplePathResolutions
| main.rs:532:10:532:18 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:532:10:532:18 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:532:10:532:18 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:532:10:532:18 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:532:10:532:18 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:532:10:532:18 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:532:10:532:18 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:538:10:538:18 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:538:10:538:18 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:538:10:538:18 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:538:10:538:18 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:538:10:538:18 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:538:10:538:18 | ...::from | file://:0:0:0:0 | fn from |
| main.rs:538:10:538:18 | ...::from | file://:0:0:0:0 | fn from |
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ models
| 2 | Summary: lang:core; <crate::option::Option>::unwrap; Argument[self].Field[crate::option::Option::Some(0)]; ReturnValue; value |
| 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 |
| 4 | Summary: lang:core; <crate::result::Result>::unwrap; Argument[self].Field[crate::result::Result::Ok(0)]; ReturnValue; value |
| 5 | Summary: lang:core; crate::ptr::read; Argument[0].Reference; ReturnValue; value |
| 6 | Summary: lang:core; crate::ptr::write; Argument[1]; Argument[0].Reference; value |
| 5 | Summary: lang:core; <i64 as crate::clone::Clone>::clone; Argument[self].Reference; ReturnValue; value |
| 6 | Summary: lang:core; crate::ptr::read; Argument[0].Reference; ReturnValue; value |
| 7 | Summary: lang:core; crate::ptr::write; Argument[1]; Argument[0].Reference; value |
edges
| main.rs:12:9:12:9 | a [Some] | main.rs:13:10:13:19 | a.unwrap() | provenance | MaD:2 |
| main.rs:12:9:12:9 | a [Some] | main.rs:14:13:14:13 | a [Some] | provenance | |
Expand All @@ -22,7 +23,12 @@ edges
| main.rs:21:13:21:13 | a [Ok] | main.rs:21:13:21:21 | a.clone() [Ok] | provenance | generated |
| main.rs:21:13:21:21 | a.clone() [Ok] | main.rs:21:9:21:9 | b [Ok] | provenance | |
| main.rs:26:9:26:9 | a | main.rs:27:10:27:10 | a | provenance | |
| main.rs:26:9:26:9 | a | main.rs:28:13:28:13 | a | provenance | |
| main.rs:26:13:26:22 | source(...) | main.rs:26:9:26:9 | a | provenance | |
| main.rs:28:9:28:9 | b | main.rs:29:10:29:10 | b | provenance | |
| main.rs:28:13:28:13 | a | main.rs:28:13:28:21 | a.clone() | provenance | MaD:5 |
| main.rs:28:13:28:13 | a | main.rs:28:13:28:21 | a.clone() | provenance | generated |
| main.rs:28:13:28:21 | a.clone() | main.rs:28:9:28:9 | b | provenance | |
| main.rs:41:13:41:13 | w [Wrapper] | main.rs:42:15:42:15 | w [Wrapper] | provenance | |
| main.rs:41:17:41:41 | Wrapper {...} [Wrapper] | main.rs:41:13:41:13 | w [Wrapper] | provenance | |
| main.rs:41:30:41:39 | source(...) | main.rs:41:17:41:41 | Wrapper {...} [Wrapper] | provenance | |
Expand All @@ -47,8 +53,8 @@ edges
| main.rs:61:18:61:23 | TuplePat [tuple.1] | main.rs:61:22:61:22 | m | provenance | |
| main.rs:61:22:61:22 | m | main.rs:63:22:63:22 | m | provenance | |
| main.rs:84:29:84:29 | [post] y [&ref] | main.rs:85:33:85:33 | y [&ref] | provenance | |
| main.rs:84:32:84:41 | source(...) | main.rs:84:29:84:29 | [post] y [&ref] | provenance | MaD:6 |
| main.rs:85:33:85:33 | y [&ref] | main.rs:85:18:85:34 | ...::read(...) | provenance | MaD:5 |
| main.rs:84:32:84:41 | source(...) | main.rs:84:29:84:29 | [post] y [&ref] | provenance | MaD:7 |
| main.rs:85:33:85:33 | y [&ref] | main.rs:85:18:85:34 | ...::read(...) | provenance | MaD:6 |
nodes
| main.rs:12:9:12:9 | a [Some] | semmle.label | a [Some] |
| main.rs:12:13:12:28 | Some(...) [Some] | semmle.label | Some(...) [Some] |
Expand All @@ -69,6 +75,10 @@ nodes
| main.rs:26:9:26:9 | a | semmle.label | a |
| main.rs:26:13:26:22 | source(...) | semmle.label | source(...) |
| main.rs:27:10:27:10 | a | semmle.label | a |
| main.rs:28:9:28:9 | b | semmle.label | b |
| main.rs:28:13:28:13 | a | semmle.label | a |
| main.rs:28:13:28:21 | a.clone() | semmle.label | a.clone() |
| main.rs:29:10:29:10 | b | semmle.label | b |
| main.rs:41:13:41:13 | w [Wrapper] | semmle.label | w [Wrapper] |
| main.rs:41:17:41:41 | Wrapper {...} [Wrapper] | semmle.label | Wrapper {...} [Wrapper] |
| main.rs:41:30:41:39 | source(...) | semmle.label | source(...) |
Expand Down Expand Up @@ -106,6 +116,7 @@ testFailures
| 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(...) |
| 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(...) |
| 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(...) |
| 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(...) |
| 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(...) |
| 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(...) |
| 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(...) |
Expand Down
2 changes: 1 addition & 1 deletion rust/ql/test/library-tests/dataflow/modeled/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ fn i64_clone() {
let a = source(12);
sink(a); // $ hasValueFlow=12
let b = a.clone();
sink(b); // $ MISSING: hasValueFlow=12 - lack of builtins means that we cannot resolve clone call above, and hence not insert implicit borrow
sink(b); // $ hasValueFlow=12
}

mod my_clone {
Expand Down
12 changes: 8 additions & 4 deletions rust/ql/test/library-tests/path-resolution/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ fn i() {

{
struct Foo {
x: i32,
x: i32, // $ item=i32
} // I30

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

mod m7 {
pub enum MyEnum {
A(i32), // I42
B { x: i32 }, // I43
C, // I44
A(
i32, // $ item=i32
), // I42
B {
x: i32, // $ item=i32
}, // I43
C, // I44
} // I41

#[rustfmt::skip]
Expand Down
6 changes: 3 additions & 3 deletions rust/ql/test/library-tests/path-resolution/my.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ type Result<
>; // my::Result

fn int_div(
x: i32, //
y: i32,
) -> Result<i32> // $ item=my::Result
x: i32, // $ item=i32
y: i32, // $ item=i32
) -> Result<i32> // $ item=my::Result $ item=i32
{
if y == 0 {
return Err("Div by zero".to_string());
Expand Down
Loading