From b2231c9758d201b764292382ae8e0d660df6b6cc Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 18 Nov 2025 17:43:48 -0500 Subject: [PATCH 01/19] Number `Memory` packages --- rules.csv | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/rules.csv b/rules.csv index 3cb64a0ba..324f3220a 100644 --- a/rules.csv +++ b/rules.csv @@ -895,11 +895,11 @@ cpp,MISRA-C++-2023,RULE-8-2-10,Yes,Required,Undecidable,System,"Functions shall cpp,MISRA-C++-2023,RULE-8-2-11,Yes,Required,Decidable,Single Translation Unit,An argument passed via ellipsis shall have an appropriate type,,Preconditions,Easy, cpp,MISRA-C++-2023,RULE-8-3-1,Yes,Advisory,Decidable,Single Translation Unit,The built-in unary - operator should not be applied to an expression of unsigned type,M5-3-2,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-8-3-2,Yes,Advisory,Decidable,Single Translation Unit,The built-in unary + operator should not be used,,Banned,Easy, -cpp,MISRA-C++-2023,RULE-8-7-1,Yes,Required,Undecidable,System,Pointer arithmetic shall not form an invalid pointer,ARR30-C,Memory,Easy, -cpp,MISRA-C++-2023,RULE-8-7-2,Yes,Required,Undecidable,System,Subtraction between pointers shall only be applied to pointers that address elements of the same array,ARR36-C,Memory,Easy, -cpp,MISRA-C++-2023,RULE-8-9-1,Yes,Required,Undecidable,System,"The built-in relational operators >, >=, < and <= shall not be applied to objects of pointer type, except where they point to elements of the same array",ARR36-C,Memory,Easy, +cpp,MISRA-C++-2023,RULE-8-7-1,Yes,Required,Undecidable,System,Pointer arithmetic shall not form an invalid pointer,ARR30-C,Memory1,Easy, +cpp,MISRA-C++-2023,RULE-8-7-2,Yes,Required,Undecidable,System,Subtraction between pointers shall only be applied to pointers that address elements of the same array,ARR36-C,Memory2,Easy, +cpp,MISRA-C++-2023,RULE-8-9-1,Yes,Required,Undecidable,System,"The built-in relational operators >, >=, < and <= shall not be applied to objects of pointer type, except where they point to elements of the same array",ARR36-C,Memory3,Easy, cpp,MISRA-C++-2023,RULE-8-14-1,Yes,Advisory,Undecidable,System,The right-hand operand of a logical && or operator should not contain persistent side effects,"M5-14-1, RULE-13-5",SideEffects3,Medium, -cpp,MISRA-C++-2023,RULE-8-18-1,Yes,Mandatory,Undecidable,System,An object or subobject must not be copied to an overlapping object,"M0-2-1, RULE-19-1",Memory,Hard, +cpp,MISRA-C++-2023,RULE-8-18-1,Yes,Mandatory,Undecidable,System,An object or subobject must not be copied to an overlapping object,"M0-2-1, RULE-19-1",Memory4,Hard, cpp,MISRA-C++-2023,RULE-8-18-2,Yes,Advisory,Decidable,Single Translation Unit,The result of an assignment operator should not be used,RULE-13-4,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-8-19-1,Yes,Advisory,Decidable,Single Translation Unit,The comma operator should not be used,M5-18-1,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-8-20-1,Yes,Advisory,Decidable,Single Translation Unit,An unsigned arithmetic operation with constant operands should not wrap,INT30-C,ImportMisra23,Import, @@ -979,8 +979,8 @@ cpp,MISRA-C++-2023,RULE-21-2-2,Yes,Required,Decidable,Single Translation Unit,"T cpp,MISRA-C++-2023,RULE-21-2-3,Yes,Required,Decidable,Single Translation Unit,The library function system from shall not be used,M18-0-3,BannedAPIs,Easy, cpp,MISRA-C++-2023,RULE-21-2-4,Yes,Required,Decidable,Single Translation Unit,The macro offsetof shall not be used,M18-2-1,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-21-6-1,Yes,Advisory,Undecidable,Single Translation Unit,Dynamic memory should not be used,DIR-4-12,Banned,Easy, -cpp,MISRA-C++-2023,RULE-21-6-2,Yes,Required,Decidable,Single Translation Unit,Dynamic memory shall be managed automatically,,Memory,Easy, -cpp,MISRA-C++-2023,RULE-21-6-3,Yes,Required,Decidable,Single Translation Unit,Advanced memory management shall not be used,,Memory,Medium, +cpp,MISRA-C++-2023,RULE-21-6-2,Yes,Required,Decidable,Single Translation Unit,Dynamic memory shall be managed automatically,,Memory5,Easy, +cpp,MISRA-C++-2023,RULE-21-6-3,Yes,Required,Decidable,Single Translation Unit,Advanced memory management shall not be used,,Memory6,Medium, cpp,MISRA-C++-2023,RULE-21-6-4,Yes,Required,Decidable,System,"If a project defines either a sized or unsized version of a global operator delete, then both shall be defined",A18-5-4,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-21-6-5,Yes,Required,Decidable,Single Translation Unit,A pointer to an incomplete class type shall not be deleted,A5-3-3,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-21-10-1,Yes,Required,Decidable,Single Translation Unit,The features of shall not be used,DCL50-CPP,BannedAPIs,Easy, From 9b5d8b27c40240d9d73eb6885c715ed67646c406 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 18 Nov 2025 18:05:59 -0500 Subject: [PATCH 02/19] Add rule description files --- rule_packages/cpp/Memory1.json | 24 ++++++++++++++++++++++++ rule_packages/cpp/Memory2.json | 24 ++++++++++++++++++++++++ rule_packages/cpp/Memory3.json | 24 ++++++++++++++++++++++++ rule_packages/cpp/Memory4.json | 24 ++++++++++++++++++++++++ rule_packages/cpp/Memory5.json | 24 ++++++++++++++++++++++++ rule_packages/cpp/Memory6.json | 24 ++++++++++++++++++++++++ 6 files changed, 144 insertions(+) create mode 100644 rule_packages/cpp/Memory1.json create mode 100644 rule_packages/cpp/Memory2.json create mode 100644 rule_packages/cpp/Memory3.json create mode 100644 rule_packages/cpp/Memory4.json create mode 100644 rule_packages/cpp/Memory5.json create mode 100644 rule_packages/cpp/Memory6.json diff --git a/rule_packages/cpp/Memory1.json b/rule_packages/cpp/Memory1.json new file mode 100644 index 000000000..06bd63778 --- /dev/null +++ b/rule_packages/cpp/Memory1.json @@ -0,0 +1,24 @@ +{ + "MISRA-C++-2023": { + "RULE-8-7-1": { + "properties": { + "enforcement": "undecidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Pointers obtained as result of performing arithmetic should point to an initialized object, or an element right next to the last element of an array.", + "kind": "problem", + "name": "Pointer arithmetic shall not form an invalid pointer.", + "precision": "very-high", + "severity": "error", + "short_name": "PointerArithmeticFormsAnInvalidPointer", + "tags": [ + "scope/system" + ] + } + ], + "title": "Pointers obtained as result of performing arithmetic should point to an initialized object, or an element right next to the last element of an array." + } + } +} diff --git a/rule_packages/cpp/Memory2.json b/rule_packages/cpp/Memory2.json new file mode 100644 index 000000000..067af41b1 --- /dev/null +++ b/rule_packages/cpp/Memory2.json @@ -0,0 +1,24 @@ +{ + "MISRA-C++-2023": { + "RULE-8-7-2": { + "properties": { + "enforcement": "undecidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Pointer difference should be taken from pointers that belong to a same array.", + "kind": "problem", + "name": "Subtraction between pointers shall only be applied to ones that address elements of the same array.", + "precision": "very-high", + "severity": "error", + "short_name": "PointerDifferenceTakenBetweenDifferentArrays", + "tags": [ + "scope/system" + ] + } + ], + "title": "Pointer difference should be taken from pointers that belong to a same array." + } + } +} diff --git a/rule_packages/cpp/Memory3.json b/rule_packages/cpp/Memory3.json new file mode 100644 index 000000000..1117c552b --- /dev/null +++ b/rule_packages/cpp/Memory3.json @@ -0,0 +1,24 @@ +{ + "MISRA-C++-2023": { + "RULE-8-9-1": { + "properties": { + "enforcement": "undecidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Pointer comparison should be done between ones that belong to a same array.", + "kind": "problem", + "name": "The built-in relational operators >, >=, < and <= shall not be applied to objects of pointer type.", + "precision": "very-high", + "severity": "error", + "short_name": "PointerComparedBetweenDifferentArrays", + "tags": [ + "scope/system" + ] + } + ], + "title": "Pointer comparison should be done between ones that belong to a same array." + } + } +} diff --git a/rule_packages/cpp/Memory4.json b/rule_packages/cpp/Memory4.json new file mode 100644 index 000000000..f2fa1803c --- /dev/null +++ b/rule_packages/cpp/Memory4.json @@ -0,0 +1,24 @@ +{ + "MISRA-C++-2023": { + "RULE-8-18-1": { + "properties": { + "enforcement": "undecidable", + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Copying a member of a union to another, and copying a slice of an array to an overlapping one causes undefined behavior.", + "kind": "problem", + "name": "An object or subobject must not be copied to an overlapping object.", + "precision": "high", + "severity": "error", + "short_name": "ObjectMustNotBeCopiedToAnOverlappingObject", + "tags": [ + "scope/system" + ] + } + ], + "title": "Copying a member of a union to another, and copying a slice of an array to an overlapping one causes undefined behavior." + } + } +} diff --git a/rule_packages/cpp/Memory5.json b/rule_packages/cpp/Memory5.json new file mode 100644 index 000000000..40a5ea765 --- /dev/null +++ b/rule_packages/cpp/Memory5.json @@ -0,0 +1,24 @@ +{ + "MISRA-C++-2023": { + "RULE-21-6-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Dynamically allocated memory must not be managed manually.", + "kind": "problem", + "name": "Dynamic memory shall be managed automatically.", + "precision": "very-high", + "severity": "error", + "short_name": "DynamicMemoryManagedManually", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Dynamically allocated memory must not be managed manually." + } + } +} diff --git a/rule_packages/cpp/Memory6.json b/rule_packages/cpp/Memory6.json new file mode 100644 index 000000000..14a935afb --- /dev/null +++ b/rule_packages/cpp/Memory6.json @@ -0,0 +1,24 @@ +{ + "MISRA-C++-2023": { + "RULE-21-6-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using advanced memory management that either alters allocation and deallocation or constructs object construction on uninitalized memory may result in undefined behavior.", + "kind": "problem", + "name": "Advanced memory management shall not be used.", + "precision": "very-high", + "severity": "error", + "short_name": "AdvancedMemoryManagementUsed", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Using advanced memory management that either alters allocation and deallocation or constructs object construction on uninitalized memory may result in undefined behavior." + } + } +} From a5d41274a3a85873b79367a8eca71a26b9dd740e Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 12 Jan 2026 17:29:29 -0500 Subject: [PATCH 03/19] Add Memory1 package files --- .../cpp/exclusions/cpp/RuleMetadata.qll | 3 + .../PointerArithmeticFormsAnInvalidPointer.ql | 43 ++++++++++ ...erArithmeticFormsAnInvalidPointer.expected | 1 + ...interArithmeticFormsAnInvalidPointer.qlref | 1 + cpp/misra/test/rules/RULE-8-7-1/test.cpp | 78 +++++++++++++++++++ 5 files changed, 126 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql create mode 100644 cpp/misra/test/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.expected create mode 100644 cpp/misra/test/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.qlref create mode 100644 cpp/misra/test/rules/RULE-8-7-1/test.cpp diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index 2e2403165..e3b998660 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -36,6 +36,7 @@ import Lambdas import Literals import Loops import Macros +import Memory1 import MoveForward import Naming import Null @@ -95,6 +96,7 @@ newtype TCPPQuery = TLiteralsPackageQuery(LiteralsQuery q) or TLoopsPackageQuery(LoopsQuery q) or TMacrosPackageQuery(MacrosQuery q) or + TMemory1PackageQuery(Memory1Query q) or TMoveForwardPackageQuery(MoveForwardQuery q) or TNamingPackageQuery(NamingQuery q) or TNullPackageQuery(NullQuery q) or @@ -154,6 +156,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isLiteralsQueryMetadata(query, queryId, ruleId, category) or isLoopsQueryMetadata(query, queryId, ruleId, category) or isMacrosQueryMetadata(query, queryId, ruleId, category) or + isMemory1QueryMetadata(query, queryId, ruleId, category) or isMoveForwardQueryMetadata(query, queryId, ruleId, category) or isNamingQueryMetadata(query, queryId, ruleId, category) or isNullQueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql new file mode 100644 index 000000000..636b42c6b --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql @@ -0,0 +1,43 @@ +/** + * @id cpp/misra/pointer-arithmetic-forms-an-invalid-pointer + * @name RULE-8-7-1: Pointer arithmetic shall not form an invalid pointer. + * @description Pointers obtained as result of performing arithmetic should point to an initialized + * object, or an element right next to the last element of an array. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-7-1 + * scope/system + * external/misra/enforcement/undecidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import semmle.code.cpp.dataflow.new.DataFlow + +module TrackArrayConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { + /* 1. Declaring an array-type variable */ + none() + or + /* 2. Allocating dynamic memory as an array */ + none() + } + + predicate isSink(DataFlow::Node node) { + /* 1. Pointer arithmetic */ + none() + or + /* 2. Array access */ + none() + } +} + +module TrackArray = DataFlow::Global; + +from Expr expr +where + not isExcluded(expr, Memory1Package::pointerArithmeticFormsAnInvalidPointerQuery()) and + none() // TODO +select "TODO", "TODO" diff --git a/cpp/misra/test/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.expected b/cpp/misra/test/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.expected new file mode 100644 index 000000000..2ec1a0ac6 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.qlref b/cpp/misra/test/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.qlref new file mode 100644 index 000000000..a512fe0a6 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.qlref @@ -0,0 +1 @@ +rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-7-1/test.cpp b/cpp/misra/test/rules/RULE-8-7-1/test.cpp new file mode 100644 index 000000000..2ba7c8fa5 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-7-1/test.cpp @@ -0,0 +1,78 @@ +#include + +void f1(int *array) { + /* 1. Pointer formed from performing arithmetic */ + int *valid1 = array; // COMPLIANT: pointer is within boundary + int *valid2 = array + 1; // COMPLIANT: pointer is within boundary + int *valid3 = array + 2; // COMPLIANT: pointer is within boundary + int *valid4 = + array + 3; // COMPLIANT: pointer points one beyond the last element + int *invalid1 = + array + + 4; // NON_COMPLIANT: pointer points more than one beyond the last element + int *invalid2 = array - 1; // NON_COMPLIANT: pointer is outside boundary +} + +void f2(int *array) { + /* 2. Array Access (entails pointer arithmetic) */ + int valid1 = array[0]; // COMPLIANT: pointer is within boundary + int valid2 = array[1]; // COMPLIANT: pointer is within boundary + int valid3 = array[2]; // COMPLIANT: pointer is within boundary + int valid4 = array[3]; // COMPLIANT: pointer points one beyond the last + // element, but non-compliant to Rule 4.1.3 + int invalid1 = array[4]; // NON_COMPLIANT: pointer points more than one beyond + // the last element + int invalid2 = array[-1]; // NON_COMPLIANT: pointer is outside boundary +} + +void f1_realloc(int *array) { + /* 1. Pointer formed from performing arithmetic */ + int *valid1 = array; // COMPLIANT: pointer is within boundary + int *valid2 = array + 1; // COMPLIANT: pointer is within boundary + int *valid3 = array + 2; // COMPLIANT: pointer is within boundary + int *valid4 = + array + 3; // COMPLIANT: pointer points one beyond the last element + int *invalid1 = + array + + 4; // NON_COMPLIANT: pointer points more than one beyond the last element + int *invalid2 = array - 1; // NON_COMPLIANT: pointer is outside boundary +} + +void f2_realloc(int *array) { + /* 2. Array Access (entails pointer arithmetic) */ + int valid1 = array[0]; // COMPLIANT: pointer is within boundary + int valid2 = array[1]; // COMPLIANT: pointer is within boundary + int valid3 = array[2]; // COMPLIANT: pointer points one beyond the last + int invalid1 = array[3]; // NON_COMPLIANT: pointer points one beyond the last + // element, but non-compliant to Rule 4.1.3 + int invalid2 = array[4]; // NON_COMPLIANT: pointer points more than one beyond + // the last element + int invalid3 = array[-1]; // NON_COMPLIANT: pointer is outside boundary +} + +int main() { + int array[3] = {0, 1, 2}; + + f1(array); + f2(array); + + int num_of_elements = 3; + + int* array_malloc = (int*)std::malloc(num_of_elements * sizeof(int)); + int* array_calloc = (int*)std::calloc(num_of_elements, sizeof(int)); + + int new_num_of_elements = 2; + + int* array_realloc = (int*)std::realloc(array_malloc, new_num_of_elements * sizeof(int)); + + f1(array_malloc); + f2(array_malloc); + + f1(array_calloc); + f2(array_calloc); + + f1_realloc(array_realloc); + f2_realloc(array_realloc); + + return 0; +} From 1a2cde854dd647285394eb84fbe9a62d8e1b5198 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 12 Jan 2026 17:34:28 -0500 Subject: [PATCH 04/19] Expose malloc, calloc and realloc --- cpp/common/test/includes/standard-library/cstdlib | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cpp/common/test/includes/standard-library/cstdlib b/cpp/common/test/includes/standard-library/cstdlib index 3b1eefc4a..0eb1a3e7e 100644 --- a/cpp/common/test/includes/standard-library/cstdlib +++ b/cpp/common/test/includes/standard-library/cstdlib @@ -23,5 +23,8 @@ using ::strtoll; using ::strtoul; using ::strtoull; using ::system; +using ::malloc; +using ::calloc; +using ::realloc; } // namespace std #endif // _GHLIBCPP_CSTDLIB \ No newline at end of file From c21e862d77858da4b60b38d7736b507476fe72ac Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 12 Jan 2026 17:36:48 -0500 Subject: [PATCH 05/19] Minor comments --- cpp/misra/test/rules/RULE-8-7-1/test.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpp/misra/test/rules/RULE-8-7-1/test.cpp b/cpp/misra/test/rules/RULE-8-7-1/test.cpp index 2ba7c8fa5..4aeeb8566 100644 --- a/cpp/misra/test/rules/RULE-8-7-1/test.cpp +++ b/cpp/misra/test/rules/RULE-8-7-1/test.cpp @@ -51,11 +51,13 @@ void f2_realloc(int *array) { } int main() { + /* 1. Array initialized on the stack */ int array[3] = {0, 1, 2}; f1(array); f2(array); + /* 2. Array initialized on the heap */ int num_of_elements = 3; int* array_malloc = (int*)std::malloc(num_of_elements * sizeof(int)); From c0b1e55fce1791f23deb3303a78d0f87f04127a6 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 13 Jan 2026 14:37:55 -0500 Subject: [PATCH 06/19] Checkpoint --- .../PointerArithmeticFormsAnInvalidPointer.ql | 62 +++++++++++++++++-- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql index 636b42c6b..cf57b9c47 100644 --- a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql +++ b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql @@ -15,27 +15,79 @@ import cpp import codingstandards.cpp.misra import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.security.BufferAccess + +class ArrayDeclaration extends VariableDeclarationEntry { + int length; + + ArrayDeclaration() { this.getType().getUnderlyingType().(ArrayType).getArraySize() = length } + + /** + * Gets the declared length of this array. + */ + int getLength() { result = length } +} + +newtype TArrayAllocation = + TStackAllocation(ArrayDeclaration arrayDecl) or + TDynamicAllocation(AllocationFunction alloc) + +class ArrayAllocation extends TArrayAllocation { + ArrayDeclaration asStackAllocation() { this = TStackAllocation(result) } + + AllocationFunction asDynamicAllocation() { this = TDynamicAllocation(result) } + + string toString() { + result = this.asStackAllocation().toString() or + result = this.asDynamicAllocation().toString() + } + + int getLength() { + result = this.asStackAllocation().getLength() or + none() // TODO: this.asDynamicAllocation() + } +} module TrackArrayConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node node) { - /* 1. Declaring an array-type variable */ - none() + /* 1. Declaring / Initializing an array-type variable */ + exists(ArrayDeclaration arrayDecl | + node.asExpr() = arrayDecl.getVariable().getInitializer().getExpr() + ) or /* 2. Allocating dynamic memory as an array */ - none() + none() // TODO } predicate isSink(DataFlow::Node node) { /* 1. Pointer arithmetic */ - none() + exists(PointerArithmeticOperation pointerArithmetic | + node.asIndirectExpr() = pointerArithmetic.getAnOperand() + ) or /* 2. Array access */ - none() + node.asExpr() instanceof ArrayExprBA } } module TrackArray = DataFlow::Global; +private predicate arrayDeclarationAndAccess( + DataFlow::Node arrayDeclaration, DataFlow::Node arrayAccess +) { + TrackArray::flow(arrayDeclaration, arrayAccess) +} + +private predicate arrayIndexExceedsOutOfBounds( + DataFlow::Node arrayDeclaration, DataFlow::Node arrayAccess +) { + arrayDeclarationAndAccess(arrayDeclaration, arrayAccess) and + // exists(int declaredLength | + // declaredLength = arrayDeclaration + // ) + any() // TODO +} + from Expr expr where not isExcluded(expr, Memory1Package::pointerArithmeticFormsAnInvalidPointerQuery()) and From 9d3bab0c83a8521c65bc6c70475e448693939e42 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 13 Jan 2026 17:12:57 -0500 Subject: [PATCH 07/19] Split out source and sinks into their cases --- .../PointerArithmeticFormsAnInvalidPointer.ql | 80 +++++++++++++++---- 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql index cf57b9c47..3db105402 100644 --- a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql +++ b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql @@ -26,12 +26,21 @@ class ArrayDeclaration extends VariableDeclarationEntry { * Gets the declared length of this array. */ int getLength() { result = length } + + /** + * Gets the expression that the variable declared is initialized to, given there is such one. + */ + Expr getInitExpr() { result = this.getVariable().getInitializer().getExpr() } } newtype TArrayAllocation = TStackAllocation(ArrayDeclaration arrayDecl) or TDynamicAllocation(AllocationFunction alloc) +newtype TPointerFormation = + TArrayExpr(ArrayExprBA arrayExpr) or + TPointerArithmetic(PointerArithmeticOperation pointerArithmetic) + class ArrayAllocation extends TArrayAllocation { ArrayDeclaration asStackAllocation() { this = TStackAllocation(result) } @@ -48,11 +57,44 @@ class ArrayAllocation extends TArrayAllocation { } } +class PointerFormation extends TPointerFormation { + ArrayExprBA asArrayExpr() { this = TArrayExpr(result) } + + PointerArithmeticOperation asPointerArithmetic() { this = TPointerArithmetic(result) } + + string toString() { + result = this.asArrayExpr().toString() or + result = this.asPointerArithmetic().toString() + } + + int getOffset() { + result = this.asArrayExpr().getArrayOffset().getValue().toInt() + or + exists(PointerAddExpr pointerAddition | pointerAddition = this.asPointerArithmetic() | + result = pointerAddition.getAnOperand().getValue().toInt() // TODO: only get the number being added + ) + or + exists(PointerSubExpr pointerSubtraction | pointerSubtraction = this.asPointerArithmetic() | + result = -pointerSubtraction.getAnOperand().getValue().toInt() + ) + } + + Expr asExpr() { + result = this.asArrayExpr() or + result = this.asPointerArithmetic() + } + + DataFlow::Node getNode() { + result.asExpr() = this.asExpr() or + result.asIndirectExpr() = this.asExpr() + } +} + module TrackArrayConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node node) { /* 1. Declaring / Initializing an array-type variable */ - exists(ArrayDeclaration arrayDecl | - node.asExpr() = arrayDecl.getVariable().getInitializer().getExpr() + exists(ArrayAllocation arrayAllocation | + node.asExpr() = arrayAllocation.asStackAllocation().getInitExpr() ) or /* 2. Allocating dynamic memory as an array */ @@ -60,32 +102,36 @@ module TrackArrayConfig implements DataFlow::ConfigSig { } predicate isSink(DataFlow::Node node) { - /* 1. Pointer arithmetic */ - exists(PointerArithmeticOperation pointerArithmetic | - node.asIndirectExpr() = pointerArithmetic.getAnOperand() - ) - or - /* 2. Array access */ - node.asExpr() instanceof ArrayExprBA + exists(PointerFormation pointerFormation | node = pointerFormation.getNode()) } } module TrackArray = DataFlow::Global; private predicate arrayDeclarationAndAccess( - DataFlow::Node arrayDeclaration, DataFlow::Node arrayAccess + DataFlow::Node arrayDeclarationNode, DataFlow::Node arrayAccessNode ) { - TrackArray::flow(arrayDeclaration, arrayAccess) + TrackArray::flow(arrayDeclarationNode, arrayAccessNode) } private predicate arrayIndexExceedsOutOfBounds( - DataFlow::Node arrayDeclaration, DataFlow::Node arrayAccess + DataFlow::Node arrayDeclarationNode, DataFlow::Node arrayAccessNode ) { - arrayDeclarationAndAccess(arrayDeclaration, arrayAccess) and - // exists(int declaredLength | - // declaredLength = arrayDeclaration - // ) - any() // TODO + /* 1. Ensure the array access is reachable from the array declaration. */ + arrayDeclarationAndAccess(arrayDeclarationNode, arrayAccessNode) and + exists(ArrayAllocation arrayAllocation, PointerFormation pointerFormation | + arrayDeclarationNode.asExpr() = arrayAllocation.asStackAllocation().getInitExpr() and + arrayAccessNode = pointerFormation.getNode() + | + /* 2. Cases where a pointer formation becomes illegal. */ + ( + /* 2-1. An offset cannot be negative. */ + pointerFormation.getOffset() < 0 + or + /* 2-2. The offset should be at most (number of elements) + 1 = (the declared length). */ + arrayAllocation.getLength() < pointerFormation.getOffset() + ) + ) } from Expr expr From a8a6db700adbb44819db7e583c91df1aea25e5b2 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 14 Jan 2026 14:29:12 -0500 Subject: [PATCH 08/19] Checkpoint --- .../PointerArithmeticFormsAnInvalidPointer.ql | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql index 3db105402..d8cea6c1a 100644 --- a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql +++ b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql @@ -55,6 +55,11 @@ class ArrayAllocation extends TArrayAllocation { result = this.asStackAllocation().getLength() or none() // TODO: this.asDynamicAllocation() } + + Location getLocation() { + result = this.asStackAllocation().getLocation() or + result = this.asDynamicAllocation().getLocation() + } } class PointerFormation extends TPointerFormation { @@ -88,6 +93,11 @@ class PointerFormation extends TPointerFormation { result.asExpr() = this.asExpr() or result.asIndirectExpr() = this.asExpr() } + + Location getLocation() { + result = this.asArrayExpr().getLocation() or + result = this.asPointerArithmetic().getLocation() + } } module TrackArrayConfig implements DataFlow::ConfigSig { @@ -109,19 +119,19 @@ module TrackArrayConfig implements DataFlow::ConfigSig { module TrackArray = DataFlow::Global; private predicate arrayDeclarationAndAccess( - DataFlow::Node arrayDeclarationNode, DataFlow::Node arrayAccessNode + DataFlow::Node arrayDeclarationNode, DataFlow::Node pointerFormationNode ) { - TrackArray::flow(arrayDeclarationNode, arrayAccessNode) + TrackArray::flow(arrayDeclarationNode, pointerFormationNode) } private predicate arrayIndexExceedsOutOfBounds( - DataFlow::Node arrayDeclarationNode, DataFlow::Node arrayAccessNode + DataFlow::Node arrayDeclarationNode, DataFlow::Node pointerFormationNode ) { /* 1. Ensure the array access is reachable from the array declaration. */ - arrayDeclarationAndAccess(arrayDeclarationNode, arrayAccessNode) and + arrayDeclarationAndAccess(arrayDeclarationNode, pointerFormationNode) and exists(ArrayAllocation arrayAllocation, PointerFormation pointerFormation | arrayDeclarationNode.asExpr() = arrayAllocation.asStackAllocation().getInitExpr() and - arrayAccessNode = pointerFormation.getNode() + pointerFormationNode = pointerFormation.getNode() | /* 2. Cases where a pointer formation becomes illegal. */ ( @@ -134,8 +144,11 @@ private predicate arrayIndexExceedsOutOfBounds( ) } -from Expr expr +from PointerFormation pointerFormation where - not isExcluded(expr, Memory1Package::pointerArithmeticFormsAnInvalidPointerQuery()) and - none() // TODO -select "TODO", "TODO" + not isExcluded(pointerFormation.asExpr(), + Memory1Package::pointerArithmeticFormsAnInvalidPointerQuery()) and + exists(DataFlow::Node pointerFormationNode | pointerFormationNode = pointerFormation.getNode() | + arrayIndexExceedsOutOfBounds(_, pointerFormationNode) + ) +select pointerFormation, "TODO" From e2c5870b5032bc70bf1d0fc87664b2246b80a537 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 16 Jan 2026 13:38:16 -0500 Subject: [PATCH 09/19] Checkpoint: Add `DynamicAllocation` case --- .../PointerArithmeticFormsAnInvalidPointer.ql | 51 +++++++++++++++++-- cpp/misra/test/rules/RULE-8-7-1/test.cpp | 25 ++++++--- 2 files changed, 66 insertions(+), 10 deletions(-) diff --git a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql index d8cea6c1a..762b28a43 100644 --- a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql +++ b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql @@ -33,9 +33,50 @@ class ArrayDeclaration extends VariableDeclarationEntry { Expr getInitExpr() { result = this.getVariable().getInitializer().getExpr() } } +class HeapAllocationFunctionCall extends FunctionCall { + AllocationFunction heapAllocFunction; + + HeapAllocationFunctionCall() { this.getTarget() = heapAllocFunction } + + predicate isMallocCall() { heapAllocFunction.getName() = "malloc" } + + predicate isCallocCall() { heapAllocFunction.getName() = "calloc" } + + predicate isReallocCall() { heapAllocFunction.getName() = "realloc" } + + abstract Expr getByteArgument(); + + int getByteLowerBound() { result = lowerBound(this.getByteArgument()) } +} + +class MallocFunctionCall extends HeapAllocationFunctionCall { + MallocFunctionCall() { this.isMallocCall() } + + override Expr getByteArgument() { result = this.getArgument(0) } +} + +class CallocReallocFunctionCall extends HeapAllocationFunctionCall { + CallocReallocFunctionCall() { this.isCallocCall() or this.isReallocCall() } + + override Expr getByteArgument() { result = this.getArgument(1) } +} + +class NarrowedHeapAllocationFunctionCall extends Cast { + HeapAllocationFunctionCall alloc; + + NarrowedHeapAllocationFunctionCall() { alloc = this.getExpr() } + + int getMinNumElements() { + result = + alloc.getByteLowerBound() / this.getUnderlyingType().(PointerType).getBaseType().getSize() + } + + HeapAllocationFunctionCall getAllocFunctionCall() { result = alloc } +} + newtype TArrayAllocation = TStackAllocation(ArrayDeclaration arrayDecl) or - TDynamicAllocation(AllocationFunction alloc) + TDynamicAllocation(NarrowedHeapAllocationFunctionCall narrowedAlloc) newtype TPointerFormation = TArrayExpr(ArrayExprBA arrayExpr) or @@ -44,16 +85,20 @@ newtype TPointerFormation = class ArrayAllocation extends TArrayAllocation { ArrayDeclaration asStackAllocation() { this = TStackAllocation(result) } - AllocationFunction asDynamicAllocation() { this = TDynamicAllocation(result) } + NarrowedHeapAllocationFunctionCall asDynamicAllocation() { this = TDynamicAllocation(result) } string toString() { result = this.asStackAllocation().toString() or result = this.asDynamicAllocation().toString() } + /** + * Gets the number of the object that the array holds. This number is exact for a stack-allocated + * array, and the minimum estimated value for a heap-allocated one. + */ int getLength() { result = this.asStackAllocation().getLength() or - none() // TODO: this.asDynamicAllocation() + result = this.asDynamicAllocation().getMinNumElements() } Location getLocation() { diff --git a/cpp/misra/test/rules/RULE-8-7-1/test.cpp b/cpp/misra/test/rules/RULE-8-7-1/test.cpp index 4aeeb8566..117959967 100644 --- a/cpp/misra/test/rules/RULE-8-7-1/test.cpp +++ b/cpp/misra/test/rules/RULE-8-7-1/test.cpp @@ -43,14 +43,14 @@ void f2_realloc(int *array) { int valid1 = array[0]; // COMPLIANT: pointer is within boundary int valid2 = array[1]; // COMPLIANT: pointer is within boundary int valid3 = array[2]; // COMPLIANT: pointer points one beyond the last - int invalid1 = array[3]; // NON_COMPLIANT: pointer points one beyond the last + int invalid1 = array[3]; // NON_COMPLIANT: pointer points one beyond the last // element, but non-compliant to Rule 4.1.3 int invalid2 = array[4]; // NON_COMPLIANT: pointer points more than one beyond // the last element int invalid3 = array[-1]; // NON_COMPLIANT: pointer is outside boundary } -int main() { +int main(int argc, char *argv[]) { /* 1. Array initialized on the stack */ int array[3] = {0, 1, 2}; @@ -58,14 +58,25 @@ int main() { f2(array); /* 2. Array initialized on the heap */ - int num_of_elements = 3; + int num_of_elements_malloc; + int num_of_elements_calloc; + int num_of_elements_realloc; - int* array_malloc = (int*)std::malloc(num_of_elements * sizeof(int)); - int* array_calloc = (int*)std::calloc(num_of_elements, sizeof(int)); + if (argc) { + num_of_elements_malloc = 1; + num_of_elements_calloc = 2; + num_of_elements_realloc = 3; + } else { + num_of_elements_malloc = 4; + num_of_elements_calloc = 5; + num_of_elements_realloc = 6; + } - int new_num_of_elements = 2; + int *array_malloc = (int *)std::malloc(num_of_elements_malloc * sizeof(int)); + int *array_calloc = (int *)std::calloc(num_of_elements_calloc, sizeof(int)); - int* array_realloc = (int*)std::realloc(array_malloc, new_num_of_elements * sizeof(int)); + int *array_realloc = + (int *)std::realloc(array_malloc, num_of_elements_realloc * sizeof(int)); f1(array_malloc); f2(array_malloc); From fe2a3c420eb06d49671eba574a4bb756da6a6310 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 20 Jan 2026 13:57:09 -0500 Subject: [PATCH 10/19] First working draft --- .../PointerArithmeticFormsAnInvalidPointer.ql | 16 ++++++++-------- cpp/misra/test/rules/RULE-8-7-1/test.cpp | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql index 762b28a43..8bc269042 100644 --- a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql +++ b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql @@ -105,6 +105,11 @@ class ArrayAllocation extends TArrayAllocation { result = this.asStackAllocation().getLocation() or result = this.asDynamicAllocation().getLocation() } + + DataFlow::Node getNode() { + result.asExpr() = this.asStackAllocation().getInitExpr() or + result.asConvertedExpr() = this.asDynamicAllocation() + } } class PointerFormation extends TPointerFormation { @@ -147,13 +152,7 @@ class PointerFormation extends TPointerFormation { module TrackArrayConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node node) { - /* 1. Declaring / Initializing an array-type variable */ - exists(ArrayAllocation arrayAllocation | - node.asExpr() = arrayAllocation.asStackAllocation().getInitExpr() - ) - or - /* 2. Allocating dynamic memory as an array */ - none() // TODO + exists(ArrayAllocation arrayAllocation | node = arrayAllocation.getNode()) } predicate isSink(DataFlow::Node node) { @@ -161,7 +160,8 @@ module TrackArrayConfig implements DataFlow::ConfigSig { } } -module TrackArray = DataFlow::Global; +import semmle.code.cpp.dataflow.new.TaintTracking +module TrackArray = TaintTracking::Global; private predicate arrayDeclarationAndAccess( DataFlow::Node arrayDeclarationNode, DataFlow::Node pointerFormationNode diff --git a/cpp/misra/test/rules/RULE-8-7-1/test.cpp b/cpp/misra/test/rules/RULE-8-7-1/test.cpp index 117959967..8ea987bf1 100644 --- a/cpp/misra/test/rules/RULE-8-7-1/test.cpp +++ b/cpp/misra/test/rules/RULE-8-7-1/test.cpp @@ -72,11 +72,11 @@ int main(int argc, char *argv[]) { num_of_elements_realloc = 6; } - int *array_malloc = (int *)std::malloc(num_of_elements_malloc * sizeof(int)); - int *array_calloc = (int *)std::calloc(num_of_elements_calloc, sizeof(int)); + int *array_malloc = (int *)malloc(num_of_elements_malloc * sizeof(int)); + int *array_calloc = (int *)calloc(num_of_elements_calloc, sizeof(int)); int *array_realloc = - (int *)std::realloc(array_malloc, num_of_elements_realloc * sizeof(int)); + (int *)realloc(array_malloc, num_of_elements_realloc * sizeof(int)); f1(array_malloc); f2(array_malloc); From 5ea652b101b03b7febd55a5efb95274e258c99f2 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 20 Jan 2026 19:05:34 -0500 Subject: [PATCH 11/19] Refine into path-problem --- .../PointerArithmeticFormsAnInvalidPointer.ql | 48 +++---- cpp/misra/test/rules/RULE-8-7-1/test.cpp | 118 ++++++++++++++---- 2 files changed, 110 insertions(+), 56 deletions(-) diff --git a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql index 8bc269042..7ba43f0fd 100644 --- a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql +++ b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql @@ -3,7 +3,7 @@ * @name RULE-8-7-1: Pointer arithmetic shall not form an invalid pointer. * @description Pointers obtained as result of performing arithmetic should point to an initialized * object, or an element right next to the last element of an array. - * @kind problem + * @kind path-problem * @precision very-high * @problem.severity error * @tags external/misra/id/rule-8-7-1 @@ -14,7 +14,7 @@ import cpp import codingstandards.cpp.misra -import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.dataflow.new.TaintTracking import semmle.code.cpp.security.BufferAccess class ArrayDeclaration extends VariableDeclarationEntry { @@ -135,14 +135,11 @@ class PointerFormation extends TPointerFormation { } Expr asExpr() { - result = this.asArrayExpr() or + result = this.asArrayExpr() or // This needs to be array base, as we are only dealing with pointers here. result = this.asPointerArithmetic() } - DataFlow::Node getNode() { - result.asExpr() = this.asExpr() or - result.asIndirectExpr() = this.asExpr() - } + DataFlow::Node getNode() { result.asExpr() = this.asExpr() } Location getLocation() { result = this.asArrayExpr().getLocation() or @@ -160,40 +157,31 @@ module TrackArrayConfig implements DataFlow::ConfigSig { } } -import semmle.code.cpp.dataflow.new.TaintTracking module TrackArray = TaintTracking::Global; -private predicate arrayDeclarationAndAccess( - DataFlow::Node arrayDeclarationNode, DataFlow::Node pointerFormationNode -) { - TrackArray::flow(arrayDeclarationNode, pointerFormationNode) -} - private predicate arrayIndexExceedsOutOfBounds( DataFlow::Node arrayDeclarationNode, DataFlow::Node pointerFormationNode ) { /* 1. Ensure the array access is reachable from the array declaration. */ - arrayDeclarationAndAccess(arrayDeclarationNode, pointerFormationNode) and + TrackArray::flow(arrayDeclarationNode, pointerFormationNode) and + /* 2. Cases where a pointer formation becomes illegal. */ exists(ArrayAllocation arrayAllocation, PointerFormation pointerFormation | - arrayDeclarationNode.asExpr() = arrayAllocation.asStackAllocation().getInitExpr() and + arrayDeclarationNode = arrayAllocation.getNode() and pointerFormationNode = pointerFormation.getNode() | - /* 2. Cases where a pointer formation becomes illegal. */ - ( - /* 2-1. An offset cannot be negative. */ - pointerFormation.getOffset() < 0 - or - /* 2-2. The offset should be at most (number of elements) + 1 = (the declared length). */ - arrayAllocation.getLength() < pointerFormation.getOffset() - ) + /* 2-1. An offset cannot be negative. */ + pointerFormation.getOffset() < 0 + or + /* 2-2. The offset should be at most (number of elements) + 1 = (the declared length). */ + arrayAllocation.getLength() < pointerFormation.getOffset() ) } -from PointerFormation pointerFormation +import TrackArray::PathGraph + +from TrackArray::PathNode source, TrackArray::PathNode sink where - not isExcluded(pointerFormation.asExpr(), + not isExcluded(sink.getNode().asExpr(), Memory1Package::pointerArithmeticFormsAnInvalidPointerQuery()) and - exists(DataFlow::Node pointerFormationNode | pointerFormationNode = pointerFormation.getNode() | - arrayIndexExceedsOutOfBounds(_, pointerFormationNode) - ) -select pointerFormation, "TODO" + arrayIndexExceedsOutOfBounds(source.getNode(), sink.getNode()) +select sink, source, sink, "TODO" diff --git a/cpp/misra/test/rules/RULE-8-7-1/test.cpp b/cpp/misra/test/rules/RULE-8-7-1/test.cpp index 8ea987bf1..214bf5f57 100644 --- a/cpp/misra/test/rules/RULE-8-7-1/test.cpp +++ b/cpp/misra/test/rules/RULE-8-7-1/test.cpp @@ -1,6 +1,6 @@ #include -void f1(int *array) { +void stack_allocation_pointer_arithmetic(int *array) { /* 1. Pointer formed from performing arithmetic */ int *valid1 = array; // COMPLIANT: pointer is within boundary int *valid2 = array + 1; // COMPLIANT: pointer is within boundary @@ -13,7 +13,7 @@ void f1(int *array) { int *invalid2 = array - 1; // NON_COMPLIANT: pointer is outside boundary } -void f2(int *array) { +void stack_allocation_array_access(int *array) { /* 2. Array Access (entails pointer arithmetic) */ int valid1 = array[0]; // COMPLIANT: pointer is within boundary int valid2 = array[1]; // COMPLIANT: pointer is within boundary @@ -25,37 +25,103 @@ void f2(int *array) { int invalid2 = array[-1]; // NON_COMPLIANT: pointer is outside boundary } -void f1_realloc(int *array) { +void malloc_pointer_arithmetic(int *array) { // [1, 4] /* 1. Pointer formed from performing arithmetic */ - int *valid1 = array; // COMPLIANT: pointer is within boundary - int *valid2 = array + 1; // COMPLIANT: pointer is within boundary - int *valid3 = array + 2; // COMPLIANT: pointer is within boundary - int *valid4 = - array + 3; // COMPLIANT: pointer points one beyond the last element - int *invalid1 = - array + - 4; // NON_COMPLIANT: pointer points more than one beyond the last element + int *valid1 = array; // COMPLIANT: pointer is within boundary (lower bound: 1) + int *valid2 = array + 1; // COMPLIANT: pointer points more than one beyond the + // last element (lower bound: 1) + int *valid3 = array + 2; // NON_COMPLIANT: pointer points more than one beyond + // the last element (lower bound: 1) + int *valid4 = array + 3; // NON_COMPLIANT: pointer points more than one beyond + // the last element (lower bound: 1) + int *invalid1 = array + 4; // NON_COMPLIANT: pointer points more than one + // beyond the last element (lower bound: 1) + int *invalid2 = array + 5; // NON_COMPLIANT: pointer points more than one + // beyond the last element (lower bound: 1) + int *invalid3 = array - 1; // NON_COMPLIANT: pointer is outside boundary +} + +void malloc_array_access(int *array) { // [1, 4] + /* 2. Array Access (entails pointer arithmetic) */ + int valid1 = + array[0]; // COMPLIANT: pointer is within boundary (lower bound: 1) + int valid2 = array[1]; // COMPLIANT: pointer points more than one beyond the + // last element, but non-compliant to Rule 4.1.3 (lower + // bound: 1) + int valid3 = array[2]; // NON_COMPLIANT: pointer points more than one beyond + // the last element (lower bound: 1) + int valid4 = array[3]; // NON_COMPLIANT: pointer points more than one beyond + // the last element (lower bound: 1) + int invalid1 = array[4]; // NON_COMPLIANT: pointer points more than one beyond + // the last element (lower bound: 1) + int invalid2 = array[-1]; // NON_COMPLIANT: pointer is outside boundary +} + +void calloc_pointer_arithmetic(int *array) { // [2, 5] + /* 1. Pointer formed from performing arithmetic */ + int *valid1 = array; // COMPLIANT: pointer is within boundary (lower bound: 2) + int *valid2 = + array + 1; // COMPLIANT: pointer is within boundary (lower bound: 2) + int *valid3 = array + 2; // COMPLIANT: pointer points more than one beyond the + // last element, but non-compliant to Rule 4.1.3 + // (lower bound: 2) + int *valid4 = array + 3; // NON_COMPLIANT: pointer points more than one beyond + // the last element (lower bound: 2) + int *invalid1 = array + 4; // NON_COMPLIANT: pointer points more than one + // beyond the last element (lower bound: 2) int *invalid2 = array - 1; // NON_COMPLIANT: pointer is outside boundary } -void f2_realloc(int *array) { +void calloc_array_access(int *array) { // [2, 5] /* 2. Array Access (entails pointer arithmetic) */ int valid1 = array[0]; // COMPLIANT: pointer is within boundary int valid2 = array[1]; // COMPLIANT: pointer is within boundary - int valid3 = array[2]; // COMPLIANT: pointer points one beyond the last - int invalid1 = array[3]; // NON_COMPLIANT: pointer points one beyond the last - // element, but non-compliant to Rule 4.1.3 - int invalid2 = array[4]; // NON_COMPLIANT: pointer points more than one beyond - // the last element - int invalid3 = array[-1]; // NON_COMPLIANT: pointer is outside boundary + int valid3 = array[2]; // COMPLIANT: pointer points more than one beyond the + // last element, but non-compliant to Rule 4.1.3 + // (lower bound: 2) + int valid4 = array[3]; // NON_COMPLIANT: pointer points more than one beyond + // the last element (lower bound: 2) + int invalid1 = array[4]; // NON_COMPLIANT: pointer points more than one + // beyond the last element (lower bound: 2) + int invalid2 = array[-1]; // NON_COMPLIANT: pointer is outside boundary +} + +void realloc_pointer_arithmetic(int *array) { // [3, 6] + /* 1. Pointer formed from performing arithmetic */ + int *valid1 = array; // COMPLIANT: pointer is within boundary (lower bound: 3) + int *valid2 = + array + 1; // COMPLIANT: pointer is within boundary (lower bound: 3) + int *valid3 = + array + 2; // COMPLIANT: pointer is within boundary (lower bound: 3) + int *valid4 = array + 3; // COMPLIANT: pointer points one beyond the last + // element (lower bound: 3) + int *invalid1 = array + 4; // NON_COMPLIANT: pointer points more than one + // beyond the last element (lower bound: 3) + int *invalid2 = array - 1; // NON_COMPLIANT: pointer is outside boundary +} + +void realloc_array_access(int *array) { // [3, 6] + /* 2. Array Access (entails pointer arithmetic) */ + int valid1 = + array[0]; // COMPLIANT: pointer is within boundary (lower bound: 3) + int valid2 = + array[1]; // COMPLIANT: pointer is within boundary (lower bound: 3) + int valid3 = + array[2]; // COMPLIANT: pointer is within boundary (lower bound: 3) + int valid4 = + array[3]; // COMPLIANT: pointer points one beyond the last + // element, but non-compliant to Rule 4.1.3 (lower bound: 3) + int invalid1 = array[4]; // NON_COMPLIANT: pointer points more than one beyond + // the last element (lower bound: 3) + int invalid2 = array[-1]; // NON_COMPLIANT: pointer is outside boundary } int main(int argc, char *argv[]) { /* 1. Array initialized on the stack */ int array[3] = {0, 1, 2}; - f1(array); - f2(array); + stack_allocation_pointer_arithmetic(array); + stack_allocation_array_access(array); /* 2. Array initialized on the heap */ int num_of_elements_malloc; @@ -78,14 +144,14 @@ int main(int argc, char *argv[]) { int *array_realloc = (int *)realloc(array_malloc, num_of_elements_realloc * sizeof(int)); - f1(array_malloc); - f2(array_malloc); + malloc_pointer_arithmetic(array_malloc); + malloc_array_access(array_malloc); - f1(array_calloc); - f2(array_calloc); + calloc_pointer_arithmetic(array_calloc); + calloc_array_access(array_calloc); - f1_realloc(array_realloc); - f2_realloc(array_realloc); + realloc_pointer_arithmetic(array_realloc); + realloc_array_access(array_realloc); return 0; } From 7b860d97250e3bdbd75b3c1422c1f9b4bceda13d Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 21 Jan 2026 16:40:20 -0500 Subject: [PATCH 12/19] Change `TaintTracking` to `DataFlow` --- .../PointerArithmeticFormsAnInvalidPointer.ql | 64 ++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql index 7ba43f0fd..9b2f7c079 100644 --- a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql +++ b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql @@ -16,6 +16,11 @@ import cpp import codingstandards.cpp.misra import semmle.code.cpp.dataflow.new.TaintTracking import semmle.code.cpp.security.BufferAccess +private import semmle.code.cpp.ir.IR // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) +private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) +private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) +private import semmle.code.cpp.ir.dataflow.FlowSteps // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) +private import semmle.code.cpp.ir.dataflow.internal.SsaInternals as Ssa class ArrayDeclaration extends VariableDeclarationEntry { int length; @@ -147,6 +152,50 @@ class PointerFormation extends TPointerFormation { } } +/** + * NOTE + */ +private predicate operandToInstructionTaintStep(Operand opFrom, Instruction instrTo) { + // Taint can flow through expressions that alter the value but preserve + // more than one bit of it _or_ expressions that follow data through + // pointer indirections. + instrTo.getAnOperand() = opFrom and + ( + instrTo instanceof ArithmeticInstruction + or + instrTo instanceof BitwiseInstruction + or + instrTo instanceof PointerArithmeticInstruction + ) + or + // Taint flow from an address to its dereference. + Ssa::isDereference(instrTo, opFrom, _) + or + // Unary instructions tend to preserve enough information in practice that we + // want taint to flow through. + // The exception is `FieldAddressInstruction`. Together with the rules below for + // `LoadInstruction`s and `ChiInstruction`s, flow through `FieldAddressInstruction` + // could cause flow into one field to come out an unrelated field. + // This would happen across function boundaries, where the IR would not be able to + // match loads to stores. + instrTo.(UnaryInstruction).getUnaryOperand() = opFrom and + ( + not instrTo instanceof FieldAddressInstruction + or + instrTo.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union + ) + or + // Taint from int to boolean casts. This ensures that we have flow to `!x` in: + // ```cpp + // x = integer_source(); + // if(!x) { ... } + // ``` + exists(Operand zero | + zero.getDef().(ConstantValueInstruction).getValue() = "0" and + instrTo.(CompareNEInstruction).hasOperands(opFrom, zero) + ) +} + module TrackArrayConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node node) { exists(ArrayAllocation arrayAllocation | node = arrayAllocation.getNode()) @@ -155,9 +204,22 @@ module TrackArrayConfig implements DataFlow::ConfigSig { predicate isSink(DataFlow::Node node) { exists(PointerFormation pointerFormation | node = pointerFormation.getNode()) } + + predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { + /* + * NOTE + */ + + operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) + or + exists(PointerArithmeticInstruction pai, int indirectionIndex | + nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and + hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1) + ) + } } -module TrackArray = TaintTracking::Global; +module TrackArray = DataFlow::Global; private predicate arrayIndexExceedsOutOfBounds( DataFlow::Node arrayDeclarationNode, DataFlow::Node pointerFormationNode From 08b8bf7b370f19fe9a0f5885c44929c4748aa61c Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 22 Jan 2026 16:05:04 -0500 Subject: [PATCH 13/19] Finalize first working draft for stack / heap arrays --- .../PointerArithmeticFormsAnInvalidPointer.ql | 171 ++++++++++-------- 1 file changed, 95 insertions(+), 76 deletions(-) diff --git a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql index 9b2f7c079..f767c5639 100644 --- a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql +++ b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql @@ -16,11 +16,6 @@ import cpp import codingstandards.cpp.misra import semmle.code.cpp.dataflow.new.TaintTracking import semmle.code.cpp.security.BufferAccess -private import semmle.code.cpp.ir.IR // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) -private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) -private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) -private import semmle.code.cpp.ir.dataflow.FlowSteps // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) -private import semmle.code.cpp.ir.dataflow.internal.SsaInternals as Ssa class ArrayDeclaration extends VariableDeclarationEntry { int length; @@ -31,11 +26,6 @@ class ArrayDeclaration extends VariableDeclarationEntry { * Gets the declared length of this array. */ int getLength() { result = length } - - /** - * Gets the expression that the variable declared is initialized to, given there is such one. - */ - Expr getInitExpr() { result = this.getVariable().getInitializer().getExpr() } } class HeapAllocationFunctionCall extends FunctionCall { @@ -49,21 +39,27 @@ class HeapAllocationFunctionCall extends FunctionCall { predicate isReallocCall() { heapAllocFunction.getName() = "realloc" } - abstract Expr getByteArgument(); - - int getByteLowerBound() { result = lowerBound(this.getByteArgument()) } + abstract int getMinNumBytes(); } class MallocFunctionCall extends HeapAllocationFunctionCall { MallocFunctionCall() { this.isMallocCall() } - override Expr getByteArgument() { result = this.getArgument(0) } + override int getMinNumBytes() { result = lowerBound(this.getArgument(0)) } } -class CallocReallocFunctionCall extends HeapAllocationFunctionCall { - CallocReallocFunctionCall() { this.isCallocCall() or this.isReallocCall() } +class CallocFunctionCall extends HeapAllocationFunctionCall { + CallocFunctionCall() { this.isCallocCall() } - override Expr getByteArgument() { result = this.getArgument(1) } + override int getMinNumBytes() { + result = lowerBound(this.getArgument(0)) * lowerBound(this.getArgument(1)) + } +} + +class ReallocFunctionCall extends HeapAllocationFunctionCall { + ReallocFunctionCall() { this.isReallocCall() } + + override int getMinNumBytes() { result = lowerBound(this.getArgument(1)) } } class NarrowedHeapAllocationFunctionCall extends Cast { @@ -72,8 +68,7 @@ class NarrowedHeapAllocationFunctionCall extends Cast { NarrowedHeapAllocationFunctionCall() { alloc = this.getExpr() } int getMinNumElements() { - result = - alloc.getByteLowerBound() / this.getUnderlyingType().(PointerType).getBaseType().getSize() + result = alloc.getMinNumBytes() / this.getUnderlyingType().(PointerType).getBaseType().getSize() } HeapAllocationFunctionCall getAllocFunctionCall() { result = alloc } @@ -112,7 +107,7 @@ class ArrayAllocation extends TArrayAllocation { } DataFlow::Node getNode() { - result.asExpr() = this.asStackAllocation().getInitExpr() or + result.asUninitialized() = this.asStackAllocation().getVariable() or result.asConvertedExpr() = this.asDynamicAllocation() } } @@ -140,8 +135,8 @@ class PointerFormation extends TPointerFormation { } Expr asExpr() { - result = this.asArrayExpr() or // This needs to be array base, as we are only dealing with pointers here. - result = this.asPointerArithmetic() + result = this.asArrayExpr() or + /*.getArrayBase()*/ result = this.asPointerArithmetic() } DataFlow::Node getNode() { result.asExpr() = this.asExpr() } @@ -155,47 +150,57 @@ class PointerFormation extends TPointerFormation { /** * NOTE */ -private predicate operandToInstructionTaintStep(Operand opFrom, Instruction instrTo) { - // Taint can flow through expressions that alter the value but preserve - // more than one bit of it _or_ expressions that follow data through - // pointer indirections. - instrTo.getAnOperand() = opFrom and - ( - instrTo instanceof ArithmeticInstruction +module Copied { + import semmle.code.cpp.ir.IR // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) + import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) + import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) + import semmle.code.cpp.ir.dataflow.FlowSteps // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) + import semmle.code.cpp.ir.dataflow.internal.SsaInternals as Ssa + + predicate operandToInstructionTaintStep(Operand opFrom, Instruction instrTo) { + // Taint can flow through expressions that alter the value but preserve + // more than one bit of it _or_ expressions that follow data through + // pointer indirections. + instrTo.getAnOperand() = opFrom and + ( + instrTo instanceof ArithmeticInstruction + or + instrTo instanceof BitwiseInstruction + or + instrTo instanceof PointerArithmeticInstruction + ) or - instrTo instanceof BitwiseInstruction + // Taint flow from an address to its dereference. + Ssa::isDereference(instrTo, opFrom, _) or - instrTo instanceof PointerArithmeticInstruction - ) - or - // Taint flow from an address to its dereference. - Ssa::isDereference(instrTo, opFrom, _) - or - // Unary instructions tend to preserve enough information in practice that we - // want taint to flow through. - // The exception is `FieldAddressInstruction`. Together with the rules below for - // `LoadInstruction`s and `ChiInstruction`s, flow through `FieldAddressInstruction` - // could cause flow into one field to come out an unrelated field. - // This would happen across function boundaries, where the IR would not be able to - // match loads to stores. - instrTo.(UnaryInstruction).getUnaryOperand() = opFrom and - ( - not instrTo instanceof FieldAddressInstruction + // Unary instructions tend to preserve enough information in practice that we + // want taint to flow through. + // The exception is `FieldAddressInstruction`. Together with the rules below for + // `LoadInstruction`s and `ChiInstruction`s, flow through `FieldAddressInstruction` + // could cause flow into one field to come out an unrelated field. + // This would happen across function boundaries, where the IR would not be able to + // match loads to stores. + instrTo.(UnaryInstruction).getUnaryOperand() = opFrom and + ( + not instrTo instanceof FieldAddressInstruction + or + instrTo.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union + ) or - instrTo.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union - ) - or - // Taint from int to boolean casts. This ensures that we have flow to `!x` in: - // ```cpp - // x = integer_source(); - // if(!x) { ... } - // ``` - exists(Operand zero | - zero.getDef().(ConstantValueInstruction).getValue() = "0" and - instrTo.(CompareNEInstruction).hasOperands(opFrom, zero) - ) + // Taint from int to boolean casts. This ensures that we have flow to `!x` in: + // ```cpp + // x = integer_source(); + // if(!x) { ... } + // ``` + exists(Operand zero | + zero.getDef().(ConstantValueInstruction).getValue() = "0" and + instrTo.(CompareNEInstruction).hasOperands(opFrom, zero) + ) + } } +import Copied + module TrackArrayConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node node) { exists(ArrayAllocation arrayAllocation | node = arrayAllocation.getNode()) @@ -206,44 +211,58 @@ module TrackArrayConfig implements DataFlow::ConfigSig { } predicate isAdditionalFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { - /* - * NOTE - */ - operandToInstructionTaintStep(nodeFrom.asOperand(), nodeTo.asInstruction()) - or - exists(PointerArithmeticInstruction pai, int indirectionIndex | - nodeHasOperand(nodeFrom, pai.getAnOperand(), pragma[only_bind_into](indirectionIndex)) and - hasInstructionAndIndex(nodeTo, pai, indirectionIndex + 1) - ) } } module TrackArray = DataFlow::Global; -private predicate arrayIndexExceedsOutOfBounds( +predicate arrayIndexIsNegative( DataFlow::Node arrayDeclarationNode, DataFlow::Node pointerFormationNode ) { /* 1. Ensure the array access is reachable from the array declaration. */ TrackArray::flow(arrayDeclarationNode, pointerFormationNode) and - /* 2. Cases where a pointer formation becomes illegal. */ + /* 2. An offset cannot be negative. */ exists(ArrayAllocation arrayAllocation, PointerFormation pointerFormation | arrayDeclarationNode = arrayAllocation.getNode() and pointerFormationNode = pointerFormation.getNode() | - /* 2-1. An offset cannot be negative. */ pointerFormation.getOffset() < 0 - or - /* 2-2. The offset should be at most (number of elements) + 1 = (the declared length). */ - arrayAllocation.getLength() < pointerFormation.getOffset() + ) +} + +predicate arrayIndexExceedsBounds( + DataFlow::Node arrayDeclarationNode, DataFlow::Node pointerFormationNode, int pointerOffset, + int arrayLength +) { + /* 1. Ensure the array access is reachable from the array declaration. */ + TrackArray::flow(arrayDeclarationNode, pointerFormationNode) and + /* 2. The offset must be at most (number of elements) + 1 = (the declared length). */ + exists(ArrayAllocation arrayAllocation, PointerFormation pointerFormation | + arrayDeclarationNode = arrayAllocation.getNode() and + pointerFormationNode = pointerFormation.getNode() and + pointerOffset = pointerFormation.getOffset() and + arrayLength = arrayAllocation.getLength() + | + arrayLength < pointerOffset ) } import TrackArray::PathGraph -from TrackArray::PathNode source, TrackArray::PathNode sink +from TrackArray::PathNode source, TrackArray::PathNode sink, string message where not isExcluded(sink.getNode().asExpr(), Memory1Package::pointerArithmeticFormsAnInvalidPointerQuery()) and - arrayIndexExceedsOutOfBounds(source.getNode(), sink.getNode()) -select sink, source, sink, "TODO" + ( + exists(int pointerOffset, int arrayLength | + arrayIndexExceedsBounds(source.getNode(), sink.getNode(), pointerOffset, arrayLength) and + message = + "This pointer has offset " + pointerOffset + + " when the minimum possible length of the object is " + arrayLength + "." + ) + or + arrayIndexIsNegative(source.getNode(), sink.getNode()) and + message = "This pointer has a negative offset." + ) +select sink, source, sink, message From 062c62f752fac02ad10a2992499727b40255e800 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 23 Jan 2026 11:40:06 -0500 Subject: [PATCH 14/19] Document code copy and clean up imports --- .../PointerArithmeticFormsAnInvalidPointer.ql | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql index f767c5639..6fefe3a2e 100644 --- a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql +++ b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql @@ -148,13 +148,13 @@ class PointerFormation extends TPointerFormation { } /** - * NOTE + * NOTE The code in the below module is copied from + * `cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/TaintTrackingUtil.qll` in `github/codeql`, commit hash + * `960e990`. This commit hash is the latest of the ones with tag `codeql-cli-2.21.4` which is the CLI version + * compatible with `codeql/cpp-all: 5.0.0` that this query depends on. */ module Copied { - import semmle.code.cpp.ir.IR // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) - import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) - import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) - import semmle.code.cpp.ir.dataflow.FlowSteps // For PointerArithmeticInstruction (see TrackArray::isAdditionalFlowStep/2 below) + import semmle.code.cpp.ir.IR import semmle.code.cpp.ir.dataflow.internal.SsaInternals as Ssa predicate operandToInstructionTaintStep(Operand opFrom, Instruction instrTo) { From e264dfde6959d9a5a7f7dbf1b79cd29d65d4366e Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 23 Jan 2026 11:40:28 -0500 Subject: [PATCH 15/19] Add multidimensional arrays alloc'ed on stack --- cpp/misra/test/rules/RULE-8-7-1/test.cpp | 108 ++++++++++++++++++----- 1 file changed, 85 insertions(+), 23 deletions(-) diff --git a/cpp/misra/test/rules/RULE-8-7-1/test.cpp b/cpp/misra/test/rules/RULE-8-7-1/test.cpp index 214bf5f57..bbfa93b12 100644 --- a/cpp/misra/test/rules/RULE-8-7-1/test.cpp +++ b/cpp/misra/test/rules/RULE-8-7-1/test.cpp @@ -1,6 +1,6 @@ #include -void stack_allocation_pointer_arithmetic(int *array) { +void stack_allocated_single_dimensional_pointer_arithmetic(int *array) { /* 1. Pointer formed from performing arithmetic */ int *valid1 = array; // COMPLIANT: pointer is within boundary int *valid2 = array + 1; // COMPLIANT: pointer is within boundary @@ -13,7 +13,7 @@ void stack_allocation_pointer_arithmetic(int *array) { int *invalid2 = array - 1; // NON_COMPLIANT: pointer is outside boundary } -void stack_allocation_array_access(int *array) { +void stack_allocated_single_dimensional_array_access(int *array) { /* 2. Array Access (entails pointer arithmetic) */ int valid1 = array[0]; // COMPLIANT: pointer is within boundary int valid2 = array[1]; // COMPLIANT: pointer is within boundary @@ -25,7 +25,7 @@ void stack_allocation_array_access(int *array) { int invalid2 = array[-1]; // NON_COMPLIANT: pointer is outside boundary } -void malloc_pointer_arithmetic(int *array) { // [1, 4] +void malloc_single_dimensional_pointer_arithmetic(int *array) { // [1, 4] /* 1. Pointer formed from performing arithmetic */ int *valid1 = array; // COMPLIANT: pointer is within boundary (lower bound: 1) int *valid2 = array + 1; // COMPLIANT: pointer points more than one beyond the @@ -41,7 +41,7 @@ void malloc_pointer_arithmetic(int *array) { // [1, 4] int *invalid3 = array - 1; // NON_COMPLIANT: pointer is outside boundary } -void malloc_array_access(int *array) { // [1, 4] +void malloc_single_dimensional_array_access(int *array) { // [1, 4] /* 2. Array Access (entails pointer arithmetic) */ int valid1 = array[0]; // COMPLIANT: pointer is within boundary (lower bound: 1) @@ -57,7 +57,7 @@ void malloc_array_access(int *array) { // [1, 4] int invalid2 = array[-1]; // NON_COMPLIANT: pointer is outside boundary } -void calloc_pointer_arithmetic(int *array) { // [2, 5] +void calloc_single_dimensional_pointer_arithmetic(int *array) { // [2, 5] /* 1. Pointer formed from performing arithmetic */ int *valid1 = array; // COMPLIANT: pointer is within boundary (lower bound: 2) int *valid2 = @@ -72,7 +72,7 @@ void calloc_pointer_arithmetic(int *array) { // [2, 5] int *invalid2 = array - 1; // NON_COMPLIANT: pointer is outside boundary } -void calloc_array_access(int *array) { // [2, 5] +void calloc_single_dimensional_array_access(int *array) { // [2, 5] /* 2. Array Access (entails pointer arithmetic) */ int valid1 = array[0]; // COMPLIANT: pointer is within boundary int valid2 = array[1]; // COMPLIANT: pointer is within boundary @@ -86,7 +86,7 @@ void calloc_array_access(int *array) { // [2, 5] int invalid2 = array[-1]; // NON_COMPLIANT: pointer is outside boundary } -void realloc_pointer_arithmetic(int *array) { // [3, 6] +void realloc_single_dimensional_pointer_arithmetic(int *array) { // [3, 6] /* 1. Pointer formed from performing arithmetic */ int *valid1 = array; // COMPLIANT: pointer is within boundary (lower bound: 3) int *valid2 = @@ -100,7 +100,7 @@ void realloc_pointer_arithmetic(int *array) { // [3, 6] int *invalid2 = array - 1; // NON_COMPLIANT: pointer is outside boundary } -void realloc_array_access(int *array) { // [3, 6] +void realloc_single_dimensional_array_access(int *array) { // [3, 6] /* 2. Array Access (entails pointer arithmetic) */ int valid1 = array[0]; // COMPLIANT: pointer is within boundary (lower bound: 3) @@ -116,14 +116,62 @@ void realloc_array_access(int *array) { // [3, 6] int invalid2 = array[-1]; // NON_COMPLIANT: pointer is outside boundary } +void stack_allocated_multi_dimensional_array_access(int array[2][3]) { + int valid11 = array[0][0]; // COMPLIANT: pointer is within boundary + int valid12 = array[0][1]; // COMPLIANT: pointer is within boundary + int valid13 = array[0][2]; // COMPLIANT: pointer points one beyond the last + // element, but non-compliant to Rule 4.1.3 + int invalid1 = array[0][3]; // NON_COMPLIANT: pointer points more than one + // beyond the last element + + int valid21 = array[1][0]; // COMPLIANT: pointer is within boundary + int valid22 = array[1][1]; // COMPLIANT: pointer is within boundary + int valid23 = array[1][2]; // COMPLIANT: pointer points one beyond the last + // element, but non-compliant to Rule 4.1.3 + + int invalid2 = array[1][3]; // NON_COMPLIANT: pointer points more than one + // beyond the last element + + int valid31 = array[2][0]; // COMPLIANT: pointer points one beyond the last + // element, but non-compliant to Rule 4.1.3 + int invalid3 = array[3][0]; // NON_COMPLIANT: pointer points more than one + // beyond the last element +} + +void stack_allocated_multi_dimensional_pointer_arithmetic(int array[2][3]) { + int valid11 = *(*(array + 0) + 0); // COMPLIANT: pointer is within boundary + int valid12 = *(*(array + 0) + 1); // COMPLIANT: pointer is within boundary + int valid13 = + *(*(array + 0) + 2); // COMPLIANT: pointer points one beyond the last + // element, but non-compliant to Rule 4.1.3 + int invalid1 = *(*(array + 0) + 3); // NON_COMPLIANT: pointer points more than + // one beyond the last element + + int valid21 = *(*(array + 1) + 0); // COMPLIANT: pointer is within boundary + int valid22 = *(*(array + 1) + 1); // COMPLIANT: pointer is within boundary + int valid23 = + *(*(array + 1) + 2); // COMPLIANT: pointer points one beyond the last + // element, but non-compliant to Rule 4.1.3 + int invalid2 = *(*(array + 1) + 3); // NON_COMPLIANT: pointer points more than + // one beyond the last element + + int valid31 = + *(*(array + 2) + 0); // COMPLIANT: pointer points one beyond the last + // element, but non-compliant to Rule 4.1.3 + int invalid3 = *(*(array + 3) + 0); // NON_COMPLIANT: pointer points more than + // one beyond the last element +} + int main(int argc, char *argv[]) { - /* 1. Array initialized on the stack */ - int array[3] = {0, 1, 2}; + /* 1. Single-dimensional array initialized on the stack */ + int stack_single_dimensional_array[3] = {0, 1, 2}; - stack_allocation_pointer_arithmetic(array); - stack_allocation_array_access(array); + stack_allocated_single_dimensional_pointer_arithmetic( + stack_single_dimensional_array); + stack_allocated_single_dimensional_array_access( + stack_single_dimensional_array); - /* 2. Array initialized on the heap */ + /* 2. Single-dimensional array initialized on the heap */ int num_of_elements_malloc; int num_of_elements_calloc; int num_of_elements_realloc; @@ -138,20 +186,34 @@ int main(int argc, char *argv[]) { num_of_elements_realloc = 6; } - int *array_malloc = (int *)malloc(num_of_elements_malloc * sizeof(int)); - int *array_calloc = (int *)calloc(num_of_elements_calloc, sizeof(int)); + int *single_dimensional_array_malloc = + (int *)malloc(num_of_elements_malloc * sizeof(int)); + int *single_dimensional_array_calloc = + (int *)calloc(num_of_elements_calloc, sizeof(int)); + + int *single_dimensional_array_realloc = (int *)realloc( + single_dimensional_array_malloc, num_of_elements_realloc * sizeof(int)); + + malloc_single_dimensional_pointer_arithmetic(single_dimensional_array_malloc); + malloc_single_dimensional_array_access(single_dimensional_array_malloc); + + calloc_single_dimensional_pointer_arithmetic(single_dimensional_array_calloc); + calloc_single_dimensional_array_access(single_dimensional_array_calloc); - int *array_realloc = - (int *)realloc(array_malloc, num_of_elements_realloc * sizeof(int)); + realloc_single_dimensional_pointer_arithmetic( + single_dimensional_array_realloc); + realloc_single_dimensional_array_access(single_dimensional_array_realloc); - malloc_pointer_arithmetic(array_malloc); - malloc_array_access(array_malloc); + /* 3. Multi-dimensional array initialized on the stack */ + int stack_multi_dimensional_array[2][3] = {{1, 2, 3}, {4, 5, 6}}; - calloc_pointer_arithmetic(array_calloc); - calloc_array_access(array_calloc); + /* 4. Multi-dimensional array initialized on the heap */ + int (*heap_multi_dimensional_array)[3] = + (int (*)[3])malloc(sizeof(int[2][3])); - realloc_pointer_arithmetic(array_realloc); - realloc_array_access(array_realloc); + stack_allocated_multi_dimensional_array_access(stack_multi_dimensional_array); + stack_allocated_multi_dimensional_pointer_arithmetic( + stack_multi_dimensional_array); return 0; } From 4d2bc8b92a44f5e81379421d872bdda410329b81 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 23 Jan 2026 16:32:18 -0500 Subject: [PATCH 16/19] Add test.cpp and expected test results --- ...erArithmeticFormsAnInvalidPointer.expected | 283 +++++++++++++++++- cpp/misra/test/rules/RULE-8-7-1/test.cpp | 45 ++- 2 files changed, 317 insertions(+), 11 deletions(-) diff --git a/cpp/misra/test/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.expected b/cpp/misra/test/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.expected index 2ec1a0ac6..7cf6ed525 100644 --- a/cpp/misra/test/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.expected +++ b/cpp/misra/test/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.expected @@ -1 +1,282 @@ -No expected results have yet been specified \ No newline at end of file +WARNING: unused method 'getAllocFunctionCall' (PointerArithmeticFormsAnInvalidPointer.ql:74,30-50) +edges +| test.cpp:3:65:3:69 | array | test.cpp:5:17:5:21 | array | provenance | | +| test.cpp:5:17:5:21 | array | test.cpp:6:17:6:25 | ... + ... | provenance | Config | +| test.cpp:5:17:5:21 | array | test.cpp:7:17:7:25 | ... + ... | provenance | Config | +| test.cpp:5:17:5:21 | array | test.cpp:9:7:9:15 | ... + ... | provenance | Config | +| test.cpp:5:17:5:21 | array | test.cpp:11:7:12:7 | ... + ... | provenance | Config | +| test.cpp:5:17:5:21 | array | test.cpp:13:19:13:27 | ... - ... | provenance | Config | +| test.cpp:16:59:16:63 | array | test.cpp:18:16:18:23 | access to array | provenance | Config | +| test.cpp:16:59:16:63 | array | test.cpp:19:16:19:23 | access to array | provenance | Config | +| test.cpp:16:59:16:63 | array | test.cpp:20:16:20:23 | access to array | provenance | Config | +| test.cpp:16:59:16:63 | array | test.cpp:21:16:21:23 | access to array | provenance | Config | +| test.cpp:16:59:16:63 | array | test.cpp:23:18:23:25 | access to array | provenance | Config | +| test.cpp:16:59:16:63 | array | test.cpp:25:18:25:26 | access to array | provenance | Config | +| test.cpp:28:56:28:60 | array | test.cpp:30:17:30:21 | array | provenance | | +| test.cpp:30:17:30:21 | array | test.cpp:31:17:31:25 | ... + ... | provenance | Config | +| test.cpp:30:17:30:21 | array | test.cpp:33:17:33:25 | ... + ... | provenance | Config | +| test.cpp:30:17:30:21 | array | test.cpp:35:17:35:25 | ... + ... | provenance | Config | +| test.cpp:30:17:30:21 | array | test.cpp:37:19:37:27 | ... + ... | provenance | Config | +| test.cpp:30:17:30:21 | array | test.cpp:39:19:39:27 | ... + ... | provenance | Config | +| test.cpp:30:17:30:21 | array | test.cpp:41:19:41:27 | ... - ... | provenance | Config | +| test.cpp:44:50:44:54 | array | test.cpp:47:7:47:14 | access to array | provenance | Config | +| test.cpp:44:50:44:54 | array | test.cpp:48:16:48:23 | access to array | provenance | Config | +| test.cpp:44:50:44:54 | array | test.cpp:51:16:51:23 | access to array | provenance | Config | +| test.cpp:44:50:44:54 | array | test.cpp:53:16:53:23 | access to array | provenance | Config | +| test.cpp:44:50:44:54 | array | test.cpp:55:18:55:25 | access to array | provenance | Config | +| test.cpp:44:50:44:54 | array | test.cpp:57:18:57:26 | access to array | provenance | Config | +| test.cpp:60:56:60:60 | array | test.cpp:62:17:62:21 | array | provenance | | +| test.cpp:62:17:62:21 | array | test.cpp:64:7:64:15 | ... + ... | provenance | Config | +| test.cpp:62:17:62:21 | array | test.cpp:65:17:65:25 | ... + ... | provenance | Config | +| test.cpp:62:17:62:21 | array | test.cpp:68:17:68:25 | ... + ... | provenance | Config | +| test.cpp:62:17:62:21 | array | test.cpp:70:19:70:27 | ... + ... | provenance | Config | +| test.cpp:62:17:62:21 | array | test.cpp:72:19:72:27 | ... - ... | provenance | Config | +| test.cpp:75:50:75:54 | array | test.cpp:77:16:77:23 | access to array | provenance | Config | +| test.cpp:75:50:75:54 | array | test.cpp:78:16:78:23 | access to array | provenance | Config | +| test.cpp:75:50:75:54 | array | test.cpp:79:16:79:23 | access to array | provenance | Config | +| test.cpp:75:50:75:54 | array | test.cpp:82:16:82:23 | access to array | provenance | Config | +| test.cpp:75:50:75:54 | array | test.cpp:84:18:84:25 | access to array | provenance | Config | +| test.cpp:75:50:75:54 | array | test.cpp:86:18:86:26 | access to array | provenance | Config | +| test.cpp:89:57:89:61 | array | test.cpp:91:17:91:21 | array | provenance | | +| test.cpp:91:17:91:21 | array | test.cpp:93:7:93:15 | ... + ... | provenance | Config | +| test.cpp:91:17:91:21 | array | test.cpp:95:7:95:15 | ... + ... | provenance | Config | +| test.cpp:91:17:91:21 | array | test.cpp:96:17:96:25 | ... + ... | provenance | Config | +| test.cpp:91:17:91:21 | array | test.cpp:98:19:98:27 | ... + ... | provenance | Config | +| test.cpp:91:17:91:21 | array | test.cpp:100:19:100:27 | ... - ... | provenance | Config | +| test.cpp:103:51:103:55 | array | test.cpp:106:7:106:14 | access to array | provenance | Config | +| test.cpp:103:51:103:55 | array | test.cpp:108:7:108:14 | access to array | provenance | Config | +| test.cpp:103:51:103:55 | array | test.cpp:110:7:110:14 | access to array | provenance | Config | +| test.cpp:103:51:103:55 | array | test.cpp:112:7:112:14 | access to array | provenance | Config | +| test.cpp:103:51:103:55 | array | test.cpp:114:18:114:25 | access to array | provenance | Config | +| test.cpp:103:51:103:55 | array | test.cpp:116:18:116:26 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:120:17:120:24 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:120:17:120:27 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:121:17:121:24 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:121:17:121:27 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:122:17:122:24 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:122:17:122:27 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:124:18:124:25 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:124:18:124:28 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:127:17:127:24 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:127:17:127:27 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:128:17:128:24 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:128:17:128:27 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:129:17:129:24 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:129:17:129:27 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:132:18:132:25 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:132:18:132:28 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:135:17:135:24 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:135:17:135:27 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:137:18:137:25 | access to array | provenance | Config | +| test.cpp:119:57:119:61 | array | test.cpp:137:18:137:28 | access to array | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:142:20:142:31 | * ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:142:20:142:35 | ... + ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:144:7:145:10 | * ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:148:20:148:31 | * ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:148:20:148:35 | ... + ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:150:9:151:9 | ... + ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:153:9:153:20 | * ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:153:9:153:24 | ... + ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:156:7:157:7 | ... + ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:159:21:159:32 | * ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:159:21:159:36 | ... + ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:162:9:162:18 | ... + ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:165:20:165:31 | * ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:165:20:165:35 | ... + ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:167:7:168:10 | * ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:169:19:169:30 | * ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:169:19:169:34 | ... + ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:171:9:171:20 | * ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:171:9:171:24 | ... + ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:173:20:173:31 | * ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:173:20:173:35 | ... + ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:177:9:177:20 | * ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:177:9:177:24 | ... + ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:179:20:181:8 | * ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:183:21:183:32 | * ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:183:21:183:36 | ... + ... | provenance | Config | +| test.cpp:141:63:141:67 | array | test.cpp:186:9:186:20 | * ... | provenance | Config | +| test.cpp:192:7:192:36 | definition of stack_single_dimensional_array | test.cpp:195:7:195:36 | stack_single_dimensional_array | provenance | | +| test.cpp:195:7:195:36 | stack_single_dimensional_array | test.cpp:3:65:3:69 | array | provenance | | +| test.cpp:195:7:195:36 | stack_single_dimensional_array | test.cpp:197:7:197:36 | stack_single_dimensional_array | provenance | | +| test.cpp:197:7:197:36 | stack_single_dimensional_array | test.cpp:16:59:16:63 | array | provenance | | +| test.cpp:215:7:215:57 | call to malloc | test.cpp:215:7:215:57 | call to malloc | provenance | | +| test.cpp:215:7:215:57 | call to malloc | test.cpp:220:7:220:37 | single_dimensional_array_malloc | provenance | | +| test.cpp:215:7:215:57 | call to malloc | test.cpp:220:7:220:37 | single_dimensional_array_malloc | provenance | Config | +| test.cpp:217:7:217:56 | call to calloc | test.cpp:217:7:217:56 | call to calloc | provenance | | +| test.cpp:217:7:217:56 | call to calloc | test.cpp:225:48:225:78 | single_dimensional_array_calloc | provenance | | +| test.cpp:219:43:220:77 | call to realloc | test.cpp:219:43:220:77 | call to realloc | provenance | | +| test.cpp:219:43:220:77 | call to realloc | test.cpp:229:7:229:38 | single_dimensional_array_realloc | provenance | | +| test.cpp:220:7:220:37 | single_dimensional_array_malloc | test.cpp:222:48:222:78 | single_dimensional_array_malloc | provenance | | +| test.cpp:222:48:222:78 | single_dimensional_array_malloc | test.cpp:28:56:28:60 | array | provenance | | +| test.cpp:222:48:222:78 | single_dimensional_array_malloc | test.cpp:223:42:223:72 | single_dimensional_array_malloc | provenance | | +| test.cpp:223:42:223:72 | single_dimensional_array_malloc | test.cpp:44:50:44:54 | array | provenance | | +| test.cpp:225:48:225:78 | single_dimensional_array_calloc | test.cpp:60:56:60:60 | array | provenance | | +| test.cpp:225:48:225:78 | single_dimensional_array_calloc | test.cpp:226:42:226:72 | single_dimensional_array_calloc | provenance | | +| test.cpp:226:42:226:72 | single_dimensional_array_calloc | test.cpp:75:50:75:54 | array | provenance | | +| test.cpp:229:7:229:38 | single_dimensional_array_realloc | test.cpp:89:57:89:61 | array | provenance | | +| test.cpp:229:7:229:38 | single_dimensional_array_realloc | test.cpp:230:43:230:74 | single_dimensional_array_realloc | provenance | | +| test.cpp:230:43:230:74 | single_dimensional_array_realloc | test.cpp:103:51:103:55 | array | provenance | | +| test.cpp:233:7:233:35 | definition of stack_multi_dimensional_array | test.cpp:239:50:239:78 | stack_multi_dimensional_array | provenance | | +| test.cpp:239:50:239:78 | stack_multi_dimensional_array | test.cpp:119:57:119:61 | array | provenance | | +| test.cpp:239:50:239:78 | stack_multi_dimensional_array | test.cpp:241:7:241:35 | stack_multi_dimensional_array | provenance | | +| test.cpp:241:7:241:35 | stack_multi_dimensional_array | test.cpp:141:63:141:67 | array | provenance | | +nodes +| test.cpp:3:65:3:69 | array | semmle.label | array | +| test.cpp:5:17:5:21 | array | semmle.label | array | +| test.cpp:6:17:6:25 | ... + ... | semmle.label | ... + ... | +| test.cpp:7:17:7:25 | ... + ... | semmle.label | ... + ... | +| test.cpp:9:7:9:15 | ... + ... | semmle.label | ... + ... | +| test.cpp:11:7:12:7 | ... + ... | semmle.label | ... + ... | +| test.cpp:13:19:13:27 | ... - ... | semmle.label | ... - ... | +| test.cpp:16:59:16:63 | array | semmle.label | array | +| test.cpp:18:16:18:23 | access to array | semmle.label | access to array | +| test.cpp:19:16:19:23 | access to array | semmle.label | access to array | +| test.cpp:20:16:20:23 | access to array | semmle.label | access to array | +| test.cpp:21:16:21:23 | access to array | semmle.label | access to array | +| test.cpp:23:18:23:25 | access to array | semmle.label | access to array | +| test.cpp:25:18:25:26 | access to array | semmle.label | access to array | +| test.cpp:28:56:28:60 | array | semmle.label | array | +| test.cpp:30:17:30:21 | array | semmle.label | array | +| test.cpp:31:17:31:25 | ... + ... | semmle.label | ... + ... | +| test.cpp:33:17:33:25 | ... + ... | semmle.label | ... + ... | +| test.cpp:35:17:35:25 | ... + ... | semmle.label | ... + ... | +| test.cpp:37:19:37:27 | ... + ... | semmle.label | ... + ... | +| test.cpp:39:19:39:27 | ... + ... | semmle.label | ... + ... | +| test.cpp:41:19:41:27 | ... - ... | semmle.label | ... - ... | +| test.cpp:44:50:44:54 | array | semmle.label | array | +| test.cpp:47:7:47:14 | access to array | semmle.label | access to array | +| test.cpp:48:16:48:23 | access to array | semmle.label | access to array | +| test.cpp:51:16:51:23 | access to array | semmle.label | access to array | +| test.cpp:53:16:53:23 | access to array | semmle.label | access to array | +| test.cpp:55:18:55:25 | access to array | semmle.label | access to array | +| test.cpp:57:18:57:26 | access to array | semmle.label | access to array | +| test.cpp:60:56:60:60 | array | semmle.label | array | +| test.cpp:62:17:62:21 | array | semmle.label | array | +| test.cpp:64:7:64:15 | ... + ... | semmle.label | ... + ... | +| test.cpp:65:17:65:25 | ... + ... | semmle.label | ... + ... | +| test.cpp:68:17:68:25 | ... + ... | semmle.label | ... + ... | +| test.cpp:70:19:70:27 | ... + ... | semmle.label | ... + ... | +| test.cpp:72:19:72:27 | ... - ... | semmle.label | ... - ... | +| test.cpp:75:50:75:54 | array | semmle.label | array | +| test.cpp:77:16:77:23 | access to array | semmle.label | access to array | +| test.cpp:78:16:78:23 | access to array | semmle.label | access to array | +| test.cpp:79:16:79:23 | access to array | semmle.label | access to array | +| test.cpp:82:16:82:23 | access to array | semmle.label | access to array | +| test.cpp:84:18:84:25 | access to array | semmle.label | access to array | +| test.cpp:86:18:86:26 | access to array | semmle.label | access to array | +| test.cpp:89:57:89:61 | array | semmle.label | array | +| test.cpp:91:17:91:21 | array | semmle.label | array | +| test.cpp:93:7:93:15 | ... + ... | semmle.label | ... + ... | +| test.cpp:95:7:95:15 | ... + ... | semmle.label | ... + ... | +| test.cpp:96:17:96:25 | ... + ... | semmle.label | ... + ... | +| test.cpp:98:19:98:27 | ... + ... | semmle.label | ... + ... | +| test.cpp:100:19:100:27 | ... - ... | semmle.label | ... - ... | +| test.cpp:103:51:103:55 | array | semmle.label | array | +| test.cpp:106:7:106:14 | access to array | semmle.label | access to array | +| test.cpp:108:7:108:14 | access to array | semmle.label | access to array | +| test.cpp:110:7:110:14 | access to array | semmle.label | access to array | +| test.cpp:112:7:112:14 | access to array | semmle.label | access to array | +| test.cpp:114:18:114:25 | access to array | semmle.label | access to array | +| test.cpp:116:18:116:26 | access to array | semmle.label | access to array | +| test.cpp:119:57:119:61 | array | semmle.label | array | +| test.cpp:120:17:120:24 | access to array | semmle.label | access to array | +| test.cpp:120:17:120:27 | access to array | semmle.label | access to array | +| test.cpp:121:17:121:24 | access to array | semmle.label | access to array | +| test.cpp:121:17:121:27 | access to array | semmle.label | access to array | +| test.cpp:122:17:122:24 | access to array | semmle.label | access to array | +| test.cpp:122:17:122:27 | access to array | semmle.label | access to array | +| test.cpp:124:18:124:25 | access to array | semmle.label | access to array | +| test.cpp:124:18:124:28 | access to array | semmle.label | access to array | +| test.cpp:127:17:127:24 | access to array | semmle.label | access to array | +| test.cpp:127:17:127:27 | access to array | semmle.label | access to array | +| test.cpp:128:17:128:24 | access to array | semmle.label | access to array | +| test.cpp:128:17:128:27 | access to array | semmle.label | access to array | +| test.cpp:129:17:129:24 | access to array | semmle.label | access to array | +| test.cpp:129:17:129:27 | access to array | semmle.label | access to array | +| test.cpp:132:18:132:25 | access to array | semmle.label | access to array | +| test.cpp:132:18:132:28 | access to array | semmle.label | access to array | +| test.cpp:135:17:135:24 | access to array | semmle.label | access to array | +| test.cpp:135:17:135:27 | access to array | semmle.label | access to array | +| test.cpp:137:18:137:25 | access to array | semmle.label | access to array | +| test.cpp:137:18:137:28 | access to array | semmle.label | access to array | +| test.cpp:141:63:141:67 | array | semmle.label | array | +| test.cpp:142:20:142:31 | * ... | semmle.label | * ... | +| test.cpp:142:20:142:35 | ... + ... | semmle.label | ... + ... | +| test.cpp:144:7:145:10 | * ... | semmle.label | * ... | +| test.cpp:148:20:148:31 | * ... | semmle.label | * ... | +| test.cpp:148:20:148:35 | ... + ... | semmle.label | ... + ... | +| test.cpp:150:9:151:9 | ... + ... | semmle.label | ... + ... | +| test.cpp:153:9:153:20 | * ... | semmle.label | * ... | +| test.cpp:153:9:153:24 | ... + ... | semmle.label | ... + ... | +| test.cpp:156:7:157:7 | ... + ... | semmle.label | ... + ... | +| test.cpp:159:21:159:32 | * ... | semmle.label | * ... | +| test.cpp:159:21:159:36 | ... + ... | semmle.label | ... + ... | +| test.cpp:162:9:162:18 | ... + ... | semmle.label | ... + ... | +| test.cpp:165:20:165:31 | * ... | semmle.label | * ... | +| test.cpp:165:20:165:35 | ... + ... | semmle.label | ... + ... | +| test.cpp:167:7:168:10 | * ... | semmle.label | * ... | +| test.cpp:169:19:169:30 | * ... | semmle.label | * ... | +| test.cpp:169:19:169:34 | ... + ... | semmle.label | ... + ... | +| test.cpp:171:9:171:20 | * ... | semmle.label | * ... | +| test.cpp:171:9:171:24 | ... + ... | semmle.label | ... + ... | +| test.cpp:173:20:173:31 | * ... | semmle.label | * ... | +| test.cpp:173:20:173:35 | ... + ... | semmle.label | ... + ... | +| test.cpp:177:9:177:20 | * ... | semmle.label | * ... | +| test.cpp:177:9:177:24 | ... + ... | semmle.label | ... + ... | +| test.cpp:179:20:181:8 | * ... | semmle.label | * ... | +| test.cpp:183:21:183:32 | * ... | semmle.label | * ... | +| test.cpp:183:21:183:36 | ... + ... | semmle.label | ... + ... | +| test.cpp:186:9:186:20 | * ... | semmle.label | * ... | +| test.cpp:192:7:192:36 | definition of stack_single_dimensional_array | semmle.label | definition of stack_single_dimensional_array | +| test.cpp:195:7:195:36 | stack_single_dimensional_array | semmle.label | stack_single_dimensional_array | +| test.cpp:197:7:197:36 | stack_single_dimensional_array | semmle.label | stack_single_dimensional_array | +| test.cpp:215:7:215:57 | call to malloc | semmle.label | call to malloc | +| test.cpp:215:7:215:57 | call to malloc | semmle.label | call to malloc | +| test.cpp:217:7:217:56 | call to calloc | semmle.label | call to calloc | +| test.cpp:217:7:217:56 | call to calloc | semmle.label | call to calloc | +| test.cpp:219:43:220:77 | call to realloc | semmle.label | call to realloc | +| test.cpp:219:43:220:77 | call to realloc | semmle.label | call to realloc | +| test.cpp:220:7:220:37 | single_dimensional_array_malloc | semmle.label | single_dimensional_array_malloc | +| test.cpp:222:48:222:78 | single_dimensional_array_malloc | semmle.label | single_dimensional_array_malloc | +| test.cpp:223:42:223:72 | single_dimensional_array_malloc | semmle.label | single_dimensional_array_malloc | +| test.cpp:225:48:225:78 | single_dimensional_array_calloc | semmle.label | single_dimensional_array_calloc | +| test.cpp:226:42:226:72 | single_dimensional_array_calloc | semmle.label | single_dimensional_array_calloc | +| test.cpp:229:7:229:38 | single_dimensional_array_realloc | semmle.label | single_dimensional_array_realloc | +| test.cpp:230:43:230:74 | single_dimensional_array_realloc | semmle.label | single_dimensional_array_realloc | +| test.cpp:233:7:233:35 | definition of stack_multi_dimensional_array | semmle.label | definition of stack_multi_dimensional_array | +| test.cpp:239:50:239:78 | stack_multi_dimensional_array | semmle.label | stack_multi_dimensional_array | +| test.cpp:241:7:241:35 | stack_multi_dimensional_array | semmle.label | stack_multi_dimensional_array | +subpaths +#select +| test.cpp:11:7:12:7 | ... + ... | test.cpp:192:7:192:36 | definition of stack_single_dimensional_array | test.cpp:11:7:12:7 | ... + ... | This pointer has offset 4 when the minimum possible length of the object is 3. | +| test.cpp:13:19:13:27 | ... - ... | test.cpp:192:7:192:36 | definition of stack_single_dimensional_array | test.cpp:13:19:13:27 | ... - ... | This pointer has a negative offset. | +| test.cpp:23:18:23:25 | access to array | test.cpp:192:7:192:36 | definition of stack_single_dimensional_array | test.cpp:23:18:23:25 | access to array | This pointer has offset 4 when the minimum possible length of the object is 3. | +| test.cpp:25:18:25:26 | access to array | test.cpp:192:7:192:36 | definition of stack_single_dimensional_array | test.cpp:25:18:25:26 | access to array | This pointer has a negative offset. | +| test.cpp:33:17:33:25 | ... + ... | test.cpp:215:7:215:57 | call to malloc | test.cpp:33:17:33:25 | ... + ... | This pointer has offset 2 when the minimum possible length of the object is 1. | +| test.cpp:35:17:35:25 | ... + ... | test.cpp:215:7:215:57 | call to malloc | test.cpp:35:17:35:25 | ... + ... | This pointer has offset 3 when the minimum possible length of the object is 1. | +| test.cpp:37:19:37:27 | ... + ... | test.cpp:215:7:215:57 | call to malloc | test.cpp:37:19:37:27 | ... + ... | This pointer has offset 4 when the minimum possible length of the object is 1. | +| test.cpp:39:19:39:27 | ... + ... | test.cpp:215:7:215:57 | call to malloc | test.cpp:39:19:39:27 | ... + ... | This pointer has offset 5 when the minimum possible length of the object is 1. | +| test.cpp:41:19:41:27 | ... - ... | test.cpp:215:7:215:57 | call to malloc | test.cpp:41:19:41:27 | ... - ... | This pointer has a negative offset. | +| test.cpp:51:16:51:23 | access to array | test.cpp:215:7:215:57 | call to malloc | test.cpp:51:16:51:23 | access to array | This pointer has offset 2 when the minimum possible length of the object is 1. | +| test.cpp:53:16:53:23 | access to array | test.cpp:215:7:215:57 | call to malloc | test.cpp:53:16:53:23 | access to array | This pointer has offset 3 when the minimum possible length of the object is 1. | +| test.cpp:55:18:55:25 | access to array | test.cpp:215:7:215:57 | call to malloc | test.cpp:55:18:55:25 | access to array | This pointer has offset 4 when the minimum possible length of the object is 1. | +| test.cpp:57:18:57:26 | access to array | test.cpp:215:7:215:57 | call to malloc | test.cpp:57:18:57:26 | access to array | This pointer has a negative offset. | +| test.cpp:68:17:68:25 | ... + ... | test.cpp:217:7:217:56 | call to calloc | test.cpp:68:17:68:25 | ... + ... | This pointer has offset 3 when the minimum possible length of the object is 2. | +| test.cpp:70:19:70:27 | ... + ... | test.cpp:217:7:217:56 | call to calloc | test.cpp:70:19:70:27 | ... + ... | This pointer has offset 4 when the minimum possible length of the object is 2. | +| test.cpp:72:19:72:27 | ... - ... | test.cpp:217:7:217:56 | call to calloc | test.cpp:72:19:72:27 | ... - ... | This pointer has a negative offset. | +| test.cpp:82:16:82:23 | access to array | test.cpp:217:7:217:56 | call to calloc | test.cpp:82:16:82:23 | access to array | This pointer has offset 3 when the minimum possible length of the object is 2. | +| test.cpp:84:18:84:25 | access to array | test.cpp:217:7:217:56 | call to calloc | test.cpp:84:18:84:25 | access to array | This pointer has offset 4 when the minimum possible length of the object is 2. | +| test.cpp:86:18:86:26 | access to array | test.cpp:217:7:217:56 | call to calloc | test.cpp:86:18:86:26 | access to array | This pointer has a negative offset. | +| test.cpp:98:19:98:27 | ... + ... | test.cpp:219:43:220:77 | call to realloc | test.cpp:98:19:98:27 | ... + ... | This pointer has offset 4 when the minimum possible length of the object is 3. | +| test.cpp:100:19:100:27 | ... - ... | test.cpp:219:43:220:77 | call to realloc | test.cpp:100:19:100:27 | ... - ... | This pointer has a negative offset. | +| test.cpp:114:18:114:25 | access to array | test.cpp:219:43:220:77 | call to realloc | test.cpp:114:18:114:25 | access to array | This pointer has offset 4 when the minimum possible length of the object is 3. | +| test.cpp:116:18:116:26 | access to array | test.cpp:219:43:220:77 | call to realloc | test.cpp:116:18:116:26 | access to array | This pointer has a negative offset. | +| test.cpp:124:18:124:28 | access to array | test.cpp:233:7:233:35 | definition of stack_multi_dimensional_array | test.cpp:124:18:124:28 | access to array | This pointer has offset 3 when the minimum possible length of the object is 2. | +| test.cpp:132:18:132:28 | access to array | test.cpp:233:7:233:35 | definition of stack_multi_dimensional_array | test.cpp:132:18:132:28 | access to array | This pointer has offset 3 when the minimum possible length of the object is 2. | +| test.cpp:137:18:137:25 | access to array | test.cpp:233:7:233:35 | definition of stack_multi_dimensional_array | test.cpp:137:18:137:25 | access to array | This pointer has offset 3 when the minimum possible length of the object is 2. | +| test.cpp:159:21:159:36 | ... + ... | test.cpp:233:7:233:35 | definition of stack_multi_dimensional_array | test.cpp:159:21:159:36 | ... + ... | This pointer has offset 3 when the minimum possible length of the object is 2. | +| test.cpp:162:9:162:18 | ... + ... | test.cpp:233:7:233:35 | definition of stack_multi_dimensional_array | test.cpp:162:9:162:18 | ... + ... | This pointer has offset 3 when the minimum possible length of the object is 2. | +| test.cpp:173:20:173:35 | ... + ... | test.cpp:233:7:233:35 | definition of stack_multi_dimensional_array | test.cpp:173:20:173:35 | ... + ... | This pointer has offset 3 when the minimum possible length of the object is 2. | +| test.cpp:183:21:183:32 | * ... | test.cpp:233:7:233:35 | definition of stack_multi_dimensional_array | test.cpp:183:21:183:32 | * ... | This pointer has offset 3 when the minimum possible length of the object is 2. | +| test.cpp:186:9:186:20 | * ... | test.cpp:233:7:233:35 | definition of stack_multi_dimensional_array | test.cpp:186:9:186:20 | * ... | This pointer has offset 3 when the minimum possible length of the object is 2. | diff --git a/cpp/misra/test/rules/RULE-8-7-1/test.cpp b/cpp/misra/test/rules/RULE-8-7-1/test.cpp index bbfa93b12..793607879 100644 --- a/cpp/misra/test/rules/RULE-8-7-1/test.cpp +++ b/cpp/misra/test/rules/RULE-8-7-1/test.cpp @@ -139,15 +139,33 @@ void stack_allocated_multi_dimensional_array_access(int array[2][3]) { } void stack_allocated_multi_dimensional_pointer_arithmetic(int array[2][3]) { - int valid11 = *(*(array + 0) + 0); // COMPLIANT: pointer is within boundary - int valid12 = *(*(array + 0) + 1); // COMPLIANT: pointer is within boundary - int valid13 = + int valid111 = *(*(array + 0) + 0); // COMPLIANT: pointer is within boundary + int valid112 = *( + *(array + + 0)); // COMPLIANT: pointer is within boundary (equivalent to the above) + int valid113 = **array; // COMPLIANT: pointer is within boundary (equivalent + // to the above) + int valid121 = *(*(array + 0) + 1); // COMPLIANT: pointer is within boundary + int valid122 = + *(*array + + 1); // COMPLIANT: pointer is within boundary (equivalent to the above) + int valid131 = *(*(array + 0) + 2); // COMPLIANT: pointer points one beyond the last // element, but non-compliant to Rule 4.1.3 - int invalid1 = *(*(array + 0) + 3); // NON_COMPLIANT: pointer points more than - // one beyond the last element - - int valid21 = *(*(array + 1) + 0); // COMPLIANT: pointer is within boundary + int valid132 = *( + *array + + 2); // COMPLIANT: pointer points one beyond the last + // element, but non-compliant to Rule 4.1.3 (equivalent to the above) + int invalid11 = *(*(array + 0) + 3); // NON_COMPLIANT: pointer points more + // than one beyond the last element + int invalid12 = + *(*array + 3); // NON_COMPLIANT: pointer points more than + // one beyond the last element (equivalent to the above) + + int valid211 = *(*(array + 1) + 0); // COMPLIANT: pointer is within boundary + int valid212 = *( + *(array + + 1)); // COMPLIANT: pointer is within boundary (equivalent to the above) int valid22 = *(*(array + 1) + 1); // COMPLIANT: pointer is within boundary int valid23 = *(*(array + 1) + 2); // COMPLIANT: pointer points one beyond the last @@ -155,11 +173,18 @@ void stack_allocated_multi_dimensional_pointer_arithmetic(int array[2][3]) { int invalid2 = *(*(array + 1) + 3); // NON_COMPLIANT: pointer points more than // one beyond the last element - int valid31 = + int valid311 = *(*(array + 2) + 0); // COMPLIANT: pointer points one beyond the last // element, but non-compliant to Rule 4.1.3 - int invalid3 = *(*(array + 3) + 0); // NON_COMPLIANT: pointer points more than - // one beyond the last element + int valid312 = *(*( + array + + 2)); // COMPLIANT: pointer points one beyond the last + // element, but non-compliant to Rule 4.1.3 (equivalent to the above) + int invalid31 = *(*(array + 3) + 0); // NON_COMPLIANT: pointer points more + // than one beyond the last element + int invalid32 = + *(*(array + 3)); // NON_COMPLIANT: pointer points more than + // one beyond the last element (equivalent to the above) } int main(int argc, char *argv[]) { From 21500b848c5b5b4b0a14319aed52f09cdf16b790 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 23 Jan 2026 16:48:35 -0500 Subject: [PATCH 17/19] Add exclusion for Memory1.qll --- .../cpp/exclusions/cpp/Memory1.qll | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/cpp/Memory1.qll diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Memory1.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Memory1.qll new file mode 100644 index 000000000..02b5789c8 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Memory1.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Memory1Query = TPointerArithmeticFormsAnInvalidPointerQuery() + +predicate isMemory1QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `pointerArithmeticFormsAnInvalidPointer` query + Memory1Package::pointerArithmeticFormsAnInvalidPointerQuery() and + queryId = + // `@id` for the `pointerArithmeticFormsAnInvalidPointer` query + "cpp/misra/pointer-arithmetic-forms-an-invalid-pointer" and + ruleId = "RULE-8-7-1" and + category = "required" +} + +module Memory1Package { + Query pointerArithmeticFormsAnInvalidPointerQuery() { + //autogenerate `Query` type + result = + // `Query` type for `pointerArithmeticFormsAnInvalidPointer` query + TQueryCPP(TMemory1PackageQuery(TPointerArithmeticFormsAnInvalidPointerQuery())) + } +} From e9f39a2e07aeb305241de1932dd95e852e0551cd Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 23 Jan 2026 17:32:36 -0500 Subject: [PATCH 18/19] Adjust precision of existing rule and add a supplementary rule --- rule_packages/cpp/Memory1.json | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/rule_packages/cpp/Memory1.json b/rule_packages/cpp/Memory1.json index 06bd63778..b8c5005ca 100644 --- a/rule_packages/cpp/Memory1.json +++ b/rule_packages/cpp/Memory1.json @@ -10,12 +10,23 @@ "description": "Pointers obtained as result of performing arithmetic should point to an initialized object, or an element right next to the last element of an array.", "kind": "problem", "name": "Pointer arithmetic shall not form an invalid pointer.", - "precision": "very-high", + "precision": "high", "severity": "error", "short_name": "PointerArithmeticFormsAnInvalidPointer", "tags": [ "scope/system" ] + }, + { + "description": "Pointer and index arguments passed to functions in should result in valid reads and/or writes.", + "kind": "problem", + "name": "Pointer and index arguments passed to functions in shall not be invalid.", + "precision": "high", + "severity": "error", + "short_name": "PointerArgumentToCstringFunctionIsInvalid", + "tags": [ + "scope/system" + ] } ], "title": "Pointers obtained as result of performing arithmetic should point to an initialized object, or an element right next to the last element of an array." From a62e2e1833b356b79cc968ff1a4af1833089660d Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 23 Jan 2026 17:40:45 -0500 Subject: [PATCH 19/19] Add supplementary query files --- .../cpp/exclusions/cpp/Memory1.qll | 20 +++++++++++++- ...interArgumentToCstringFunctionIsInvalid.ql | 26 +++++++++++++++++++ .../PointerArithmeticFormsAnInvalidPointer.ql | 4 +-- ...rgumentToCstringFunctionIsInvalid.expected | 1 + ...erArgumentToCstringFunctionIsInvalid.qlref | 1 + 5 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 cpp/misra/src/rules/RULE-8-7-1/PointerArgumentToCstringFunctionIsInvalid.ql create mode 100644 cpp/misra/test/rules/RULE-8-7-1/PointerArgumentToCstringFunctionIsInvalid.expected create mode 100644 cpp/misra/test/rules/RULE-8-7-1/PointerArgumentToCstringFunctionIsInvalid.qlref diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Memory1.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Memory1.qll index 02b5789c8..d59212417 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Memory1.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Memory1.qll @@ -3,7 +3,9 @@ import cpp import RuleMetadata import codingstandards.cpp.exclusions.RuleMetadata -newtype Memory1Query = TPointerArithmeticFormsAnInvalidPointerQuery() +newtype Memory1Query = + TPointerArithmeticFormsAnInvalidPointerQuery() or + TPointerArgumentToCstringFunctionIsInvalidQuery() predicate isMemory1QueryMetadata(Query query, string queryId, string ruleId, string category) { query = @@ -14,6 +16,15 @@ predicate isMemory1QueryMetadata(Query query, string queryId, string ruleId, str "cpp/misra/pointer-arithmetic-forms-an-invalid-pointer" and ruleId = "RULE-8-7-1" and category = "required" + or + query = + // `Query` instance for the `pointerArgumentToCstringFunctionIsInvalid` query + Memory1Package::pointerArgumentToCstringFunctionIsInvalidQuery() and + queryId = + // `@id` for the `pointerArgumentToCstringFunctionIsInvalid` query + "cpp/misra/pointer-argument-to-cstring-function-is-invalid" and + ruleId = "RULE-8-7-1" and + category = "required" } module Memory1Package { @@ -23,4 +34,11 @@ module Memory1Package { // `Query` type for `pointerArithmeticFormsAnInvalidPointer` query TQueryCPP(TMemory1PackageQuery(TPointerArithmeticFormsAnInvalidPointerQuery())) } + + Query pointerArgumentToCstringFunctionIsInvalidQuery() { + //autogenerate `Query` type + result = + // `Query` type for `pointerArgumentToCstringFunctionIsInvalid` query + TQueryCPP(TMemory1PackageQuery(TPointerArgumentToCstringFunctionIsInvalidQuery())) + } } diff --git a/cpp/misra/src/rules/RULE-8-7-1/PointerArgumentToCstringFunctionIsInvalid.ql b/cpp/misra/src/rules/RULE-8-7-1/PointerArgumentToCstringFunctionIsInvalid.ql new file mode 100644 index 000000000..ce9bac81f --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-7-1/PointerArgumentToCstringFunctionIsInvalid.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/pointer-argument-to-cstring-function-is-invalid + * @name RULE-8-7-1: Pointer and index arguments passed to functions in shall not be invalid. + * @description Pointer and index arguments passed to functions in should result in valid + * reads and/or writes. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-8-7-1 + * scope/system + * external/misra/enforcement/undecidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.cert +import codingstandards.c.OutOfBounds + +from + OOB::BufferAccessLibraryFunctionCall fc, string message, Expr bufferArg, string bufferArgStr, + Expr sizeOrOtherBufferArg, string otherStr +where + not isExcluded(fc, OutOfBoundsPackage::libraryFunctionArgumentOutOfBoundsQuery()) and + OOB::problems(fc, message, bufferArg, bufferArgStr, sizeOrOtherBufferArg, otherStr) +select fc, message, bufferArg, bufferArgStr, sizeOrOtherBufferArg, otherStr + diff --git a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql index 6fefe3a2e..bcb13c77b 100644 --- a/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql +++ b/cpp/misra/src/rules/RULE-8-7-1/PointerArithmeticFormsAnInvalidPointer.ql @@ -3,8 +3,8 @@ * @name RULE-8-7-1: Pointer arithmetic shall not form an invalid pointer. * @description Pointers obtained as result of performing arithmetic should point to an initialized * object, or an element right next to the last element of an array. - * @kind path-problem - * @precision very-high + * @kind problem + * @precision high * @problem.severity error * @tags external/misra/id/rule-8-7-1 * scope/system diff --git a/cpp/misra/test/rules/RULE-8-7-1/PointerArgumentToCstringFunctionIsInvalid.expected b/cpp/misra/test/rules/RULE-8-7-1/PointerArgumentToCstringFunctionIsInvalid.expected new file mode 100644 index 000000000..2ec1a0ac6 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-7-1/PointerArgumentToCstringFunctionIsInvalid.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-7-1/PointerArgumentToCstringFunctionIsInvalid.qlref b/cpp/misra/test/rules/RULE-8-7-1/PointerArgumentToCstringFunctionIsInvalid.qlref new file mode 100644 index 000000000..049e02582 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-7-1/PointerArgumentToCstringFunctionIsInvalid.qlref @@ -0,0 +1 @@ +rules/RULE-8-7-1/PointerArgumentToCstringFunctionIsInvalid.ql \ No newline at end of file