From c8d668bcee40338b04c03f1bdf9d96b5bc7fa144 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Wed, 11 Dec 2024 17:07:06 +0100 Subject: [PATCH] Rust: add "standard path" --- rust/ql/.generated.list | 2 -- rust/ql/.gitattributes | 2 -- .../lib/codeql/rust/dataflow/FlowSummary.qll | 20 ++++++++----- .../internal/CanonicalPathImpl.qll | 20 +++++++++++-- .../internal/ModuleItemCanonicalPathImpl.qll | 4 +++ .../internal/NamespaceImpl.qll | 12 ++++++++ .../TypeImplItemCanonicalPathImpl.qll | 4 +++ .../internal/TypeItemCanonicalPathImpl.qll | 4 +++ .../elements/internal/AddressableImpl.qll | 18 +++++++++-- .../rust/elements/internal/ResolvableImpl.qll | 11 ++----- .../canonical_path/canonical_paths.expected | 30 ++++++++++++++++++- .../canonical_path/canonical_paths.ql | 11 +++++++ 12 files changed, 113 insertions(+), 25 deletions(-) diff --git a/rust/ql/.generated.list b/rust/ql/.generated.list index 12447d41a38..756a5375d9f 100644 --- a/rust/ql/.generated.list +++ b/rust/ql/.generated.list @@ -194,7 +194,6 @@ lib/codeql/rust/elements/canonical_paths/TypeImplItemCanonicalPath.qll a482bf323 lib/codeql/rust/elements/canonical_paths/TypeItemCanonicalPath.qll 3cdd980844dac4533bf7fc82c1679af39b151aecbe325a9dbd7a2275ecc3b72b df6232001508086a62ad0e629287d0705a072ba26437f8a55d8aad977e11f554 lib/codeql/rust/elements/canonical_paths/internal/BuiltinTypeCanonicalPathConstructor.qll c33ca6a182eae907bc01a11bbe9e10a705889d6d383cd8804c5380368cf785d4 af1677ff43fcb22dedde3dfa853dc12a197c6e5db7ec6191cfd6c9197e371a05 lib/codeql/rust/elements/canonical_paths/internal/BuiltinTypeCanonicalPathImpl.qll 6dbc6981e280717eb8a7cc2bf06bb91e760cc168e262dcf87db53f610b3a0362 ce81251f033173baabcfa9dd2a6a760169015329daac738760bb4e6689c0fe85 -lib/codeql/rust/elements/canonical_paths/internal/CanonicalPathImpl.qll c368afc58a57feb86acde466eb33ed74d17bcd8360219ddf93b0302ea43504ee 42df02e0a15c0555ca1cf830debbc94f647c38c7f6ca8f7640f2cbe8f36d4ac6 lib/codeql/rust/elements/canonical_paths/internal/ConcreteTypeCanonicalPathConstructor.qll 122781ed5b5bfddc0f6c5243d3a77eb969559115c7f612b81291f62b5790b48d 348ee1d8c92b803a1aaf8e3fc5a9061a41cd2a4c6f2f6fa51910659a1edfa00f lib/codeql/rust/elements/canonical_paths/internal/ConstGenericTypeArgConstructor.qll a2ef92745e712b091367e063662e800b8f84efdf28b02e7116c7c8ab0629e0fc 4a2689f585c0de2f77ca64620bb65986bafab6209fbc383646335040d6155018 lib/codeql/rust/elements/canonical_paths/internal/DerivedTypeCanonicalPathConstructor.qll 1127f0e1eaed5da946a5288271f679ef1984d984a3686cd59d9ec89a8251a234 04419a1231179c8d39637edd443c4ff038e010753f4e6a016ac8c9dbc8f6cccd @@ -212,7 +211,6 @@ lib/codeql/rust/elements/canonical_paths/internal/TypeImplItemCanonicalPathConst lib/codeql/rust/elements/canonical_paths/internal/TypeItemCanonicalPathConstructor.qll b23c6d7902c56c758bc121cd5d3c7e351eccb66503131bc2fa4dda60abb9b4ae b097ab6555f06b12f7ae99378dc9bc347a8b7b7b2691d6a636b9392178cb5692 lib/codeql/rust/elements/internal/AbiConstructor.qll 4484538db49d7c1d31c139f0f21879fceb48d00416e24499a1d4b1337b4141ac 460818e397f2a1a8f2e5466d9551698b0e569d4640fcb87de6c4268a519b3da1 lib/codeql/rust/elements/internal/AbiImpl.qll 01439712ecadc9dc8da6f74d2e19cee13c77f8e1e25699055da675b2c88cb02d dcc9395ef8abd1af3805f3e7fcbc2d7ce30affbce654b6f5e559924768db403c -lib/codeql/rust/elements/internal/AddressableImpl.qll e01a6104980960f5708d5a0ada774ba21db9a344e33deeaf3d3239c627268c77 b8bfc711b267df305ac9fe5f6a994f051ddeca7fc95dacd76d1bae2d4fa7adde lib/codeql/rust/elements/internal/ArgListConstructor.qll a73685c8792ae23a2d628e7357658efb3f6e34006ff6e9661863ef116ec0b015 0bee572a046e8dfc031b1216d729843991519d94ae66280f5e795d20aea07a22 lib/codeql/rust/elements/internal/ArgListImpl.qll 19664651c06b46530f0ae5745ccb3233afc97b9152e053761d641de6e9c62d38 40af167e571f5c255f264b3be7cc7f5ff42ec109661ca03dcee94e92f8facfc6 lib/codeql/rust/elements/internal/ArrayExprInternal.qll 07a219b3d3fba3ff8b18e77686b2f58ab01acd99e0f5d5cad5d91af937e228f5 7528fc0e2064c481f0d6cbff3835950a044e429a2cd00c4d8442d2e132560d37 diff --git a/rust/ql/.gitattributes b/rust/ql/.gitattributes index 27000b1123a..e96a1d29394 100644 --- a/rust/ql/.gitattributes +++ b/rust/ql/.gitattributes @@ -196,7 +196,6 @@ /lib/codeql/rust/elements/canonical_paths/TypeItemCanonicalPath.qll linguist-generated /lib/codeql/rust/elements/canonical_paths/internal/BuiltinTypeCanonicalPathConstructor.qll linguist-generated /lib/codeql/rust/elements/canonical_paths/internal/BuiltinTypeCanonicalPathImpl.qll linguist-generated -/lib/codeql/rust/elements/canonical_paths/internal/CanonicalPathImpl.qll linguist-generated /lib/codeql/rust/elements/canonical_paths/internal/ConcreteTypeCanonicalPathConstructor.qll linguist-generated /lib/codeql/rust/elements/canonical_paths/internal/ConstGenericTypeArgConstructor.qll linguist-generated /lib/codeql/rust/elements/canonical_paths/internal/DerivedTypeCanonicalPathConstructor.qll linguist-generated @@ -214,7 +213,6 @@ /lib/codeql/rust/elements/canonical_paths/internal/TypeItemCanonicalPathConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/AbiConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/AbiImpl.qll linguist-generated -/lib/codeql/rust/elements/internal/AddressableImpl.qll linguist-generated /lib/codeql/rust/elements/internal/ArgListConstructor.qll linguist-generated /lib/codeql/rust/elements/internal/ArgListImpl.qll linguist-generated /lib/codeql/rust/elements/internal/ArrayExprInternal.qll linguist-generated diff --git a/rust/ql/lib/codeql/rust/dataflow/FlowSummary.qll b/rust/ql/lib/codeql/rust/dataflow/FlowSummary.qll index f0457c960ce..0b1c8f5f427 100644 --- a/rust/ql/lib/codeql/rust/dataflow/FlowSummary.qll +++ b/rust/ql/lib/codeql/rust/dataflow/FlowSummary.qll @@ -29,14 +29,20 @@ module LibraryCallable { /** Gets a call to this library callable. */ CallExprBase getACall() { - exists(Resolvable r, string crate | - r = CallExprBaseImpl::getCallResolvable(result) and - this = crate + r.getResolvedPath() + exists( + TypeItemCanonicalPath path, ModuleItemCanonicalPath item, Namespace namespace, + string namespace_path | - crate = r.getResolvedCrateOrigin() + "::_::" - or - not r.hasResolvedCrateOrigin() and - crate = "" + path = CallExprBaseImpl::getCallResolvable(result).getResolvedCanonicalPath() and + item = path.getParent() and + namespace = item.getNamespace() and + namespace_path = namespace.getPath() and + if namespace_path = "" + then this = namespace.getRoot().toString() + "::" + item.getName() + "::" + path.getName() + else + this = + namespace.getRoot().toString() + "::" + namespace_path + "::" + item.getName() + "::" + + path.getName() ) } } diff --git a/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/CanonicalPathImpl.qll b/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/CanonicalPathImpl.qll index 9865fe1df33..445cf103741 100644 --- a/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/CanonicalPathImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/CanonicalPathImpl.qll @@ -1,4 +1,3 @@ -// generated by codegen, remove this comment if you wish to edit this file /** * This module provides a hand-modifiable wrapper around the generated class `CanonicalPath`. * @@ -12,8 +11,25 @@ private import codeql.rust.elements.internal.generated.canonical_paths.Canonical * be referenced directly. */ module Impl { + // the following QLdoc is generated: if you need to edit it, do it in the schema file /** * The base class for all canonical paths that can be the result of a path resolution. */ - class CanonicalPath extends Generated::CanonicalPath { } + class CanonicalPath extends Generated::CanonicalPath { + /** + * If this canonical path is of the form `crate::mod1::mod2::Type::name`, then this predicate + * splits it into its components `crate::mod1::mod2`, `Type` and `name`. This applies to + * type, trait and type impl items, not to module items (see `hasStandardPath/2`) nor to + * trait impl items (TODO). + */ + predicate hasStandardPath(string namespace, string type, string name) { none() } + + /** + * If this canonical path is of the form `crate::mod1::mod2::name`, then this predicate + * splits it into its components `crate::mod1::mod2` and `name`. This applies to + * module items, but not to type, trait and type impl items (see `hasStandardPath/3`) nor to + * trait impl items (TODO). + */ + predicate hasStandardPath(string namespace, string name) { none() } + } } diff --git a/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/ModuleItemCanonicalPathImpl.qll b/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/ModuleItemCanonicalPathImpl.qll index 31538d7ab69..cfbf706793b 100644 --- a/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/ModuleItemCanonicalPathImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/ModuleItemCanonicalPathImpl.qll @@ -19,5 +19,9 @@ module Impl { override string toString() { result = this.getNamespace().toAbbreviatedString() + "::" + this.getName() } + + override predicate hasStandardPath(string namespace, string name) { + this.getName() = name and namespace = this.getNamespace().getNamespaceString() + } } } diff --git a/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/NamespaceImpl.qll b/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/NamespaceImpl.qll index 67bdd6b99ed..a3ea449660c 100644 --- a/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/NamespaceImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/NamespaceImpl.qll @@ -22,5 +22,17 @@ module Impl { if this.getPath() = "" then result = root else result = root + "::" + this.getPath() ) } + + /** + * Returns a string representation of this namespace, with the root and path separated by `::`. + */ + cached + string getNamespaceString() { + exists(string root, string path | + root = this.getRoot().toString() and + path = this.getPath() and + if path = "" then result = root else result = root + "::" + path + ) + } } } diff --git a/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/TypeImplItemCanonicalPathImpl.qll b/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/TypeImplItemCanonicalPathImpl.qll index 67d31b77784..6e7a1dda08b 100644 --- a/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/TypeImplItemCanonicalPathImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/TypeImplItemCanonicalPathImpl.qll @@ -19,5 +19,9 @@ module Impl { override string toString() { result = "<" + this.getParent().toAbbreviatedString() + ">::" + this.getName() } + + override predicate hasStandardPath(string namespace, string type, string name) { + this.getName() = name and this.getParent().hasStandardPath(namespace, type) + } } } diff --git a/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/TypeItemCanonicalPathImpl.qll b/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/TypeItemCanonicalPathImpl.qll index 22fbaae334a..e99c01b1469 100644 --- a/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/TypeItemCanonicalPathImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/canonical_paths/internal/TypeItemCanonicalPathImpl.qll @@ -19,5 +19,9 @@ module Impl { override string toString() { result = this.getParent().toAbbreviatedString() + "::" + this.getName() } + + override predicate hasStandardPath(string namespace, string type, string name) { + this.getName() = name and this.getParent().hasStandardPath(namespace, type) + } } } diff --git a/rust/ql/lib/codeql/rust/elements/internal/AddressableImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/AddressableImpl.qll index b3fe47b294a..ebf0230ad79 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/AddressableImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/AddressableImpl.qll @@ -1,4 +1,3 @@ -// generated by codegen, remove this comment if you wish to edit this file /** * This module provides a hand-modifiable wrapper around the generated class `Addressable`. * @@ -12,10 +11,25 @@ private import codeql.rust.elements.internal.generated.Addressable * be referenced directly. */ module Impl { + // the following QLdoc is generated: if you need to edit it, do it in the schema file /** * Something that can be addressed by a path. * * TODO: This does not yet include all possible cases. */ - class Addressable extends Generated::Addressable { } + class Addressable extends Generated::Addressable { + /** + * Splits the standard path into its components (see `CanonicalPath::hasStandardPath/3`). + */ + predicate hasStandardPath(string namespace, string type, string name) { + this.getCanonicalPath().hasStandardPath(namespace, type, name) + } + + /** + * Splits the standard path into its components (see `CanonicalPath::hasStandardPath/2`). + */ + predicate hasStandardPath(string namespace, string name) { + this.getCanonicalPath().hasStandardPath(namespace, name) + } + } } diff --git a/rust/ql/lib/codeql/rust/elements/internal/ResolvableImpl.qll b/rust/ql/lib/codeql/rust/elements/internal/ResolvableImpl.qll index 86304cd23de..6f6291df241 100644 --- a/rust/ql/lib/codeql/rust/elements/internal/ResolvableImpl.qll +++ b/rust/ql/lib/codeql/rust/elements/internal/ResolvableImpl.qll @@ -20,16 +20,9 @@ module Impl { class Resolvable extends Generated::Resolvable { /** * Holds if this resolvable and the item `i` resolves to the same canonical - * path in the same crate + * path */ pragma[nomagic] - predicate resolvesAsItem(Item i) { - this.getResolvedPath() = i.getExtendedCanonicalPath() and - ( - this.getResolvedCrateOrigin() = i.getCrateOrigin() - or - not this.hasResolvedCrateOrigin() and not i.hasCrateOrigin() - ) - } + predicate resolvesAsItem(Item i) { this.getResolvedCanonicalPath() = i.getCanonicalPath() } } } diff --git a/rust/ql/test/extractor-tests/canonical_path/canonical_paths.expected b/rust/ql/test/extractor-tests/canonical_path/canonical_paths.expected index 495316bb189..13100aebb47 100644 --- a/rust/ql/test/extractor-tests/canonical_path/canonical_paths.expected +++ b/rust/ql/test/extractor-tests/canonical_path/canonical_paths.expected @@ -121,12 +121,40 @@ resolvedPaths | usage.rs:48:5:48:23 | ... .generic_method(...) | <... as ...>::generic_method | | usage.rs:52:5:52:10 | ... .f(...) | <... as ...>::f | | usage.rs:53:5:53:15 | ... .f(...) | <... as ...>::f | -| usage.rs:54:5:54:17 | ...::into_vec | <...>::into_vec | +| usage.rs:54:5:54:17 | ...::into_vec | None | | usage.rs:54:5:54:17 | ...::new | None | | usage.rs:54:5:54:28 | ... .as_slice(...) | <...>::as_slice | | usage.rs:54:5:54:32 | ... .f(...) | <... as ...>::f | | usage.rs:55:5:55:16 | ... .f(...) | <... as ...>::f | | usage.rs:56:5:56:20 | ... .f(...) | <... as ...>::f | +standardPaths +| anonymous.rs:3:1:32:1 | fn canonicals | test::anonymous::canonicals | +| anonymous.rs:15:9:15:22 | fn g | test::regular::Struct::g | +| anonymous.rs:34:1:36:1 | fn other | test::anonymous::other | +| regular.rs:1:1:2:18 | struct Struct | test::regular::Struct | +| regular.rs:4:1:6:1 | trait Trait | test::regular::Trait | +| regular.rs:5:5:5:16 | fn f | test::regular::Trait::f | +| regular.rs:13:5:13:22 | fn g | test::regular::Struct::g | +| regular.rs:16:1:18:1 | trait TraitWithBlanketImpl | test::regular::TraitWithBlanketImpl | +| regular.rs:17:5:17:16 | fn h | test::regular::TraitWithBlanketImpl::h | +| regular.rs:24:1:24:16 | fn free | test::regular::free | +| regular.rs:26:1:30:1 | enum MyEnum | test::regular::MyEnum | +| regular.rs:27:5:27:12 | Variant1 | test::regular::MyEnum::Variant1 | +| regular.rs:28:5:28:19 | Variant2 | test::regular::MyEnum::Variant2 | +| regular.rs:29:5:29:25 | Variant3 | test::regular::MyEnum::Variant3 | +| regular.rs:32:1:34:1 | trait GenericTrait | test::regular::GenericTrait | +| regular.rs:33:5:33:35 | fn generic_method | test::regular::GenericTrait::generic_method | +| regular.rs:36:1:39:1 | struct GenericStruct | test::regular::GenericStruct | +| regular.rs:41:1:41:50 | struct GenericTupleStruct | test::regular::GenericTupleStruct | +| regular.rs:44:1:47:1 | enum GenericEnum | test::regular::GenericEnum | +| regular.rs:45:5:45:8 | T | test::regular::GenericEnum::T | +| regular.rs:46:5:46:8 | U | test::regular::GenericEnum::U | +| usage.rs:3:1:9:1 | fn usage | test::usage::usage | +| usage.rs:11:1:17:1 | fn enum_qualified_usage | test::usage::enum_qualified_usage | +| usage.rs:19:1:26:1 | fn enum_unqualified_usage | test::usage::enum_unqualified_usage | +| usage.rs:28:1:34:1 | fn enum_match | test::usage::enum_match | +| usage.rs:36:1:49:1 | fn generic_usage | test::usage::generic_usage | +| usage.rs:51:1:57:1 | fn use_trait | test::usage::use_trait | resolve | usage.rs:4:13:4:21 | Struct {...} | regular.rs:1:1:2:18 | struct Struct | | usage.rs:5:5:5:9 | ... .f(...) | regular.rs:9:5:9:18 | fn f | diff --git a/rust/ql/test/extractor-tests/canonical_path/canonical_paths.ql b/rust/ql/test/extractor-tests/canonical_path/canonical_paths.ql index bcf4c9d7152..b8cd62f4936 100644 --- a/rust/ql/test/extractor-tests/canonical_path/canonical_paths.ql +++ b/rust/ql/test/extractor-tests/canonical_path/canonical_paths.ql @@ -19,6 +19,17 @@ query predicate resolvedPaths(Resolvable i, string answer) { ) } +query predicate standardPaths(Addressable i, string answer) { + toBeTested(i) and + exists(string namespace, string name | + i.hasStandardPath(namespace, name) and answer = namespace + "::" + name + or + exists(string type | + i.hasStandardPath(namespace, type, name) and answer = namespace + "::" + type + "::" + name + ) + ) +} + query predicate resolve(Resolvable i, Addressable j) { toBeTested(i) and toBeTested(j) and