From 4ed4f6878f4f726bada29c634aa4f054716333b1 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 14 Jan 2025 16:40:20 +0000 Subject: [PATCH 01/21] Rust: Add summary query rust/summary/cryptographic-ops. --- .../summary/CryptographicOperations.ql | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 rust/ql/src/queries/summary/CryptographicOperations.ql diff --git a/rust/ql/src/queries/summary/CryptographicOperations.ql b/rust/ql/src/queries/summary/CryptographicOperations.ql new file mode 100644 index 000000000000..3b8b3342c2c7 --- /dev/null +++ b/rust/ql/src/queries/summary/CryptographicOperations.ql @@ -0,0 +1,59 @@ +/** + * @name Cryptographic Operations + * @description List all cryptographic operations found in the database. + * @kind problem + * @problem.severity info + * @id rust/summary/cryptographic-operations + * @tags summary + */ + +import rust +import codeql.rust.Concepts +import codeql.rust.security.WeakSensitiveDataHashingExtensions + +/** + * Gets the type of cryptographic algorithm `alg`. + */ +string getAlgorithmType(Cryptography::CryptographicAlgorithm alg) { + alg instanceof Cryptography::EncryptionAlgorithm and result = "EncryptionAlgorithm" + or + alg instanceof Cryptography::HashingAlgorithm and result = "HashingAlgorithm" + or + alg instanceof Cryptography::PasswordHashingAlgorithm and result = "PasswordHashingAlgorithm" +} + +/** + * Gets a feature of cryptographic algorithm `alg`. + */ +string getAlgorithmFeature(Cryptography::CryptographicAlgorithm alg) { + alg.isWeak() and result = "WEAK" +} + +/** + * Gets a description of cryptographic algorithm `alg`. + */ +string describeAlgorithm(Cryptography::CryptographicAlgorithm alg) { + result = + getAlgorithmType(alg) + " " + alg.getName() + " " + concat(getAlgorithmFeature(alg), ", ") +} + +/** + * Gets a feature of cryptographic operation `operation`. + */ +string getOperationFeature(Cryptography::CryptographicOperation op) { + result = "inputs:" + strictcount(op.getAnInput()).toString() or + result = "blockmodes:" + strictcount(op.getBlockMode()).toString() +} + +/** + * Gets a description of cryptographic operation `operation`. + */ +string describeOperation(Cryptography::CryptographicOperation op) { + result = describeAlgorithm(op.getAlgorithm()) + " " + concat(getOperationFeature(op), ", ") + or + not exists(op.getAlgorithm()) and + result = "(unknown) " + concat(getOperationFeature(op), ", ") +} + +from Cryptography::CryptographicOperation operation +select operation, describeOperation(operation) From 75f0a7f529d33e9d00ad0182aedc2ddcf7fa2d30 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 14 Jan 2025 16:40:36 +0000 Subject: [PATCH 02/21] Rust: Add summary query rust/summary/query-sinks. --- rust/ql/src/queries/summary/QuerySinks.ql | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 rust/ql/src/queries/summary/QuerySinks.ql diff --git a/rust/ql/src/queries/summary/QuerySinks.ql b/rust/ql/src/queries/summary/QuerySinks.ql new file mode 100644 index 000000000000..befc200f186c --- /dev/null +++ b/rust/ql/src/queries/summary/QuerySinks.ql @@ -0,0 +1,25 @@ +/** + * @name Query Sinks + * @description Lists query sinks that are found in the database. Query sinks are flow sinks that + * are used as possible locations for query results. Cryptographic operations are + * excluded (see `rust/summary/cryptographic-operations` instead). + * @kind problem + * @problem.severity info + * @id rust/summary/query-sinks + * @tags summary + */ + +import rust +import codeql.rust.dataflow.DataFlow +import codeql.rust.security.SqlInjectionExtensions +import Stats + +/** + * Gets a kind of query for which `n` is a sink (if any). + */ +string getAQuerySinkKind(DataFlow::Node n) { + (n instanceof SqlInjection::Sink and result = "SqlInjection") +} + +from DataFlow::Node n +select n, "sink for " + strictconcat(getAQuerySinkKind(n), ", ") From c6a7be671b6cacd9e13334cc2db035ad7d661b8f Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:28:23 +0000 Subject: [PATCH 03/21] Rust: Add both totals to rust/summary/summary-statistics. --- rust/ql/src/queries/summary/QuerySinks.ql | 8 -------- rust/ql/src/queries/summary/Stats.qll | 14 ++++++++++++++ rust/ql/src/queries/summary/SummaryStats.ql | 6 ++++++ .../query-tests/diagnostics/SummaryStats.expected | 2 ++ 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/rust/ql/src/queries/summary/QuerySinks.ql b/rust/ql/src/queries/summary/QuerySinks.ql index befc200f186c..33234fe5f9f7 100644 --- a/rust/ql/src/queries/summary/QuerySinks.ql +++ b/rust/ql/src/queries/summary/QuerySinks.ql @@ -11,15 +11,7 @@ import rust import codeql.rust.dataflow.DataFlow -import codeql.rust.security.SqlInjectionExtensions import Stats -/** - * Gets a kind of query for which `n` is a sink (if any). - */ -string getAQuerySinkKind(DataFlow::Node n) { - (n instanceof SqlInjection::Sink and result = "SqlInjection") -} - from DataFlow::Node n select n, "sink for " + strictconcat(getAQuerySinkKind(n), ", ") diff --git a/rust/ql/src/queries/summary/Stats.qll b/rust/ql/src/queries/summary/Stats.qll index c2993b47899f..42001080ad86 100644 --- a/rust/ql/src/queries/summary/Stats.qll +++ b/rust/ql/src/queries/summary/Stats.qll @@ -3,11 +3,13 @@ */ import rust +private import codeql.rust.dataflow.DataFlow private import codeql.rust.dataflow.internal.DataFlowImpl private import codeql.rust.dataflow.internal.TaintTrackingImpl private import codeql.rust.AstConsistency as AstConsistency private import codeql.rust.controlflow.internal.CfgConsistency as CfgConsistency private import codeql.rust.dataflow.internal.DataFlowConsistency as DataFlowConsistency +private import codeql.rust.security.SqlInjectionExtensions /** * Gets a count of the total number of lines of code in the database. @@ -41,3 +43,15 @@ int getTotalCfgInconsistencies() { int getTotalDataFlowInconsistencies() { result = sum(string type | | DataFlowConsistency::getInconsistencyCounts(type)) } + +/** + * Gets a kind of query for which `n` is a sink (if any). + */ +string getAQuerySinkKind(DataFlow::Node n) { + (n instanceof SqlInjection::Sink and result = "SqlInjection") +} + +/** + * Gets a count of the total number of query sinks in the database. + */ +int getQuerySinksCount() { result = count(DataFlow::Node n | exists(getAQuerySinkKind(n)) | n) } diff --git a/rust/ql/src/queries/summary/SummaryStats.ql b/rust/ql/src/queries/summary/SummaryStats.ql index 005233f87cf3..ee4818a9ff33 100644 --- a/rust/ql/src/queries/summary/SummaryStats.ql +++ b/rust/ql/src/queries/summary/SummaryStats.ql @@ -9,6 +9,7 @@ import rust import codeql.rust.Concepts import codeql.rust.security.SensitiveData +import codeql.rust.security.WeakSensitiveDataHashingExtensions import codeql.rust.Diagnostics import Stats @@ -59,4 +60,9 @@ where key = "Taint sources - active" and value = count(ActiveThreatModelSource s) or key = "Sensitive data" and value = count(SensitiveData d) + or + key = "Taint sinks - query sinks" and value = getQuerySinksCount() + or + key = "Taint sinks - cryptographic operations" and + value = count(Cryptography::CryptographicOperation o) select key, value order by key diff --git a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected index c8c0fe398aaf..48915680692a 100644 --- a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected +++ b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected @@ -15,5 +15,7 @@ | Macro calls - total | 9 | | Macro calls - unresolved | 1 | | Sensitive data | 0 | +| Taint sinks - cryptographic operations | 0 | +| Taint sinks - query sinks | 0 | | Taint sources - active | 0 | | Taint sources - total | 0 | From 7904ed965b1b6c96968bfbe3515369aa90ffdab3 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 15 Jan 2025 08:55:56 +0000 Subject: [PATCH 04/21] Rust: Add query sink counts query for getting a breakdown. --- rust/ql/src/queries/summary/QuerySinkCounts.ql | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 rust/ql/src/queries/summary/QuerySinkCounts.ql diff --git a/rust/ql/src/queries/summary/QuerySinkCounts.ql b/rust/ql/src/queries/summary/QuerySinkCounts.ql new file mode 100644 index 000000000000..6525c3263a11 --- /dev/null +++ b/rust/ql/src/queries/summary/QuerySinkCounts.ql @@ -0,0 +1,17 @@ +/** + * @name Query Sink Counts + * @description Lists the number of query sinks of each type found in the database. Query sinks are + * flow sinks that are used as possible locations for query results. Cryptographic + * operations are excluded. + * @kind metric + * @id rust/summary/query-sink-counts + * @tags summary + */ + +import rust +import codeql.rust.dataflow.DataFlow +import Stats + +from string kind, int num +where num = strictcount(DataFlow::Node n | getAQuerySinkKind(n) = kind) +select kind, num From 72c62ac192d9e1a9576fc9b088665a72fdd764cc Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:57:16 +0000 Subject: [PATCH 05/21] Rust: Add taint reach to rust/summary/summary-statistics. --- rust/ql/src/queries/summary/SummaryStats.ql | 5 +++ rust/ql/src/queries/summary/TaintReach.qll | 31 +++++++++++++++++++ .../diagnostics/SummaryStats.expected | 2 ++ 3 files changed, 38 insertions(+) create mode 100644 rust/ql/src/queries/summary/TaintReach.qll diff --git a/rust/ql/src/queries/summary/SummaryStats.ql b/rust/ql/src/queries/summary/SummaryStats.ql index ee4818a9ff33..9f7106bf1352 100644 --- a/rust/ql/src/queries/summary/SummaryStats.ql +++ b/rust/ql/src/queries/summary/SummaryStats.ql @@ -12,6 +12,7 @@ import codeql.rust.security.SensitiveData import codeql.rust.security.WeakSensitiveDataHashingExtensions import codeql.rust.Diagnostics import Stats +import TaintReach from string key, int value where @@ -59,6 +60,10 @@ where or key = "Taint sources - active" and value = count(ActiveThreatModelSource s) or + key = "Taint reach - nodes tainted" and value = getTaintedNodesCount() + or + key = "Taint reach - per million nodes" and value = getTaintReach().floor() + or key = "Sensitive data" and value = count(SensitiveData d) or key = "Taint sinks - query sinks" and value = getQuerySinksCount() diff --git a/rust/ql/src/queries/summary/TaintReach.qll b/rust/ql/src/queries/summary/TaintReach.qll new file mode 100644 index 000000000000..281cbe6461e9 --- /dev/null +++ b/rust/ql/src/queries/summary/TaintReach.qll @@ -0,0 +1,31 @@ +/** + * Taint reach computation. Taint reach is the proportion of all dataflow nodes that can be reached + * via taint flow from any active thread model source. It's usually expressed per million nodes. + */ + +import rust +private import codeql.rust.Concepts +private import codeql.rust.dataflow.DataFlow +private import codeql.rust.dataflow.TaintTracking + +/** + * A taint configuration for taint reach (flow to any node from any modelled source). + */ +private module TaintReachConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { node instanceof ActiveThreatModelSource } + + predicate isSink(DataFlow::Node node) { any() } +} + +private module TaintReachFlow = TaintTracking::Global; + +/** + * Gets the total number of dataflow nodes that taint reaches (from any source). + */ +int getTaintedNodesCount() { result = count(DataFlow::Node n | TaintReachFlow::flowTo(n)) } + +/** + * Gets the proportion of dataflow nodes that taint reaches (from any source), + * expressed as a count per million nodes. + */ +float getTaintReach() { result = (getTaintedNodesCount() * 1000000.0) / count(DataFlow::Node n) } diff --git a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected index 48915680692a..b026674dd5ce 100644 --- a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected +++ b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected @@ -15,6 +15,8 @@ | Macro calls - total | 9 | | Macro calls - unresolved | 1 | | Sensitive data | 0 | +| Taint reach - nodes tainted | 0 | +| Taint reach - per million nodes | 0 | | Taint sinks - cryptographic operations | 0 | | Taint sinks - query sinks | 0 | | Taint sources - active | 0 | From 5a037bcbc45fb082fb3391d36149fcf2c2012722 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 15 Jan 2025 12:43:38 +0000 Subject: [PATCH 06/21] Rust: Count taint edges as well. --- rust/ql/src/queries/summary/Stats.qll | 10 ++++++++++ rust/ql/src/queries/summary/SummaryStats.ql | 2 ++ .../test/query-tests/diagnostics/SummaryStats.expected | 1 + 3 files changed, 13 insertions(+) diff --git a/rust/ql/src/queries/summary/Stats.qll b/rust/ql/src/queries/summary/Stats.qll index 42001080ad86..05057fe8209b 100644 --- a/rust/ql/src/queries/summary/Stats.qll +++ b/rust/ql/src/queries/summary/Stats.qll @@ -44,6 +44,16 @@ int getTotalDataFlowInconsistencies() { result = sum(string type | | DataFlowConsistency::getInconsistencyCounts(type)) } +/** + * Gets the total number of taint edges in the database. + */ +int getTaintEdgesCount() { + result = + count(DataFlow::Node a, DataFlow::Node b | + RustTaintTracking::defaultAdditionalTaintStep(a, b, _) + ) +} + /** * Gets a kind of query for which `n` is a sink (if any). */ diff --git a/rust/ql/src/queries/summary/SummaryStats.ql b/rust/ql/src/queries/summary/SummaryStats.ql index 9f7106bf1352..01440f5ee1f1 100644 --- a/rust/ql/src/queries/summary/SummaryStats.ql +++ b/rust/ql/src/queries/summary/SummaryStats.ql @@ -60,6 +60,8 @@ where or key = "Taint sources - active" and value = count(ActiveThreatModelSource s) or + key = "Taint edges - number of edges" and value = getTaintEdgesCount() + or key = "Taint reach - nodes tainted" and value = getTaintedNodesCount() or key = "Taint reach - per million nodes" and value = getTaintReach().floor() diff --git a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected index b026674dd5ce..6d1c9a51ad28 100644 --- a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected +++ b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected @@ -15,6 +15,7 @@ | Macro calls - total | 9 | | Macro calls - unresolved | 1 | | Sensitive data | 0 | +| Taint edges - number of edges | 2 | | Taint reach - nodes tainted | 0 | | Taint reach - per million nodes | 0 | | Taint sinks - cryptographic operations | 0 | From 65b33f3f96db440bb43b28d3507429d443d4a77e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 15 Jan 2025 16:14:03 +0000 Subject: [PATCH 07/21] Rust: Improve rust/summary/summary-statistics organization. --- rust/ql/src/queries/summary/SummaryStats.ql | 8 ++++---- .../ql/test/query-tests/diagnostics/SummaryStats.expected | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust/ql/src/queries/summary/SummaryStats.ql b/rust/ql/src/queries/summary/SummaryStats.ql index 01440f5ee1f1..46cf678b69fd 100644 --- a/rust/ql/src/queries/summary/SummaryStats.ql +++ b/rust/ql/src/queries/summary/SummaryStats.ql @@ -56,18 +56,18 @@ where or key = "Macro calls - unresolved" and value = count(MacroCall mc | not mc.hasExpanded()) or - key = "Taint sources - total" and value = count(ThreatModelSource s) - or key = "Taint sources - active" and value = count(ActiveThreatModelSource s) or + key = "Taint sources - disabled" and value = count(ThreatModelSource s | not s instanceof ActiveThreatModelSource) + or + key = "Taint sources - sensitive data" and value = count(SensitiveData d) + or key = "Taint edges - number of edges" and value = getTaintEdgesCount() or key = "Taint reach - nodes tainted" and value = getTaintedNodesCount() or key = "Taint reach - per million nodes" and value = getTaintReach().floor() or - key = "Sensitive data" and value = count(SensitiveData d) - or key = "Taint sinks - query sinks" and value = getQuerySinksCount() or key = "Taint sinks - cryptographic operations" and diff --git a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected index 6d1c9a51ad28..917bf92efbe8 100644 --- a/rust/ql/test/query-tests/diagnostics/SummaryStats.expected +++ b/rust/ql/test/query-tests/diagnostics/SummaryStats.expected @@ -14,11 +14,11 @@ | Macro calls - resolved | 8 | | Macro calls - total | 9 | | Macro calls - unresolved | 1 | -| Sensitive data | 0 | | Taint edges - number of edges | 2 | | Taint reach - nodes tainted | 0 | | Taint reach - per million nodes | 0 | | Taint sinks - cryptographic operations | 0 | | Taint sinks - query sinks | 0 | | Taint sources - active | 0 | -| Taint sources - total | 0 | +| Taint sources - disabled | 0 | +| Taint sources - sensitive data | 0 | From 787a6d11a3d530af1cbf4b503ccb5db08e58458e Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 15 Jan 2025 17:25:44 +0000 Subject: [PATCH 08/21] Rust: Autoformat. --- rust/ql/src/queries/summary/SummaryStats.ql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rust/ql/src/queries/summary/SummaryStats.ql b/rust/ql/src/queries/summary/SummaryStats.ql index 46cf678b69fd..4e14045428f2 100644 --- a/rust/ql/src/queries/summary/SummaryStats.ql +++ b/rust/ql/src/queries/summary/SummaryStats.ql @@ -58,7 +58,8 @@ where or key = "Taint sources - active" and value = count(ActiveThreatModelSource s) or - key = "Taint sources - disabled" and value = count(ThreatModelSource s | not s instanceof ActiveThreatModelSource) + key = "Taint sources - disabled" and + value = count(ThreatModelSource s | not s instanceof ActiveThreatModelSource) or key = "Taint sources - sensitive data" and value = count(SensitiveData d) or From 98e0b642663109ec1015f511d5bf2a7def7428ed Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 15 Jan 2025 17:51:49 +0000 Subject: [PATCH 09/21] Rust: Make QL-for-QL happy. --- rust/ql/src/queries/summary/CryptographicOperations.ql | 4 ++-- rust/ql/src/queries/summary/QuerySinks.ql | 2 +- rust/ql/src/queries/summary/TaintReach.qll | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/ql/src/queries/summary/CryptographicOperations.ql b/rust/ql/src/queries/summary/CryptographicOperations.ql index 3b8b3342c2c7..3b4c03c40fd2 100644 --- a/rust/ql/src/queries/summary/CryptographicOperations.ql +++ b/rust/ql/src/queries/summary/CryptographicOperations.ql @@ -38,7 +38,7 @@ string describeAlgorithm(Cryptography::CryptographicAlgorithm alg) { } /** - * Gets a feature of cryptographic operation `operation`. + * Gets a feature of cryptographic operation `op`. */ string getOperationFeature(Cryptography::CryptographicOperation op) { result = "inputs:" + strictcount(op.getAnInput()).toString() or @@ -46,7 +46,7 @@ string getOperationFeature(Cryptography::CryptographicOperation op) { } /** - * Gets a description of cryptographic operation `operation`. + * Gets a description of cryptographic operation `op`. */ string describeOperation(Cryptography::CryptographicOperation op) { result = describeAlgorithm(op.getAlgorithm()) + " " + concat(getOperationFeature(op), ", ") diff --git a/rust/ql/src/queries/summary/QuerySinks.ql b/rust/ql/src/queries/summary/QuerySinks.ql index 33234fe5f9f7..bc89f801f715 100644 --- a/rust/ql/src/queries/summary/QuerySinks.ql +++ b/rust/ql/src/queries/summary/QuerySinks.ql @@ -14,4 +14,4 @@ import codeql.rust.dataflow.DataFlow import Stats from DataFlow::Node n -select n, "sink for " + strictconcat(getAQuerySinkKind(n), ", ") +select n, "Sink for " + strictconcat(getAQuerySinkKind(n), ", ") diff --git a/rust/ql/src/queries/summary/TaintReach.qll b/rust/ql/src/queries/summary/TaintReach.qll index 281cbe6461e9..f2463b204f4a 100644 --- a/rust/ql/src/queries/summary/TaintReach.qll +++ b/rust/ql/src/queries/summary/TaintReach.qll @@ -9,7 +9,7 @@ private import codeql.rust.dataflow.DataFlow private import codeql.rust.dataflow.TaintTracking /** - * A taint configuration for taint reach (flow to any node from any modelled source). + * A taint configuration for taint reach (flow to any node from any modeled source). */ private module TaintReachConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node node) { node instanceof ActiveThreatModelSource } From bec01daa452ebbb953d49d0d4fec6857b13b91be Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Wed, 15 Jan 2025 17:55:08 +0000 Subject: [PATCH 10/21] Rust: Update integration tests. --- rust/ql/integration-tests/hello-project/summary.expected | 9 +++++++-- .../hello-workspace/summary.cargo.expected | 9 +++++++-- .../hello-workspace/summary.rust-project.expected | 9 +++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/rust/ql/integration-tests/hello-project/summary.expected b/rust/ql/integration-tests/hello-project/summary.expected index 07c48c7a5b75..533262ac6862 100644 --- a/rust/ql/integration-tests/hello-project/summary.expected +++ b/rust/ql/integration-tests/hello-project/summary.expected @@ -14,6 +14,11 @@ | Macro calls - resolved | 2 | | Macro calls - total | 2 | | Macro calls - unresolved | 0 | -| Sensitive data | 0 | +| Taint edges - number of edges | 2 | +| Taint reach - nodes tainted | 0 | +| Taint reach - per million nodes | 0 | +| Taint sinks - cryptographic operations | 0 | +| Taint sinks - query sinks | 0 | | Taint sources - active | 0 | -| Taint sources - total | 0 | +| Taint sources - disabled | 0 | +| Taint sources - sensitive data | 0 | diff --git a/rust/ql/integration-tests/hello-workspace/summary.cargo.expected b/rust/ql/integration-tests/hello-workspace/summary.cargo.expected index eb8f861f9358..e0d5ce240a39 100644 --- a/rust/ql/integration-tests/hello-workspace/summary.cargo.expected +++ b/rust/ql/integration-tests/hello-workspace/summary.cargo.expected @@ -14,6 +14,11 @@ | Macro calls - resolved | 2 | | Macro calls - total | 2 | | Macro calls - unresolved | 0 | -| Sensitive data | 0 | +| Taint edges - number of edges | 2 | +| Taint reach - nodes tainted | 0 | +| Taint reach - per million nodes | 0 | +| Taint sinks - cryptographic operations | 0 | +| Taint sinks - query sinks | 0 | | Taint sources - active | 0 | -| Taint sources - total | 0 | +| Taint sources - disabled | 0 | +| Taint sources - sensitive data | 0 | diff --git a/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected b/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected index 5c57c488fda0..a8c511ebf70d 100644 --- a/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected +++ b/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected @@ -14,6 +14,11 @@ | Macro calls - resolved | 2 | | Macro calls - total | 2 | | Macro calls - unresolved | 0 | -| Sensitive data | 0 | +| Taint edges - number of edges | 2 | +| Taint reach - nodes tainted | 0 | +| Taint reach - per million nodes | 0 | +| Taint sinks - cryptographic operations | 0 | +| Taint sinks - query sinks | 0 | | Taint sources - active | 0 | -| Taint sources - total | 0 | +| Taint sources - disabled | 0 | +| Taint sources - sensitive data | 0 | From dca87f37276e39ec123c568b02fc97ec29427ee0 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 16 Jan 2025 16:42:35 +0100 Subject: [PATCH 11/21] C++: Uncomment preprocessor test cases and add addition `#if` test case Note that the new test case shows that line splicing is not correctly handled in the case of `#if`. --- .../test/library-tests/preprocessor/preprocessor/pp.cpp | 7 +++++++ cpp/ql/test/library-tests/preprocessor/preprocessor/pp.h | 8 ++++---- .../preprocessor/preprocessor/preproc.expected | 7 +++++++ 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.cpp b/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.cpp index 20beabf8c932..a67fa4cdb425 100644 --- a/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.cpp +++ b/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.cpp @@ -68,3 +68,10 @@ int templateClassContext :: val = MACRO_TEMPLATECLASSCONTEXT_REFERENCED; #define INSTANTIATION templateClassContext tcci; + +#define BAR + +#if defined(BAR) && \ + defined(BAR) +#warning BAR defined +#endif diff --git a/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.h b/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.h index 288442716b52..780caa66d9ff 100644 --- a/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.h +++ b/cpp/ql/test/library-tests/preprocessor/preprocessor/pp.h @@ -4,15 +4,15 @@ //#pragma byte_order(big_endian) #warning "Not in Kansas any more" -//#define MULTILINE \ +#define MULTILINE \ /* Hello */ \ world \ /* from */ \ a long \ /* macro */ -//#undef \ +#undef \ MULTILINE -//#include \ - \ +#include \ + "pp.h" \ \ diff --git a/cpp/ql/test/library-tests/preprocessor/preprocessor/preproc.expected b/cpp/ql/test/library-tests/preprocessor/preprocessor/preproc.expected index cff0dd489eaa..dd8696b31650 100644 --- a/cpp/ql/test/library-tests/preprocessor/preprocessor/preproc.expected +++ b/cpp/ql/test/library-tests/preprocessor/preprocessor/preproc.expected @@ -27,6 +27,13 @@ | pp.cpp:0:0:0:0 | pp.cpp | 60 | 3 | 60 | 21 | Macro | IN_TEMPLATE | | | pp.cpp:0:0:0:0 | pp.cpp | 61 | 1 | 61 | 7 | PreprocessorEndif | N/A | N/A | | pp.cpp:0:0:0:0 | pp.cpp | 69 | 1 | 69 | 21 | Macro | INSTANTIATION | | +| pp.cpp:0:0:0:0 | pp.cpp | 72 | 1 | 72 | 11 | Macro | BAR | | +| pp.cpp:0:0:0:0 | pp.cpp | 74 | 1 | 74 | 21 | PreprocessorIf | defined(BAR) && \\ | N/A | +| pp.cpp:0:0:0:0 | pp.cpp | 76 | 1 | 76 | 20 | PreprocessorWarning | BAR defined | N/A | +| pp.cpp:0:0:0:0 | pp.cpp | 77 | 1 | 77 | 6 | PreprocessorEndif | N/A | N/A | | pp.h:0:0:0:0 | pp.h | 1 | 1 | 1 | 12 | PreprocessorPragma | once | N/A | | pp.h:0:0:0:0 | pp.h | 3 | 1 | 3 | 27 | PreprocessorLine | 33 "emerald_city.h" | N/A | | pp.h:0:0:0:0 | pp.h | 5 | 1 | 5 | 33 | PreprocessorWarning | "Not in Kansas any more" | N/A | +| pp.h:0:0:0:0 | pp.h | 7 | 1 | 11 | 8 | Macro | MULTILINE | world a long | +| pp.h:0:0:0:0 | pp.h | 13 | 1 | 14 | 11 | PreprocessorUndef | MULTILINE | N/A | +| pp.h:0:0:0:0 | pp.h | 16 | 1 | 17 | 8 | Include | "pp.h" | N/A | From ec256c327708cb1b64d1d8d0dcc3e97995659e51 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 16 Jan 2025 12:47:40 +0100 Subject: [PATCH 12/21] C#: More implicit ToString examples. --- .../library-tests/implicittostring/implicitToString.cs | 10 ++++++++++ .../implicittostring/implicitToString.expected | 8 ++++---- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/csharp/ql/test/library-tests/implicittostring/implicitToString.cs b/csharp/ql/test/library-tests/implicittostring/implicitToString.cs index d75044246f8e..8d74d23791ad 100644 --- a/csharp/ql/test/library-tests/implicittostring/implicitToString.cs +++ b/csharp/ql/test/library-tests/implicittostring/implicitToString.cs @@ -10,6 +10,10 @@ public override string ToString() } } + public class Container2 : Container { } + + public class Container3 { } + public class FormattableContainer : IFormattable { public string ToString(string format, IFormatProvider formatProvider) @@ -40,5 +44,11 @@ public void M() y = "Hello" + formattableContainer; // Implicit call to ToString(). y = $"Hello {formattableContainer}"; // Implicit call to ToString(string, IFormatProvider). We don't handle this. y = $"Hello {formattableContainer:D}"; // Implicit call to ToString(string, IFormatProvider). We don't handle this. + + var container2 = new Container2(); + y = "Hello" + container2; // Implicit Container.ToString call. + + var container3 = new Container3(); + y = "Hello" + container3; // Implicit Object.ToString call. } } diff --git a/csharp/ql/test/library-tests/implicittostring/implicitToString.expected b/csharp/ql/test/library-tests/implicittostring/implicitToString.expected index 4878b12a4fdb..371cb34c0d85 100644 --- a/csharp/ql/test/library-tests/implicittostring/implicitToString.expected +++ b/csharp/ql/test/library-tests/implicittostring/implicitToString.expected @@ -1,4 +1,4 @@ -| implicitToString.cs:31:27:31:35 | call to method ToString | -| implicitToString.cs:33:22:33:30 | call to method ToString | -| implicitToString.cs:35:22:35:30 | call to method ToString | -| implicitToString.cs:40:23:40:42 | call to method ToString | +| implicitToString.cs:35:27:35:35 | call to method ToString | +| implicitToString.cs:37:22:37:30 | call to method ToString | +| implicitToString.cs:39:22:39:30 | call to method ToString | +| implicitToString.cs:44:23:44:42 | call to method ToString | From 260ce805d1592af8afcf5a28032df617637da8ac Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 16 Jan 2025 12:52:33 +0100 Subject: [PATCH 13/21] C#: Also support implicit inherited ToString synthetic calls. --- .../Entities/Expressions/ImplicitToString.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitToString.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitToString.cs index f424e98a7a51..32c00f8a729e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitToString.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/ImplicitToString.cs @@ -14,7 +14,12 @@ internal sealed class ImplicitToString : Expression /// private static IMethodSymbol? GetToStringMethod(ITypeSymbol? type) { - return type? + if (type is null) + { + return null; + } + + var toString = type .GetMembers() .OfType() .Where(method => @@ -22,6 +27,8 @@ internal sealed class ImplicitToString : Expression method.Parameters.Length == 0 ) .FirstOrDefault(); + + return toString ?? GetToStringMethod(type.BaseType); } private ImplicitToString(ExpressionNodeInfo info, IMethodSymbol toString) : base(new ExpressionInfo(info.Context, AnnotatedTypeSymbol.CreateNotAnnotated(toString.ReturnType), info.Location, ExprKind.METHOD_INVOCATION, info.Parent, info.Child, isCompilerGenerated: true, info.ExprValue)) From aab88da11734b2c4b957151db0e2e3cc46dd7725 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 16 Jan 2025 12:52:56 +0100 Subject: [PATCH 14/21] C#: Update test expected output. --- .../library-tests/implicittostring/implicitToString.expected | 2 ++ 1 file changed, 2 insertions(+) diff --git a/csharp/ql/test/library-tests/implicittostring/implicitToString.expected b/csharp/ql/test/library-tests/implicittostring/implicitToString.expected index 371cb34c0d85..e75095f0a99f 100644 --- a/csharp/ql/test/library-tests/implicittostring/implicitToString.expected +++ b/csharp/ql/test/library-tests/implicittostring/implicitToString.expected @@ -2,3 +2,5 @@ | implicitToString.cs:37:22:37:30 | call to method ToString | | implicitToString.cs:39:22:39:30 | call to method ToString | | implicitToString.cs:44:23:44:42 | call to method ToString | +| implicitToString.cs:49:23:49:32 | call to method ToString | +| implicitToString.cs:52:23:52:32 | call to method ToString | From b6db1a34d6beb504cfdd622ca02ca64694aade86 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 16 Jan 2025 12:56:40 +0100 Subject: [PATCH 15/21] C#: Also make the implicitToString test print the type declaring the ToString call being synthesized. --- .../implicittostring/implicitToString.expected | 12 ++++++------ .../implicittostring/implicitToString.ql | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/csharp/ql/test/library-tests/implicittostring/implicitToString.expected b/csharp/ql/test/library-tests/implicittostring/implicitToString.expected index e75095f0a99f..14efebf23207 100644 --- a/csharp/ql/test/library-tests/implicittostring/implicitToString.expected +++ b/csharp/ql/test/library-tests/implicittostring/implicitToString.expected @@ -1,6 +1,6 @@ -| implicitToString.cs:35:27:35:35 | call to method ToString | -| implicitToString.cs:37:22:37:30 | call to method ToString | -| implicitToString.cs:39:22:39:30 | call to method ToString | -| implicitToString.cs:44:23:44:42 | call to method ToString | -| implicitToString.cs:49:23:49:32 | call to method ToString | -| implicitToString.cs:52:23:52:32 | call to method ToString | +| implicitToString.cs:35:27:35:35 | call to method ToString | Container | +| implicitToString.cs:37:22:37:30 | call to method ToString | Container | +| implicitToString.cs:39:22:39:30 | call to method ToString | Container | +| implicitToString.cs:44:23:44:42 | call to method ToString | FormattableContainer | +| implicitToString.cs:49:23:49:32 | call to method ToString | Container | +| implicitToString.cs:52:23:52:32 | call to method ToString | Object | diff --git a/csharp/ql/test/library-tests/implicittostring/implicitToString.ql b/csharp/ql/test/library-tests/implicittostring/implicitToString.ql index 4eb518d84c39..fee24b480c9c 100644 --- a/csharp/ql/test/library-tests/implicittostring/implicitToString.ql +++ b/csharp/ql/test/library-tests/implicittostring/implicitToString.ql @@ -2,4 +2,4 @@ import csharp from MethodCall c where c.isImplicit() -select c +select c, c.getTarget().getDeclaringType().toString() From bae29aeee44c1f8cc4e1b375f38dbd78afb85ca1 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 16 Jan 2025 13:50:04 +0100 Subject: [PATCH 16/21] C#: Update implications test expected output. --- csharp/ql/test/query-tests/Nullness/Implications.expected | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/csharp/ql/test/query-tests/Nullness/Implications.expected b/csharp/ql/test/query-tests/Nullness/Implications.expected index 45ffbc1d92b0..dbb6ab23a9aa 100644 --- a/csharp/ql/test/query-tests/Nullness/Implications.expected +++ b/csharp/ql/test/query-tests/Nullness/Implications.expected @@ -908,8 +908,8 @@ | D.cs:253:13:253:14 | access to local variable o2 | null | D.cs:249:18:249:38 | ... ? ... : ... | null | | D.cs:266:13:266:27 | ... is ... | true | D.cs:266:13:266:17 | access to local variable other | non-null | | D.cs:310:21:310:26 | ... + ... | non-null | D.cs:310:21:310:22 | "" | non-null | -| D.cs:310:21:310:26 | ... + ... | non-null | D.cs:310:26:310:26 | access to parameter a | non-null | -| D.cs:310:21:310:26 | ... + ... | null | D.cs:310:26:310:26 | access to parameter a | null | +| D.cs:310:21:310:26 | ... + ... | non-null | D.cs:310:26:310:26 | call to method ToString | non-null | +| D.cs:310:21:310:26 | ... + ... | null | D.cs:310:26:310:26 | call to method ToString | null | | D.cs:312:17:312:23 | !... | false | D.cs:312:18:312:23 | access to local variable s_null | true | | D.cs:312:17:312:23 | !... | true | D.cs:312:18:312:23 | access to local variable s_null | false | | D.cs:318:16:318:62 | ... && ... | true | D.cs:318:16:318:36 | ... == ... | true | From 5f9e1c37885bed399a19cf98d89d4a29f6b02427 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 16 Jan 2025 16:14:33 +0000 Subject: [PATCH 17/21] Apply suggestions from code review Co-authored-by: Simon Friis Vindum --- rust/ql/src/queries/summary/Stats.qll | 2 +- rust/ql/src/queries/summary/TaintReach.qll | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust/ql/src/queries/summary/Stats.qll b/rust/ql/src/queries/summary/Stats.qll index 05057fe8209b..8bdb25381bc6 100644 --- a/rust/ql/src/queries/summary/Stats.qll +++ b/rust/ql/src/queries/summary/Stats.qll @@ -64,4 +64,4 @@ string getAQuerySinkKind(DataFlow::Node n) { /** * Gets a count of the total number of query sinks in the database. */ -int getQuerySinksCount() { result = count(DataFlow::Node n | exists(getAQuerySinkKind(n)) | n) } +int getQuerySinksCount() { result = count(DataFlow::Node n | exists(getAQuerySinkKind(n))) } diff --git a/rust/ql/src/queries/summary/TaintReach.qll b/rust/ql/src/queries/summary/TaintReach.qll index f2463b204f4a..0f00fe6f7c6e 100644 --- a/rust/ql/src/queries/summary/TaintReach.qll +++ b/rust/ql/src/queries/summary/TaintReach.qll @@ -20,12 +20,12 @@ private module TaintReachConfig implements DataFlow::ConfigSig { private module TaintReachFlow = TaintTracking::Global; /** - * Gets the total number of dataflow nodes that taint reaches (from any source). + * Gets the total number of data flow nodes that taint reaches (from any source). */ int getTaintedNodesCount() { result = count(DataFlow::Node n | TaintReachFlow::flowTo(n)) } /** - * Gets the proportion of dataflow nodes that taint reaches (from any source), + * Gets the proportion of data flow nodes that taint reaches (from any source), * expressed as a count per million nodes. */ float getTaintReach() { result = (getTaintedNodesCount() * 1000000.0) / count(DataFlow::Node n) } From e5faf92babaa163f79d348300c3c4a3210859c16 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 16 Jan 2025 16:16:02 +0000 Subject: [PATCH 18/21] Rust: Make QL-for-QL happy (part 2). --- rust/ql/src/queries/summary/QuerySinks.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust/ql/src/queries/summary/QuerySinks.ql b/rust/ql/src/queries/summary/QuerySinks.ql index bc89f801f715..09cd7fcb2991 100644 --- a/rust/ql/src/queries/summary/QuerySinks.ql +++ b/rust/ql/src/queries/summary/QuerySinks.ql @@ -14,4 +14,4 @@ import codeql.rust.dataflow.DataFlow import Stats from DataFlow::Node n -select n, "Sink for " + strictconcat(getAQuerySinkKind(n), ", ") +select n, "Sink for " + strictconcat(getAQuerySinkKind(n), ", ") + "." From eadccf27ef50f5c8627786190d28144bcd066ebe Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 10 Jan 2025 20:54:03 +0000 Subject: [PATCH 19/21] C++: Add test cases with missing inferred equalities. --- .../controlflow/guards/Guards.expected | 8 +++ .../controlflow/guards/GuardsCompare.expected | 44 ++++++++++++ .../controlflow/guards/GuardsControl.expected | 16 +++++ .../controlflow/guards/GuardsEnsure.expected | 68 +++++++++++++++++++ .../library-tests/controlflow/guards/test.cpp | 22 ++++++ 5 files changed, 158 insertions(+) diff --git a/cpp/ql/test/library-tests/controlflow/guards/Guards.expected b/cpp/ql/test/library-tests/controlflow/guards/Guards.expected index a56d8964c095..48bfb7aaf966 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/Guards.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/Guards.expected @@ -69,3 +69,11 @@ | test.cpp:168:8:168:8 | b | | test.cpp:176:7:176:8 | ! ... | | test.cpp:176:8:176:8 | c | +| test.cpp:182:6:182:16 | ! ... | +| test.cpp:182:8:182:9 | b1 | +| test.cpp:182:8:182:15 | ... && ... | +| test.cpp:182:14:182:15 | b2 | +| test.cpp:193:6:193:16 | ! ... | +| test.cpp:193:8:193:9 | b1 | +| test.cpp:193:8:193:15 | ... \|\| ... | +| test.cpp:193:14:193:15 | b2 | diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected index f2ce7f611f39..f39eab45826e 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected @@ -545,8 +545,12 @@ | 182 | ! ... == 1 when ... && ... is false | | 182 | ... && ... != 0 when ! ... is false | | 182 | ... && ... != 0 when ... && ... is true | +| 182 | ... && ... != 1 when ! ... is true | +| 182 | ... && ... != 1 when ... && ... is false | | 182 | ... && ... == 0 when ! ... is true | | 182 | ... && ... == 0 when ... && ... is false | +| 182 | ... && ... == 1 when ! ... is false | +| 182 | ... && ... == 1 when ... && ... is true | | 182 | ... < ... != 0 when ... && ... is true | | 182 | ... < ... != 0 when ... < ... is true | | 182 | ... < ... != 1 when ... < ... is false | @@ -559,6 +563,18 @@ | 182 | ... >= ... == 0 when ... >= ... is false | | 182 | ... >= ... == 1 when ... && ... is true | | 182 | ... >= ... == 1 when ... >= ... is true | +| 182 | b1 != 0 when ... && ... is true | +| 182 | b1 != 0 when b1 is true | +| 182 | b1 != 1 when b1 is false | +| 182 | b1 == 0 when b1 is false | +| 182 | b1 == 1 when ... && ... is true | +| 182 | b1 == 1 when b1 is true | +| 182 | b2 != 0 when ... && ... is true | +| 182 | b2 != 0 when b2 is true | +| 182 | b2 != 1 when b2 is false | +| 182 | b2 == 0 when b2 is false | +| 182 | b2 == 1 when ... && ... is true | +| 182 | b2 == 1 when b2 is true | | 182 | foo < 1.0+0 when ... && ... is true | | 182 | foo < 1.0+0 when ... < ... is true | | 182 | foo < 9.999999999999999547e-07+0 when ... >= ... is false | @@ -577,6 +593,34 @@ | 190 | c != 0 when c is true | | 190 | c == 0 when ! ... is true | | 190 | c == 0 when c is false | +| 193 | ! ... != 0 when ! ... is true | +| 193 | ! ... != 0 when ... \|\| ... is false | +| 193 | ! ... != 1 when ! ... is false | +| 193 | ! ... != 1 when ... \|\| ... is true | +| 193 | ! ... == 0 when ! ... is false | +| 193 | ! ... == 0 when ... \|\| ... is true | +| 193 | ! ... == 1 when ! ... is true | +| 193 | ! ... == 1 when ... \|\| ... is false | +| 193 | ... \|\| ... != 0 when ! ... is false | +| 193 | ... \|\| ... != 0 when ... \|\| ... is true | +| 193 | ... \|\| ... != 1 when ! ... is true | +| 193 | ... \|\| ... != 1 when ... \|\| ... is false | +| 193 | ... \|\| ... == 0 when ! ... is true | +| 193 | ... \|\| ... == 0 when ... \|\| ... is false | +| 193 | ... \|\| ... == 1 when ! ... is false | +| 193 | ... \|\| ... == 1 when ... \|\| ... is true | +| 193 | b1 != 0 when b1 is true | +| 193 | b1 != 1 when ... \|\| ... is false | +| 193 | b1 != 1 when b1 is false | +| 193 | b1 == 0 when ... \|\| ... is false | +| 193 | b1 == 0 when b1 is false | +| 193 | b1 == 1 when b1 is true | +| 193 | b2 != 0 when b2 is true | +| 193 | b2 != 1 when ... \|\| ... is false | +| 193 | b2 != 1 when b2 is false | +| 193 | b2 == 0 when ... \|\| ... is false | +| 193 | b2 == 0 when b2 is false | +| 193 | b2 == 1 when b2 is true | | 198 | ! ... != 0 when ! ... is true | | 198 | ! ... != 0 when b is false | | 198 | ! ... != 1 when ! ... is false | diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected index 2857bdf511bf..cee020adadd9 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsControl.expected @@ -130,3 +130,19 @@ | test.cpp:168:8:168:8 | b | false | 168 | 170 | | test.cpp:176:7:176:8 | ! ... | true | 176 | 178 | | test.cpp:176:8:176:8 | c | false | 176 | 178 | +| test.cpp:182:6:182:16 | ! ... | false | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | true | 182 | 184 | +| test.cpp:182:8:182:9 | b1 | true | 181 | 182 | +| test.cpp:182:8:182:9 | b1 | true | 182 | 182 | +| test.cpp:182:8:182:15 | ... && ... | false | 182 | 184 | +| test.cpp:182:8:182:15 | ... && ... | true | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | true | 185 | 188 | +| test.cpp:182:14:182:15 | b2 | true | 181 | 182 | +| test.cpp:193:6:193:16 | ! ... | false | 197 | 199 | +| test.cpp:193:6:193:16 | ! ... | true | 193 | 196 | +| test.cpp:193:8:193:9 | b1 | false | 192 | 193 | +| test.cpp:193:8:193:9 | b1 | false | 193 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | false | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | false | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | true | 197 | 199 | +| test.cpp:193:14:193:15 | b2 | false | 192 | 193 | diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected index 73a809b3175c..9ff363e33109 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected @@ -636,3 +636,71 @@ unary | test.cpp:176:8:176:8 | c | test.cpp:176:7:176:8 | ! ... | == | 1 | 176 | 178 | | test.cpp:176:8:176:8 | c | test.cpp:176:8:176:8 | c | != | 1 | 176 | 178 | | test.cpp:176:8:176:8 | c | test.cpp:176:8:176:8 | c | == | 0 | 176 | 178 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:6:182:16 | ! ... | != | 0 | 182 | 184 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:6:182:16 | ! ... | != | 1 | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:6:182:16 | ! ... | == | 0 | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:6:182:16 | ! ... | == | 1 | 182 | 184 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:15 | ... && ... | != | 0 | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:15 | ... && ... | != | 1 | 182 | 184 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:15 | ... && ... | == | 0 | 182 | 184 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:15 | ... && ... | == | 1 | 185 | 188 | +| test.cpp:182:8:182:9 | b1 | test.cpp:182:8:182:9 | b1 | != | 0 | 181 | 182 | +| test.cpp:182:8:182:9 | b1 | test.cpp:182:8:182:9 | b1 | != | 0 | 182 | 182 | +| test.cpp:182:8:182:9 | b1 | test.cpp:182:8:182:9 | b1 | == | 1 | 181 | 182 | +| test.cpp:182:8:182:9 | b1 | test.cpp:182:8:182:9 | b1 | == | 1 | 182 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:6:182:16 | ! ... | != | 0 | 182 | 184 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:6:182:16 | ! ... | != | 1 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:6:182:16 | ! ... | != | 1 | 185 | 188 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:6:182:16 | ! ... | == | 0 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:6:182:16 | ! ... | == | 0 | 185 | 188 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:6:182:16 | ! ... | == | 1 | 182 | 184 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:9 | b1 | != | 0 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:9 | b1 | != | 0 | 185 | 188 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:9 | b1 | == | 1 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:9 | b1 | == | 1 | 185 | 188 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:15 | ... && ... | != | 0 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:15 | ... && ... | != | 0 | 185 | 188 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:15 | ... && ... | != | 1 | 182 | 184 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:15 | ... && ... | == | 0 | 182 | 184 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:15 | ... && ... | == | 1 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:8:182:15 | ... && ... | == | 1 | 185 | 188 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:14:182:15 | b2 | != | 0 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:14:182:15 | b2 | != | 0 | 185 | 188 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:14:182:15 | b2 | == | 1 | 181 | 182 | +| test.cpp:182:8:182:15 | ... && ... | test.cpp:182:14:182:15 | b2 | == | 1 | 185 | 188 | +| test.cpp:182:14:182:15 | b2 | test.cpp:182:14:182:15 | b2 | != | 0 | 181 | 182 | +| test.cpp:182:14:182:15 | b2 | test.cpp:182:14:182:15 | b2 | == | 1 | 181 | 182 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:6:193:16 | ! ... | != | 0 | 193 | 196 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:6:193:16 | ! ... | != | 1 | 197 | 199 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:6:193:16 | ! ... | == | 0 | 197 | 199 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:6:193:16 | ! ... | == | 1 | 193 | 196 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:15 | ... \|\| ... | != | 0 | 197 | 199 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:15 | ... \|\| ... | != | 1 | 193 | 196 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:15 | ... \|\| ... | == | 0 | 193 | 196 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:15 | ... \|\| ... | == | 1 | 197 | 199 | +| test.cpp:193:8:193:9 | b1 | test.cpp:193:8:193:9 | b1 | != | 1 | 192 | 193 | +| test.cpp:193:8:193:9 | b1 | test.cpp:193:8:193:9 | b1 | != | 1 | 193 | 193 | +| test.cpp:193:8:193:9 | b1 | test.cpp:193:8:193:9 | b1 | == | 0 | 192 | 193 | +| test.cpp:193:8:193:9 | b1 | test.cpp:193:8:193:9 | b1 | == | 0 | 193 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:6:193:16 | ! ... | != | 0 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:6:193:16 | ! ... | != | 0 | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:6:193:16 | ! ... | != | 1 | 197 | 199 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:6:193:16 | ! ... | == | 0 | 197 | 199 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:6:193:16 | ! ... | == | 1 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:6:193:16 | ! ... | == | 1 | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:9 | b1 | != | 1 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:9 | b1 | != | 1 | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:9 | b1 | == | 0 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:9 | b1 | == | 0 | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:15 | ... \|\| ... | != | 0 | 197 | 199 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:15 | ... \|\| ... | != | 1 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:15 | ... \|\| ... | != | 1 | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:15 | ... \|\| ... | == | 0 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:15 | ... \|\| ... | == | 0 | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:8:193:15 | ... \|\| ... | == | 1 | 197 | 199 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:14:193:15 | b2 | != | 1 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:14:193:15 | b2 | != | 1 | 193 | 196 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:14:193:15 | b2 | == | 0 | 192 | 193 | +| test.cpp:193:8:193:15 | ... \|\| ... | test.cpp:193:14:193:15 | b2 | == | 0 | 193 | 196 | +| test.cpp:193:14:193:15 | b2 | test.cpp:193:14:193:15 | b2 | != | 1 | 192 | 193 | +| test.cpp:193:14:193:15 | b2 | test.cpp:193:14:193:15 | b2 | == | 0 | 192 | 193 | diff --git a/cpp/ql/test/library-tests/controlflow/guards/test.cpp b/cpp/ql/test/library-tests/controlflow/guards/test.cpp index 3bdcdcc01ff5..7349671633d4 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/test.cpp +++ b/cpp/ql/test/library-tests/controlflow/guards/test.cpp @@ -176,4 +176,26 @@ void test_with_negated_binary_relational(int a, int b) { if (!c) { } +} + +void test_logical_and(bool b1, bool b2) { + if(!(b1 && b2)) { + use(b1); + use(b2); + } else { + // b1 = true and b2 = true + use(b1); + use(b2); + } +} + +void test_logical_or(bool b1, bool b2) { + if(!(b1 || b2)) { + // b1 = false and b2 = false + use(b1); + use(b2); + } else { + use(b1); + use(b2); + } } \ No newline at end of file From 5c494c3f66cf8349a357369734552d513011a491 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 17 Jan 2025 13:07:41 +0000 Subject: [PATCH 20/21] C++: Infer 'b1 = true' and 'b2 = true' from 'b1 && b2 = true', and infer 'b1 = false' and 'b2 = false' from 'b1 || b2 = false'. --- cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll | 12 ++++++++++++ .../controlflow/guards/GuardsCompare.expected | 8 ++++++++ .../controlflow/guards/GuardsEnsure.expected | 8 ++++++++ 3 files changed, 28 insertions(+) diff --git a/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll b/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll index b836f12c96f4..76a1299cb536 100644 --- a/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll +++ b/cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll @@ -994,6 +994,18 @@ private module Cached { ) or unary_compares_eq(test.(BuiltinExpectCallValueNumber).getCondition(), op, k, areEqual, value) + or + exists(BinaryLogicalOperation logical, Expr operand, boolean b | + test.getAnInstruction().getUnconvertedResultExpression() = logical and + op.getDef().getUnconvertedResultExpression() = operand and + logical.impliesValue(operand, b, value.(BooleanValue).getValue()) + | + k = 1 and + areEqual = b + or + k = 0 and + areEqual = b.booleanNot() + ) } /** Rearrange various simple comparisons into `left == right + k` form. */ diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected index f39eab45826e..2ff93603a267 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsCompare.expected @@ -563,16 +563,20 @@ | 182 | ... >= ... == 0 when ... >= ... is false | | 182 | ... >= ... == 1 when ... && ... is true | | 182 | ... >= ... == 1 when ... >= ... is true | +| 182 | b1 != 0 when ! ... is false | | 182 | b1 != 0 when ... && ... is true | | 182 | b1 != 0 when b1 is true | | 182 | b1 != 1 when b1 is false | | 182 | b1 == 0 when b1 is false | +| 182 | b1 == 1 when ! ... is false | | 182 | b1 == 1 when ... && ... is true | | 182 | b1 == 1 when b1 is true | +| 182 | b2 != 0 when ! ... is false | | 182 | b2 != 0 when ... && ... is true | | 182 | b2 != 0 when b2 is true | | 182 | b2 != 1 when b2 is false | | 182 | b2 == 0 when b2 is false | +| 182 | b2 == 1 when ! ... is false | | 182 | b2 == 1 when ... && ... is true | | 182 | b2 == 1 when b2 is true | | 182 | foo < 1.0+0 when ... && ... is true | @@ -610,14 +614,18 @@ | 193 | ... \|\| ... == 1 when ! ... is false | | 193 | ... \|\| ... == 1 when ... \|\| ... is true | | 193 | b1 != 0 when b1 is true | +| 193 | b1 != 1 when ! ... is true | | 193 | b1 != 1 when ... \|\| ... is false | | 193 | b1 != 1 when b1 is false | +| 193 | b1 == 0 when ! ... is true | | 193 | b1 == 0 when ... \|\| ... is false | | 193 | b1 == 0 when b1 is false | | 193 | b1 == 1 when b1 is true | | 193 | b2 != 0 when b2 is true | +| 193 | b2 != 1 when ! ... is true | | 193 | b2 != 1 when ... \|\| ... is false | | 193 | b2 != 1 when b2 is false | +| 193 | b2 == 0 when ! ... is true | | 193 | b2 == 0 when ... \|\| ... is false | | 193 | b2 == 0 when b2 is false | | 193 | b2 == 1 when b2 is true | diff --git a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected index 9ff363e33109..288b49ceb687 100644 --- a/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected +++ b/cpp/ql/test/library-tests/controlflow/guards/GuardsEnsure.expected @@ -640,10 +640,14 @@ unary | test.cpp:182:6:182:16 | ! ... | test.cpp:182:6:182:16 | ! ... | != | 1 | 185 | 188 | | test.cpp:182:6:182:16 | ! ... | test.cpp:182:6:182:16 | ! ... | == | 0 | 185 | 188 | | test.cpp:182:6:182:16 | ! ... | test.cpp:182:6:182:16 | ! ... | == | 1 | 182 | 184 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:9 | b1 | != | 0 | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:9 | b1 | == | 1 | 185 | 188 | | test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:15 | ... && ... | != | 0 | 185 | 188 | | test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:15 | ... && ... | != | 1 | 182 | 184 | | test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:15 | ... && ... | == | 0 | 182 | 184 | | test.cpp:182:6:182:16 | ! ... | test.cpp:182:8:182:15 | ... && ... | == | 1 | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:14:182:15 | b2 | != | 0 | 185 | 188 | +| test.cpp:182:6:182:16 | ! ... | test.cpp:182:14:182:15 | b2 | == | 1 | 185 | 188 | | test.cpp:182:8:182:9 | b1 | test.cpp:182:8:182:9 | b1 | != | 0 | 181 | 182 | | test.cpp:182:8:182:9 | b1 | test.cpp:182:8:182:9 | b1 | != | 0 | 182 | 182 | | test.cpp:182:8:182:9 | b1 | test.cpp:182:8:182:9 | b1 | == | 1 | 181 | 182 | @@ -674,10 +678,14 @@ unary | test.cpp:193:6:193:16 | ! ... | test.cpp:193:6:193:16 | ! ... | != | 1 | 197 | 199 | | test.cpp:193:6:193:16 | ! ... | test.cpp:193:6:193:16 | ! ... | == | 0 | 197 | 199 | | test.cpp:193:6:193:16 | ! ... | test.cpp:193:6:193:16 | ! ... | == | 1 | 193 | 196 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:9 | b1 | != | 1 | 193 | 196 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:9 | b1 | == | 0 | 193 | 196 | | test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:15 | ... \|\| ... | != | 0 | 197 | 199 | | test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:15 | ... \|\| ... | != | 1 | 193 | 196 | | test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:15 | ... \|\| ... | == | 0 | 193 | 196 | | test.cpp:193:6:193:16 | ! ... | test.cpp:193:8:193:15 | ... \|\| ... | == | 1 | 197 | 199 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:14:193:15 | b2 | != | 1 | 193 | 196 | +| test.cpp:193:6:193:16 | ! ... | test.cpp:193:14:193:15 | b2 | == | 0 | 193 | 196 | | test.cpp:193:8:193:9 | b1 | test.cpp:193:8:193:9 | b1 | != | 1 | 192 | 193 | | test.cpp:193:8:193:9 | b1 | test.cpp:193:8:193:9 | b1 | != | 1 | 193 | 193 | | test.cpp:193:8:193:9 | b1 | test.cpp:193:8:193:9 | b1 | == | 0 | 192 | 193 | From 00dca292166b410984ccd75db29bf59292aad040 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 00:21:01 +0000 Subject: [PATCH 21/21] Add changed framework coverage reports --- csharp/documentation/library-coverage/coverage.csv | 1 + csharp/documentation/library-coverage/coverage.rst | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/csharp/documentation/library-coverage/coverage.csv b/csharp/documentation/library-coverage/coverage.csv index 44738dfc03b3..2855bd9644c4 100644 --- a/csharp/documentation/library-coverage/coverage.csv +++ b/csharp/documentation/library-coverage/coverage.csv @@ -14,6 +14,7 @@ Microsoft.Android.Build,,1,14,,,,,,,,,,,,,1,,,,,,12,2 Microsoft.Apple.Build,,,7,,,,,,,,,,,,,,,,,,,7, Microsoft.ApplicationBlocks.Data,28,,,,,,,,,,,,28,,,,,,,,,, Microsoft.AspNetCore.Components,2,4,2,,,,,,,2,,,,,,,,,4,,,1,1 +Microsoft.AspNetCore.Http,,,1,,,,,,,,,,,,,,,,,,,1, Microsoft.AspNetCore.Mvc,,,2,,,,,,,,,,,,,,,,,,,,2 Microsoft.AspNetCore.WebUtilities,,,2,,,,,,,,,,,,,,,,,,,2, Microsoft.CSharp,,,2,,,,,,,,,,,,,,,,,,,2, diff --git a/csharp/documentation/library-coverage/coverage.rst b/csharp/documentation/library-coverage/coverage.rst index 1d3285094a23..b2786d66767d 100644 --- a/csharp/documentation/library-coverage/coverage.rst +++ b/csharp/documentation/library-coverage/coverage.rst @@ -9,6 +9,6 @@ C# framework & library support Framework / library,Package,Flow sources,Taint & value steps,Sinks (total),`CWE-079` :sub:`Cross-site scripting` `ServiceStack `_,"``ServiceStack.*``, ``ServiceStack``",,7,194, System,"``System.*``, ``System``",47,10819,54,5 - Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``JsonToItemsTaskFactory``, ``Microsoft.Android.Build``, ``Microsoft.Apple.Build``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.AspNetCore.Components``, ``Microsoft.AspNetCore.Mvc``, ``Microsoft.AspNetCore.WebUtilities``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.DotNet.Build.Tasks``, ``Microsoft.DotNet.PlatformAbstractions``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.JSInterop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NET.Sdk.WebAssembly``, ``Microsoft.NET.WebAssembly.Webcil``, ``Microsoft.VisualBasic``, ``Microsoft.WebAssembly.Build.Tasks``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",61,2074,152,4 - Totals,,108,12900,400,9 + Others,"``Amazon.Lambda.APIGatewayEvents``, ``Amazon.Lambda.Core``, ``Dapper``, ``ILCompiler``, ``ILLink.RoslynAnalyzer``, ``ILLink.Shared``, ``ILLink.Tasks``, ``Internal.IL``, ``Internal.Pgo``, ``Internal.TypeSystem``, ``JsonToItemsTaskFactory``, ``Microsoft.Android.Build``, ``Microsoft.Apple.Build``, ``Microsoft.ApplicationBlocks.Data``, ``Microsoft.AspNetCore.Components``, ``Microsoft.AspNetCore.Http``, ``Microsoft.AspNetCore.Mvc``, ``Microsoft.AspNetCore.WebUtilities``, ``Microsoft.CSharp``, ``Microsoft.Diagnostics.Tools.Pgo``, ``Microsoft.DotNet.Build.Tasks``, ``Microsoft.DotNet.PlatformAbstractions``, ``Microsoft.EntityFrameworkCore``, ``Microsoft.Extensions.Caching.Distributed``, ``Microsoft.Extensions.Caching.Memory``, ``Microsoft.Extensions.Configuration``, ``Microsoft.Extensions.DependencyInjection``, ``Microsoft.Extensions.DependencyModel``, ``Microsoft.Extensions.Diagnostics.Metrics``, ``Microsoft.Extensions.FileProviders``, ``Microsoft.Extensions.FileSystemGlobbing``, ``Microsoft.Extensions.Hosting``, ``Microsoft.Extensions.Http``, ``Microsoft.Extensions.Logging``, ``Microsoft.Extensions.Options``, ``Microsoft.Extensions.Primitives``, ``Microsoft.Interop``, ``Microsoft.JSInterop``, ``Microsoft.NET.Build.Tasks``, ``Microsoft.NET.Sdk.WebAssembly``, ``Microsoft.NET.WebAssembly.Webcil``, ``Microsoft.VisualBasic``, ``Microsoft.WebAssembly.Build.Tasks``, ``Microsoft.Win32``, ``Mono.Linker``, ``MySql.Data.MySqlClient``, ``Newtonsoft.Json``, ``SourceGenerators``, ``Windows.Security.Cryptography.Core``",61,2075,152,4 + Totals,,108,12901,400,9