diff --git a/change_notes/2026-03-13-share-array-delete-type-mismatch-query.md b/change_notes/2026-03-13-share-array-delete-type-mismatch-query.md new file mode 100644 index 0000000000..38b11f3517 --- /dev/null +++ b/change_notes/2026-03-13-share-array-delete-type-mismatch-query.md @@ -0,0 +1,3 @@ + - `EXP51-CPP` - `DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql`: + - Refactored query logic into a shared library (`DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.qll`) to enable reuse by MISRA C++ `RULE-4-1-3`. The query logic is unchanged and no visible changes to results or performance are expected. + - The query now uses a `query predicate problems` instead of a `from/where/select`. In path-problem BQRS output, the results section header changes from `#select` to `problems`. Alert results and their content are otherwise identical. diff --git a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql index d0935cc798..ae1a767f66 100644 --- a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql +++ b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql @@ -18,29 +18,18 @@ import cpp import codingstandards.cpp.cert -import semmle.code.cpp.dataflow.DataFlow -import AllocationToDeleteFlow::PathGraph +import codingstandards.cpp.rules.donotdeleteanarraythroughapointeroftheincorrecttypeshared.DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared -module AllocationToDeleteConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NewArrayExpr } - - predicate isSink(DataFlow::Node sink) { - exists(DeleteArrayExpr dae | dae.getExpr() = sink.asExpr()) +module DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeConfig implements + DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeSharedConfigSig +{ + Query getQuery() { + result = FreedPackage::doNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeQuery() } } -module AllocationToDeleteFlow = DataFlow::Global; +module Shared = + DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared; -from - AllocationToDeleteFlow::PathNode source, AllocationToDeleteFlow::PathNode sink, - NewArrayExpr newArray, DeleteArrayExpr deleteArray -where - not isExcluded(deleteArray.getExpr(), - FreedPackage::doNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeQuery()) and - AllocationToDeleteFlow::flowPath(source, sink) and - newArray = source.getNode().asExpr() and - deleteArray.getExpr() = sink.getNode().asExpr() and - not newArray.getType().getUnspecifiedType() = deleteArray.getExpr().getType().getUnspecifiedType() -select sink, source, sink, - "Array of type " + newArray.getType() + " is deleted through a pointer of type " + - deleteArray.getExpr().getType() + "." +import Shared::PathGraph +import Shared diff --git a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected deleted file mode 100644 index 8b7a4902cc..0000000000 --- a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected +++ /dev/null @@ -1,15 +0,0 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:24,44-52) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:25,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:27,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:32,33-41) -edges -| test.cpp:6:19:6:37 | new[] | test.cpp:9:12:9:13 | l1 | provenance | | -| test.cpp:7:22:7:40 | new[] | test.cpp:10:12:10:13 | l2 | provenance | | -nodes -| test.cpp:6:19:6:37 | new[] | semmle.label | new[] | -| test.cpp:7:22:7:40 | new[] | semmle.label | new[] | -| test.cpp:9:12:9:13 | l1 | semmle.label | l1 | -| test.cpp:10:12:10:13 | l2 | semmle.label | l2 | -subpaths -#select -| test.cpp:9:12:9:13 | l1 | test.cpp:6:19:6:37 | new[] | test.cpp:9:12:9:13 | l1 | Array of type DerivedClass * is deleted through a pointer of type BaseClass *. | diff --git a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.qlref b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.qlref deleted file mode 100644 index fbeac87143..0000000000 --- a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql \ No newline at end of file diff --git a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.testref b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.testref new file mode 100644 index 0000000000..069f5724f8 --- /dev/null +++ b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.ql diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Undefined.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Undefined.qll index a1fcf5afd3..6c865693ff 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Undefined.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Undefined.qll @@ -5,6 +5,7 @@ import codingstandards.cpp.exclusions.RuleMetadata newtype UndefinedQuery = TPossibleDataRaceBetweenThreadsQuery() or + TArrayDeletedThroughPointerOfIncorrectTypeQuery() or TSignedIntegerOverflowQuery() or TDivisionByZeroUndefinedBehaviorQuery() or TDeallocationTypeMismatchQuery() or @@ -24,6 +25,15 @@ predicate isUndefinedQueryMetadata(Query query, string queryId, string ruleId, s ruleId = "RULE-4-1-3" and category = "required" or + query = + // `Query` instance for the `arrayDeletedThroughPointerOfIncorrectType` query + UndefinedPackage::arrayDeletedThroughPointerOfIncorrectTypeQuery() and + queryId = + // `@id` for the `arrayDeletedThroughPointerOfIncorrectType` query + "cpp/misra/array-deleted-through-pointer-of-incorrect-type" and + ruleId = "RULE-4-1-3" and + category = "required" + or query = // `Query` instance for the `signedIntegerOverflow` query UndefinedPackage::signedIntegerOverflowQuery() and @@ -105,6 +115,13 @@ module UndefinedPackage { TQueryCPP(TUndefinedPackageQuery(TPossibleDataRaceBetweenThreadsQuery())) } + Query arrayDeletedThroughPointerOfIncorrectTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `arrayDeletedThroughPointerOfIncorrectType` query + TQueryCPP(TUndefinedPackageQuery(TArrayDeletedThroughPointerOfIncorrectTypeQuery())) + } + Query signedIntegerOverflowQuery() { //autogenerate `Query` type result = diff --git a/cpp/common/src/codingstandards/cpp/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.qll b/cpp/common/src/codingstandards/cpp/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.qll new file mode 100644 index 0000000000..d526632f89 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.qll @@ -0,0 +1,48 @@ +/** + * Provides a configurable module DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared + * with a `problems` predicate for the following issue: + * Deleting an array through a pointer of an incorrect type leads to undefined behavior. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import semmle.code.cpp.dataflow.DataFlow + +signature module DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeSharedConfigSig { + Query getQuery(); +} + +module DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared< + DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeSharedConfigSig Config> +{ + private module AllocationToDeleteConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source.asExpr() instanceof NewArrayExpr } + + predicate isSink(DataFlow::Node sink) { + exists(DeleteArrayExpr dae | dae.getExpr() = sink.asExpr()) + } + } + + module AllocationToDeleteFlow = DataFlow::Global; + + module PathGraph = AllocationToDeleteFlow::PathGraph; + + query predicate problems( + Expr deleteExpr, AllocationToDeleteFlow::PathNode source, AllocationToDeleteFlow::PathNode sink, + string message + ) { + exists(NewArrayExpr newArray, DeleteArrayExpr deleteArray | + not isExcluded(deleteArray.getExpr(), Config::getQuery()) and + AllocationToDeleteFlow::flowPath(source, sink) and + newArray = source.getNode().asExpr() and + deleteArray.getExpr() = sink.getNode().asExpr() and + not newArray.getType().getUnspecifiedType() = + deleteArray.getExpr().getType().getUnspecifiedType() and + deleteExpr = sink.getNode().asExpr() and + message = + "Array of type " + newArray.getType() + " is deleted through a pointer of type " + + deleteArray.getExpr().getType() + "." + ) + } +} diff --git a/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.expected b/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.expected new file mode 100644 index 0000000000..7debcf36ab --- /dev/null +++ b/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.expected @@ -0,0 +1,11 @@ +problems +| test.cpp:9:12:9:13 | l1 | test.cpp:6:19:6:37 | new[] | test.cpp:9:12:9:13 | l1 | Array of type DerivedClass * is deleted through a pointer of type BaseClass *. | +edges +| test.cpp:6:19:6:37 | new[] | test.cpp:9:12:9:13 | l1 | provenance | | +| test.cpp:7:22:7:40 | new[] | test.cpp:10:12:10:13 | l2 | provenance | | +nodes +| test.cpp:6:19:6:37 | new[] | semmle.label | new[] | +| test.cpp:7:22:7:40 | new[] | semmle.label | new[] | +| test.cpp:9:12:9:13 | l1 | semmle.label | l1 | +| test.cpp:10:12:10:13 | l2 | semmle.label | l2 | +subpaths diff --git a/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.ql b/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.ql new file mode 100644 index 0000000000..769bb3c1b5 --- /dev/null +++ b/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.ql @@ -0,0 +1,11 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.donotdeleteanarraythroughapointeroftheincorrecttypeshared.DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared + +module TestFileConfig implements DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeSharedConfigSig { + Query getQuery() { result instanceof TestQuery } +} + +module Shared = DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared; + +import Shared::PathGraph +import Shared diff --git a/cpp/cert/test/rules/EXP51-CPP/test.cpp b/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/test.cpp similarity index 99% rename from cpp/cert/test/rules/EXP51-CPP/test.cpp rename to cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/test.cpp index a09dd276fa..4efbc87159 100644 --- a/cpp/cert/test/rules/EXP51-CPP/test.cpp +++ b/cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/test.cpp @@ -8,4 +8,4 @@ void test() { delete[] l1; // NON_COMPLIANT - pointer to base class delete[] l2; // COMPLIANT - pointer to derived class -} \ No newline at end of file +} diff --git a/cpp/misra/src/rules/RULE-4-1-3/ArrayDeletedThroughPointerOfIncorrectType.ql b/cpp/misra/src/rules/RULE-4-1-3/ArrayDeletedThroughPointerOfIncorrectType.ql new file mode 100644 index 0000000000..ac9bab4d6e --- /dev/null +++ b/cpp/misra/src/rules/RULE-4-1-3/ArrayDeletedThroughPointerOfIncorrectType.ql @@ -0,0 +1,30 @@ +/** + * @id cpp/misra/array-deleted-through-pointer-of-incorrect-type + * @name RULE-4-1-3: Array deleted through pointer of incorrect type leads to undefined behavior + * @description Deleting an array through a pointer of an incorrect type leads to undefined + * behavior. + * @kind path-problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-4-1-3 + * correctness + * scope/system + * external/misra/enforcement/undecidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.donotdeleteanarraythroughapointeroftheincorrecttypeshared.DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared + +module ArrayDeletedThroughPointerOfIncorrectTypeConfig implements + DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeSharedConfigSig +{ + Query getQuery() { result = UndefinedPackage::arrayDeletedThroughPointerOfIncorrectTypeQuery() } +} + +module Shared = + DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared; + +import Shared::PathGraph +import Shared diff --git a/cpp/misra/test/rules/RULE-4-1-3/ArrayDeletedThroughPointerOfIncorrectType.testref b/cpp/misra/test/rules/RULE-4-1-3/ArrayDeletedThroughPointerOfIncorrectType.testref new file mode 100644 index 0000000000..069f5724f8 --- /dev/null +++ b/cpp/misra/test/rules/RULE-4-1-3/ArrayDeletedThroughPointerOfIncorrectType.testref @@ -0,0 +1 @@ +cpp/common/test/rules/donotdeleteanarraythroughapointeroftheincorrecttypeshared/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared.ql diff --git a/rule_packages/cpp/Freed.json b/rule_packages/cpp/Freed.json index 30ab6982b2..4fd0fddb05 100644 --- a/rule_packages/cpp/Freed.json +++ b/rule_packages/cpp/Freed.json @@ -109,6 +109,7 @@ "name": "Do not delete an array through a pointer of the incorrect type", "precision": "high", "severity": "error", + "shared_implementation_short_name": "DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared", "short_name": "DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType", "tags": [ "correctness", diff --git a/rule_packages/cpp/Undefined.json b/rule_packages/cpp/Undefined.json index be82bd5d77..d42960360f 100644 --- a/rule_packages/cpp/Undefined.json +++ b/rule_packages/cpp/Undefined.json @@ -20,6 +20,19 @@ "scope/system" ] }, + { + "description": "Deleting an array through a pointer of an incorrect type leads to undefined behavior.", + "kind": "path-problem", + "name": "Array deleted through pointer of incorrect type leads to undefined behavior", + "precision": "high", + "severity": "error", + "shared_implementation_short_name": "DoNotDeleteAnArrayThroughAPointerOfTheIncorrectTypeShared", + "short_name": "ArrayDeletedThroughPointerOfIncorrectType", + "tags": [ + "correctness", + "scope/system" + ] + }, { "description": "Signed integer overflow or underflow from arithmetic operations results in critical unspecified behavior.", "kind": "problem",