diff --git a/rust/ql/consistency-queries/SsaConsistency.ql b/rust/ql/consistency-queries/SsaConsistency.ql index 51a5f97e9786..1774f269749c 100644 --- a/rust/ql/consistency-queries/SsaConsistency.ql +++ b/rust/ql/consistency-queries/SsaConsistency.ql @@ -1,3 +1,10 @@ +/** + * @name Static single assignment inconsistencies + * @description Lists the static single assignment inconsistencies in the database. This query is intended for internal use. + * @kind table + * @id rust/diagnostics/ssa-consistency + */ + import codeql.rust.dataflow.Ssa import codeql.rust.dataflow.internal.SsaImpl import Consistency diff --git a/rust/ql/integration-tests/hello-project/summary.expected b/rust/ql/integration-tests/hello-project/summary.expected index 1ce4e784cbf2..1f343b197c0f 100644 --- a/rust/ql/integration-tests/hello-project/summary.expected +++ b/rust/ql/integration-tests/hello-project/summary.expected @@ -7,6 +7,7 @@ | Inconsistencies - AST | 0 | | Inconsistencies - CFG | 0 | | Inconsistencies - Path resolution | 0 | +| Inconsistencies - SSA | 0 | | Inconsistencies - data flow | 0 | | Lines of code extracted | 6 | | Lines of user code extracted | 6 | diff --git a/rust/ql/integration-tests/hello-workspace/summary.cargo.expected b/rust/ql/integration-tests/hello-workspace/summary.cargo.expected index 67da3bcf3090..5912f7d69baf 100644 --- a/rust/ql/integration-tests/hello-workspace/summary.cargo.expected +++ b/rust/ql/integration-tests/hello-workspace/summary.cargo.expected @@ -7,6 +7,7 @@ | Inconsistencies - AST | 0 | | Inconsistencies - CFG | 0 | | Inconsistencies - Path resolution | 0 | +| Inconsistencies - SSA | 0 | | Inconsistencies - data flow | 0 | | Lines of code extracted | 9 | | Lines of user code extracted | 9 | 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 67da3bcf3090..5912f7d69baf 100644 --- a/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected +++ b/rust/ql/integration-tests/hello-workspace/summary.rust-project.expected @@ -7,6 +7,7 @@ | Inconsistencies - AST | 0 | | Inconsistencies - CFG | 0 | | Inconsistencies - Path resolution | 0 | +| Inconsistencies - SSA | 0 | | Inconsistencies - data flow | 0 | | Lines of code extracted | 9 | | Lines of user code extracted | 9 | diff --git a/rust/ql/src/queries/diagnostics/SsaConsistencyCounts.ql b/rust/ql/src/queries/diagnostics/SsaConsistencyCounts.ql new file mode 100644 index 000000000000..7b79a275f0ad --- /dev/null +++ b/rust/ql/src/queries/diagnostics/SsaConsistencyCounts.ql @@ -0,0 +1,14 @@ +/** + * @name Static single assignment inconsistency counts + * @description Counts the number of static single assignment inconsistencies of each type. This query is intended for internal use. + * @kind diagnostic + * @id rust/diagnostics/ssa-consistency-counts + */ + +private import codeql.rust.dataflow.internal.SsaImpl::Consistency as SsaConsistency + +// see also `rust/diagnostics/ssa-consistency`, which lists the +// individual inconsistency results. +from string type, int num +where num = SsaConsistency::getInconsistencyCounts(type) +select type, num diff --git a/rust/ql/src/queries/summary/Stats.qll b/rust/ql/src/queries/summary/Stats.qll index ec252c36d701..17ce97871d0f 100644 --- a/rust/ql/src/queries/summary/Stats.qll +++ b/rust/ql/src/queries/summary/Stats.qll @@ -10,6 +10,7 @@ private import codeql.rust.internal.AstConsistency as AstConsistency private import codeql.rust.internal.PathResolutionConsistency as PathResolutionConsistency private import codeql.rust.controlflow.internal.CfgConsistency as CfgConsistency private import codeql.rust.dataflow.internal.DataFlowConsistency as DataFlowConsistency +private import codeql.rust.dataflow.internal.SsaImpl::Consistency as SsaConsistency private import codeql.rust.Concepts private import codeql.rust.Diagnostics private import codeql.rust.security.SensitiveData @@ -57,6 +58,13 @@ int getTotalCfgInconsistencies() { result = sum(string type | | CfgConsistency::getCfgInconsistencyCounts(type)) } +/** + * Gets a count of the total number of SSA inconsistencies in the database. + */ +int getTotalSsaInconsistencies() { + result = sum(string type | | SsaConsistency::getInconsistencyCounts(type)) +} + /** * Gets a count of the total number of data flow inconsistencies in the database. */ @@ -142,6 +150,8 @@ predicate inconsistencyStats(string key, int value) { or key = "Inconsistencies - CFG" and value = getTotalCfgInconsistencies() or + key = "Inconsistencies - SSA" and value = getTotalSsaInconsistencies() + or key = "Inconsistencies - data flow" and value = getTotalDataFlowInconsistencies() } diff --git a/rust/ql/test/query-tests/diagnostics/SsaConsistencyCounts.expected b/rust/ql/test/query-tests/diagnostics/SsaConsistencyCounts.expected new file mode 100644 index 000000000000..7e264176d32d --- /dev/null +++ b/rust/ql/test/query-tests/diagnostics/SsaConsistencyCounts.expected @@ -0,0 +1,10 @@ +| Definition cannot reach a read | 0 | +| End of a basic block can be reached by multiple definitions | 0 | +| Phi has less than 2 immediately prior references | 0 | +| Phi node has less than two inputs | 0 | +| Phi read has less than 2 immediately prior references | 0 | +| Read can be reached from multiple definitions | 0 | +| Read cannot be reached from a definition | 0 | +| Read does not have a prior reference | 0 | +| Read has multiple prior references | 0 | +| Read is not dominated by a definition | 0 | diff --git a/rust/ql/test/query-tests/diagnostics/SsaConsistencyCounts.qlref b/rust/ql/test/query-tests/diagnostics/SsaConsistencyCounts.qlref new file mode 100644 index 000000000000..40242e81c245 --- /dev/null +++ b/rust/ql/test/query-tests/diagnostics/SsaConsistencyCounts.qlref @@ -0,0 +1 @@ +queries/diagnostics/SsaConsistencyCounts.ql diff --git a/rust/ql/test/query-tests/diagnostics/SummaryStatsReduced.expected b/rust/ql/test/query-tests/diagnostics/SummaryStatsReduced.expected index 640bd179abd3..ed21d9772fce 100644 --- a/rust/ql/test/query-tests/diagnostics/SummaryStatsReduced.expected +++ b/rust/ql/test/query-tests/diagnostics/SummaryStatsReduced.expected @@ -7,6 +7,7 @@ | Inconsistencies - AST | 0 | | Inconsistencies - CFG | 0 | | Inconsistencies - Path resolution | 0 | +| Inconsistencies - SSA | 0 | | Inconsistencies - data flow | 0 | | Lines of code extracted | 60 | | Lines of user code extracted | 60 | diff --git a/shared/ssa/codeql/ssa/Ssa.qll b/shared/ssa/codeql/ssa/Ssa.qll index 5a18d128ab62..a0a8a1c864de 100644 --- a/shared/ssa/codeql/ssa/Ssa.qll +++ b/shared/ssa/codeql/ssa/Ssa.qll @@ -1468,6 +1468,58 @@ module Make Input> { inputRefs = count(BasicBlock bb, int i | AdjacentSsaRefs::adjacentRefPhi(bb, i, _, bbPhi, v)) and inputRefs < 2 } + + /** + * Gets counts of inconsistencies of each type. + */ + int getInconsistencyCounts(string type) { + // total results from all the SSA consistency query predicates. + type = "Read can be reached from multiple definitions" and + result = + count(Definition def, SourceVariable v, BasicBlock bb, int i | nonUniqueDef(def, v, bb, i)) + or + type = "Read cannot be reached from a definition" and + result = count(SourceVariable v, BasicBlock bb, int i | readWithoutDef(v, bb, i)) + or + type = "Definition cannot reach a read" and + result = count(Definition def, SourceVariable v | deadDef(def, v)) + or + type = "Read is not dominated by a definition" and + result = + count(Definition def, SourceVariable v, BasicBlock bb, int i | + notDominatedByDef(def, v, bb, i) + ) + or + type = "End of a basic block can be reached by multiple definitions" and + result = + count(Definition def, SourceVariable v, BasicBlock bb | + nonUniqueDefReachesEndOfBlock(def, v, bb) + ) + or + type = "Phi node has less than two inputs" and + result = count(PhiNode phi, int inputs | uselessPhiNode(phi, inputs)) + or + type = "Read does not have a prior reference" and + result = count(SourceVariable v, BasicBlock bb, int i | readWithoutPriorRef(v, bb, i)) + or + type = "Read has multiple prior references" and + result = + count(SourceVariable v, BasicBlock bb1, int i1, BasicBlock bb2, int i2 | + readWithMultiplePriorRefs(v, bb1, i1, bb2, i2) + ) + or + type = "Phi has less than 2 immediately prior references" and + result = + count(PhiNode phi, BasicBlock bbPhi, SourceVariable v, int inputRefs | + phiWithoutTwoPriorRefs(phi, bbPhi, v, inputRefs) + ) + or + type = "Phi read has less than 2 immediately prior references" and + result = + count(BasicBlock bbPhi, SourceVariable v, int inputRefs | + phiReadWithoutTwoPriorRefs(bbPhi, v, inputRefs) + ) + } } /** Provides the input to `DataFlowIntegration`. */