From a07e357e67b4a7e0f7f405f8d7d29a5391765ba3 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 8 Aug 2025 11:51:48 +0200 Subject: [PATCH] Rust: Distinguish internal/external items in path resolution --- .../lib/codeql/rust/internal/CachedStages.qll | 4 +- .../codeql/rust/internal/PathResolution.qll | 371 ++++++++++-------- .../codeql/rust/internal/TypeInference.qll | 8 +- .../internal/TypeInferenceConsistency.qll | 4 + .../TypeInferenceConsistency.expected | 3 - .../TypeInferenceConsistency.expected | 4 - .../PathResolutionConsistency.expected | 15 - .../PathResolutionConsistency.expected | 6 - 8 files changed, 223 insertions(+), 192 deletions(-) delete mode 100644 rust/ql/test/query-tests/security/CWE-089/CONSISTENCY/TypeInferenceConsistency.expected delete mode 100644 rust/ql/test/query-tests/security/CWE-312/CONSISTENCY/TypeInferenceConsistency.expected diff --git a/rust/ql/lib/codeql/rust/internal/CachedStages.qll b/rust/ql/lib/codeql/rust/internal/CachedStages.qll index ad011a753c89..c2dc21661783 100644 --- a/rust/ql/lib/codeql/rust/internal/CachedStages.qll +++ b/rust/ql/lib/codeql/rust/internal/CachedStages.qll @@ -120,9 +120,7 @@ module Stages { or exists(resolvePath(_)) or - exists(any(ItemNode i).getASuccessor(_)) - or - exists(any(ItemNode i).getASuccessorRec(_)) + exists(any(ItemNode i).getASuccessor(_, _)) or exists(any(ImplOrTraitItemNode i).getASelfPath()) or diff --git a/rust/ql/lib/codeql/rust/internal/PathResolution.qll b/rust/ql/lib/codeql/rust/internal/PathResolution.qll index 354cab5a6de9..0af75f380b94 100644 --- a/rust/ql/lib/codeql/rust/internal/PathResolution.qll +++ b/rust/ql/lib/codeql/rust/internal/PathResolution.qll @@ -32,13 +32,71 @@ final class Namespace extends TNamespace { } } +private newtype TSuccessorKind = + TInternal() or + TExternal() or + TBoth() + +/** A successor kind. */ +class SuccessorKind extends TSuccessorKind { + predicate isInternal() { this = TInternal() } + + predicate isExternal() { this = TExternal() } + + predicate isBoth() { this = TBoth() } + + predicate isInternalOrBoth() { this.isInternal() or this.isBoth() } + + predicate isExternalOrBoth() { this.isExternal() or this.isBoth() } + + string toString() { + this.isInternal() and result = "internal" + or + this.isExternal() and result = "external" + or + this.isBoth() and result = "both" + } +} + +pragma[nomagic] +private ItemNode getAChildSuccessor(ItemNode item, string name, SuccessorKind kind) { + item = result.getImmediateParent() and + name = result.getName() and + ( + // type parameters are only available inside the declaring item + if result instanceof TypeParam + then kind.isInternal() + else + // associated items must always be qualified, also within the declaring + // item (using `Self`) + if item instanceof ImplOrTraitItemNode and result instanceof AssocItem + then kind.isExternal() + else + if result instanceof Use + then kind.isInternal() + else kind.isBoth() + ) +} + /** * An item that may be referred to by a path, and which is a node in * the _item graph_. * * The item graph is a labeled directed graph, where an edge - * `item1 --name--> item2` means that `item2` is available inside the - * scope of `item1` under the name `name`. For example, if we have + * + * ``` + * item1 --name,kind--> item2 + * ``` + * + * means that: + * + * - `item2` is available _inside_ the scope of `item1` under the name `name`, + * when `kind` is either `internal` or `both`, and + * + * - `item2` is available _externally_ from `item1` under the name `name`, when + * `kind` is either `external` or `both`. + * + * For example, if we have * * ```rust * mod m1 { @@ -46,10 +104,10 @@ final class Namespace extends TNamespace { * } * ``` * - * then there is an edge `m1 --m2--> m1::m2`. + * then there is an edge `m1 --m2,both--> m1::m2`. * * Source files are also considered nodes in the item graph, and for - * each source file `f` there is an edge `f --name--> item` when `f` + * each source file `f` there is an edge `f --name,both--> item` when `f` * declares `item` with the name `name`. * * For imports like @@ -61,11 +119,13 @@ final class Namespace extends TNamespace { * } * ``` * - * we first generate an edge `m1::m2 --name--> f::item`, where `item` is - * any item (named `name`) inside the imported source file `f`. Using this - * edge, `m2::foo` can resolve to `f::foo`, which results in the edge - * `m1::use m2 --foo--> f::foo`. Lastly, all edges out of `use` nodes are - * lifted to predecessors in the graph, so we get an edge `m1 --foo--> f::foo`. + * we first generate an edge `m1::m2 --name,kind--> f::item`, where `item` is + * any item (named `name`) inside the imported source file `f`, and `kind` is + * either `external` or `both`. Using this edge, `m2::foo` can resolve to + * `f::foo`, which results in the edge `m1::use m2 --foo,internal--> f::foo` + * (would have been `external` if it was `pub use m2::foo`). Lastly, all edges + * out of `use` nodes are lifted to predecessors in the graph, so we get + * an edge `m1 --foo,internal--> f::foo`. * * * References: @@ -112,42 +172,40 @@ abstract class ItemNode extends Locatable { result = this.(SourceFileItemNode).getSuper() } - pragma[nomagic] - private ItemNode getAChildSuccessor(string name) { - this = result.getImmediateParent() and - name = result.getName() - } - + /** Gets a successor named `name` of the given `kind`, if any. */ cached - ItemNode getASuccessorRec(string name) { + ItemNode getASuccessor(string name, SuccessorKind kind) { Stages::PathResolutionStage::ref() and - sourceFileEdge(this, name, result) + sourceFileEdge(this, name, result) and + kind.isBoth() or - result = this.getAChildSuccessor(name) + result = getAChildSuccessor(this, name, kind) or - fileImportEdge(this, name, result) + fileImportEdge(this, name, result, kind) or - useImportEdge(this, name, result) + useImportEdge(this, name, result, kind) or - crateDefEdge(this, name, result) + crateDefEdge(this, name, result, kind) or - crateDependencyEdge(this, name, result) + crateDependencyEdge(this, name, result) and + kind.isInternal() or - externCrateEdge(this, name, result) + externCrateEdge(this, name, result) and + kind.isInternal() or // items made available through `use` are available to nodes that contain the `use` exists(UseItemNode use | - use = this.getASuccessorRec(_) and - result = use.(ItemNode).getASuccessorRec(name) + use = this.getASuccessor(_, _) and + result = use.(ItemNode).getASuccessor(name, kind) ) or - exists(ExternCrateItemNode ec | result = ec.(ItemNode).getASuccessorRec(name) | - ec = this.getASuccessorRec(_) + exists(ExternCrateItemNode ec | result = ec.(ItemNode).getASuccessor(name, kind) | + ec = this.getASuccessor(_, _) or // if the extern crate appears in the crate root, then the crate name is also added // to the 'extern prelude', see https://doc.rust-lang.org/reference/items/extern-crates.html exists(Crate c | - ec = c.getSourceFile().(ItemNode).getASuccessorRec(_) and + ec = c.getSourceFile().(ItemNode).getASuccessor(_, _) and this = c.getASourceFile() ) ) @@ -155,7 +213,8 @@ abstract class ItemNode extends Locatable { // a trait has access to the associated items of its supertraits this = any(TraitItemNode trait | - result = trait.resolveABound().getASuccessorRec(name) and + result = trait.resolveABound().getASuccessor(name, kind) and + kind.isExternalOrBoth() and result instanceof AssocItemNode and not trait.hasAssocItem(name) ) @@ -163,50 +222,39 @@ abstract class ItemNode extends Locatable { // items made available by an implementation where `this` is the implementing type exists(ItemNode node | this = node.(ImplItemNode).resolveSelfTy() and - result = node.getASuccessorRec(name) and - result instanceof AssocItemNode and - not result instanceof TypeAlias + result = node.getASuccessor(name, kind) and + kind.isExternalOrBoth() and + result instanceof AssocItemNode ) or // trait items with default implementations made available in an implementation exists(ImplItemNode impl, ItemNode trait | this = impl and trait = impl.resolveTraitTy() and - result = trait.getASuccessorRec(name) and + result = trait.getASuccessor(name, kind) and result.(AssocItemNode).hasImplementation() and + kind.isExternalOrBoth() and not impl.hasAssocItem(name) ) or // type parameters have access to the associated items of its bounds - result = this.(TypeParamItemNode).resolveABound().getASuccessorRec(name).(AssocItemNode) + result = this.(TypeParamItemNode).resolveABound().getASuccessor(name, kind).(AssocItemNode) and + kind.isExternalOrBoth() or - result = this.(ImplTraitTypeReprItemNode).resolveABound().getASuccessorRec(name).(AssocItemNode) + result = + this.(ImplTraitTypeReprItemNode).resolveABound().getASuccessor(name, kind).(AssocItemNode) and + kind.isExternalOrBoth() or - result = this.(TypeAliasItemNode).resolveAlias().getASuccessorRec(name) and - // type parameters defined in the RHS are not available in the LHS - not result instanceof TypeParam - } - - /** - * Gets a successor named `name` of this item, if any. - * - * Whenever a function exists in both source code and in library code, - * both are included - */ - cached - ItemNode getASuccessor(string name) { - Stages::PathResolutionStage::ref() and - result = this.getASuccessorRec(name) - or - preludeEdge(this, name, result) - or - this instanceof SourceFile and - builtin(name, result) + result = this.(TypeAliasItemNode).resolveAlias().getASuccessor(name, kind) and + kind.isExternalOrBoth() or name = "super" and if this instanceof Module or this instanceof SourceFile - then result = this.getImmediateParentModule() - else result = this.getImmediateParentModule().getImmediateParentModule() + then ( + kind.isBoth() and result = this.getImmediateParentModule() + ) else ( + kind.isInternal() and result = this.getImmediateParentModule().getImmediateParentModule() + ) or name = "self" and if @@ -214,51 +262,40 @@ abstract class ItemNode extends Locatable { this instanceof Enum or this instanceof Struct or this instanceof Crate - then result = this - else result = this.getImmediateParentModule() - or - name = "Self" and - this = result.(ImplOrTraitItemNode).getAnItemInSelfScope() - or - name = "crate" and - this = result.(CrateItemNode).getASourceFile() + then ( + kind.isBoth() and + result = this + ) else ( + kind.isInternal() and + result = this.getImmediateParentModule() + ) or - // todo: implement properly - name = "$crate" and - result = any(CrateItemNode crate | this = crate.getASourceFile()).(Crate).getADependency*() and - result.(CrateItemNode).isPotentialDollarCrateTarget() - } - - /** - * Holds if the successor `item` with the name `name` is not available locally - * for unqualified paths. - * - * This has the effect that a path of the form `name` inside `this` will not - * resolve to `item`. - */ - pragma[nomagic] - predicate excludedLocally(string name, ItemNode item) { - // Associated items in an impl or trait block are not directly available - // inside the block, they require a qualified path with a `Self` prefix. - item = this.getAChildSuccessor(name) and - this instanceof ImplOrTraitItemNode and - item instanceof AssocItemNode + kind.isInternal() and + ( + preludeEdge(this, name, result) + or + this instanceof SourceFile and + builtin(name, result) + or + name = "Self" and + this = result.(ImplOrTraitItemNode).getAnItemInSelfScope() + or + name = "crate" and + this = result.(CrateItemNode).getASourceFile() + or + // todo: implement properly + name = "$crate" and + result = any(CrateItemNode crate | this = crate.getASourceFile()).(Crate).getADependency*() and + result.(CrateItemNode).isPotentialDollarCrateTarget() + ) } - /** - * Holds if the successor `item` with the name `name` is not available - * externally for qualified paths that resolve to this item. - * - * This has the effect that a path of the form `Qualifier::name`, where - * `Qualifier` resolves to this item, will not resolve to `item`. - */ - pragma[nomagic] - predicate excludedExternally(string name, ItemNode item) { - // Type parameters for an `impl` or trait block are not available outside of - // the block. - item = this.getAChildSuccessor(name) and - this instanceof ImplOrTraitItemNode and - item instanceof TypeParamItemNode + /** Gets an _external_ successor named `name`, if any. */ + ItemNode getASuccessor(string name) { + exists(SuccessorKind kind | + result = this.getASuccessor(name, kind) and + kind.isExternalOrBoth() + ) } /** Holds if this item has a canonical path belonging to the crate `c`. */ @@ -552,7 +589,7 @@ abstract class ImplOrTraitItemNode extends ItemNode { Path getASelfPath() { Stages::PathResolutionStage::ref() and isUnqualifiedSelfPath(result) and - this = unqualifiedPathLookup(result, _) + this = unqualifiedPathLookup(result, _, _) } /** Gets an associated item belonging to this trait or `impl` block. */ @@ -580,7 +617,7 @@ class ImplItemNode extends ImplOrTraitItemNode instanceof Impl { Path getTraitPath() { result = super.getTrait().(PathTypeRepr).getPath() } - ItemNode resolveSelfTy() { result = resolvePath(this.getSelfPath()) } + TypeItemNode resolveSelfTy() { result = resolvePath(this.getSelfPath()) } TraitItemNode resolveTraitTy() { result = resolvePath(this.getTraitPath()) } @@ -669,7 +706,7 @@ class ImplItemNode extends ImplOrTraitItemNode instanceof Impl { } } -private class ImplTraitTypeReprItemNode extends ItemNode instanceof ImplTraitTypeRepr { +private class ImplTraitTypeReprItemNode extends TypeItemNode instanceof ImplTraitTypeRepr { pragma[nomagic] Path getABoundPath() { result = super.getTypeBoundList().getABound().getTypeRepr().(PathTypeRepr).getPath() @@ -1090,10 +1127,10 @@ predicate fileImport(Module m, SourceFile f) { * in scope under the name `name`. */ pragma[nomagic] -private predicate fileImportEdge(Module mod, string name, ItemNode item) { +private predicate fileImportEdge(Module mod, string name, ItemNode item, SuccessorKind kind) { exists(SourceFileItemNode f | fileImport(mod, f) and - item = f.getASuccessorRec(name) + item = f.getASuccessor(name, kind) ) } @@ -1101,9 +1138,9 @@ private predicate fileImportEdge(Module mod, string name, ItemNode item) { * Holds if crate `c` defines the item `i` named `name`. */ pragma[nomagic] -private predicate crateDefEdge(CrateItemNode c, string name, ItemNode i) { - i = c.getSourceFile().getASuccessorRec(name) and - not i instanceof Crate +private predicate crateDefEdge(CrateItemNode c, string name, ItemNode i, SuccessorKind kind) { + i = c.getSourceFile().getASuccessor(name, kind) and + kind.isExternalOrBoth() } private class BuiltinSourceFile extends SourceFileItemNode { @@ -1116,11 +1153,6 @@ private class BuiltinSourceFile extends SourceFileItemNode { pragma[nomagic] private predicate crateDependencyEdge(SourceFileItemNode file, string name, CrateItemNode dep) { exists(CrateItemNode c | dep = c.(Crate).getDependency(name) | file = c.getASourceFile()) - or - // Give builtin files access to `std` - file instanceof BuiltinSourceFile and - dep.getName() = name and - name = "std" } private predicate useTreeDeclares(UseTree tree, string name) { @@ -1147,12 +1179,13 @@ private predicate useTreeDeclares(UseTree tree, string name) { */ pragma[nomagic] private predicate declares(ItemNode item, Namespace ns, string name) { - exists(ItemNode child | child.getImmediateParent() = item | - child.getName() = name and + exists(ItemNode child, SuccessorKind kind | child = getAChildSuccessor(item, name, kind) | child.getNamespace() = ns and - // If `item` is excluded locally then it does not declare `name`. - not item.excludedLocally(name, child) - or + kind.isInternalOrBoth() + ) + or + exists(ItemNode child | + child.getImmediateParent() = item and useTreeDeclares(child.(Use).getUseTree(), name) and exists(ns) // `use foo::bar` can refer to both a value and a type ) @@ -1224,8 +1257,8 @@ private predicate unqualifiedPathLookup(ItemNode encl, string name, Namespace ns } pragma[nomagic] -private ItemNode getASuccessor(ItemNode pred, string name, Namespace ns) { - result = pred.getASuccessor(name) and +private ItemNode getASuccessor(ItemNode pred, string name, Namespace ns, SuccessorKind kind) { + result = pred.getASuccessor(name, kind) and ns = result.getNamespace() } @@ -1258,9 +1291,10 @@ private predicate keywordLookup(ItemNode encl, string name, RelevantPath p) { } pragma[nomagic] -private ItemNode unqualifiedPathLookup(RelevantPath p, Namespace ns) { +private ItemNode unqualifiedPathLookup(RelevantPath p, Namespace ns, SuccessorKind kind) { exists(ItemNode encl, string name | - result = getASuccessor(encl, name, ns) and not encl.excludedLocally(name, result) + result = getASuccessor(encl, name, ns, kind) and + kind.isInternalOrBoth() | unqualifiedPathLookup(encl, name, ns, p) or @@ -1272,9 +1306,9 @@ pragma[nomagic] private predicate isUnqualifiedSelfPath(RelevantPath path) { path.isUnqualified("Self") } pragma[nomagic] -private ItemNode resolvePath0(RelevantPath path, Namespace ns) { +private ItemNode resolvePath0(RelevantPath path, Namespace ns, SuccessorKind kind) { exists(ItemNode res | - res = unqualifiedPathLookup(path, ns) and + res = unqualifiedPathLookup(path, ns, kind) and if not any(RelevantPath parent).getQualifier() = path and isUnqualifiedSelfPath(path) and @@ -1285,11 +1319,11 @@ private ItemNode resolvePath0(RelevantPath path, Namespace ns) { or exists(ItemNode q, string name | q = resolvePathQualifier(path, name) and - result = getASuccessor(q, name, ns) and - not q.excludedExternally(name, result) + result = getASuccessor(q, name, ns, kind) and + kind.isExternalOrBoth() ) or - result = resolveUseTreeListItem(_, _, path) and + result = resolveUseTreeListItem(_, _, path, kind) and ns = result.getNamespace() } @@ -1326,7 +1360,17 @@ private predicate pathUsesNamespace(Path p, Namespace n) { /** Gets the item that `path` resolves to, if any. */ cached ItemNode resolvePath(RelevantPath path) { - exists(Namespace ns | result = resolvePath0(path, ns) | + exists(Namespace ns | + result = resolvePath0(path, ns, _) and + if path = any(ImplItemNode i).getSelfPath() + then + result instanceof TypeItemNode and + not result instanceof TraitItemNode + else + if path = any(ImplItemNode i).getTraitPath() + then result instanceof TraitItemNode + else any() + | pathUsesNamespace(path, ns) or not pathUsesNamespace(path, _) and @@ -1357,17 +1401,20 @@ private predicate isUseTreeSubPathUnqualified(UseTree tree, RelevantPath path, s } pragma[nomagic] -private ItemNode resolveUseTreeListItem(Use use, UseTree tree, RelevantPath path) { - exists(UseTree midTree, ItemNode mid, string name | - mid = resolveUseTreeListItem(use, midTree) and - tree = midTree.getUseTreeList().getAUseTree() and - isUseTreeSubPathUnqualified(tree, path, pragma[only_bind_into](name)) and - result = mid.getASuccessor(pragma[only_bind_into](name)) - ) - or - exists(ItemNode q, string name | - q = resolveUseTreeListItemQualifier(use, tree, path, name) and - result = q.getASuccessor(name) +private ItemNode resolveUseTreeListItem(Use use, UseTree tree, RelevantPath path, SuccessorKind kind) { + kind.isExternalOrBoth() and + ( + exists(UseTree midTree, ItemNode mid, string name | + mid = resolveUseTreeListItem(use, midTree) and + tree = midTree.getUseTreeList().getAUseTree() and + isUseTreeSubPathUnqualified(tree, path, pragma[only_bind_into](name)) and + result = mid.getASuccessor(pragma[only_bind_into](name), kind) + ) + or + exists(ItemNode q, string name | + q = resolveUseTreeListItemQualifier(use, tree, path, name) and + result = q.getASuccessor(name, kind) + ) ) } @@ -1375,7 +1422,7 @@ pragma[nomagic] private ItemNode resolveUseTreeListItemQualifier( Use use, UseTree tree, RelevantPath path, string name ) { - result = resolveUseTreeListItem(use, tree, path.getQualifier()) and + result = resolveUseTreeListItem(use, tree, path.getQualifier(), _) and name = path.getText() } @@ -1384,23 +1431,25 @@ private ItemNode resolveUseTreeListItem(Use use, UseTree tree) { tree = use.getUseTree() and result = resolvePath(tree.getPath()) or - result = resolveUseTreeListItem(use, tree, tree.getPath()) + result = resolveUseTreeListItem(use, tree, tree.getPath(), _) } /** Holds if `use` imports `item` as `name`. */ pragma[nomagic] -private predicate useImportEdge(Use use, string name, ItemNode item) { +private predicate useImportEdge(Use use, string name, ItemNode item, SuccessorKind kind) { + (if use.hasVisibility() then kind.isBoth() else kind.isInternal()) and exists(UseTree tree, ItemNode used | used = resolveUseTreeListItem(use, tree) and not tree.hasUseTreeList() and if tree.isGlob() then - exists(ItemNode encl, Namespace ns | + exists(ItemNode encl, Namespace ns, SuccessorKind kind1 | encl.getADescendant() = use and - item = getASuccessor(used, name, ns) and + item = getASuccessor(used, name, ns, kind1) and + kind1.isExternalOrBoth() and // glob imports can be shadowed not declares(encl, ns, name) and - not name = ["super", "self", "Self", "$crate", "crate"] + not name = ["super", "self"] ) else ( item = used and @@ -1433,13 +1482,21 @@ private predicate externCrateEdge(ExternCrateItemNode ec, string name, CrateItem pragma[nomagic] private predicate preludeItem(string name, ItemNode i) { - exists(Crate stdOrCore, ModuleLikeNode mod, ModuleItemNode prelude, ModuleItemNode rust | - stdOrCore.getName() = ["std", "core"] and + exists( + Crate stdOrCore, string stdOrCoreName, ModuleLikeNode mod, ModuleItemNode prelude, + ModuleItemNode rust + | + stdOrCore.getName() = stdOrCoreName and + stdOrCoreName = ["std", "core"] and mod = stdOrCore.getSourceFile() and - prelude = mod.getASuccessorRec("prelude") and - rust = prelude.getASuccessorRec(["rust_2015", "rust_2018", "rust_2021", "rust_2024"]) and - i = rust.getASuccessorRec(name) and - not i instanceof Use + prelude = mod.getASuccessor("prelude") and + rust = prelude.getASuccessor(["rust_2015", "rust_2018", "rust_2021", "rust_2024"]) + | + i = rust.getASuccessor(name) and + not name = ["super", "self"] + or + name = stdOrCoreName and + i = stdOrCore ) } @@ -1463,7 +1520,7 @@ pragma[nomagic] private predicate builtin(string name, ItemNode i) { exists(BuiltinSourceFile builtins | builtins.getFile().getBaseName() = "types.rs" and - i = builtins.getASuccessorRec(name) + i = builtins.getASuccessor(name) ) } @@ -1490,19 +1547,19 @@ private module Debug { result = resolvePath(path) } - predicate debugUseImportEdge(Use use, string name, ItemNode item) { + predicate debugUseImportEdge(Use use, string name, ItemNode item, SuccessorKind kind) { use = getRelevantLocatable() and - useImportEdge(use, name, item) + useImportEdge(use, name, item, kind) } - ItemNode debugGetASuccessorRec(ItemNode i, string name) { + ItemNode debuggetASuccessor(ItemNode i, string name, SuccessorKind kind) { i = getRelevantLocatable() and - result = i.getASuccessor(name) + result = i.getASuccessor(name, kind) } - predicate debugFileImportEdge(Module mod, string name, ItemNode item) { + predicate debugFileImportEdge(Module mod, string name, ItemNode item, SuccessorKind kind) { mod = getRelevantLocatable() and - fileImportEdge(mod, name, item) + fileImportEdge(mod, name, item, kind) } predicate debugFileImport(Module m, SourceFile f) { diff --git a/rust/ql/lib/codeql/rust/internal/TypeInference.qll b/rust/ql/lib/codeql/rust/internal/TypeInference.qll index 07f1180f1bd7..d9a5bef9a653 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInference.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInference.qll @@ -224,8 +224,9 @@ private import M2 module Consistency { import M2::Consistency - query predicate nonUniqueCertainType(AstNode n, TypePath path) { - strictcount(CertainTypeInference::inferCertainType(n, path)) > 1 + predicate nonUniqueCertainType(AstNode n, TypePath path, Type t) { + strictcount(CertainTypeInference::inferCertainType(n, path)) > 1 and + t = CertainTypeInference::inferCertainType(n, path) } } @@ -2513,7 +2514,6 @@ private module Debug { Type debugInferCertainNonUniqueType(AstNode n, TypePath path) { n = getRelevantLocatable() and - Consistency::nonUniqueCertainType(n, path) and - result = CertainTypeInference::inferCertainType(n, path) + Consistency::nonUniqueCertainType(n, path, result) } } diff --git a/rust/ql/lib/codeql/rust/internal/TypeInferenceConsistency.qll b/rust/ql/lib/codeql/rust/internal/TypeInferenceConsistency.qll index fd6257fc2602..16eaff92bb6c 100644 --- a/rust/ql/lib/codeql/rust/internal/TypeInferenceConsistency.qll +++ b/rust/ql/lib/codeql/rust/internal/TypeInferenceConsistency.qll @@ -17,6 +17,10 @@ query predicate illFormedTypeMention(TypeMention tm) { tm.fromSource() } +query predicate nonUniqueCertainType(AstNode n, TypePath path) { + Consistency::nonUniqueCertainType(n, path, _) +} + int getTypeInferenceInconsistencyCounts(string type) { type = "Missing type parameter ID" and result = count(TypeParameter tp | missingTypeParameterId(tp) | tp) diff --git a/rust/ql/test/query-tests/security/CWE-089/CONSISTENCY/TypeInferenceConsistency.expected b/rust/ql/test/query-tests/security/CWE-089/CONSISTENCY/TypeInferenceConsistency.expected deleted file mode 100644 index 6a60922b6f0f..000000000000 --- a/rust/ql/test/query-tests/security/CWE-089/CONSISTENCY/TypeInferenceConsistency.expected +++ /dev/null @@ -1,3 +0,0 @@ -nonUniqueCertainType -| sqlx.rs:158:13:158:81 | { ... } | E | -| sqlx.rs:160:17:160:86 | { ... } | E | diff --git a/rust/ql/test/query-tests/security/CWE-312/CONSISTENCY/TypeInferenceConsistency.expected b/rust/ql/test/query-tests/security/CWE-312/CONSISTENCY/TypeInferenceConsistency.expected deleted file mode 100644 index 952a4afe86b9..000000000000 --- a/rust/ql/test/query-tests/security/CWE-312/CONSISTENCY/TypeInferenceConsistency.expected +++ /dev/null @@ -1,4 +0,0 @@ -nonUniqueCertainType -| test_logging.rs:17:8:19:12 | { ... } | E | -| test_logging.rs:29:8:31:12 | { ... } | E | -| test_storage.rs:177:8:179:9 | { ... } | E | diff --git a/rust/ql/test/query-tests/security/CWE-770/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/query-tests/security/CWE-770/CONSISTENCY/PathResolutionConsistency.expected index 6e88d5bdf866..6c3b9efca14b 100644 --- a/rust/ql/test/query-tests/security/CWE-770/CONSISTENCY/PathResolutionConsistency.expected +++ b/rust/ql/test/query-tests/security/CWE-770/CONSISTENCY/PathResolutionConsistency.expected @@ -1,18 +1,3 @@ multipleCallTargets -| main.rs:218:14:218:30 | ...::malloc(...) | -| main.rs:219:13:219:27 | ...::malloc(...) | -| main.rs:220:13:220:37 | ...::aligned_alloc(...) | -| main.rs:221:13:221:37 | ...::aligned_alloc(...) | -| main.rs:222:13:222:31 | ...::calloc(...) | -| main.rs:223:13:223:55 | ...::calloc(...) | -| main.rs:224:13:224:32 | ...::realloc(...) | | main.rs:229:13:229:40 | ...::with_capacity(...) | | main.rs:233:18:233:47 | ...::with_capacity(...) | -multiplePathResolutions -| main.rs:218:14:218:17 | libc | -| main.rs:219:13:219:16 | libc | -| main.rs:220:13:220:16 | libc | -| main.rs:221:13:221:16 | libc | -| main.rs:222:13:222:16 | libc | -| main.rs:223:13:223:16 | libc | -| main.rs:224:13:224:16 | libc | diff --git a/rust/ql/test/query-tests/security/CWE-825/CONSISTENCY/PathResolutionConsistency.expected b/rust/ql/test/query-tests/security/CWE-825/CONSISTENCY/PathResolutionConsistency.expected index 22e607bfa486..d13271f5fe6e 100644 --- a/rust/ql/test/query-tests/security/CWE-825/CONSISTENCY/PathResolutionConsistency.expected +++ b/rust/ql/test/query-tests/security/CWE-825/CONSISTENCY/PathResolutionConsistency.expected @@ -1,6 +1,4 @@ multipleCallTargets -| deallocation.rs:106:16:106:32 | ...::malloc(...) | -| deallocation.rs:112:3:112:41 | ...::free(...) | | deallocation.rs:260:11:260:29 | ...::from(...) | | deallocation.rs:261:11:261:29 | ...::from(...) | | lifetime.rs:610:13:610:31 | ...::from(...) | @@ -9,7 +7,3 @@ multipleCallTargets | lifetime.rs:612:41:612:52 | bar.as_str() | | lifetime.rs:628:13:628:31 | ...::from(...) | | lifetime.rs:629:32:629:43 | baz.as_str() | -multiplePathResolutions -| deallocation.rs:106:16:106:19 | libc | -| deallocation.rs:112:3:112:6 | libc | -| deallocation.rs:112:29:112:32 | libc |