From d15d2d9091a7dcca914423bdbe4bd33d71530a37 Mon Sep 17 00:00:00 2001 From: Simon Friis Vindum Date: Thu, 11 Sep 2025 14:47:34 +0200 Subject: [PATCH] Rust: Block non-numeric types for number literals --- .../rust/frameworks/stdlib/Builtins.qll | 35 +++++++++++-------- rust/ql/lib/codeql/rust/internal/Type.qll | 2 ++ .../codeql/rust/internal/TypeInference.qll | 15 ++++++-- 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/rust/ql/lib/codeql/rust/frameworks/stdlib/Builtins.qll b/rust/ql/lib/codeql/rust/frameworks/stdlib/Builtins.qll index 0c4999bba5e7..965bc0e41960 100644 --- a/rust/ql/lib/codeql/rust/frameworks/stdlib/Builtins.qll +++ b/rust/ql/lib/codeql/rust/frameworks/stdlib/Builtins.qll @@ -46,72 +46,79 @@ class Str extends BuiltinType { Str() { this.getName() = "str" } } +/** + * A numeric type. + * + * See: https://doc.rust-lang.org/reference/types/numeric.html + */ +abstract class NumericType extends BuiltinType { } + /** The builtin `i8` type. */ -class I8 extends BuiltinType { +class I8 extends NumericType { I8() { this.getName() = "i8" } } /** The builtin `i16` type. */ -class I16 extends BuiltinType { +class I16 extends NumericType { I16() { this.getName() = "i16" } } /** The builtin `i32` type. */ -class I32 extends BuiltinType { +class I32 extends NumericType { I32() { this.getName() = "i32" } } /** The builtin `i64` type. */ -class I64 extends BuiltinType { +class I64 extends NumericType { I64() { this.getName() = "i64" } } /** The builtin `i128` type. */ -class I128 extends BuiltinType { +class I128 extends NumericType { I128() { this.getName() = "i128" } } /** The builtin `u8` type. */ -class U8 extends BuiltinType { +class U8 extends NumericType { U8() { this.getName() = "u8" } } /** The builtin `u16` type. */ -class U16 extends BuiltinType { +class U16 extends NumericType { U16() { this.getName() = "u16" } } /** The builtin `u32` type. */ -class U32 extends BuiltinType { +class U32 extends NumericType { U32() { this.getName() = "u32" } } /** The builtin `u64` type. */ -class U64 extends BuiltinType { +class U64 extends NumericType { U64() { this.getName() = "u64" } } /** The builtin `u128` type. */ -class U128 extends BuiltinType { +class U128 extends NumericType { U128() { this.getName() = "u128" } } /** The builtin `usize` type. */ -class Usize extends BuiltinType { +class Usize extends NumericType { Usize() { this.getName() = "usize" } } /** The builtin `isize` type. */ -class Isize extends BuiltinType { +class Isize extends NumericType { Isize() { this.getName() = "isize" } } /** The builtin `f32` type. */ -class F32 extends BuiltinType { +class F32 extends NumericType { F32() { this.getName() = "f32" } } /** The builtin `f64` type. */ -class F64 extends BuiltinType { +class F64 extends NumericType { F64() { this.getName() = "f64" } } diff --git a/rust/ql/lib/codeql/rust/internal/Type.qll b/rust/ql/lib/codeql/rust/internal/Type.qll index eaa7e83fc6da..231078613174 100644 --- a/rust/ql/lib/codeql/rust/internal/Type.qll +++ b/rust/ql/lib/codeql/rust/internal/Type.qll @@ -146,6 +146,8 @@ class StructType extends StructOrEnumType, TStruct { StructType() { this = TStruct(struct) } + Struct asStruct() { result = struct } + override ItemNode asItemNode() { result = struct } override StructField getStructField(string name) { result = struct.getStructField(name) } diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 5342bf335da6..4a89f86205aa 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -500,10 +500,10 @@ module CertainTypeInference { } private Type inferLogicalOperationType(AstNode n, TypePath path) { - exists(Builtins::Bool t, BinaryLogicalOperation be | + exists(BinaryLogicalOperation be | n = [be, be.getLhs(), be.getRhs()] and path.isEmpty() and - result = TStruct(t) + result.(StructType).asStruct() instanceof Builtins::Bool ) } @@ -1467,6 +1467,11 @@ private Type inferLiteralType(LiteralExpr le, TypePath path, boolean certain) { certain = true } +predicate uncertainNumberLiteral(LiteralExpr le) { + le instanceof NumberLiteralExpr and + not CertainTypeInference::hasInferredCertainType(le) +} + pragma[nomagic] private TraitType getFutureTraitType() { result.getTrait() instanceof FutureTrait } @@ -2433,6 +2438,12 @@ private module Cached { then not CertainTypeInference::certainTypeConflict(n, path, result) else any() ) and + // Don't infer non-numerical types for number literals. + ( + if uncertainNumberLiteral(n) + then result.(StructType).asStruct() instanceof Builtins::NumericType and path.isEmpty() + else any() + ) and ( result = inferAssignmentOperationType(n, path) or