From a53e650850b43db669c02dc2857c68bc1eac9144 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Thu, 12 Jan 2023 23:46:54 +0000 Subject: [PATCH 01/25] EssentialTypes: create a new package Update the rules.csv to identify a new package dealing with the "essential" types identified by MISRA C 2012. --- rules.csv | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/rules.csv b/rules.csv index 1e299ae44c..d6d625bfe2 100644 --- a/rules.csv +++ b/rules.csv @@ -665,14 +665,14 @@ c,MISRA-C-2012,RULE-9-2,Yes,Required,,,The initializer for an aggregate or union c,MISRA-C-2012,RULE-9-3,Yes,Required,,,Arrays shall not be partially initialized,,Memory,Medium, c,MISRA-C-2012,RULE-9-4,Yes,Required,,,An element of an object shall not be initialized more than once,,Memory,Medium, c,MISRA-C-2012,RULE-9-5,Yes,Required,,,Where designated initializers are used to initialize an array object the size of the array shall be specified explicitly,,Memory,Medium, -c,MISRA-C-2012,RULE-10-1,Yes,Required,,,Operands shall not be of an inappropriate essential type,,Types,Hard, -c,MISRA-C-2012,RULE-10-2,Yes,Required,,,Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations,,Types,Medium, -c,MISRA-C-2012,RULE-10-3,Yes,Required,,,The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category,,Types,Hard, -c,MISRA-C-2012,RULE-10-4,Yes,Required,,,Both operands of an operator in which the usual arithmetic conversions are performed shall have the same essential type category,,Types,Medium, -c,MISRA-C-2012,RULE-10-5,Yes,Advisory,,,The value of an expression should not be cast to an inappropriate essential type,,Types,Medium, -c,MISRA-C-2012,RULE-10-6,Yes,Required,,,The value of a composite expression shall not be assigned to an object with wider essential type,,Types,Medium, -c,MISRA-C-2012,RULE-10-7,Yes,Required,,,If a composite expression is used as one operand of an operator in which the usual arithmetic conversions are performed then the other operand shall not have wider essential type,,Types,Medium, -c,MISRA-C-2012,RULE-10-8,Yes,Required,,,The value of a composite expression shall not be cast to a different essential type category or a wider essential type,,Types,Medium, +c,MISRA-C-2012,RULE-10-1,Yes,Required,,,Operands shall not be of an inappropriate essential type,,EssentialTypes,Hard, +c,MISRA-C-2012,RULE-10-2,Yes,Required,,,Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations,,EssentialTypes,Medium, +c,MISRA-C-2012,RULE-10-3,Yes,Required,,,The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category,,EssentialTypes,Hard, +c,MISRA-C-2012,RULE-10-4,Yes,Required,,,Both operands of an operator in which the usual arithmetic conversions are performed shall have the same essential type category,,EssentialTypes,Medium, +c,MISRA-C-2012,RULE-10-5,Yes,Advisory,,,The value of an expression should not be cast to an inappropriate essential type,,EssentialTypes,Medium, +c,MISRA-C-2012,RULE-10-6,Yes,Required,,,The value of a composite expression shall not be assigned to an object with wider essential type,,EssentialTypes,Medium, +c,MISRA-C-2012,RULE-10-7,Yes,Required,,,If a composite expression is used as one operand of an operator in which the usual arithmetic conversions are performed then the other operand shall not have wider essential type,,EssentialTypes,Medium, +c,MISRA-C-2012,RULE-10-8,Yes,Required,,,The value of a composite expression shall not be cast to a different essential type category or a wider essential type,,EssentialTypes,Medium, c,MISRA-C-2012,RULE-11-1,Yes,Required,,,Conversions shall not be performed between a pointer to a function and any other type,M5-2-6,Pointers1,Import, c,MISRA-C-2012,RULE-11-2,Yes,Required,,,Conversions shall not be performed between a pointer to an incomplete type and any other type,,Pointers1,Easy, c,MISRA-C-2012,RULE-11-3,Yes,Required,,,A cast shall not be performed between a pointer to object type and a pointer to a different object type,,Pointers1,Easy, @@ -693,7 +693,7 @@ c,MISRA-C-2012,RULE-13-3,Yes,Advisory,,,A full expression containing an incremen c,MISRA-C-2012,RULE-13-4,Yes,Advisory,,,The result of an assignment operator should not be used,M6-2-1,SideEffects1,Easy, c,MISRA-C-2012,RULE-13-5,Yes,Required,,,The right hand operand of a logical && or || operator shall not contain persistent side effects,M5-14-1,SideEffects1,Import, c,MISRA-C-2012,RULE-13-6,Yes,Mandatory,,,The operand of the sizeof operator shall not contain any expression which has potential side effects,M5-3-4,SideEffects1,Import, -c,MISRA-C-2012,RULE-14-1,Yes,Required,,,A loop counter shall not have essentially floating type,FLP30-C A6-5-2,Types,Hard, +c,MISRA-C-2012,RULE-14-1,Yes,Required,,,A loop counter shall not have essentially floating type,FLP30-C A6-5-2,EssentialTypes,Hard, c,MISRA-C-2012,RULE-14-2,Yes,Required,,,A for loop shall be well-formed,M6-5-1...M6-5-6,Statements,Medium, c,MISRA-C-2012,RULE-14-3,Yes,Required,,,Controlling expressions shall not be invariant,,Statements,Medium, c,MISRA-C-2012,RULE-14-4,Yes,Required,,,The controlling expression of an if statement and the controlling expression of an iteration-statement shall have essentially Boolean type,A5-0-2,Statements,Medium, @@ -756,7 +756,7 @@ c,MISRA-C-2012,RULE-21-10,Yes,Required,,,The Standard Library time and date func c,MISRA-C-2012,RULE-21-11,Yes,Required,,,The standard header file shall not be used,,Banned,Easy, c,MISRA-C-2012,RULE-21-12,Yes,Advisory,,,The exception handling features of should not be used,,Banned,Easy, c,MISRA-C-2012,RULE-21-13,Yes,Mandatory,,,Any value passed to a function in shall be representable as an unsigned char or be the value EOF,,Types,Medium, -c,MISRA-C-2012,RULE-21-14,Yes,Required,,,The Standard Library function memcmp shall not be used to compare null terminated strings,,Types,Hard, +c,MISRA-C-2012,RULE-21-14,Yes,Required,,,The Standard Library function memcmp shall not be used to compare null terminated strings,,EssentialTypes,Hard, c,MISRA-C-2012,RULE-21-15,Yes,Required,,,"The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers to qualified or unqualified versions of compatible types",,Types,Medium, c,MISRA-C-2012,RULE-21-16,Yes,Required,,,"The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type",,Types,Medium, c,MISRA-C-2012,RULE-21-17,Yes,Mandatory,,,Use of the string handling functions from shall not result in accesses beyond the bounds of the objects referenced by their pointer parameters,,Memory,Hard, From 60dc594d7ecbd09521a85b7397c2b7929234fc8f Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Mon, 6 Feb 2023 23:58:47 +0000 Subject: [PATCH 02/25] EssentialTypes: Refine set of rules and commit package files. --- .../cpp/exclusions/c/EssentialTypes.qll | 197 ++++++++++++++++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + rule_packages/c/EssentialTypes.json | 183 ++++++++++++++++ rules.csv | 4 +- 4 files changed, 385 insertions(+), 2 deletions(-) create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes.qll create mode 100644 rule_packages/c/EssentialTypes.json diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes.qll new file mode 100644 index 0000000000..5e3be0cebb --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes.qll @@ -0,0 +1,197 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype EssentialTypesQuery = + TOperandsOfAnInappropriateEssentialTypeQuery() or + TPointerTypeOnLogicalOperatorQuery() or + TAdditionSubtractionOnEssentiallyCharTypeQuery() or + TAssignmentOfIncompatibleEssentialTypeQuery() or + TOperandsWithMismatchedEssentialTypeCategoryQuery() or + TInappropriateEssentialTypeCastQuery() or + TAssignmentToWiderEssentialTypeQuery() or + TImplicitConversionOfCompositeExpressionQuery() or + TInappropriateCastOfCompositeExpressionQuery() or + TLoopOverEssentiallyFloatTypeQuery() or + TMemcmpOnInappropriateEssentialTypeArgsQuery() + +predicate isEssentialTypesQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `operandsOfAnInappropriateEssentialType` query + EssentialTypesPackage::operandsOfAnInappropriateEssentialTypeQuery() and + queryId = + // `@id` for the `operandsOfAnInappropriateEssentialType` query + "c/misra/operands-of-an-inappropriate-essential-type" and + ruleId = "RULE-10-1" and + category = "required" + or + query = + // `Query` instance for the `pointerTypeOnLogicalOperator` query + EssentialTypesPackage::pointerTypeOnLogicalOperatorQuery() and + queryId = + // `@id` for the `pointerTypeOnLogicalOperator` query + "c/misra/pointer-type-on-logical-operator" and + ruleId = "RULE-10-1" and + category = "required" + or + query = + // `Query` instance for the `additionSubtractionOnEssentiallyCharType` query + EssentialTypesPackage::additionSubtractionOnEssentiallyCharTypeQuery() and + queryId = + // `@id` for the `additionSubtractionOnEssentiallyCharType` query + "c/misra/addition-subtraction-on-essentially-char-type" and + ruleId = "RULE-10-2" and + category = "required" + or + query = + // `Query` instance for the `assignmentOfIncompatibleEssentialType` query + EssentialTypesPackage::assignmentOfIncompatibleEssentialTypeQuery() and + queryId = + // `@id` for the `assignmentOfIncompatibleEssentialType` query + "c/misra/assignment-of-incompatible-essential-type" and + ruleId = "RULE-10-3" and + category = "required" + or + query = + // `Query` instance for the `operandsWithMismatchedEssentialTypeCategory` query + EssentialTypesPackage::operandsWithMismatchedEssentialTypeCategoryQuery() and + queryId = + // `@id` for the `operandsWithMismatchedEssentialTypeCategory` query + "c/misra/operands-with-mismatched-essential-type-category" and + ruleId = "RULE-10-4" and + category = "required" + or + query = + // `Query` instance for the `inappropriateEssentialTypeCast` query + EssentialTypesPackage::inappropriateEssentialTypeCastQuery() and + queryId = + // `@id` for the `inappropriateEssentialTypeCast` query + "c/misra/inappropriate-essential-type-cast" and + ruleId = "RULE-10-5" and + category = "advisory" + or + query = + // `Query` instance for the `assignmentToWiderEssentialType` query + EssentialTypesPackage::assignmentToWiderEssentialTypeQuery() and + queryId = + // `@id` for the `assignmentToWiderEssentialType` query + "c/misra/assignment-to-wider-essential-type" and + ruleId = "RULE-10-6" and + category = "required" + or + query = + // `Query` instance for the `implicitConversionOfCompositeExpression` query + EssentialTypesPackage::implicitConversionOfCompositeExpressionQuery() and + queryId = + // `@id` for the `implicitConversionOfCompositeExpression` query + "c/misra/implicit-conversion-of-composite-expression" and + ruleId = "RULE-10-7" and + category = "required" + or + query = + // `Query` instance for the `inappropriateCastOfCompositeExpression` query + EssentialTypesPackage::inappropriateCastOfCompositeExpressionQuery() and + queryId = + // `@id` for the `inappropriateCastOfCompositeExpression` query + "c/misra/inappropriate-cast-of-composite-expression" and + ruleId = "RULE-10-8" and + category = "required" + or + query = + // `Query` instance for the `loopOverEssentiallyFloatType` query + EssentialTypesPackage::loopOverEssentiallyFloatTypeQuery() and + queryId = + // `@id` for the `loopOverEssentiallyFloatType` query + "c/misra/loop-over-essentially-float-type" and + ruleId = "RULE-14-1" and + category = "required" + or + query = + // `Query` instance for the `memcmpOnInappropriateEssentialTypeArgs` query + EssentialTypesPackage::memcmpOnInappropriateEssentialTypeArgsQuery() and + queryId = + // `@id` for the `memcmpOnInappropriateEssentialTypeArgs` query + "c/misra/memcmp-on-inappropriate-essential-type-args" and + ruleId = "RULE-21-16" and + category = "required" +} + +module EssentialTypesPackage { + Query operandsOfAnInappropriateEssentialTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `operandsOfAnInappropriateEssentialType` query + TQueryC(TEssentialTypesPackageQuery(TOperandsOfAnInappropriateEssentialTypeQuery())) + } + + Query pointerTypeOnLogicalOperatorQuery() { + //autogenerate `Query` type + result = + // `Query` type for `pointerTypeOnLogicalOperator` query + TQueryC(TEssentialTypesPackageQuery(TPointerTypeOnLogicalOperatorQuery())) + } + + Query additionSubtractionOnEssentiallyCharTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `additionSubtractionOnEssentiallyCharType` query + TQueryC(TEssentialTypesPackageQuery(TAdditionSubtractionOnEssentiallyCharTypeQuery())) + } + + Query assignmentOfIncompatibleEssentialTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `assignmentOfIncompatibleEssentialType` query + TQueryC(TEssentialTypesPackageQuery(TAssignmentOfIncompatibleEssentialTypeQuery())) + } + + Query operandsWithMismatchedEssentialTypeCategoryQuery() { + //autogenerate `Query` type + result = + // `Query` type for `operandsWithMismatchedEssentialTypeCategory` query + TQueryC(TEssentialTypesPackageQuery(TOperandsWithMismatchedEssentialTypeCategoryQuery())) + } + + Query inappropriateEssentialTypeCastQuery() { + //autogenerate `Query` type + result = + // `Query` type for `inappropriateEssentialTypeCast` query + TQueryC(TEssentialTypesPackageQuery(TInappropriateEssentialTypeCastQuery())) + } + + Query assignmentToWiderEssentialTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `assignmentToWiderEssentialType` query + TQueryC(TEssentialTypesPackageQuery(TAssignmentToWiderEssentialTypeQuery())) + } + + Query implicitConversionOfCompositeExpressionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `implicitConversionOfCompositeExpression` query + TQueryC(TEssentialTypesPackageQuery(TImplicitConversionOfCompositeExpressionQuery())) + } + + Query inappropriateCastOfCompositeExpressionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `inappropriateCastOfCompositeExpression` query + TQueryC(TEssentialTypesPackageQuery(TInappropriateCastOfCompositeExpressionQuery())) + } + + Query loopOverEssentiallyFloatTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `loopOverEssentiallyFloatType` query + TQueryC(TEssentialTypesPackageQuery(TLoopOverEssentiallyFloatTypeQuery())) + } + + Query memcmpOnInappropriateEssentialTypeArgsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `memcmpOnInappropriateEssentialTypeArgs` query + TQueryC(TEssentialTypesPackageQuery(TMemcmpOnInappropriateEssentialTypeArgsQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 004719516c..ff0142b94d 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -16,6 +16,7 @@ import Declarations1 import Declarations2 import Declarations3 import Declarations4 +import EssentialTypes import Expressions import IO1 import IO2 @@ -55,6 +56,7 @@ newtype TCQuery = TDeclarations2PackageQuery(Declarations2Query q) or TDeclarations3PackageQuery(Declarations3Query q) or TDeclarations4PackageQuery(Declarations4Query q) or + TEssentialTypesPackageQuery(EssentialTypesQuery q) or TExpressionsPackageQuery(ExpressionsQuery q) or TIO1PackageQuery(IO1Query q) or TIO2PackageQuery(IO2Query q) or @@ -94,6 +96,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isDeclarations2QueryMetadata(query, queryId, ruleId, category) or isDeclarations3QueryMetadata(query, queryId, ruleId, category) or isDeclarations4QueryMetadata(query, queryId, ruleId, category) or + isEssentialTypesQueryMetadata(query, queryId, ruleId, category) or isExpressionsQueryMetadata(query, queryId, ruleId, category) or isIO1QueryMetadata(query, queryId, ruleId, category) or isIO2QueryMetadata(query, queryId, ruleId, category) or diff --git a/rule_packages/c/EssentialTypes.json b/rule_packages/c/EssentialTypes.json new file mode 100644 index 0000000000..15c01100b9 --- /dev/null +++ b/rule_packages/c/EssentialTypes.json @@ -0,0 +1,183 @@ +{ + "MISRA-C-2012": { + "RULE-10-1": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "", + "kind": "problem", + "name": "Operands shall not be of an inappropriate essential type", + "precision": "very-high", + "severity": "error", + "short_name": "OperandsOfAnInappropriateEssentialType", + "tags": [] + }, + { + "description": "", + "kind": "problem", + "name": "Logical operators should not be used with pointer types", + "precision": "very-high", + "severity": "error", + "short_name": "PointerTypeOnLogicalOperator", + "tags": [] + } + ], + "title": "Operands shall not be of an inappropriate essential type" + }, + "RULE-10-2": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations", + "kind": "problem", + "name": "Expressions of essentially character type shall not be used inappropriately in addition and", + "precision": "very-high", + "severity": "error", + "short_name": "AdditionSubtractionOnEssentiallyCharType", + "tags": [] + } + ], + "title": "Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations" + }, + "RULE-10-3": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category", + "kind": "problem", + "name": "The value of an expression shall not be assigned to an object with a narrower essential type or of a", + "precision": "high", + "severity": "error", + "short_name": "AssignmentOfIncompatibleEssentialType", + "tags": [] + } + ], + "title": "The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category" + }, + "RULE-10-4": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Both operands of an operator in which the usual arithmetic conversions are performed shall have the same essential type category", + "kind": "problem", + "name": "Both operands of an operator in which the usual arithmetic conversions are performed shall have the", + "precision": "very-high", + "severity": "error", + "short_name": "OperandsWithMismatchedEssentialTypeCategory", + "tags": [] + } + ], + "title": "Both operands of an operator in which the usual arithmetic conversions are performed shall have the same essential type category" + }, + "RULE-10-5": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "", + "kind": "problem", + "name": "The value of an expression should not be cast to an inappropriate essential type", + "precision": "very-high", + "severity": "error", + "short_name": "InappropriateEssentialTypeCast", + "tags": [] + } + ], + "title": "The value of an expression should not be cast to an inappropriate essential type" + }, + "RULE-10-6": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "", + "kind": "problem", + "name": "The value of a composite expression shall not be assigned to an object with wider essential type", + "precision": "very-high", + "severity": "error", + "short_name": "AssignmentToWiderEssentialType", + "tags": [] + } + ], + "title": "The value of a composite expression shall not be assigned to an object with wider essential type" + }, + "RULE-10-7": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "If a composite expression is used as one operand of an operator in which the usual arithmetic conversions are performed then the other operand shall not have wider essential type", + "kind": "problem", + "name": "If a composite expression is used as one operand of an operator in which the usual arithmetic", + "precision": "very-high", + "severity": "error", + "short_name": "ImplicitConversionOfCompositeExpression", + "tags": [] + } + ], + "title": "If a composite expression is used as one operand of an operator in which the usual arithmetic conversions are performed then the other operand shall not have wider essential type" + }, + "RULE-10-8": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The value of a composite expression shall not be cast to a different essential type category or a wider essential type", + "kind": "problem", + "name": "The value of a composite expression shall not be cast to a different essential type category or a", + "precision": "very-high", + "severity": "error", + "short_name": "InappropriateCastOfCompositeExpression", + "tags": [] + } + ], + "title": "The value of a composite expression shall not be cast to a different essential type category or a wider essential type" + }, + "RULE-14-1": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "", + "kind": "problem", + "name": "A loop counter shall not have essentially floating type", + "precision": "high", + "severity": "error", + "short_name": "LoopOverEssentiallyFloatType", + "tags": [] + } + ], + "title": "A loop counter shall not have essentially floating type" + }, + "RULE-21-16": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type", + "kind": "problem", + "name": "The pointer arguments to the Standard Library function memcmp shall point to either a pointer type,", + "precision": "very-high", + "severity": "error", + "short_name": "MemcmpOnInappropriateEssentialTypeArgs", + "tags": [] + } + ], + "title": "The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index d6d625bfe2..e89f2bc18b 100644 --- a/rules.csv +++ b/rules.csv @@ -756,9 +756,9 @@ c,MISRA-C-2012,RULE-21-10,Yes,Required,,,The Standard Library time and date func c,MISRA-C-2012,RULE-21-11,Yes,Required,,,The standard header file shall not be used,,Banned,Easy, c,MISRA-C-2012,RULE-21-12,Yes,Advisory,,,The exception handling features of should not be used,,Banned,Easy, c,MISRA-C-2012,RULE-21-13,Yes,Mandatory,,,Any value passed to a function in shall be representable as an unsigned char or be the value EOF,,Types,Medium, -c,MISRA-C-2012,RULE-21-14,Yes,Required,,,The Standard Library function memcmp shall not be used to compare null terminated strings,,EssentialTypes,Hard, +c,MISRA-C-2012,RULE-21-14,Yes,Required,,,The Standard Library function memcmp shall not be used to compare null terminated strings,,Types,Hard, c,MISRA-C-2012,RULE-21-15,Yes,Required,,,"The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers to qualified or unqualified versions of compatible types",,Types,Medium, -c,MISRA-C-2012,RULE-21-16,Yes,Required,,,"The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type",,Types,Medium, +c,MISRA-C-2012,RULE-21-16,Yes,Required,,,"The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type",,EssentialTypes,Medium, c,MISRA-C-2012,RULE-21-17,Yes,Mandatory,,,Use of the string handling functions from shall not result in accesses beyond the bounds of the objects referenced by their pointer parameters,,Memory,Hard, c,MISRA-C-2012,RULE-21-18,Yes,Mandatory,,,The size_t argument passed to any function in shall have an appropriate value,,OutOfBounds,Hard, c,MISRA-C-2012,RULE-21-19,Yes,Mandatory,,,"The pointers returned by the Standard Library functions localeconv, getenv, setlocale or, strerror shall only be used as if they have pointer to const-qualified type",ENV30-C,Contracts2,Medium, From 8423344980bbc7b1154e23ed2e7675dde30abe88 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Mon, 13 Feb 2023 14:17:01 +0000 Subject: [PATCH 03/25] EssentialTypes: Add a utility module for MISRA definitions The essential types rules refer to a number of shared MISRA definitions which have been represented in this utility module. --- .../c/misra/MisraExpressions.qll | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 c/misra/src/codingstandards/c/misra/MisraExpressions.qll diff --git a/c/misra/src/codingstandards/c/misra/MisraExpressions.qll b/c/misra/src/codingstandards/c/misra/MisraExpressions.qll new file mode 100644 index 0000000000..b5f03838cc --- /dev/null +++ b/c/misra/src/codingstandards/c/misra/MisraExpressions.qll @@ -0,0 +1,106 @@ +/** + * A module for representing expressions and related types defined in the MISRA C 2012 standard. + */ + +import codingstandards.c.misra + +/** + * A `bool` type, either `stdbool.h` or a hand-coded bool type acceptable to MISRA C 2012. + */ +class MisraBoolType extends Type { + MisraBoolType() { + this instanceof BoolType + or + exists(Enum e | this = e | + count(e.getAnEnumConstant()) = 2 and + e.getEnumConstant(0).getName().toLowerCase() = ["false", "f"] and + e.getEnumConstant(1).getName().toLowerCase() = ["true", "t"] + ) + or + exists(TypedefType t | this = t | t.getName().toLowerCase() = ["bool", "boolean"]) + } +} + +/** + * A boolean literal as defined by the C standard and acceptable to MISRA C 2012. + */ +class BooleanLiteral extends Literal { + BooleanLiteral() { + exists(MacroInvocation mi, int value, string macroName | + macroName = mi.getMacroName() and mi.getExpr() = this and value = this.getValue().toInt() + | + macroName = "false" and value = 0 + or + macroName = "true" and value = 1 + ) + } +} + +/** + * A composite operator as defined in MISRA C:2012 8.10.3. + */ +class CompositeOperator extends Expr { + CompositeOperator() { + // + - * / % + - + this instanceof BinaryArithmeticOperation and + not this instanceof MaxExpr and + not this instanceof MinExpr + or + // << >> & ^ | + this instanceof BinaryBitwiseOperation + or + // ~ + this instanceof ComplementExpr + or + exists(ConditionalExpr ce | ce = this | + ce.getElse() instanceof CompositeExpression or ce.getThen() instanceof CompositeExpression + ) + } +} + +/** + * A composite expression as defined in MISRA C:2012 8.10.3. + */ +class CompositeExpression extends Expr { + CompositeExpression() { + this instanceof CompositeOperator and + // A non-constant expression that is the result of a composite operator + not exists(this.getValue()) + } +} + +/** + * An operator on which the usual arithmetic conversions apply to the operands, as defined in MISRA + * C:2012 6.3.1.8. + */ +class OperationWithUsualArithmeticConversions extends Expr { + OperationWithUsualArithmeticConversions() { + this instanceof BinaryOperation and + not this instanceof LShiftExpr and + not this instanceof RShiftExpr and + not this instanceof LogicalAndExpr and + not this instanceof LogicalOrExpr + or + this instanceof AssignArithmeticOperation + } + + Expr getLeftOperand() { + result = this.(BinaryOperation).getLeftOperand() + or + result = this.(AssignArithmeticOperation).getLValue() + } + + Expr getRightOperand() { + result = this.(BinaryOperation).getRightOperand() + or + result = this.(AssignArithmeticOperation).getRValue() + } + + Expr getAnOperand() { result = this.getLeftOperand() or result = this.getRightOperand() } + + string getOperator() { + result = this.(BinaryOperation).getOperator() + or + result = this.(AssignArithmeticOperation).getOperator() + } +} From 79e44e31ab2e4de82b046a3657b7cc238512d023 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Mon, 13 Feb 2023 14:18:16 +0000 Subject: [PATCH 04/25] EssentialTypes: Add essential types library This module calculates and reports the essential type of each given expression in the program, as defined in the MISRA C:2012 standard. The essential type for an expression is calculated based on the AST type of the expression. Where it differs from the standard type, the calculation is overridden to implement the MISRA definition. Various utility methods related to essential types are included. --- .../c/misra/EssentialTypes.qll | 366 ++++++++++++++++++ 1 file changed, 366 insertions(+) create mode 100644 c/misra/src/codingstandards/c/misra/EssentialTypes.qll diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll new file mode 100644 index 0000000000..06e1ff20fc --- /dev/null +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -0,0 +1,366 @@ +/** + * A module for identifying essential types as defined by MISRA C 2012. + */ + +import codingstandards.c.misra +import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils +import MisraExpressions + +newtype TEssentialTypeCategory = + EssentiallyBooleanType() or + EssentiallyCharacterType() or + EssentiallyEnumType() or + EssentiallySignedType() or + EssentiallyUnsignedType() or + EssentiallyFloatingType() + +/** An essential type category, as specified by Appendix D.1. */ +class EssentialTypeCategory extends TEssentialTypeCategory { + string toString() { + this = EssentiallyBooleanType() and result = "essentially Boolean type" + or + this = EssentiallyCharacterType() and result = "essentially Character type" + or + this = EssentiallyEnumType() and result = "essentially Enum Type" + or + this = EssentiallySignedType() and result = "essentially Signed type" + or + this = EssentiallyUnsignedType() and result = "essentially Unsigned type" + or + this = EssentiallyFloatingType() and result = "essentially Floating type" + } +} + +/** + * Gets the unsigned type of lowest rank that can represent the value of the given expression, + * assuming that the expression is essentially unsigned. + */ +private IntegralType utlr(Expr const) { + getEssentialTypeCategory(const.getType()) = EssentiallyUnsignedType() and + getEssentialTypeCategory(result) = EssentiallyUnsignedType() and + exists(float c | c = const.getValue().toFloat() | + // As with range analysis, we assume two's complement representation + typeLowerBound(result) <= c and + typeUpperBound(result) >= c and + forall(IntegralType it | + getEssentialTypeCategory(it) = EssentiallyUnsignedType() and + typeLowerBound(it) <= c and + typeUpperBound(it) >= c + | + result.getSize() <= it.getSize() + ) + ) +} + +/** + * Gets the signed type of lowest rank that can represent the value of the given expression, + * assuming that the expression is essentially signed. + */ +private IntegralType stlr(Expr const) { + getEssentialTypeCategory(const.getType()) = EssentiallySignedType() and + getEssentialTypeCategory(result) = EssentiallySignedType() and + exists(float c | c = const.getValue().toFloat() | + // As with range analysis, we assume two's complement representation + typeLowerBound(result) <= c and + typeUpperBound(result) >= c and + forall(IntegralType it | + getEssentialTypeCategory(it) = EssentiallySignedType() and + typeLowerBound(it) <= c and + typeUpperBound(it) >= c + | + result.getSize() <= it.getSize() + ) + ) +} + +/** + * Define the essential type category for an IntegralOrEnumType. + */ +EssentialTypeCategory getEssentialTypeCategory(Type at) { + result = EssentiallyBooleanType() and at instanceof MisraBoolType + or + result = EssentiallyCharacterType() and at instanceof PlainCharType + or + result = EssentiallySignedType() and + at.(IntegralType).isSigned() and + not at instanceof PlainCharType + or + result = EssentiallyUnsignedType() and + at.(IntegralType).isUnsigned() and + not at instanceof PlainCharType + or + result = EssentiallyEnumType() and at instanceof Enum and not at instanceof MisraBoolType + or + result = EssentiallyFloatingType() and + at instanceof FloatingPointType +} + +/** + * Gets the essential type of the given expression `e`, considering any explicit conversions. + */ +Type getEssentialType(Expr e) { + if e.hasExplicitConversion() + then + if e.getConversion() instanceof ParenthesisExpr + then + if e.getConversion().(ParenthesisExpr).hasExplicitConversion() + then result = e.getConversion().(ParenthesisExpr).getConversion().getType() + else result = e.getConversion().(ParenthesisExpr).getExpr().(EssentialExpr).getEssentialType() + else result = e.getConversion().getType() + else result = e.(EssentialExpr).getEssentialType() +} + +Type getEssentialTypeBeforeConversions(Expr e) { result = e.(EssentialExpr).getEssentialType() } + +class EssentialExpr extends Expr { + Type getEssentialType() { result = this.getType() } + + Type getStandardType() { result = this.getType() } +} + +class EssentialCommaExpr extends EssentialExpr, CommaExpr { + override Type getEssentialType() { result = getEssentialType(getRightOperand()) } +} + +class EssentialRelationalOperationExpr extends EssentialExpr, RelationalOperation { + override Type getEssentialType() { result instanceof BoolType } +} + +class EssentialBinaryLogicalOperationExpr extends EssentialExpr, BinaryLogicalOperation { + override Type getEssentialType() { result instanceof BoolType } +} + +class EssentialEqualityOperationExpr extends EssentialExpr, EqualityOperation { + override Type getEssentialType() { result instanceof BoolType } +} + +class EssentialBinaryBitwiseOperationExpr extends EssentialExpr, BinaryBitwiseOperation { + EssentialBinaryBitwiseOperationExpr() { + this instanceof LShiftExpr or + this instanceof RShiftExpr + } + + override Type getEssentialType() { + exists(Type operandEssentialType, EssentialTypeCategory operandEssentialTypeCategory | + operandEssentialType = getEssentialType(getLeftOperand()) and + operandEssentialTypeCategory = getEssentialTypeCategory(operandEssentialType) + | + if operandEssentialTypeCategory instanceof EssentiallyUnsignedType + then + if exists(this.getValue()) + then result = utlr(this) // If constant and essentially unsigned us the utlr + else result = operandEssentialType + else result = this.getStandardType() + ) + } +} + +class EssentialBitwiseComplementExpr extends EssentialExpr, ComplementExpr { + override Type getEssentialType() { + exists(Type operandEssentialType, EssentialTypeCategory operandEssentialTypeCategory | + operandEssentialType = getEssentialType(getOperand()) and + operandEssentialTypeCategory = getEssentialTypeCategory(operandEssentialType) + | + if operandEssentialTypeCategory instanceof EssentiallyUnsignedType + then + if exists(this.getValue()) + then result = utlr(this) // If constant and essentially unsigned us the utlr + else result = operandEssentialType + else result = this.getStandardType() + ) + } +} + +class EssentialUnaryPlusExpr extends EssentialExpr, UnaryPlusExpr { + override Type getEssentialType() { + exists(Type operandEssentialType, EssentialTypeCategory operandEssentialTypeCategory | + operandEssentialType = getEssentialType(getOperand()) and + operandEssentialTypeCategory = getEssentialTypeCategory(operandEssentialType) + | + if + operandEssentialTypeCategory = + [EssentiallyUnsignedType().(TEssentialTypeCategory), EssentiallySignedType()] + then result = operandEssentialType + else result = getStandardType() + ) + } +} + +class EssentialUnaryMinusExpr extends EssentialExpr, UnaryMinusExpr { + override Type getEssentialType() { + exists(Type operandEssentialType, EssentialTypeCategory operandEssentialTypeCategory | + operandEssentialType = getEssentialType(getOperand()) and + operandEssentialTypeCategory = getEssentialTypeCategory(operandEssentialType) + | + if operandEssentialTypeCategory = EssentiallySignedType() + then if exists(this.getValue()) then result = stlr(this) else result = operandEssentialType + else result = getStandardType() + ) + } +} + +class EssentialConditionalExpr extends EssentialExpr, ConditionalExpr { + override Type getEssentialType() { + exists(Type thenEssentialType, Type elseEssentialType | + thenEssentialType = getEssentialType(getThen()) and + elseEssentialType = getEssentialType(getElse()) + | + if thenEssentialType = elseEssentialType + then result = thenEssentialType + else + if + getEssentialTypeCategory(thenEssentialType) = EssentiallySignedType() and + getEssentialTypeCategory(elseEssentialType) = EssentiallySignedType() + then + if thenEssentialType.getSize() > elseEssentialType.getSize() + then result = thenEssentialType + else result = elseEssentialType + else + if + getEssentialTypeCategory(thenEssentialType) = EssentiallyUnsignedType() and + getEssentialTypeCategory(elseEssentialType) = EssentiallyUnsignedType() + then + if thenEssentialType.getSize() > elseEssentialType.getSize() + then result = thenEssentialType + else result = elseEssentialType + else result = this.getStandardType() + ) + } +} + +class EssentialBinaryArithmeticExpr extends EssentialExpr, BinaryArithmeticOperation { + EssentialBinaryArithmeticExpr() { + // GNU C extension has min/max which we can ignore + not this instanceof MinExpr and + not this instanceof MaxExpr + } + + override Type getEssentialType() { + exists( + Type leftEssentialType, Type rightEssentialType, + EssentialTypeCategory leftEssentialTypeCategory, + EssentialTypeCategory rightEssentialTypeCategory + | + leftEssentialType = getEssentialType(getLeftOperand()) and + rightEssentialType = getEssentialType(getRightOperand()) and + leftEssentialTypeCategory = getEssentialTypeCategory(leftEssentialType) and + rightEssentialTypeCategory = getEssentialTypeCategory(rightEssentialType) + | + if + leftEssentialTypeCategory = EssentiallySignedType() and + rightEssentialTypeCategory = EssentiallySignedType() + then + if exists(getValue()) + then result = stlr(this) + else ( + if leftEssentialType.getSize() > rightEssentialType.getSize() + then result = leftEssentialType + else result = rightEssentialType + ) + else + if + leftEssentialTypeCategory = EssentiallyUnsignedType() and + rightEssentialTypeCategory = EssentiallyUnsignedType() + then + if exists(getValue()) + then result = utlr(this) + else ( + if leftEssentialType.getSize() > rightEssentialType.getSize() + then result = leftEssentialType + else result = rightEssentialType + ) + else + if + this instanceof AddExpr and + ( + leftEssentialTypeCategory = EssentiallyCharacterType() + or + rightEssentialTypeCategory = EssentiallyCharacterType() + ) and + ( + leftEssentialTypeCategory = + [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] + or + rightEssentialTypeCategory = + [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] + ) + or + this instanceof SubExpr and + leftEssentialTypeCategory = EssentiallyCharacterType() and + rightEssentialTypeCategory = + [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] + then result instanceof PlainCharType + else result = this.getStandardType() + ) + } +} + +class EssentialEnumConstantAccess extends EssentialExpr, EnumConstantAccess { + override Type getEssentialType() { result = getTarget().getDeclaringEnum() } +} + +class EssentialLiteral extends EssentialExpr, Literal { + override Type getEssentialType() { + if this instanceof BooleanLiteral + then result instanceof MisraBoolType + else ( + if this.(CharLiteral).getCharacter().length() = 1 + then result instanceof PlainCharType + else ( + getStandardType().(IntegralType).isSigned() and + result = stlr(this) + or + not getStandardType().(IntegralType).isSigned() and + result = utlr(this) + ) + ) + } +} + +/** + * Holds if `rValue` is assigned to an object of type `lValueEssentialType`. + * + * Assignment is according to "Assignment" in Appendix J of MISRA C 2012, with the inclusion of a + * special case for switch statements as specified for Rule 10.3 and Rule 10.6. + */ +predicate isAssignmentToEssentialType(Type lValueEssentialType, Expr rValue) { + // Special case for Rule 10.3/ Rule 10.6. + exists(SwitchCase sc | + lValueEssentialType = sc.getSwitchStmt().getControllingExpr().getType() and + rValue = sc.getExpr() + ) + or + exists(Assignment a | + lValueEssentialType = a.getLValue().getType() and + rValue = a.getRValue() + ) + or + exists(FunctionCall fc, int i | + lValueEssentialType = fc.getTarget().getParameter(i).getType() and + rValue = fc.getArgument(i) + ) + or + exists(Function f, ReturnStmt rs | + lValueEssentialType = f.getType() and + rs.getEnclosingFunction() = f and + rValue = rs.getExpr() + ) + or + // Initializing a non-aggregate type + exists(Initializer i | + lValueEssentialType = i.getDeclaration().(Variable).getType() and + rValue = i.getExpr() + ) + or + // Initializing an array + exists(ArrayAggregateLiteral aal | + lValueEssentialType = aal.getElementType() and + rValue = aal.getElementExpr(_) + ) + or + // Initializing a struct or union + exists(ClassAggregateLiteral cal, Field field | + lValueEssentialType = field.getType() and + rValue = cal.getFieldExpr(field) + ) +} From 7c5fea9fe2300e047b2de2aaa3caa072473a1ff1 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Mon, 13 Feb 2023 14:20:35 +0000 Subject: [PATCH 05/25] EssentialTypes: Implement Rule 10.1 Adds queries to identify operators where the operands are of an inappropriate essential type, according to the MISRA specified rules. --- .../OperandsOfAnInappropriateEssentialType.ql | 251 +++++++++ .../RULE-10-1/PointerTypeOnLogicalOperator.ql | 24 + ...ndsOfAnInappropriateEssentialType.expected | 187 +++++++ ...erandsOfAnInappropriateEssentialType.qlref | 1 + .../PointerTypeOnLogicalOperator.expected | 5 + .../PointerTypeOnLogicalOperator.qlref | 1 + c/misra/test/rules/RULE-10-1/test.c | 495 ++++++++++++++++++ 7 files changed, 964 insertions(+) create mode 100644 c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql create mode 100644 c/misra/src/rules/RULE-10-1/PointerTypeOnLogicalOperator.ql create mode 100644 c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected create mode 100644 c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.qlref create mode 100644 c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.expected create mode 100644 c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.qlref create mode 100644 c/misra/test/rules/RULE-10-1/test.c diff --git a/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql b/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql new file mode 100644 index 0000000000..0245f3cbc5 --- /dev/null +++ b/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql @@ -0,0 +1,251 @@ +/** + * @id c/misra/operands-of-an-inappropriate-essential-type + * @name RULE-10-1: Operands shall not be of an inappropriate essential type + * @description + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-10-1 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.misra.EssentialTypes + +/** + * Holds if the operator `operator` has an operand `child` that is of an inappropriate essential type + * according to MISRA C 2012 Rule 10.1. + */ +predicate isInappropriateEssentialType( + Expr operator, Expr child, EssentialTypeCategory etc, int rationaleId +) { + etc = getEssentialTypeCategory(getEssentialType(child)) and + ( + child = operator.(ArrayExpr).getArrayOffset() and + ( + etc = EssentiallyBooleanType() and + rationaleId = 3 + or + etc = EssentiallyCharacterType() and + rationaleId = 4 + or + etc = EssentiallyFloatingType() and + rationaleId = 1 + ) + or + child = operator.(UnaryPlusExpr).getOperand() and + ( + etc = EssentiallyBooleanType() and + rationaleId = 3 + or + etc = EssentiallyCharacterType() and + rationaleId = 4 + or + etc = EssentiallyEnumType() and + rationaleId = 5 + ) + or + child = operator.(UnaryMinusExpr).getOperand() and + ( + etc = EssentiallyBooleanType() and + rationaleId = 3 + or + etc = EssentiallyCharacterType() and + rationaleId = 4 + or + etc = EssentiallyEnumType() and + rationaleId = 5 + or + etc = EssentiallyUnsignedType() and + rationaleId = 8 + ) + or + // The table only talks about + and -, but below it clarifies ++ and -- are also considered to + // be equivalent. + child = + [ + operator.(AddExpr).getAnOperand(), operator.(SubExpr).getAnOperand(), + operator.(IncrementOperation).getAnOperand(), operator.(DecrementOperation).getAnOperand(), + operator.(AssignAddExpr).getAnOperand(), operator.(AssignSubExpr).getAnOperand() + ] and + ( + etc = EssentiallyBooleanType() and + rationaleId = 3 + or + etc = EssentiallyEnumType() and + rationaleId = 5 + ) + or + child = + [ + operator.(DivExpr).getAnOperand(), operator.(MulExpr).getAnOperand(), + operator.(AssignDivExpr).getAnOperand(), operator.(AssignMulExpr).getAnOperand() + ] and + ( + etc = EssentiallyBooleanType() and + rationaleId = 3 + or + etc = EssentiallyCharacterType() and + rationaleId = 4 + or + etc = EssentiallyEnumType() and + rationaleId = 5 + ) + or + child = [operator.(RemExpr).getAnOperand(), operator.(AssignRemExpr).getAnOperand()] and + ( + etc = EssentiallyBooleanType() and + rationaleId = 3 + or + etc = EssentiallyCharacterType() and + rationaleId = 4 + or + etc = EssentiallyEnumType() and + rationaleId = 5 + or + etc = EssentiallyFloatingType() and + rationaleId = 1 + ) + or + child = operator.(RelationalOperation).getAnOperand() and + etc = EssentiallyBooleanType() and + rationaleId = 3 + or + child = [operator.(NotExpr).getAnOperand(), operator.(BinaryLogicalOperation).getAnOperand()] and + rationaleId = 2 and + ( + etc = EssentiallyCharacterType() + or + etc = EssentiallyEnumType() + or + etc = EssentiallySignedType() + or + etc = EssentiallyUnsignedType() + or + etc = EssentiallyFloatingType() + ) + or + child = + [ + operator.(LShiftExpr).getLeftOperand(), operator.(RShiftExpr).getLeftOperand(), + operator.(AssignLShiftExpr).getLValue(), operator.(AssignRShiftExpr).getLValue() + ] and + ( + etc = EssentiallyBooleanType() and + rationaleId = 3 + or + etc = EssentiallyCharacterType() and + rationaleId = 4 + or + etc = EssentiallyEnumType() and + rationaleId = 6 // 5 also applies, but 6 is sufficient explanation + or + etc = EssentiallySignedType() and + rationaleId = 6 + or + etc = EssentiallyFloatingType() and + rationaleId = 1 + ) + or + child = + [ + operator.(LShiftExpr).getRightOperand(), operator.(RShiftExpr).getRightOperand(), + operator.(AssignLShiftExpr).getRValue(), operator.(AssignRShiftExpr).getRValue() + ] and + // Integer constant non negative essentially signed types are allowed by exception + not (child.getValue().toInt() >= 0 and etc = EssentiallySignedType()) and + ( + etc = EssentiallyBooleanType() and + rationaleId = 3 + or + etc = EssentiallyCharacterType() and + rationaleId = 4 + or + etc = EssentiallyEnumType() and + rationaleId = 7 + or + etc = EssentiallySignedType() and + rationaleId = 7 + or + etc = EssentiallyFloatingType() and + rationaleId = 1 + ) + or + child = + [ + operator.(BinaryBitwiseOperation).getAnOperand(), + operator.(AssignBitwiseOperation).getAnOperand() + ] and + not operator instanceof LShiftExpr and + not operator instanceof RShiftExpr and + not operator instanceof AssignLShiftExpr and + not operator instanceof AssignRShiftExpr and + ( + etc = EssentiallyBooleanType() and + rationaleId = 3 + or + etc = EssentiallyCharacterType() and + rationaleId = 4 + or + etc = EssentiallyEnumType() and + rationaleId = 6 + or + etc = EssentiallySignedType() and + rationaleId = 6 + or + etc = EssentiallyFloatingType() and + rationaleId = 1 + ) + or + child = operator.(ConditionalExpr).getCondition() and + ( + etc = EssentiallyCharacterType() and + rationaleId = 2 + or + etc = EssentiallyEnumType() and + rationaleId = 2 + or + etc = EssentiallySignedType() and + rationaleId = 2 + or + etc = EssentiallyUnsignedType() and + rationaleId = 2 + or + etc = EssentiallyFloatingType() and + rationaleId = 2 + ) + ) +} + +string getRationaleMessage(int rationaleId, EssentialTypeCategory etc) { + rationaleId = 1 and + result = "Constraint violation from using an operand of essentially Floating type." + or + rationaleId = 2 and result = "Operand of " + etc + " type interpreted as a Boolean value." + or + rationaleId = 3 and result = "Operand of essentially Boolean type interpreted as a numeric value." + or + rationaleId = 4 and + result = "Operand of essentially Charater type interpreted as a numeric value." + or + rationaleId = 5 and + result = + "Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type." + or + rationaleId = 6 and + result = "Bitwise operator applied to operand of " + etc + " and not essentially unsigned." + or + rationaleId = 7 and + result = "Right hand operatand of shift operator is " + etc + " and not not essentially unsigned." + or + rationaleId = 8 and + result = + "Operand of essentially Unsigned type will be converted to a signed type with the signedness dependent on the implemented size of int." +} + +from Expr operator, Expr child, int rationaleId, EssentialTypeCategory etc +where + not isExcluded(operator, EssentialTypesPackage::operandsOfAnInappropriateEssentialTypeQuery()) and + isInappropriateEssentialType(operator, child, etc, rationaleId) +select operator, getRationaleMessage(rationaleId, etc) diff --git a/c/misra/src/rules/RULE-10-1/PointerTypeOnLogicalOperator.ql b/c/misra/src/rules/RULE-10-1/PointerTypeOnLogicalOperator.ql new file mode 100644 index 0000000000..53d4a79ffc --- /dev/null +++ b/c/misra/src/rules/RULE-10-1/PointerTypeOnLogicalOperator.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/pointer-type-on-logical-operator + * @name RULE-10-1: Logical operators should not be used with pointer types + * @description + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-10-1 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from Expr logicalOperator, Expr operand +where + not isExcluded(operand, EssentialTypesPackage::pointerTypeOnLogicalOperatorQuery()) and + ( + operand = logicalOperator.(BinaryLogicalOperation).getAnOperand() + or + operand = logicalOperator.(NotExpr).getOperand() + ) and + operand.getType() instanceof PointerType +select operand, "Logical operators should not be used with pointer types." diff --git a/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected b/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected new file mode 100644 index 0000000000..b04a4ee4aa --- /dev/null +++ b/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected @@ -0,0 +1,187 @@ +| test.c:13:3:13:6 | access to array | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:14:3:14:6 | access to array | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:20:3:20:4 | + ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:21:3:21:4 | + ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:22:3:22:5 | + ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:27:3:27:4 | - ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:28:3:28:4 | - ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:29:3:29:5 | - ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:31:3:31:4 | - ... | Operand of essentially Unsigned type will be converted to a signed type with the signedness dependent on the implemented size of int. | +| test.c:34:3:34:7 | ... + ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:36:3:36:8 | ... + ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:41:3:41:7 | ... - ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:43:3:43:8 | ... - ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:48:3:48:7 | ... + ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:50:3:50:8 | ... + ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:55:3:55:7 | ... - ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:57:3:57:8 | ... - ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:62:3:62:5 | ... ++ | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:64:3:64:6 | ... ++ | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:69:3:69:5 | ... -- | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:71:3:71:6 | ... -- | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:76:3:76:5 | ++ ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:78:3:78:6 | ++ ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:83:3:83:5 | -- ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:85:3:85:6 | -- ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:90:3:90:7 | ... * ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:91:3:91:7 | ... * ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:92:3:92:8 | ... * ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:97:3:97:7 | ... / ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:98:3:98:7 | ... / ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:99:3:99:8 | ... / ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:104:3:104:7 | ... * ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:105:3:105:7 | ... * ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:106:3:106:8 | ... * ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:111:3:111:7 | ... / ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:112:3:112:7 | ... / ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:113:3:113:8 | ... / ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:118:3:118:7 | ... % ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:119:3:119:7 | ... % ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:120:3:120:8 | ... % ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:125:3:125:7 | ... % ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:126:3:126:7 | ... % ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:127:3:127:8 | ... % ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:132:3:132:7 | ... < ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:139:3:139:7 | ... > ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:146:3:146:8 | ... <= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:153:3:153:8 | ... >= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:160:3:160:7 | ... < ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:167:3:167:7 | ... > ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:174:3:174:8 | ... <= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:181:3:181:8 | ... >= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:217:3:217:4 | ! ... | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:218:3:218:5 | ! ... | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:219:3:219:4 | ! ... | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:220:3:220:4 | ! ... | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:221:3:221:4 | ! ... | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:224:3:224:11 | ... && ... | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:225:3:225:12 | ... && ... | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:226:3:226:11 | ... && ... | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:227:3:227:11 | ... && ... | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:228:3:228:11 | ... && ... | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:231:3:231:12 | ... \|\| ... | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:232:3:232:13 | ... \|\| ... | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:233:3:233:12 | ... \|\| ... | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:234:3:234:12 | ... \|\| ... | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:235:3:235:12 | ... \|\| ... | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:238:3:238:11 | ... && ... | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:239:3:239:12 | ... && ... | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:240:3:240:11 | ... && ... | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:241:3:241:11 | ... && ... | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:242:3:242:11 | ... && ... | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:245:3:245:12 | ... \|\| ... | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:246:3:246:13 | ... \|\| ... | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:247:3:247:12 | ... \|\| ... | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:248:3:248:12 | ... \|\| ... | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:249:3:249:12 | ... \|\| ... | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:251:3:251:8 | ... << ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:252:3:252:8 | ... << ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:253:3:253:9 | ... << ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:254:3:254:8 | ... << ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:258:3:258:8 | ... >> ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:259:3:259:8 | ... >> ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:260:3:260:9 | ... >> ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:261:3:261:8 | ... >> ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:265:3:265:8 | ... << ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:266:3:266:8 | ... << ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:267:3:267:9 | ... << ... | Right hand operatand of shift operator is essentially Enum Type and not not essentially unsigned. | +| test.c:268:3:268:8 | ... << ... | Right hand operatand of shift operator is essentially Signed type and not not essentially unsigned. | +| test.c:272:3:272:8 | ... >> ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:273:3:273:8 | ... >> ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:274:3:274:9 | ... >> ... | Right hand operatand of shift operator is essentially Enum Type and not not essentially unsigned. | +| test.c:275:3:275:8 | ... >> ... | Right hand operatand of shift operator is essentially Signed type and not not essentially unsigned. | +| test.c:279:3:279:6 | ... & ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:280:3:280:6 | ... & ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:281:3:281:7 | ... & ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:282:3:282:6 | ... & ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:286:3:286:7 | ... \| ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:287:3:287:7 | ... \| ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:288:3:288:8 | ... \| ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:289:3:289:7 | ... \| ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:293:3:293:7 | ... ^ ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:294:3:294:7 | ... ^ ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:295:3:295:8 | ... ^ ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:296:3:296:7 | ... ^ ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:300:3:300:6 | ... & ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:301:3:301:6 | ... & ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:302:3:302:7 | ... & ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:303:3:303:6 | ... & ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:307:3:307:7 | ... \| ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:308:3:308:7 | ... \| ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:309:3:309:8 | ... \| ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:310:3:310:7 | ... \| ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:314:3:314:7 | ... ^ ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:315:3:315:7 | ... ^ ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:316:3:316:8 | ... ^ ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:317:3:317:7 | ... ^ ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:329:3:329:11 | ... ? ... : ... | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:330:3:330:12 | ... ? ... : ... | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:331:3:331:11 | ... ? ... : ... | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:332:3:332:11 | ... ? ... : ... | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:333:3:333:11 | ... ? ... : ... | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:342:3:342:8 | ... += ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:344:3:344:9 | ... += ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:349:3:349:8 | ... -= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:351:3:351:9 | ... -= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:356:3:356:8 | ... += ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:358:3:358:9 | ... += ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:363:3:363:8 | ... -= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:365:3:365:9 | ... -= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:370:3:370:8 | ... *= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:371:3:371:8 | ... *= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:372:3:372:9 | ... *= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:377:3:377:8 | ... /= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:378:3:378:8 | ... /= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:379:3:379:9 | ... /= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:384:3:384:8 | ... *= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:385:3:385:8 | ... *= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:386:3:386:9 | ... *= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:391:3:391:8 | ... /= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:392:3:392:8 | ... /= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:393:3:393:9 | ... /= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:398:3:398:8 | ... %= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:399:3:399:8 | ... %= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:400:3:400:9 | ... %= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:405:3:405:8 | ... %= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:406:3:406:8 | ... %= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:407:3:407:9 | ... %= ... | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:412:3:412:9 | ... <<= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:413:3:413:9 | ... <<= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:414:3:414:10 | ... <<= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:415:3:415:9 | ... <<= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:419:3:419:9 | ... >>= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:420:3:420:9 | ... >>= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:421:3:421:10 | ... >>= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:422:3:422:9 | ... >>= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:426:3:426:9 | ... <<= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:427:3:427:9 | ... <<= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:428:3:428:10 | ... <<= ... | Right hand operatand of shift operator is essentially Enum Type and not not essentially unsigned. | +| test.c:429:3:429:9 | ... <<= ... | Right hand operatand of shift operator is essentially Signed type and not not essentially unsigned. | +| test.c:433:3:433:9 | ... >>= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:434:3:434:9 | ... >>= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:435:3:435:10 | ... >>= ... | Right hand operatand of shift operator is essentially Enum Type and not not essentially unsigned. | +| test.c:436:3:436:9 | ... >>= ... | Right hand operatand of shift operator is essentially Signed type and not not essentially unsigned. | +| test.c:440:3:440:8 | ... &= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:441:3:441:8 | ... &= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:442:3:442:9 | ... &= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:443:3:443:8 | ... &= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:447:3:447:8 | ... ^= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:448:3:448:8 | ... ^= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:449:3:449:9 | ... ^= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:450:3:450:8 | ... ^= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:454:3:454:8 | ... \|= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:455:3:455:8 | ... \|= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:456:3:456:9 | ... \|= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:457:3:457:8 | ... \|= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:461:3:461:8 | ... &= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:462:3:462:8 | ... &= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:463:3:463:9 | ... &= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:464:3:464:8 | ... &= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:468:3:468:8 | ... ^= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:469:3:469:8 | ... ^= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:470:3:470:9 | ... ^= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:471:3:471:8 | ... ^= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:475:3:475:8 | ... \|= ... | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:476:3:476:8 | ... \|= ... | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:477:3:477:9 | ... \|= ... | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:478:3:478:8 | ... \|= ... | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | diff --git a/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.qlref b/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.qlref new file mode 100644 index 0000000000..f3120fd81f --- /dev/null +++ b/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.qlref @@ -0,0 +1 @@ +rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.expected b/c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.expected new file mode 100644 index 0000000000..35a55919fd --- /dev/null +++ b/c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.expected @@ -0,0 +1,5 @@ +| test.c:488:4:488:4 | p | Logical operators should not be used with pointer types. | +| test.c:490:3:490:3 | p | Logical operators should not be used with pointer types. | +| test.c:491:7:491:7 | p | Logical operators should not be used with pointer types. | +| test.c:493:3:493:3 | p | Logical operators should not be used with pointer types. | +| test.c:494:8:494:8 | p | Logical operators should not be used with pointer types. | diff --git a/c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.qlref b/c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.qlref new file mode 100644 index 0000000000..cec5f51a3a --- /dev/null +++ b/c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.qlref @@ -0,0 +1 @@ +rules/RULE-10-1/PointerTypeOnLogicalOperator.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-1/test.c b/c/misra/test/rules/RULE-10-1/test.c new file mode 100644 index 0000000000..8945890d4c --- /dev/null +++ b/c/misra/test/rules/RULE-10-1/test.c @@ -0,0 +1,495 @@ +#include "stdbool.h" + +void testInappropriateOperands() { + _Bool b = true; + char c = 'c'; + enum E1 { A, B, C } e1 = A; + signed int s = 100; + unsigned int u = 1; + float f = 1.0; + + int a[20]; + + a[b]; // NON_COMPLIANT + a[c]; // NON_COMPLIANT + a[e1]; // COMPLIANT + a[s]; // COMPLIANT + a[u]; // COMPLIANT + // a[f]; // NON_COMPILABLE + + +b; // NON_COMPLIANT + +c; // NON_COMPLIANT + +e1; // NON_COMPLIANT + +s; // COMPLIANT + +u; // COMPLIANT + +f; // COMPLIANT + + -b; // NON_COMPLIANT + -c; // NON_COMPLIANT + -e1; // NON_COMPLIANT + -s; // COMPLIANT + -u; // NON_COMPLIANT + -f; // COMPLIANT + + 1 + b; // NON_COMPLIANT + 1 + c; // COMPLIANT + 1 + e1; // NON_COMPLIANT + 1 + s; // COMPLIANT + 1 + u; // COMPLIANT + 1 + f; // COMPLIANT + + 1 - b; // NON_COMPLIANT + 1 - c; // COMPLIANT + 1 - e1; // NON_COMPLIANT + 1 - s; // COMPLIANT + 1 - u; // COMPLIANT + 1 - f; // COMPLIANT + + b + 1; // NON_COMPLIANT + c + 1; // COMPLIANT + e1 + 1; // NON_COMPLIANT + s + 1; // COMPLIANT + u + 1; // COMPLIANT + f + 1; // COMPLIANT + + b - 1; // NON_COMPLIANT + c - 1; // COMPLIANT + e1 - 1; // NON_COMPLIANT + s - 1; // COMPLIANT + u - 1; // COMPLIANT + f - 1; // COMPLIANT + + b++; // NON_COMPLIANT + c++; // COMPLIANT + e1++; // NON_COMPLIANT + s++; // COMPLIANT + u++; // COMPLIANT + f++; // COMPLIANT + + b--; // NON_COMPLIANT + c--; // COMPLIANT + e1--; // NON_COMPLIANT + s--; // COMPLIANT + u--; // COMPLIANT + f--; // COMPLIANT + + ++b; // NON_COMPLIANT + ++c; // COMPLIANT + ++e1; // NON_COMPLIANT + ++s; // COMPLIANT + ++u; // COMPLIANT + ++f; // COMPLIANT + + --b; // NON_COMPLIANT + --c; // COMPLIANT + --e1; // NON_COMPLIANT + --s; // COMPLIANT + --u; // COMPLIANT + --f; // COMPLIANT + + 1 * b; // NON_COMPLIANT + 1 * c; // NON_COMPLIANT + 1 * e1; // NON_COMPLIANT + 1 * s; // COMPLIANT + 1 * u; // COMPLIANT + 1 * f; // COMPLIANT + + 1 / b; // NON_COMPLIANT + 1 / c; // NON_COMPLIANT + 1 / e1; // NON_COMPLIANT + 1 / s; // COMPLIANT + 1 / u; // COMPLIANT + 1 / f; // COMPLIANT + + b * 1; // NON_COMPLIANT + c * 1; // NON_COMPLIANT + e1 * 1; // NON_COMPLIANT + s * 1; // COMPLIANT + u * 1; // COMPLIANT + f * 1; // COMPLIANT + + b / 1; // NON_COMPLIANT + c / 1; // NON_COMPLIANT + e1 / 1; // NON_COMPLIANT + s / 1; // COMPLIANT + u / 1; // COMPLIANT + f / 1; // COMPLIANT + + b % 1; // NON_COMPLIANT + c % 1; // NON_COMPLIANT + e1 % 1; // NON_COMPLIANT + s % 1; // COMPLIANT + u % 1; // COMPLIANT + // f % 1; // NON_COMPILABLE + + 1 % b; // NON_COMPLIANT + 1 % c; // NON_COMPLIANT + 1 % e1; // NON_COMPLIANT + 1 % s; // COMPLIANT + 1 % u; // COMPLIANT + // 1 % f; // NON_COMPILABLE + + 1 < b; // NON_COMPLIANT + 1 < c; // COMPLIANT + 1 < e1; // COMPLIANT + 1 < s; // COMPLIANT + 1 < u; // COMPLIANT + 1 < f; // COMPLIANT + + 1 > b; // NON_COMPLIANT + 1 > c; // COMPLIANT + 1 > e1; // COMPLIANT + 1 > s; // COMPLIANT + 1 > u; // COMPLIANT + 1 > f; // COMPLIANT + + 1 <= b; // NON_COMPLIANT + 1 <= c; // COMPLIANT + 1 <= e1; // COMPLIANT + 1 <= s; // COMPLIANT + 1 <= u; // COMPLIANT + 1 <= f; // COMPLIANT + + 1 >= b; // NON_COMPLIANT + 1 >= c; // COMPLIANT + 1 >= e1; // COMPLIANT + 1 >= s; // COMPLIANT + 1 >= u; // COMPLIANT + 1 >= f; // COMPLIANT + + b < 1; // NON_COMPLIANT + c < 1; // COMPLIANT + e1 < 1; // COMPLIANT + s < 1; // COMPLIANT + u < 1; // COMPLIANT + f < 1; // COMPLIANT + + b > 1; // NON_COMPLIANT + c > 1; // COMPLIANT + e1 > 1; // COMPLIANT + s > 1; // COMPLIANT + u > 1; // COMPLIANT + f > 1; // COMPLIANT + + b <= 1; // NON_COMPLIANT + c <= 1; // COMPLIANT + e1 <= 1; // COMPLIANT + s <= 1; // COMPLIANT + u <= 1; // COMPLIANT + f <= 1; // COMPLIANT + + b >= 1; // NON_COMPLIANT + c >= 1; // COMPLIANT + e1 >= 1; // COMPLIANT + s >= 1; // COMPLIANT + u >= 1; // COMPLIANT + f >= 1; // COMPLIANT + + b == 1; // COMPLIANT + c == 1; // COMPLIANT + e1 == 1; // COMPLIANT + s == 1; // COMPLIANT + u == 1; // COMPLIANT + f == 1; // COMPLIANT + + b != 1; // COMPLIANT + c != 1; // COMPLIANT + e1 != 1; // COMPLIANT + s != 1; // COMPLIANT + u != 1; // COMPLIANT + f != 1; // COMPLIANT + + 1 == b; // COMPLIANT + 1 == c; // COMPLIANT + 1 == e1; // COMPLIANT + 1 == s; // COMPLIANT + 1 == u; // COMPLIANT + 1 == f; // COMPLIANT + + 1 != b; // COMPLIANT + 1 != c; // COMPLIANT + 1 != e1; // COMPLIANT + 1 != s; // COMPLIANT + 1 != u; // COMPLIANT + 1 != f; // COMPLIANT + + !b; // COMPLIANT + !c; // NON_COMPLIANT + !e1; // NON_COMPLIANT + !s; // NON_COMPLIANT + !u; // NON_COMPLIANT + !f; // NON_COMPLIANT + + b && true; // COMPLIANT + c && true; // NON_COMPLIANT + e1 && true; // NON_COMPLIANT + s && true; // NON_COMPLIANT + u && true; // NON_COMPLIANT + f && true; // NON_COMPLIANT + + b || false; // COMPLIANT + c || false; // NON_COMPLIANT + e1 || false; // NON_COMPLIANT + s || false; // NON_COMPLIANT + u || false; // NON_COMPLIANT + f || false; // NON_COMPLIANT + + true && b; // COMPLIANT + true && c; // NON_COMPLIANT + true && e1; // NON_COMPLIANT + true && s; // NON_COMPLIANT + true && u; // NON_COMPLIANT + true && f; // NON_COMPLIANT + + false || b; // COMPLIANT + false || c; // NON_COMPLIANT + false || e1; // NON_COMPLIANT + false || s; // NON_COMPLIANT + false || u; // NON_COMPLIANT + false || f; // NON_COMPLIANT + + b << u; // NON_COMPLIANT + c << u; // NON_COMPLIANT + e1 << u; // NON_COMPLIANT + s << u; // NON_COMPLIANT + u << u; // COMPLIANT + // f << u; // NON_COMPILABLE + + b >> u; // NON_COMPLIANT + c >> u; // NON_COMPLIANT + e1 >> u; // NON_COMPLIANT + s >> u; // NON_COMPLIANT + u >> u; // COMPLIANT + // f >> u; // NON_COMPILABLE + + u << b; // NON_COMPLIANT + u << c; // NON_COMPLIANT + u << e1; // NON_COMPLIANT + u << s; // NON_COMPLIANT + u << u; // COMPLIANT + // u << f; // NON_COMPILABLE + + u >> b; // NON_COMPLIANT + u >> c; // NON_COMPLIANT + u >> e1; // NON_COMPLIANT + u >> s; // NON_COMPLIANT + u >> u; // COMPLIANT + // u >> f; // NON_COMPILABLE + + b &u; // NON_COMPLIANT + c &u; // NON_COMPLIANT + e1 &u; // NON_COMPLIANT + s &u; // NON_COMPLIANT + u &u; // COMPLIANT + // f &u; // NON_COMPILABLE + + b | u; // NON_COMPLIANT + c | u; // NON_COMPLIANT + e1 | u; // NON_COMPLIANT + s | u; // NON_COMPLIANT + u | u; // COMPLIANT + // f | u; // NON_COMPILABLE + + b ^ u; // NON_COMPLIANT + c ^ u; // NON_COMPLIANT + e1 ^ u; // NON_COMPLIANT + s ^ u; // NON_COMPLIANT + u ^ u; // COMPLIANT + // f ^ u; // NON_COMPILABLE + + u &b; // NON_COMPLIANT + u &c; // NON_COMPLIANT + u &e1; // NON_COMPLIANT + u &s; // NON_COMPLIANT + u &u; // COMPLIANT + // u &f; // NON_COMPILABLE + + u | b; // NON_COMPLIANT + u | c; // NON_COMPLIANT + u | e1; // NON_COMPLIANT + u | s; // NON_COMPLIANT + u | u; // COMPLIANT + // u | f; // NON_COMPILABLE + + u ^ b; // NON_COMPLIANT + u ^ c; // NON_COMPLIANT + u ^ e1; // NON_COMPLIANT + u ^ s; // NON_COMPLIANT + u ^ u; // COMPLIANT + // u ^ f; // NON_COMPILABLE + + ~b; // NON_COMPLIANT + ~c; // NON_COMPLIANT + ~e1; // NON_COMPLIANT + ~s; // NON_COMPLIANT + ~u; // COMPLIANT + //~f; // NON_COMPILABLE + + b ? 1 : 2; // COMPLIANT + c ? 1 : 2; // NON_COMPLIANT + e1 ? 1 : 2; // NON_COMPLIANT + s ? 1 : 2; // NON_COMPLIANT + u ? 1 : 2; // NON_COMPLIANT + f ? 1 : 2; // NON_COMPLIANT + + b ? b : b; // COMPLIANT + b ? c : c; // COMPLIANT + b ? e1 : e1; // COMPLIANT + b ? s : s; // COMPLIANT + b ? u : u; // COMPLIANT + b ? f : f; // COMPLIANT + + b += 1; // NON_COMPLIANT + c += 1; // COMPLIANT + e1 += 1; // NON_COMPLIANT + s += 1; // COMPLIANT + u += 1; // COMPLIANT + f += 1; // COMPLIANT + + b -= 1; // NON_COMPLIANT + c -= 1; // COMPLIANT + e1 -= 1; // NON_COMPLIANT + s -= 1; // COMPLIANT + u -= 1; // COMPLIANT + f -= 1; // COMPLIANT + + u += b; // NON_COMPLIANT + u += c; // COMPLIANT + u += e1; // NON_COMPLIANT + u += s; // COMPLIANT + u += u; // COMPLIANT + u += f; // COMPLIANT + + u -= b; // NON_COMPLIANT + u -= c; // COMPLIANT + u -= e1; // NON_COMPLIANT + u -= s; // COMPLIANT + u -= u; // COMPLIANT + u -= f; // COMPLIANT + + b *= 1; // NON_COMPLIANT + c *= 1; // NON_COMPLIANT + e1 *= 1; // NON_COMPLIANT + s *= 1; // COMPLIANT + u *= 1; // COMPLIANT + f *= 1; // COMPLIANT + + b /= 1; // NON_COMPLIANT + c /= 1; // NON_COMPLIANT + e1 /= 1; // NON_COMPLIANT + s /= 1; // COMPLIANT + u /= 1; // COMPLIANT + f /= 1; // COMPLIANT + + u *= b; // NON_COMPLIANT + u *= c; // NON_COMPLIANT + u *= e1; // NON_COMPLIANT + u *= s; // COMPLIANT + u *= u; // COMPLIANT + u *= f; // COMPLIANT + + u /= b; // NON_COMPLIANT + u /= c; // NON_COMPLIANT + u /= e1; // NON_COMPLIANT + u /= s; // COMPLIANT + u /= u; // COMPLIANT + u /= f; // COMPLIANT + + b %= 1; // NON_COMPLIANT + c %= 1; // NON_COMPLIANT + e1 %= 1; // NON_COMPLIANT + s %= 1; // COMPLIANT + u %= 1; // COMPLIANT + // f %= 1; // NON_COMPILABLE + + u %= b; // NON_COMPLIANT + u %= c; // NON_COMPLIANT + u %= e1; // NON_COMPLIANT + u %= s; // COMPLIANT + u %= u; // COMPLIANT + // u %= f; // NON_COMPILABLE + + b <<= u; // NON_COMPLIANT + c <<= u; // NON_COMPLIANT + e1 <<= u; // NON_COMPLIANT + s <<= u; // NON_COMPLIANT + u <<= u; // COMPLIANT + // f <<= u; // NON_COMPILABLE + + b >>= u; // NON_COMPLIANT + c >>= u; // NON_COMPLIANT + e1 >>= u; // NON_COMPLIANT + s >>= u; // NON_COMPLIANT + u >>= u; // COMPLIANT + // f >>= u; // NON_COMPILABLE + + u <<= b; // NON_COMPLIANT + u <<= c; // NON_COMPLIANT + u <<= e1; // NON_COMPLIANT + u <<= s; // NON_COMPLIANT + u <<= u; // COMPLIANT + // u <<= f; // NON_COMPILABLE + + u >>= b; // NON_COMPLIANT + u >>= c; // NON_COMPLIANT + u >>= e1; // NON_COMPLIANT + u >>= s; // NON_COMPLIANT + u >>= u; // COMPLIANT + // u >>= f; // NON_COMPILABLE + + b &= u; // NON_COMPLIANT + c &= u; // NON_COMPLIANT + e1 &= u; // NON_COMPLIANT + s &= u; // NON_COMPLIANT + u &= u; // COMPLIANT + // f &= u; // NON_COMPILABLE + + b ^= u; // NON_COMPLIANT + c ^= u; // NON_COMPLIANT + e1 ^= u; // NON_COMPLIANT + s ^= u; // NON_COMPLIANT + u ^= u; // COMPLIANT + // f ^= u; // NON_COMPILABLE + + b |= u; // NON_COMPLIANT + c |= u; // NON_COMPLIANT + e1 |= u; // NON_COMPLIANT + s |= u; // NON_COMPLIANT + u |= u; // COMPLIANT + // f |= u; // NON_COMPILABLE + + u &= b; // NON_COMPLIANT + u &= c; // NON_COMPLIANT + u &= e1; // NON_COMPLIANT + u &= s; // NON_COMPLIANT + u &= u; // COMPLIANT + // u &= f; // NON_COMPILABLE + + u ^= b; // NON_COMPLIANT + u ^= c; // NON_COMPLIANT + u ^= e1; // NON_COMPLIANT + u ^= s; // NON_COMPLIANT + u ^= u; // COMPLIANT + // u ^= f; // NON_COMPILABLE + + u |= b; // NON_COMPLIANT + u |= c; // NON_COMPLIANT + u |= e1; // NON_COMPLIANT + u |= s; // NON_COMPLIANT + u |= u; // COMPLIANT + // u |= f; // NON_COMPILABLE +} + +void pointerType() { + _Bool b = true; + int *p; + + !b; // COMPLIANT + !p; // NON_COMPLIANT + b &&b; // COMPLIANT + p &&b; // NON_COMPLIANT + b &&p; // NON_COMPLIANT + b || b; // COMPLIANT + p || b; // NON_COMPLIANT + b || p; // NON_COMPLIANT +} From 2147282a3d82ef91b613ba964006f739149543e6 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Mon, 13 Feb 2023 14:21:59 +0000 Subject: [PATCH 06/25] EssentialTypes: Implement Rule 10.2 Adds a query that detects inappropriate addition or subtraction operations on operands of essentially character type. --- ...dditionSubtractionOnEssentiallyCharType.ql | 40 +++++++++++++++++++ ...nSubtractionOnEssentiallyCharType.expected | 15 +++++++ ...tionSubtractionOnEssentiallyCharType.qlref | 1 + c/misra/test/rules/RULE-10-2/test.c | 35 ++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql create mode 100644 c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.expected create mode 100644 c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.qlref create mode 100644 c/misra/test/rules/RULE-10-2/test.c diff --git a/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql b/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql new file mode 100644 index 0000000000..5e75f44590 --- /dev/null +++ b/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql @@ -0,0 +1,40 @@ +/** + * @id c/misra/addition-subtraction-on-essentially-char-type + * @name RULE-10-2: Expressions of essentially character type shall not be used inappropriately in addition and + * @description Expressions of essentially character type shall not be used inappropriately in + * addition and subtraction operations + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-10-2 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.misra.EssentialTypes + +from BinaryArithmeticOperation addOrSub +where + not isExcluded(addOrSub, EssentialTypesPackage::additionSubtractionOnEssentiallyCharTypeQuery()) and + addOrSub.getOperator() = ["+", "-"] and + // At least one operand is essentially character type + ( + getEssentialTypeCategory(getEssentialType(addOrSub.getLeftOperand())) = + EssentiallyCharacterType() or + getEssentialTypeCategory(getEssentialType(addOrSub.getRightOperand())) = + EssentiallyCharacterType() + ) and + not ( + // But the overall essential type is not essentially character type + getEssentialTypeCategory(getEssentialType(addOrSub)) = EssentiallyCharacterType() + or + // Or this is a subtration of one character with another, which is permitted, but produces an integral type + getEssentialTypeCategory(getEssentialType(addOrSub.getLeftOperand())) = + EssentiallyCharacterType() and + getEssentialTypeCategory(getEssentialType(addOrSub.getRightOperand())) = + EssentiallyCharacterType() and + addOrSub instanceof SubExpr + ) +select addOrSub, + "Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations" diff --git a/c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.expected b/c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.expected new file mode 100644 index 0000000000..0a5c7ae0bb --- /dev/null +++ b/c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.expected @@ -0,0 +1,15 @@ +| test.c:15:3:15:11 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:16:3:16:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:17:3:17:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:18:3:18:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:19:3:19:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:20:3:20:10 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:21:3:21:10 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:27:3:27:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:28:3:28:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:29:3:29:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:30:3:30:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:31:3:31:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:32:3:32:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:33:3:33:10 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:34:3:34:10 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | diff --git a/c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.qlref b/c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.qlref new file mode 100644 index 0000000000..774874eb62 --- /dev/null +++ b/c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.qlref @@ -0,0 +1 @@ +rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-2/test.c b/c/misra/test/rules/RULE-10-2/test.c new file mode 100644 index 0000000000..186c49226e --- /dev/null +++ b/c/misra/test/rules/RULE-10-2/test.c @@ -0,0 +1,35 @@ +#include + +void testRules() { + _Bool b = true; + enum E1 { A, B, C } e1 = A; + signed int i = 100; + unsigned int u = 100; + float f = 10.0f; + + // Addition cases + i + 'a'; // COMPLIANT + 'a' + i; // COMPLIANT + u + 'a'; // COMPLIANT + 'a' + u; // COMPLIANT + 'a' + 'a'; // NON_COMPLIANT + 'a' + f; // NON_COMPLIANT + f + 'a'; // NON_COMPLIANT + 'a' + b; // NON_COMPLIANT + b + 'a'; // NON_COMPLIANT + 'a' + e1; // NON_COMPLIANT + e1 + 'a'; // NON_COMPLIANT + + // Subtration cases + 'a' - i; // COMPLIANT + 'a' - u; // COMPLIANT + 'a' - 'a'; // COMPLIANT + 'a' - f; // NON_COMPLIANT + i - 'a'; // NON_COMPLIANT + u - 'a'; // NON_COMPLIANT + f - 'a'; // NON_COMPLIANT + b - 'a'; // NON_COMPLIANT + 'a' - b; // NON_COMPLIANT + e1 - 'a'; // NON_COMPLIANT + 'a' - e1; // NON_COMPLIANT +} \ No newline at end of file From fe01ab84808f447be71884280ef8cfc63e0fb41f Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Mon, 13 Feb 2023 14:22:52 +0000 Subject: [PATCH 07/25] EssentialTypes: Implement Rule 10.3 Adds a query that finds "assignments", as defined by MISRA C 2012, to incompatible essential types. --- .../AssignmentOfIncompatibleEssentialType.ql | 49 +++ ...gnmentOfIncompatibleEssentialType.expected | 133 +++++++ ...ssignmentOfIncompatibleEssentialType.qlref | 1 + c/misra/test/rules/RULE-10-3/test.c | 360 ++++++++++++++++++ 4 files changed, 543 insertions(+) create mode 100644 c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql create mode 100644 c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected create mode 100644 c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.qlref create mode 100644 c/misra/test/rules/RULE-10-3/test.c diff --git a/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql b/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql new file mode 100644 index 0000000000..362f0934c2 --- /dev/null +++ b/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql @@ -0,0 +1,49 @@ +/** + * @id c/misra/assignment-of-incompatible-essential-type + * @name RULE-10-3: The value of an expression shall not be assigned to an object with a narrower essential type or of a + * @description The value of an expression shall not be assigned to an object with a narrower + * essential type or of a different essential type category + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-10-3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.misra.EssentialTypes +import codingstandards.c.misra.MisraExpressions + +from + Type lValueType, Expr rValue, Type lValueEssentialType, EssentialTypeCategory lValueTypeCategory, + Type rValueEssentialType, EssentialTypeCategory rValueTypeCategory, string message +where + not isExcluded(rValue, EssentialTypesPackage::assignmentOfIncompatibleEssentialTypeQuery()) and + isAssignmentToEssentialType(lValueType, rValue) and + lValueEssentialType = lValueType and + lValueTypeCategory = getEssentialTypeCategory(lValueEssentialType) and + rValueEssentialType = getEssentialType(rValue) and + rValueTypeCategory = getEssentialTypeCategory(rValueEssentialType) and + ( + not lValueTypeCategory = rValueTypeCategory and + message = + "Assignment of " + rValueTypeCategory + " value to an object of " + lValueTypeCategory + "." + or + lValueTypeCategory = rValueTypeCategory and + lValueEssentialType.getSize() < rValueEssentialType.getSize() and + message = + "Assignment of value of " + lValueTypeCategory + " of size " + rValueEssentialType.getSize() + + " bytes to an object narrower essential type of size " + lValueEssentialType.getSize() + + " bytes." + ) and + // Exception 1: Constant signed integers can be assigned to unsigned integers in certain cases + not exists(int const | + const = rValue.getValue().toInt() and + rValueTypeCategory = EssentiallySignedType() and + rValueEssentialType.getSize() <= any(IntType t | t.isSigned()).getSize() and + lValueTypeCategory = EssentiallyUnsignedType() and + const >= 0 and + const <= 2.pow(lValueEssentialType.getSize() * 8) + ) +select rValue, message diff --git a/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected b/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected new file mode 100644 index 0000000000..3867abd0ca --- /dev/null +++ b/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected @@ -0,0 +1,133 @@ +| test.c:11:7:11:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:12:7:12:7 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:13:7:13:7 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:14:7:14:7 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:16:8:16:8 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:18:8:18:8 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:19:8:19:8 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:20:8:20:8 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:22:7:22:7 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:23:7:23:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:25:7:25:7 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:26:7:26:7 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:28:7:28:7 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:29:7:29:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:30:7:30:7 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:32:7:32:7 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:34:7:34:7 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:35:7:35:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:36:7:36:7 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:37:7:37:7 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:49:14:49:15 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:50:14:50:14 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:51:14:51:14 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:52:14:52:14 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:54:17:54:17 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:56:17:56:17 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:57:17:57:17 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:58:17:58:17 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:60:19:60:19 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:61:19:61:20 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:63:19:63:19 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:64:19:64:19 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:66:21:66:21 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:67:21:67:22 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:68:21:68:21 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:70:21:70:21 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:72:14:72:14 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:73:14:73:15 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:74:14:74:14 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:75:14:75:14 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:80:7:80:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:81:7:81:7 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:82:7:82:7 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:83:7:83:7 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:86:7:86:7 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:88:7:88:7 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:89:7:89:7 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:90:7:90:7 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:93:7:93:7 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:94:7:94:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:96:7:96:7 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:97:7:97:7 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:100:7:100:7 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:101:7:101:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:102:7:102:7 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:104:7:104:7 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:107:7:107:7 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:108:7:108:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:109:7:109:7 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:110:7:110:7 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:118:7:118:8 | - ... | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:119:7:119:16 | 4294967296 | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:131:8:131:8 | A | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:132:8:132:10 | 100 | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:133:23:133:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:138:8:138:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:140:8:140:10 | 100 | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:141:23:141:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:146:8:146:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:147:8:147:8 | A | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:149:23:149:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:154:8:154:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:155:8:155:8 | A | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:174:8:174:8 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:175:8:175:8 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:176:8:176:8 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:177:8:177:8 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:180:8:180:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:182:8:182:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:183:8:183:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:184:8:184:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:187:8:187:8 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:188:8:188:8 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:190:8:190:8 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:191:8:191:8 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:194:8:194:8 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:195:8:195:8 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:196:8:196:8 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:198:8:198:8 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:201:8:201:8 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:202:8:202:8 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:203:8:203:8 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:204:8:204:8 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:220:12:220:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:222:12:222:12 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:224:12:224:12 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:226:12:226:12 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:239:12:239:12 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:243:12:243:12 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:245:12:245:12 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:247:12:247:12 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:260:12:260:12 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:262:12:262:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:266:12:266:12 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:268:12:268:12 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:281:12:281:12 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:283:12:283:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:285:12:285:12 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:289:12:289:12 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:302:12:302:12 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:304:12:304:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:306:12:306:12 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:308:12:308:12 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:332:10:332:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:333:10:333:10 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:334:10:334:10 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:335:10:335:10 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:337:11:337:11 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:339:11:339:11 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:340:11:340:11 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:341:11:341:11 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:343:10:343:10 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:344:10:344:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:346:10:346:10 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:347:10:347:10 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:349:10:349:10 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:350:10:350:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:351:10:351:10 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:353:10:353:10 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:355:10:355:10 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:356:10:356:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:357:10:357:10 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:358:10:358:10 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | diff --git a/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.qlref b/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.qlref new file mode 100644 index 0000000000..32b138eba6 --- /dev/null +++ b/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.qlref @@ -0,0 +1 @@ +rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-3/test.c b/c/misra/test/rules/RULE-10-3/test.c new file mode 100644 index 0000000000..1eb065e58b --- /dev/null +++ b/c/misra/test/rules/RULE-10-3/test.c @@ -0,0 +1,360 @@ +#include + +void testAssignment() { + _Bool b = true; // COMPLIANT + enum E1 { A, B, C } e1 = A; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + + b = false; // COMPLIANT + b = e1; // NON_COMPLIANT + b = s; // NON_COMPLIANT + b = u; // NON_COMPLIANT + b = f; // NON_COMPLIANT + + e1 = b; // NON_COMPLIANT + e1 = e1; // COMPLIANT + e1 = s; // NON_COMPLIANT + e1 = u; // NON_COMPLIANT + e1 = f; // NON_COMPLIANT + + s = b; // NON_COMPLIANT + s = e1; // NON_COMPLIANT + s = s; // COMPLIANT + s = u; // NON_COMPLIANT + s = f; // NON_COMPLIANT + + u = b; // NON_COMPLIANT + u = e1; // NON_COMPLIANT + u = s; // NON_COMPLIANT + u = u; // COMPLIANT + u = f; // NON_COMPLIANT + + f = b; // NON_COMPLIANT + f = e1; // NON_COMPLIANT + f = s; // NON_COMPLIANT + f = u; // NON_COMPLIANT + f = f; // COMPLIANT +} + +void testInitializers() { + _Bool b = true; // COMPLIANT + enum E1 { A, B, C } e1 = A; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + + _Bool bb = b; // COMPLIANT + _Bool be = e1; // NON_COMPLIANT + _Bool bs = s; // NON_COMPLIANT + _Bool bu = u; // NON_COMPLIANT + _Bool bf = f; // NON_COMPLIANT + + enum E1 e1b = b; // NON_COMPLIANT + enum E1 e1e = e1; // COMPLIANT + enum E1 e1s = s; // NON_COMPLIANT + enum E1 e1u = u; // NON_COMPLIANT + enum E1 e1f = f; // NON_COMPLIANT + + signed int sb = b; // NON_COMPLIANT + signed int se = e1; // NON_COMPLIANT + signed int ss = s; // COMPLIANT + signed int su = u; // NON_COMPLIANT + signed int sf = f; // NON_COMPLIANT + + unsigned int ub = b; // NON_COMPLIANT + unsigned int ue = e1; // NON_COMPLIANT + unsigned int us = s; // NON_COMPLIANT + unsigned int uu = u; // COMPLIANT + unsigned int uf = f; // NON_COMPLIANT + + float fb = b; // NON_COMPLIANT + float fe = e1; // NON_COMPLIANT + float fs = s; // NON_COMPLIANT + float fu = u; // NON_COMPLIANT + float ff = f; // COMPLIANT + + _Bool ba[5] = { + b, // COMPLIANT + e1, // NON_COMPLIANT + s, // NON_COMPLIANT + u, // NON_COMPLIANT + f // NON_COMPLIANT + }; + enum E1 ea[5] = { + b, // NON_COMPLIANT + e1, // COMPLIANT + s, // NON_COMPLIANT + u, // NON_COMPLIANT + f // NON_COMPLIANT + }; + signed int sa[5] = { + b, // NON_COMPLIANT + e1, // NON_COMPLIANT + s, // COMPLIANT + u, // NON_COMPLIANT + f // NON_COMPLIANT + }; + unsigned int ua[5] = { + b, // NON_COMPLIANT + e1, // NON_COMPLIANT + s, // NON_COMPLIANT + u, // COMPLIANT + f // NON_COMPLIANT + }; + float fa[5] = { + b, // NON_COMPLIANT + e1, // NON_COMPLIANT + s, // NON_COMPLIANT + u, // NON_COMPLIANT + f // COMPLIANT + }; +} + +void testException1() { + unsigned int u = 100; // COMPLIANT - by exception 1 + u = 100; // COMPLIANT - by exception 1 + u = -1; // NON_COMPLIANT - smaller that uint, so exception doesn't apply + u = 4294967296; // NON_COMPLIANT - cannot be stored in an int, so exception + // doesn't apply +} + +void testSwitchCase() { + _Bool b = true; // COMPLIANT + enum E1 { A, B, C } e1 = A; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + switch (b) { + case true: // COMPLIANT + case A: // NON_COMPLIANT + case 100: // NON_COMPLIANT + case ((unsigned int)200): // NON_COMPLIANT + // case 1.0f: // NON_COMPILABLE + } + + switch (e1) { + case true: // NON_COMPLIANT + case A: // COMPLIANT + case 100: // NON_COMPLIANT + case ((unsigned int)200): // NON_COMPLIANT + // case 1.0f: // NON_COMPILABLE + } + + switch (s) { + case true: // NON_COMPLIANT + case A: // NON_COMPLIANT + case 100: // COMPLIANT + case ((unsigned int)200): // NON_COMPLIANT + // case 1.0f: // NON_COMPILABLE + } + + switch (u) { + case true: // NON_COMPLIANT + case A: // NON_COMPLIANT + case 100: // COMPLIANT - by exception 1 + case ((unsigned int)200): // COMPLIANT - by exception 1 + // case 1.0f: // NON_COMPILABLE + } +} + +enum EG { EGA, EGB, EGC }; + +void func(_Bool b, enum EG eg, signed int i, unsigned int u, float f); + +void testFunctionCall() { + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + + func(b, // COMPLIANT + b, // NON_COMPLIANT + b, // NON_COMPLIANT + b, // NON_COMPLIANT + b // NON_COMPLIANT + ); + + func(e1, // NON_COMPLIANT + e1, // COMPLIANT + e1, // NON_COMPLIANT + e1, // NON_COMPLIANT + e1 // NON_COMPLIANT + ); + + func(s, // NON_COMPLIANT + s, // NON_COMPLIANT + s, // COMPLIANT + s, // NON_COMPLIANT + s // NON_COMPLIANT + ); + + func(u, // NON_COMPLIANT + u, // NON_COMPLIANT + u, // NON_COMPLIANT + u, // COMPLIANT + u // NON_COMPLIANT + ); + + func(f, // NON_COMPLIANT + f, // NON_COMPLIANT + f, // NON_COMPLIANT + f, // NON_COMPLIANT + f // COMPLIANT + ); +} + +_Bool testBoolFunctionReturn(int x) { + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + + switch (x) { + case 0: + return b; // COMPLIANT + case 1: + return e1; // NON_COMPLIANT + case 2: + return s; // NON_COMPLIANT + case 3: + return u; // NON_COMPLIANT + default: + return f; // NON_COMPLIANT + } +} + +enum EG testEnumFunctionReturn(int x) { + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + + switch (x) { + case 0: + return b; // NON_COMPLIANT + case 1: + return e1; // COMPLIANT + case 2: + return s; // NON_COMPLIANT + case 3: + return u; // NON_COMPLIANT + default: + return f; // NON_COMPLIANT + } +} + +signed int testSignedIntFunctionReturn(int x) { + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + + switch (x) { + case 0: + return b; // NON_COMPLIANT + case 1: + return e1; // NON_COMPLIANT + case 2: + return s; // COMPLIANT + case 3: + return u; // NON_COMPLIANT + default: + return f; // NON_COMPLIANT + } +} + +unsigned int testUnsignedIntFunctionReturn(int x) { + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + + switch (x) { + case 0: + return b; // NON_COMPLIANT + case 1: + return e1; // NON_COMPLIANT + case 2: + return s; // NON_COMPLIANT + case 3: + return u; // COMPLIANT + default: + return f; // NON_COMPLIANT + } +} + +float testFloatFunctionReturn(int x) { + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + + switch (x) { + case 0: + return b; // NON_COMPLIANT + case 1: + return e1; // NON_COMPLIANT + case 2: + return s; // NON_COMPLIANT + case 3: + return u; // NON_COMPLIANT + default: + return f; // COMPLIANT + } +} + +struct S1 { + _Bool b; + enum EG e1; + signed int s; + unsigned int u; + float f; +}; + +void testStructAssignment() { + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + + struct S1 s1; + + s1.b = b; // COMPLIANT + s1.b = e1; // NON_COMPLIANT + s1.b = s; // NON_COMPLIANT + s1.b = u; // NON_COMPLIANT + s1.b = f; // NON_COMPLIANT + + s1.e1 = b; // NON_COMPLIANT + s1.e1 = e1; // COMPLIANT + s1.e1 = s; // NON_COMPLIANT + s1.e1 = u; // NON_COMPLIANT + s1.e1 = f; // NON_COMPLIANT + + s1.s = b; // NON_COMPLIANT + s1.s = e1; // NON_COMPLIANT + s1.s = s; // COMPLIANT + s1.s = u; // NON_COMPLIANT + s1.s = f; // NON_COMPLIANT + + s1.u = b; // NON_COMPLIANT + s1.u = e1; // NON_COMPLIANT + s1.u = s; // NON_COMPLIANT + s1.u = u; // COMPLIANT + s1.u = f; // NON_COMPLIANT + + s1.f = b; // NON_COMPLIANT + s1.f = e1; // NON_COMPLIANT + s1.f = s; // NON_COMPLIANT + s1.f = u; // NON_COMPLIANT + s1.f = f; // COMPLIANT +} \ No newline at end of file From 810a77591f9da80ceeb566b865279cecb0605e83 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Mon, 13 Feb 2023 14:23:42 +0000 Subject: [PATCH 08/25] EssentialTypes: Implement Rule 10.4 Adds a query that finds operands to operators with the usual arithmetic conversions that are incompatible. --- ...andsWithMismatchedEssentialTypeCategory.ql | 57 +++++++++++++++++++ ...thMismatchedEssentialTypeCategory.expected | 10 ++++ ...sWithMismatchedEssentialTypeCategory.qlref | 1 + c/misra/test/rules/RULE-10-4/test.c | 36 ++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql create mode 100644 c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.expected create mode 100644 c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.qlref create mode 100644 c/misra/test/rules/RULE-10-4/test.c diff --git a/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql b/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql new file mode 100644 index 0000000000..582854e77b --- /dev/null +++ b/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql @@ -0,0 +1,57 @@ +/** + * @id c/misra/operands-with-mismatched-essential-type-category + * @name RULE-10-4: Both operands of an operator in which the usual arithmetic conversions are performed shall have the + * @description Both operands of an operator in which the usual arithmetic conversions are performed + * shall have the same essential type category + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-10-4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.misra.EssentialTypes +import codingstandards.c.misra.MisraExpressions + +from + OperationWithUsualArithmeticConversions op, Type leftOpEssentialType, Type rightOpEssentialType, + EssentialTypeCategory leftOpTypeCategory, EssentialTypeCategory rightOpTypeCategory, + string message +where + not isExcluded(op, EssentialTypesPackage::operandsWithMismatchedEssentialTypeCategoryQuery()) and + leftOpEssentialType = getEssentialType(op.getLeftOperand()) and + rightOpEssentialType = getEssentialType(op.getRightOperand()) and + leftOpTypeCategory = getEssentialTypeCategory(leftOpEssentialType) and + rightOpTypeCategory = getEssentialTypeCategory(rightOpEssentialType) and + ( + not leftOpTypeCategory = rightOpTypeCategory and + message = + "The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: " + + leftOpTypeCategory + ", right operand: " + rightOpTypeCategory + ")." + or + // This is not technically covered by the rule, but the examples make it clear that this should + // be reported as non-compliant. + leftOpTypeCategory = EssentiallyEnumType() and + rightOpTypeCategory = EssentiallyEnumType() and + not leftOpEssentialType = rightOpEssentialType and + message = + "The operands of this operator with usual arithmetic conversions have mismatched essentially Enum types (left operand: " + + leftOpEssentialType + ", right operand: " + rightOpEssentialType + ")." + ) and + not ( + // Mismatch is permitted if using "+" or "+=" with one character operand and one integer operand + op.getOperator() = ["+", "+="] and + [leftOpTypeCategory, rightOpTypeCategory] = EssentiallyCharacterType() and + [leftOpTypeCategory, rightOpTypeCategory] = + [EssentiallyUnsignedType().(TEssentialTypeCategory), EssentiallySignedType()] + ) and + not ( + // Mismatch is permitted if using "+" or "+=" with one pointer operand and one integer operand + op.getOperator() = ["-", "-="] and + leftOpTypeCategory = EssentiallyCharacterType() and + rightOpTypeCategory = + [EssentiallyUnsignedType().(TEssentialTypeCategory), EssentiallySignedType()] + ) +select op, message diff --git a/c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.expected b/c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.expected new file mode 100644 index 0000000000..333c3ad581 --- /dev/null +++ b/c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.expected @@ -0,0 +1,10 @@ +| test.c:14:3:14:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Unsigned type, right operand: essentially Signed type). | +| test.c:15:3:15:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Unsigned type). | +| test.c:16:3:16:10 | ... += ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Unsigned type). | +| test.c:17:3:17:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Floating type, right operand: essentially Signed type). | +| test.c:18:3:18:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Floating type). | +| test.c:19:3:19:10 | ... += ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Floating type). | +| test.c:27:3:27:9 | ... - ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Character type). | +| test.c:28:3:28:10 | ... -= ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Character type). | +| test.c:34:3:34:11 | ... < ... | The operands of this operator with usual arithmetic conversions have mismatched essentially Enum types (left operand: E1, right operand: E2). | +| test.c:35:3:35:7 | ... < ... | The operands of this operator with usual arithmetic conversions have mismatched essentially Enum types (left operand: E1, right operand: E2). | diff --git a/c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.qlref b/c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.qlref new file mode 100644 index 0000000000..3b9a9bc32c --- /dev/null +++ b/c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.qlref @@ -0,0 +1 @@ +rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-4/test.c b/c/misra/test/rules/RULE-10-4/test.c new file mode 100644 index 0000000000..666590a2d5 --- /dev/null +++ b/c/misra/test/rules/RULE-10-4/test.c @@ -0,0 +1,36 @@ +void testOps() { + signed int s32 = 100; + signed long long s64 = 100; + unsigned int u = 100; + float f = 10.0f; + char c = 'A'; + + s32 + s32; // COMPLIANT + s64 + s64; // COMPLIANT + s32 + s64; // COMPLIANT + s64 + s32; // COMPLIANT + s64 += s32; // COMPLIANT + s32 += s64; // COMPLIANT + u + s32; // NON_COMPLIANT + s32 + u; // NON_COMPLIANT + s32 += u; // NON_COMPLIANT + f + s32; // NON_COMPLIANT + s32 + f; // NON_COMPLIANT + s32 += f; // NON_COMPLIANT + + c + s32; // COMPLIANT - by exception + c += s32; // COMPLIANT - by exception + s32 + c; // COMPLIANT - by exception + s32 += c; // COMPLIANT - by exception + c - s32; // COMPLIANT - by exception + c -= s32; // COMPLIANT - by exception + s32 - c; // NON_COMPLIANT + s32 -= c; // NON_COMPLIANT + + enum E1 { A, B, C } e1a; + enum E2 { D, E, F } e2a; + e1a < e1a; // COMPLIANT + A < A; // COMPLIANT + e1a < e2a; // NON_COMPLIANT + A < D; // NON_COMPLIANT +} \ No newline at end of file From 931aa12c7995ff384b19905aa26287ea106275bc Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Mon, 13 Feb 2023 14:24:29 +0000 Subject: [PATCH 09/25] EssentialTypes: Implement Rule 10.5 Adds a query that identifies explicit casts to an inappropriate essential type, according to the conditions set by MISRA C 2012. --- .../InappropriateEssentialTypeCast.ql | 74 ++++++++++++++++++ .../InappropriateEssentialTypeCast.expected | 20 +++++ .../InappropriateEssentialTypeCast.qlref | 1 + c/misra/test/rules/RULE-10-5/test.c | 77 +++++++++++++++++++ 4 files changed, 172 insertions(+) create mode 100644 c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql create mode 100644 c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.expected create mode 100644 c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.qlref create mode 100644 c/misra/test/rules/RULE-10-5/test.c diff --git a/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql b/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql new file mode 100644 index 0000000000..c7556729c9 --- /dev/null +++ b/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql @@ -0,0 +1,74 @@ +/** + * @id c/misra/inappropriate-essential-type-cast + * @name RULE-10-5: The value of an expression should not be cast to an inappropriate essential type + * @description + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-10-5 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.misra.EssentialTypes +import codingstandards.c.misra.MisraExpressions + +predicate isIncompatibleEssentialTypeCast(EssentialTypeCategory fromCat, EssentialTypeCategory toCat) { + fromCat = EssentiallyBooleanType() and + toCat = + [ + EssentiallyCharacterType(), EssentiallyEnumType(), EssentiallySignedType(), + EssentiallyUnsignedType(), EssentiallyFloatingType().(TEssentialTypeCategory) + ] + or + fromCat = EssentiallyCharacterType() and + toCat = + [ + EssentiallyBooleanType(), EssentiallyEnumType(), + EssentiallyFloatingType().(TEssentialTypeCategory) + ] + or + fromCat = EssentiallyEnumType() and + toCat = [EssentiallyBooleanType(), EssentiallyEnumType().(TEssentialTypeCategory)] // NOTE only if different enum types + or + fromCat = EssentiallySignedType() and + toCat = [EssentiallyBooleanType(), EssentiallyEnumType().(TEssentialTypeCategory)] + or + fromCat = EssentiallyUnsignedType() and + toCat = [EssentiallyBooleanType(), EssentiallyEnumType().(TEssentialTypeCategory)] + or + fromCat = EssentiallyFloatingType() and + toCat = + [ + EssentiallyBooleanType(), EssentiallyCharacterType(), + EssentiallyEnumType().(TEssentialTypeCategory) + ] +} + +from + Cast c, Type essentialFromType, Type essentialToType, EssentialTypeCategory fromCategory, + EssentialTypeCategory toCategory, string message +where + not isExcluded(c, EssentialTypesPackage::inappropriateEssentialTypeCastQuery()) and + not c.isImplicit() and + essentialFromType = getEssentialTypeBeforeConversions(c.getExpr()) and + essentialToType = c.getType() and + fromCategory = getEssentialTypeCategory(essentialFromType) and + toCategory = getEssentialTypeCategory(essentialToType) and + isIncompatibleEssentialTypeCast(fromCategory, toCategory) and + ( + if fromCategory = EssentiallyEnumType() and toCategory = EssentiallyEnumType() + then + // If from/to enum types, then only report if the essential types are different + not essentialToType = essentialFromType and + message = "Incompatible cast from " + essentialFromType + " to " + essentialToType + "." + else message = "Incompatible cast from " + fromCategory + " to " + toCategory + "." + ) and + not ( + // Exception - casting from `0` or `1` to a boolean type is permitted + (fromCategory = EssentiallySignedType() or fromCategory = EssentiallyUnsignedType()) and + toCategory = EssentiallyBooleanType() and + c.getExpr().getValue().toInt() = [0, 1] + ) +select c, message diff --git a/c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.expected b/c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.expected new file mode 100644 index 0000000000..731ad9f312 --- /dev/null +++ b/c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.expected @@ -0,0 +1,20 @@ +| test.c:9:3:9:9 | (char)... | Incompatible cast from essentially Boolean type to essentially Character type. | +| test.c:10:3:10:13 | (E1)... | Incompatible cast from essentially Boolean type to essentially Enum Type. | +| test.c:11:3:11:15 | (signed int)... | Incompatible cast from essentially Boolean type to essentially Signed type. | +| test.c:12:3:12:17 | (unsigned int)... | Incompatible cast from essentially Boolean type to essentially Unsigned type. | +| test.c:13:3:13:10 | (float)... | Incompatible cast from essentially Boolean type to essentially Floating type. | +| test.c:16:3:16:11 | (bool)... | Incompatible cast from essentially Character type to essentially Boolean type. | +| test.c:18:3:18:13 | (E1)... | Incompatible cast from essentially Character type to essentially Enum Type. | +| test.c:21:3:21:10 | (float)... | Incompatible cast from essentially Character type to essentially Floating type. | +| test.c:24:3:24:11 | (bool)... | Incompatible cast from essentially Enum Type to essentially Boolean type. | +| test.c:26:3:26:13 | (E1)... | Incompatible cast from E2 to E1. | +| test.c:33:3:33:11 | (bool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | +| test.c:35:3:35:13 | (E1)... | Incompatible cast from essentially Signed type to essentially Enum Type. | +| test.c:41:3:41:11 | (bool)... | Incompatible cast from essentially Unsigned type to essentially Boolean type. | +| test.c:43:3:43:13 | (E1)... | Incompatible cast from essentially Unsigned type to essentially Enum Type. | +| test.c:49:3:49:11 | (bool)... | Incompatible cast from essentially Floating type to essentially Boolean type. | +| test.c:50:3:50:9 | (char)... | Incompatible cast from essentially Floating type to essentially Character type. | +| test.c:51:3:51:13 | (E1)... | Incompatible cast from essentially Floating type to essentially Enum Type. | +| test.c:68:3:68:10 | (bool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | +| test.c:72:3:72:16 | (MyBool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | +| test.c:76:3:76:12 | (boolean)... | Incompatible cast from essentially Signed type to essentially Boolean type. | diff --git a/c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.qlref b/c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.qlref new file mode 100644 index 0000000000..e871beb36b --- /dev/null +++ b/c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.qlref @@ -0,0 +1 @@ +rules/RULE-10-5/InappropriateEssentialTypeCast.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-5/test.c b/c/misra/test/rules/RULE-10-5/test.c new file mode 100644 index 0000000000..dbc5939f0f --- /dev/null +++ b/c/misra/test/rules/RULE-10-5/test.c @@ -0,0 +1,77 @@ +#include + +void testIncompatibleCasts() { + enum E1 { A, B }; + + _Bool b = true; + + (_Bool) b; // COMPLIANT + (char)b; // NON_COMPLIANT + (enum E1) b; // NON_COMPLIANT + (signed int)b; // NON_COMPLIANT + (unsigned int)b; // NON_COMPLIANT + (float)b; // NON_COMPLIANT + + char c = 100; + (_Bool) c; // NON_COMPLIANT + (char)c; // COMPLIANT + (enum E1) c; // NON_COMPLIANT + (signed int)c; // COMPLIANT + (unsigned int)c; // COMPLIANT + (float)c; // NON_COMPLIANT + + enum E2 { C, D } e = C; + (_Bool) e; // NON_COMPLIANT + (char)e; // COMPLIANT + (enum E1) e; // NON_COMPLIANT + (enum E2) e; // COMPLIANT + (signed int)e; // COMPLIANT + (unsigned int)e; // COMPLIANT + (float)e; // COMPLIANT + + signed int i = 100; + (_Bool) i; // NON_COMPLIANT + (char)i; // COMPLIANT + (enum E1) i; // NON_COMPLIANT + (signed int)i; // COMPLIANT + (unsigned int)i; // COMPLIANT + (float)i; // COMPLIANT + + unsigned int u = 100; + (_Bool) u; // NON_COMPLIANT + (char)u; // COMPLIANT + (enum E1) u; // NON_COMPLIANT + (signed int)u; // COMPLIANT + (unsigned int)u; // COMPLIANT + (float)u; // COMPLIANT + + float f = 100.0; + (_Bool) f; // NON_COMPLIANT + (char)f; // NON_COMPLIANT + (enum E1) f; // NON_COMPLIANT + (signed int)f; // COMPLIANT + (unsigned int)f; // COMPLIANT + (float)f; // COMPLIANT +} + +void testImplicit() { + // Implicit conversions are not checked by this rule. + char c = true; // Not covered by rule + _Bool b = 100; // Not covered by rule + unsigned int u = 100; + _Bool b2 = u; // Not covered by rule +} + +void testIntegerConstantBool() { + (_Bool)0; // COMPLIANT + (_Bool)1; // COMPLIANT + (_Bool)2; // NON_COMPLIANT + enum MyBool { f, t }; + (enum MyBool)0; // COMPLIANT + (enum MyBool)1; // COMPLIANT + (enum MyBool)2; // NON_COMPLIANT + typedef int boolean; + (boolean)0; // COMPLIANT + (boolean)1; // COMPLIANT + (boolean)2; // NON_COMPLIANT +} \ No newline at end of file From 87e701316ab52ce78d947d0ea170527c6875674d Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Mon, 13 Feb 2023 14:25:14 +0000 Subject: [PATCH 10/25] EssentialTypes: Implement Rule 10.6 Adds a query which identifies "assignments" (as defined by MISRA C 2012) from composite expressions to objects of a wider essential type. --- .../AssignmentToWiderEssentialType.ql | 26 +++++++++++++++++++ .../AssignmentToWiderEssentialType.expected | 3 +++ .../AssignmentToWiderEssentialType.qlref | 1 + c/misra/test/rules/RULE-10-6/test.c | 11 ++++++++ 4 files changed, 41 insertions(+) create mode 100644 c/misra/src/rules/RULE-10-6/AssignmentToWiderEssentialType.ql create mode 100644 c/misra/test/rules/RULE-10-6/AssignmentToWiderEssentialType.expected create mode 100644 c/misra/test/rules/RULE-10-6/AssignmentToWiderEssentialType.qlref create mode 100644 c/misra/test/rules/RULE-10-6/test.c diff --git a/c/misra/src/rules/RULE-10-6/AssignmentToWiderEssentialType.ql b/c/misra/src/rules/RULE-10-6/AssignmentToWiderEssentialType.ql new file mode 100644 index 0000000000..b62eca3c29 --- /dev/null +++ b/c/misra/src/rules/RULE-10-6/AssignmentToWiderEssentialType.ql @@ -0,0 +1,26 @@ +/** + * @id c/misra/assignment-to-wider-essential-type + * @name RULE-10-6: The value of a composite expression shall not be assigned to an object with wider essential type + * @description + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-10-6 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.misra.EssentialTypes +import codingstandards.c.misra.MisraExpressions + +from CompositeExpression ce, Type lValueType, Type compositeEssentialType +where + not isExcluded(ce, EssentialTypesPackage::assignmentToWiderEssentialTypeQuery()) and + isAssignmentToEssentialType(lValueType, ce) and + compositeEssentialType = getEssentialType(ce) and + lValueType.getSize() > compositeEssentialType.getSize() and + // Assignment to a different type category is prohibited by Rule 10.3, so we only report cases + // where the assignment is to the same type category. + getEssentialTypeCategory(lValueType) = getEssentialTypeCategory(compositeEssentialType) +select ce, "Assignment to wider essential type: $@." diff --git a/c/misra/test/rules/RULE-10-6/AssignmentToWiderEssentialType.expected b/c/misra/test/rules/RULE-10-6/AssignmentToWiderEssentialType.expected new file mode 100644 index 0000000000..0813de0e7c --- /dev/null +++ b/c/misra/test/rules/RULE-10-6/AssignmentToWiderEssentialType.expected @@ -0,0 +1,3 @@ +| test.c:5:9:5:17 | ... + ... | Assignment to wider essential type: $@. | +| test.c:7:24:7:32 | ... + ... | Assignment to wider essential type: $@. | +| test.c:8:27:8:35 | ... + ... | Assignment to wider essential type: $@. | diff --git a/c/misra/test/rules/RULE-10-6/AssignmentToWiderEssentialType.qlref b/c/misra/test/rules/RULE-10-6/AssignmentToWiderEssentialType.qlref new file mode 100644 index 0000000000..5b3ab4e556 --- /dev/null +++ b/c/misra/test/rules/RULE-10-6/AssignmentToWiderEssentialType.qlref @@ -0,0 +1 @@ +rules/RULE-10-6/AssignmentToWiderEssentialType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-6/test.c b/c/misra/test/rules/RULE-10-6/test.c new file mode 100644 index 0000000000..a6ee9da77b --- /dev/null +++ b/c/misra/test/rules/RULE-10-6/test.c @@ -0,0 +1,11 @@ +void testWiderAssignment() { + unsigned int u32 = 100; + unsigned short u16 = 100; + u16 = u16 + u16; // COMPLIANT + u32 = u16 + u16; // NON_COMPLIANT + u32 = (unsigned int)(u16 + u16); // COMPLIANT + unsigned int u32_2 = u16 + u16; // NON_COMPLIANT + unsigned int u32a[1] = {u16 + u16}; // NON_COMPLIANT + + signed int s32 = u16 + u16; // ignored - prohibited by Rule 10.3 +} \ No newline at end of file From 70147d5600166e748eecd24a7de80d459d4510ae Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Mon, 13 Feb 2023 14:26:23 +0000 Subject: [PATCH 11/25] EssentialTypes: Implement Rule 10.6. Adds a query which identifies implicit conversions of composite expressions that cause it to be casted to a wider essential type. --- ...ImplicitConversionOfCompositeExpression.ql | 36 +++++++++++++++++++ ...itConversionOfCompositeExpression.expected | 3 ++ ...licitConversionOfCompositeExpression.qlref | 1 + c/misra/test/rules/RULE-10-7/test.c | 14 ++++++++ 4 files changed, 54 insertions(+) create mode 100644 c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql create mode 100644 c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.expected create mode 100644 c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.qlref create mode 100644 c/misra/test/rules/RULE-10-7/test.c diff --git a/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql b/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql new file mode 100644 index 0000000000..16cb46ce77 --- /dev/null +++ b/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql @@ -0,0 +1,36 @@ +/** + * @id c/misra/implicit-conversion-of-composite-expression + * @name RULE-10-7: If a composite expression is used as one operand of an operator in which the usual arithmetic + * @description If a composite expression is used as one operand of an operator in which the usual + * arithmetic conversions are performed then the other operand shall not have wider + * essential type + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-10-7 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.misra.EssentialTypes +import codingstandards.c.misra.MisraExpressions + +from + OperationWithUsualArithmeticConversions arith, CompositeExpression compositeOp, Expr otherOp, + Type compositeEssentialType, Type otherOpEssentialType +where + not isExcluded(arith, EssentialTypesPackage::implicitConversionOfCompositeExpressionQuery()) and + arith.getAnOperand() = compositeOp and + arith.getAnOperand() = otherOp and + not otherOp = compositeOp and + compositeEssentialType = getEssentialType(compositeOp) and + otherOpEssentialType = getEssentialType(otherOp) and + compositeEssentialType.getSize() < otherOpEssentialType.getSize() and + // Operands of a different type category in an operation with the usual arithmetic conversions is + // prohibited by Rule 10.4, so we only report cases here where the essential type categories are + // the same + getEssentialTypeCategory(compositeEssentialType) = getEssentialTypeCategory(otherOpEssentialType) +select arith, + "Implicit conversion of $@ from " + compositeEssentialType + " to " + otherOpEssentialType, + compositeOp, "composite op" diff --git a/c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.expected b/c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.expected new file mode 100644 index 0000000000..30b5e1efb7 --- /dev/null +++ b/c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.expected @@ -0,0 +1,3 @@ +| test.c:5:3:5:16 | ... + ... | Implicit conversion of $@ from unsigned short to unsigned int | test.c:5:9:5:16 | ... * ... | composite op | +| test.c:6:3:6:18 | ... * ... | Implicit conversion of $@ from unsigned short to unsigned int | test.c:6:9:6:17 | ... + ... | composite op | +| test.c:9:3:9:20 | ... += ... | Implicit conversion of $@ from unsigned short to unsigned int | test.c:9:11:9:19 | ... + ... | composite op | diff --git a/c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.qlref b/c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.qlref new file mode 100644 index 0000000000..fc83fbb902 --- /dev/null +++ b/c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.qlref @@ -0,0 +1 @@ +rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-7/test.c b/c/misra/test/rules/RULE-10-7/test.c new file mode 100644 index 0000000000..59d0ed1437 --- /dev/null +++ b/c/misra/test/rules/RULE-10-7/test.c @@ -0,0 +1,14 @@ +void testComposite() { + unsigned int u32 = 100; + unsigned short u16 = 100; + u16 + u32 *u16; // COMPLIANT + u32 + u16 *u16; // NON_COMPLIANT + u32 *(u16 + u16); // NON_COMPLIANT + u32 *(unsigned int)(u16 + u16); // COMPLIANT + u32 + u16 + u16; // COMPLIANT + u32 += (u16 + u16); // NON_COMPLIANT + u32 += (u32 + u16); // COMPLIANT + + signed int s32 = 100; + s32 += (u16 + u16); // // ignored - prohibited by Rule 10.4 +} \ No newline at end of file From 46be7be46b2e47e993008bb1ea3783693b9bac5f Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Mon, 13 Feb 2023 14:27:39 +0000 Subject: [PATCH 12/25] EssentialTypes: Implement Rule 10.8 Adds a query to check for inappropriate casts of composite expressions to wider essential types. --- .../InappropriateCastOfCompositeExpression.ql | 38 +++++++++++++++++++ ...ropriateCastOfCompositeExpression.expected | 4 ++ ...appropriateCastOfCompositeExpression.qlref | 1 + c/misra/test/rules/RULE-10-8/test.c | 22 +++++++++++ 4 files changed, 65 insertions(+) create mode 100644 c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql create mode 100644 c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.expected create mode 100644 c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.qlref create mode 100644 c/misra/test/rules/RULE-10-8/test.c diff --git a/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql b/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql new file mode 100644 index 0000000000..d371349def --- /dev/null +++ b/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql @@ -0,0 +1,38 @@ +/** + * @id c/misra/inappropriate-cast-of-composite-expression + * @name RULE-10-8: The value of a composite expression shall not be cast to a different essential type category or a + * @description The value of a composite expression shall not be cast to a different essential type + * category or a wider essential type + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-10-8 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.misra.EssentialTypes +import codingstandards.c.misra.MisraExpressions + +from + Cast c, CompositeExpression ce, Type castEssentialType, Type compositeExprEssentialType, + EssentialTypeCategory castTypeCategory, EssentialTypeCategory compositeTypeCategory, + string message +where + not isExcluded(ce, EssentialTypesPackage::inappropriateCastOfCompositeExpressionQuery()) and + c = ce.getExplicitlyConverted() and + compositeExprEssentialType = getEssentialTypeBeforeConversions(ce) and + castEssentialType = c.getType() and + castTypeCategory = getEssentialTypeCategory(castEssentialType) and + compositeTypeCategory = getEssentialTypeCategory(compositeExprEssentialType) and + ( + not castTypeCategory = compositeTypeCategory and + message = + "Cast from " + compositeTypeCategory + " to " + castTypeCategory + " changes type category." + or + castTypeCategory = compositeTypeCategory and + castEssentialType.getSize() > compositeExprEssentialType.getSize() and + message = "Cast from " + compositeTypeCategory + " to " + castTypeCategory + " widens type." + ) +select ce, message diff --git a/c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.expected b/c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.expected new file mode 100644 index 0000000000..85e2471a41 --- /dev/null +++ b/c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.expected @@ -0,0 +1,4 @@ +| test.c:4:16:4:20 | ... + ... | Cast from essentially Unsigned type to essentially Signed type changes type category. | +| test.c:5:18:5:22 | ... + ... | Cast from essentially Signed type to essentially Unsigned type changes type category. | +| test.c:14:18:14:24 | ... + ... | Cast from essentially Unsigned type to essentially Unsigned type widens type. | +| test.c:20:16:20:22 | ... + ... | Cast from essentially Signed type to essentially Signed type widens type. | diff --git a/c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.qlref b/c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.qlref new file mode 100644 index 0000000000..58e1592686 --- /dev/null +++ b/c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.qlref @@ -0,0 +1 @@ +rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-8/test.c b/c/misra/test/rules/RULE-10-8/test.c new file mode 100644 index 0000000000..41efb6b8d8 --- /dev/null +++ b/c/misra/test/rules/RULE-10-8/test.c @@ -0,0 +1,22 @@ +void testDifferentEssentialType() { + unsigned int u = 1; + signed int s = 1; + (signed int)(u + u); // NON_COMPLIANT + (unsigned int)(s + s); // NON_COMPLIANT + (signed int)(s + s); // COMPLIANT + (unsigned int)(u + u); // COMPLIANT +} + +void testWiderType() { + unsigned short us = 1; + unsigned int u = 1; + + (unsigned int)(us + us); // NON_COMPLIANT + (unsigned short)(u + u); // COMPLIANT + + signed short ss = 1; + signed int s = 1; + + (signed int)(ss + ss); // NON_COMPLIANT + (signed short)(s + s); // COMPLIANT +} \ No newline at end of file From 2d70f7bf061c6b63789408d6a1cdbb76ae09a1d6 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Mon, 13 Feb 2023 14:38:32 +0000 Subject: [PATCH 13/25] EssentialTypes: Add basic test case for library. --- c/misra/test/c/misra/EssentialTypes.expected | 0 c/misra/test/c/misra/EssentialTypes.ql | 5 +++++ c/misra/test/c/misra/test.c | 17 +++++++++++++++++ 3 files changed, 22 insertions(+) create mode 100644 c/misra/test/c/misra/EssentialTypes.expected create mode 100644 c/misra/test/c/misra/EssentialTypes.ql create mode 100644 c/misra/test/c/misra/test.c diff --git a/c/misra/test/c/misra/EssentialTypes.expected b/c/misra/test/c/misra/EssentialTypes.expected new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/test/c/misra/EssentialTypes.ql b/c/misra/test/c/misra/EssentialTypes.ql new file mode 100644 index 0000000000..64b6f30a33 --- /dev/null +++ b/c/misra/test/c/misra/EssentialTypes.ql @@ -0,0 +1,5 @@ +import codingstandards.c.misra.EssentialTypes + +from Expr e +select e, getEssentialType(e) as et, getEssentialTypeBeforeConversions(e), + getEssentialTypeCategory(et) diff --git a/c/misra/test/c/misra/test.c b/c/misra/test/c/misra/test.c new file mode 100644 index 0000000000..ab21afbdc6 --- /dev/null +++ b/c/misra/test/c/misra/test.c @@ -0,0 +1,17 @@ +#include + +void testConditional() { + unsigned int u = 1; + unsigned short us = 1; + signed int s = 1; + signed short ss = 1; + _Bool b = true; + + b ? u : u; // unsigned int + b ? s : s; // signed int + b ? s : ss; // signed int + b ? ss : s; // signed int + b ? us : u; // unsigned int + + b ? s : u; // unsigned int +} \ No newline at end of file From ebc07fe6ccbae91bb5fed6788651498fed42b780 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Tue, 14 Feb 2023 13:17:05 +0000 Subject: [PATCH 14/25] EssentialTypes: Handle typedefs When computing EssentialTypeCategories, ensure we resolve any typedefs first. --- .../c/misra/EssentialTypes.qll | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 06e1ff20fc..35feb00848 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -74,25 +74,32 @@ private IntegralType stlr(Expr const) { } /** - * Define the essential type category for an IntegralOrEnumType. + * Define the essential type category for an essentialType or a typedef of an essentialType. */ -EssentialTypeCategory getEssentialTypeCategory(Type at) { - result = EssentiallyBooleanType() and at instanceof MisraBoolType - or - result = EssentiallyCharacterType() and at instanceof PlainCharType - or - result = EssentiallySignedType() and - at.(IntegralType).isSigned() and - not at instanceof PlainCharType - or - result = EssentiallyUnsignedType() and - at.(IntegralType).isUnsigned() and - not at instanceof PlainCharType - or - result = EssentiallyEnumType() and at instanceof Enum and not at instanceof MisraBoolType - or - result = EssentiallyFloatingType() and - at instanceof FloatingPointType +EssentialTypeCategory getEssentialTypeCategory(Type type) { + exists(Type essentialType | + // Resolve typedefs to ensure + essentialType = type.getUnderlyingType() + | + result = EssentiallyBooleanType() and essentialType instanceof MisraBoolType + or + result = EssentiallyCharacterType() and essentialType instanceof PlainCharType + or + result = EssentiallySignedType() and + essentialType.(IntegralType).isSigned() and + not essentialType instanceof PlainCharType + or + result = EssentiallyUnsignedType() and + essentialType.(IntegralType).isUnsigned() and + not essentialType instanceof PlainCharType + or + result = EssentiallyEnumType() and + essentialType instanceof Enum and + not essentialType instanceof MisraBoolType + or + result = EssentiallyFloatingType() and + essentialType instanceof FloatingPointType + ) } /** From ebae3e6d305ec0a54f782566e1c411f0a6f50389 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Tue, 14 Feb 2023 13:19:27 +0000 Subject: [PATCH 15/25] EssentialTypes: Implement Rule 14.1 Adds a query that finds loop counters which are essentially floating type. --- .../RULE-14-1/LoopOverEssentiallyFloatType.ql | 23 +++++++++++++++++++ .../LoopOverEssentiallyFloatType.expected | 3 +++ .../LoopOverEssentiallyFloatType.qlref | 1 + c/misra/test/rules/RULE-14-1/test.c | 15 ++++++++++++ 4 files changed, 42 insertions(+) create mode 100644 c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql create mode 100644 c/misra/test/rules/RULE-14-1/LoopOverEssentiallyFloatType.expected create mode 100644 c/misra/test/rules/RULE-14-1/LoopOverEssentiallyFloatType.qlref create mode 100644 c/misra/test/rules/RULE-14-1/test.c diff --git a/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql b/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql new file mode 100644 index 0000000000..5bf20709e6 --- /dev/null +++ b/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/loop-over-essentially-float-type + * @name RULE-14-1: A loop counter shall not have essentially floating type + * @description + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-14-1 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.misra.EssentialTypes +import codingstandards.cpp.Loops + +from ForStmt forLoop, Variable loopIterationVariable +where + not isExcluded(loopIterationVariable, EssentialTypesPackage::loopOverEssentiallyFloatTypeQuery()) and + getAnIterationVariable(forLoop) = loopIterationVariable and + getEssentialTypeCategory(loopIterationVariable.getType()) = EssentiallyFloatingType() +select loopIterationVariable, + "Loop iteration variable " + loopIterationVariable.getName() + " is essentially Floating type." diff --git a/c/misra/test/rules/RULE-14-1/LoopOverEssentiallyFloatType.expected b/c/misra/test/rules/RULE-14-1/LoopOverEssentiallyFloatType.expected new file mode 100644 index 0000000000..0dc7c13836 --- /dev/null +++ b/c/misra/test/rules/RULE-14-1/LoopOverEssentiallyFloatType.expected @@ -0,0 +1,3 @@ +| test.c:4:14:4:14 | f | Loop iteration variable f is essentially Floating type. | +| test.c:6:15:6:15 | d | Loop iteration variable d is essentially Floating type. | +| test.c:8:18:8:18 | f | Loop iteration variable f is essentially Floating type. | diff --git a/c/misra/test/rules/RULE-14-1/LoopOverEssentiallyFloatType.qlref b/c/misra/test/rules/RULE-14-1/LoopOverEssentiallyFloatType.qlref new file mode 100644 index 0000000000..e488267d22 --- /dev/null +++ b/c/misra/test/rules/RULE-14-1/LoopOverEssentiallyFloatType.qlref @@ -0,0 +1 @@ +rules/RULE-14-1/LoopOverEssentiallyFloatType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-14-1/test.c b/c/misra/test/rules/RULE-14-1/test.c new file mode 100644 index 0000000000..50c2240735 --- /dev/null +++ b/c/misra/test/rules/RULE-14-1/test.c @@ -0,0 +1,15 @@ +typedef float float32_t; + +void test_floating_point_loop() { + for (float f = 0.0F; f < 10.0F; f += 0.2F) { // NON_COMPLIANT + } + for (double d = 0.0F; d < 10.0F; d += 0.2F) { // NON_COMPLIANT + } + for (float32_t f = 0.0F; f < 10.0F; f += 0.2F) { // NON_COMPLIANT + } +} + +void test_non_floating_point_loop() { + for (int i = 0; i < 10; i++) { // COMPLIANT + } +} \ No newline at end of file From 2c106bcfdf96760d9d990d2c76c804a0da102bde Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Tue, 14 Feb 2023 13:28:46 +0000 Subject: [PATCH 16/25] EssentialType: Handle type specifiers Ensure when calculating the essential type category, we strip the type specifiers, otherwise we will not match the correct type category. --- c/misra/src/codingstandards/c/misra/EssentialTypes.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 35feb00848..3acb041139 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -79,7 +79,7 @@ private IntegralType stlr(Expr const) { EssentialTypeCategory getEssentialTypeCategory(Type type) { exists(Type essentialType | // Resolve typedefs to ensure - essentialType = type.getUnderlyingType() + essentialType = type.getUnspecifiedType() | result = EssentiallyBooleanType() and essentialType instanceof MisraBoolType or From c330ed6afbc9ecbfcac5cc8d047aa1ba17c94f77 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Tue, 14 Feb 2023 13:32:07 +0000 Subject: [PATCH 17/25] EssentialTypes: Add test cases for library --- c/misra/test/c/misra/EssentialTypes.expected | 40 ++++++++++++++++++++ c/misra/test/c/misra/EssentialTypes.ql | 6 +-- c/misra/test/c/misra/test.c | 12 ++++++ 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/c/misra/test/c/misra/EssentialTypes.expected b/c/misra/test/c/misra/EssentialTypes.expected index e69de29bb2..8bf299bd63 100644 --- a/c/misra/test/c/misra/EssentialTypes.expected +++ b/c/misra/test/c/misra/EssentialTypes.expected @@ -0,0 +1,40 @@ +| test.c:4:20:4:20 | 1 | signed char | signed char | essentially Signed type | +| test.c:4:20:4:20 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:5:23:5:23 | 1 | signed char | signed char | essentially Signed type | +| test.c:5:23:5:23 | (unsigned short)... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:6:17:6:18 | 1 | signed char | signed char | essentially Signed type | +| test.c:7:21:7:21 | 1 | signed char | signed char | essentially Signed type | +| test.c:7:21:7:21 | (signed short)... | signed short | signed short | essentially Signed type | +| test.c:8:13:8:16 | 1 | bool | bool | essentially Boolean type | +| test.c:8:13:8:16 | (bool)... | bool | bool | essentially Boolean type | +| test.c:10:3:10:3 | b | bool | bool | essentially Boolean type | +| test.c:10:3:10:11 | ... ? ... : ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:10:7:10:7 | u | unsigned int | unsigned int | essentially Unsigned type | +| test.c:10:11:10:11 | u | unsigned int | unsigned int | essentially Unsigned type | +| test.c:11:3:11:3 | b | bool | bool | essentially Boolean type | +| test.c:11:3:11:11 | ... ? ... : ... | signed int | signed int | essentially Signed type | +| test.c:11:7:11:7 | s | signed int | signed int | essentially Signed type | +| test.c:11:11:11:11 | s | signed int | signed int | essentially Signed type | +| test.c:12:3:12:3 | b | bool | bool | essentially Boolean type | +| test.c:12:3:12:12 | ... ? ... : ... | signed int | signed int | essentially Signed type | +| test.c:12:7:12:7 | s | signed int | signed int | essentially Signed type | +| test.c:12:11:12:12 | (int)... | int | int | essentially Signed type | +| test.c:12:11:12:12 | ss | signed short | signed short | essentially Signed type | +| test.c:13:3:13:3 | b | bool | bool | essentially Boolean type | +| test.c:13:3:13:12 | ... ? ... : ... | signed int | signed int | essentially Signed type | +| test.c:13:7:13:8 | (int)... | int | int | essentially Signed type | +| test.c:13:7:13:8 | ss | signed short | signed short | essentially Signed type | +| test.c:13:12:13:12 | s | signed int | signed int | essentially Signed type | +| test.c:14:3:14:3 | b | bool | bool | essentially Boolean type | +| test.c:14:3:14:12 | ... ? ... : ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:14:7:14:8 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:14:7:14:8 | us | unsigned short | unsigned short | essentially Unsigned type | +| test.c:14:12:14:12 | u | unsigned int | unsigned int | essentially Unsigned type | +| test.c:16:3:16:3 | b | bool | bool | essentially Boolean type | +| test.c:16:3:16:11 | ... ? ... : ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:16:7:16:7 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:16:7:16:7 | s | signed int | signed int | essentially Signed type | +| test.c:16:11:16:11 | u | unsigned int | unsigned int | essentially Unsigned type | +| test.c:26:3:26:3 | f | float | float | essentially Floating type | +| test.c:27:3:27:5 | f32 | float32_t | float32_t | essentially Floating type | +| test.c:28:3:28:6 | cf32 | float | float | essentially Floating type | diff --git a/c/misra/test/c/misra/EssentialTypes.ql b/c/misra/test/c/misra/EssentialTypes.ql index 64b6f30a33..f8fe785727 100644 --- a/c/misra/test/c/misra/EssentialTypes.ql +++ b/c/misra/test/c/misra/EssentialTypes.ql @@ -1,5 +1,5 @@ import codingstandards.c.misra.EssentialTypes -from Expr e -select e, getEssentialType(e) as et, getEssentialTypeBeforeConversions(e), - getEssentialTypeCategory(et) +from Expr e, Type et +where et = getEssentialType(e) +select e, et.getName(), getEssentialTypeBeforeConversions(e).getName(), getEssentialTypeCategory(et) diff --git a/c/misra/test/c/misra/test.c b/c/misra/test/c/misra/test.c index ab21afbdc6..8788f7e93a 100644 --- a/c/misra/test/c/misra/test.c +++ b/c/misra/test/c/misra/test.c @@ -14,4 +14,16 @@ void testConditional() { b ? us : u; // unsigned int b ? s : u; // unsigned int +} + +void testCategoriesForComplexTypes() { + typedef float float32_t; + typedef const float cfloat32_t; + const float f; + const float32_t f32; + cfloat32_t cf32; + + f; // Should be essentially Floating type + f32; // Should be essentially Floating type + cf32; // Should be essentially Floating type } \ No newline at end of file From cf12521d6909cdefc0d673b043b5e2dedf45c5d2 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Tue, 14 Feb 2023 13:50:39 +0000 Subject: [PATCH 18/25] EssentialTypes: Implement Rule 21.16 Adds a query to find uses of memcmp with pointer types which are prohibited by MISRA C. --- .../MemcmpOnInappropriateEssentialTypeArgs.ql | 44 +++++++++++++++ ...pOnInappropriateEssentialTypeArgs.expected | 10 ++++ ...mcmpOnInappropriateEssentialTypeArgs.qlref | 1 + c/misra/test/rules/RULE-21-16/test.c | 54 +++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql create mode 100644 c/misra/test/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.expected create mode 100644 c/misra/test/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.qlref create mode 100644 c/misra/test/rules/RULE-21-16/test.c diff --git a/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql b/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql new file mode 100644 index 0000000000..0852595d9b --- /dev/null +++ b/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql @@ -0,0 +1,44 @@ +/** + * @id c/misra/memcmp-on-inappropriate-essential-type-args + * @name RULE-21-16: The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, + * @description The pointer arguments to the Standard Library function memcmp shall point to either + * a pointer type, an essentially signed type, an essentially unsigned type, an + * essentially Boolean type or an essentially enum type + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-16 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.misra.EssentialTypes + +from FunctionCall memcmp, Expr arg, Type argBaseType +where + not isExcluded(arg, EssentialTypesPackage::memcmpOnInappropriateEssentialTypeArgsQuery()) and + memcmp.getTarget().hasGlobalName("memcmp") and + // Pointer arguments + arg = memcmp.getArgument([0, 1]) and + exists(DerivedType pt | + // Must be a pointer type or array type + ( + pt instanceof PointerType or + pt instanceof ArrayType + ) and + pt = arg.getType() and + argBaseType = pt.getBaseType() and + // Doesn't point to a pointer type + not argBaseType instanceof PointerType and + // Doesn't point to a type which is essentially signed, unsigned, boolean or enum + not exists(EssentialTypeCategory typeCategory | + typeCategory = getEssentialTypeCategory(argBaseType) + | + typeCategory = EssentiallySignedType() or + typeCategory = EssentiallyUnsignedType() or + typeCategory = EssentiallyBooleanType() or + typeCategory = EssentiallyEnumType() + ) + ) +select arg, "Argument is a pointer to " + argBaseType + "." diff --git a/c/misra/test/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.expected b/c/misra/test/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.expected new file mode 100644 index 0000000000..d774a833f2 --- /dev/null +++ b/c/misra/test/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.expected @@ -0,0 +1,10 @@ +| test.c:23:10:23:10 | p | Argument is a pointer to float. | +| test.c:23:13:23:13 | q | Argument is a pointer to float. | +| test.c:35:10:35:10 | p | Argument is a pointer to S1. | +| test.c:35:13:35:13 | q | Argument is a pointer to S1. | +| test.c:41:10:41:10 | p | Argument is a pointer to U. | +| test.c:41:13:41:13 | q | Argument is a pointer to U. | +| test.c:45:10:45:10 | p | Argument is a pointer to char. | +| test.c:45:13:45:13 | q | Argument is a pointer to char. | +| test.c:49:10:49:10 | p | Argument is a pointer to char. | +| test.c:49:13:49:13 | q | Argument is a pointer to char. | diff --git a/c/misra/test/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.qlref b/c/misra/test/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.qlref new file mode 100644 index 0000000000..cf550d800a --- /dev/null +++ b/c/misra/test/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.qlref @@ -0,0 +1 @@ +rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-16/test.c b/c/misra/test/rules/RULE-21-16/test.c new file mode 100644 index 0000000000..f7c4c96707 --- /dev/null +++ b/c/misra/test/rules/RULE-21-16/test.c @@ -0,0 +1,54 @@ +#include +#include + +void testMemcmpSignedInt(signed int *p, signed int *q, size_t size) { + memcmp(p, q, size); // COMPLIANT +} + +void testMemcmpUnsignedInt(unsigned int *p, unsigned int *q, size_t size) { + memcmp(p, q, size); // COMPLIANT +} + +enum E1 { E1_1, E1_2 }; + +void testMemcmpEnum(enum E1 *p, enum E1 *q, size_t size) { + memcmp(p, q, size); // COMPLIANT +} + +void testMemcmpBool(bool *p, bool *q, size_t size) { + memcmp(p, q, size); // COMPLIANT +} + +void testMemcmpFloat(float *p, float *q, size_t size) { + memcmp(p, q, size); // NON_COMPLIANT +} + +void testMemcmpPointerToPointer(void **p, void **q, size_t size) { + memcmp(p, q, size); // COMPLIANT +} + +struct S1 { + int i; +}; + +void testMemcmpStruct(struct S1 *p, struct S1 *q, size_t size) { + memcmp(p, q, size); // NON_COMPLIANT +} + +union U; + +void testMemcmpUnion(union U *p, union U *q, size_t size) { + memcmp(p, q, size); // NON_COMPLIANT +} + +void testMemcmpChar(char *p, char *q, size_t size) { + memcmp(p, q, size); // NON_COMPLIANT +} + +void testMemcmpCharArray(char p[10], char q[10], size_t size) { + memcmp(p, q, size); // NON_COMPLIANT +} + +void testMemcmpIntArray(int p[10], int q[10], size_t size) { + memcmp(p, q, size); // COMPLIANT +} \ No newline at end of file From c6ce829e8cff79adb82649d7afe50b965ec5967a Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Tue, 14 Feb 2023 14:11:05 +0000 Subject: [PATCH 19/25] EssentialTypes: Update metadata --- .../OperandsOfAnInappropriateEssentialType.ql | 6 +- .../RULE-10-1/PointerTypeOnLogicalOperator.ql | 6 +- ...dditionSubtractionOnEssentiallyCharType.ql | 4 +- .../AssignmentOfIncompatibleEssentialType.ql | 8 +- ...andsWithMismatchedEssentialTypeCategory.ql | 6 +- .../InappropriateEssentialTypeCast.ql | 7 +- .../AssignmentToWiderEssentialType.ql | 7 +- ...ImplicitConversionOfCompositeExpression.ql | 6 +- .../InappropriateCastOfCompositeExpression.ql | 6 +- .../RULE-14-1/LoopOverEssentiallyFloatType.ql | 8 +- .../MemcmpOnInappropriateEssentialTypeArgs.ql | 4 +- rule_packages/c/EssentialTypes.json | 97 ++++++++++++------- 12 files changed, 110 insertions(+), 55 deletions(-) diff --git a/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql b/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql index 0245f3cbc5..005b7c6cf5 100644 --- a/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql +++ b/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql @@ -1,11 +1,13 @@ /** * @id c/misra/operands-of-an-inappropriate-essential-type * @name RULE-10-1: Operands shall not be of an inappropriate essential type - * @description + * @description Using an inappropriate essential type operand may lead to confusing or unexpected + * behavior when the operand is converted. * @kind problem * @precision very-high - * @problem.severity error + * @problem.severity warning * @tags external/misra/id/rule-10-1 + * maintainability * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-10-1/PointerTypeOnLogicalOperator.ql b/c/misra/src/rules/RULE-10-1/PointerTypeOnLogicalOperator.ql index 53d4a79ffc..21bfdcb2be 100644 --- a/c/misra/src/rules/RULE-10-1/PointerTypeOnLogicalOperator.ql +++ b/c/misra/src/rules/RULE-10-1/PointerTypeOnLogicalOperator.ql @@ -1,11 +1,13 @@ /** * @id c/misra/pointer-type-on-logical-operator * @name RULE-10-1: Logical operators should not be used with pointer types - * @description + * @description Using pointer types with logical operators should be avoid because it can cause + * confusing behavior. * @kind problem * @precision very-high - * @problem.severity error + * @problem.severity warning * @tags external/misra/id/rule-10-1 + * correctness * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql b/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql index 5e75f44590..7ed86b9210 100644 --- a/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql +++ b/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql @@ -1,12 +1,14 @@ /** * @id c/misra/addition-subtraction-on-essentially-char-type - * @name RULE-10-2: Expressions of essentially character type shall not be used inappropriately in addition and + * @name RULE-10-2: Inappropriate use of essentially character type operands in addition and subtraction operations * @description Expressions of essentially character type shall not be used inappropriately in * addition and subtraction operations * @kind problem * @precision very-high * @problem.severity error * @tags external/misra/id/rule-10-2 + * maintainability + * correctness * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql b/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql index 362f0934c2..358c0c1a09 100644 --- a/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql +++ b/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql @@ -1,12 +1,14 @@ /** * @id c/misra/assignment-of-incompatible-essential-type - * @name RULE-10-3: The value of an expression shall not be assigned to an object with a narrower essential type or of a + * @name RULE-10-3: Do not assign to an object with a different essential type category or narrower essential type * @description The value of an expression shall not be assigned to an object with a narrower * essential type or of a different essential type category * @kind problem - * @precision high - * @problem.severity error + * @precision very-high + * @problem.severity warning * @tags external/misra/id/rule-10-3 + * maintainability + * correctness * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql b/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql index 582854e77b..6619ce31e4 100644 --- a/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql +++ b/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql @@ -1,12 +1,14 @@ /** * @id c/misra/operands-with-mismatched-essential-type-category - * @name RULE-10-4: Both operands of an operator in which the usual arithmetic conversions are performed shall have the + * @name RULE-10-4: Operator with usual arithmetic conversions shall have operands with the same essential type category * @description Both operands of an operator in which the usual arithmetic conversions are performed * shall have the same essential type category * @kind problem * @precision very-high - * @problem.severity error + * @problem.severity warning * @tags external/misra/id/rule-10-4 + * maintainability + * correctness * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql b/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql index c7556729c9..10d54c4fff 100644 --- a/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql +++ b/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql @@ -1,11 +1,14 @@ /** * @id c/misra/inappropriate-essential-type-cast * @name RULE-10-5: The value of an expression should not be cast to an inappropriate essential type - * @description + * @description Casting the value of an expression to an inappropriate essential type may lead to + * confusing or unexpected behavior in the way the value is converted. * @kind problem * @precision very-high - * @problem.severity error + * @problem.severity warning * @tags external/misra/id/rule-10-5 + * maintainability + * correctness * external/misra/obligation/advisory */ diff --git a/c/misra/src/rules/RULE-10-6/AssignmentToWiderEssentialType.ql b/c/misra/src/rules/RULE-10-6/AssignmentToWiderEssentialType.ql index b62eca3c29..bc1133c784 100644 --- a/c/misra/src/rules/RULE-10-6/AssignmentToWiderEssentialType.ql +++ b/c/misra/src/rules/RULE-10-6/AssignmentToWiderEssentialType.ql @@ -1,11 +1,14 @@ /** * @id c/misra/assignment-to-wider-essential-type * @name RULE-10-6: The value of a composite expression shall not be assigned to an object with wider essential type - * @description + * @description Assigning a composite expression to an object with wider essential type can cause + * some unexpected conversions. * @kind problem * @precision very-high - * @problem.severity error + * @problem.severity warning * @tags external/misra/id/rule-10-6 + * maintainability + * correctness * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql b/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql index 16cb46ce77..c1f8c1c342 100644 --- a/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql +++ b/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql @@ -1,13 +1,15 @@ /** * @id c/misra/implicit-conversion-of-composite-expression - * @name RULE-10-7: If a composite expression is used as one operand of an operator in which the usual arithmetic + * @name RULE-10-7: Implicit conversion of composite expression operand to wider essential type * @description If a composite expression is used as one operand of an operator in which the usual * arithmetic conversions are performed then the other operand shall not have wider * essential type * @kind problem * @precision very-high - * @problem.severity error + * @problem.severity warning * @tags external/misra/id/rule-10-7 + * maintainability + * correctness * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql b/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql index d371349def..a251feefa2 100644 --- a/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql +++ b/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql @@ -1,12 +1,14 @@ /** * @id c/misra/inappropriate-cast-of-composite-expression - * @name RULE-10-8: The value of a composite expression shall not be cast to a different essential type category or a + * @name RULE-10-8: Composite expression explicitly casted to wider or different essential type * @description The value of a composite expression shall not be cast to a different essential type * category or a wider essential type * @kind problem * @precision very-high - * @problem.severity error + * @problem.severity warning * @tags external/misra/id/rule-10-8 + * maintainability + * correctness * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql b/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql index 5bf20709e6..6a0f772f61 100644 --- a/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql +++ b/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql @@ -1,11 +1,13 @@ /** * @id c/misra/loop-over-essentially-float-type * @name RULE-14-1: A loop counter shall not have essentially floating type - * @description + * @description A floating point loop counter can cause confusing behavior when incremented. * @kind problem - * @precision high - * @problem.severity error + * @precision very-high + * @problem.severity warning * @tags external/misra/id/rule-14-1 + * maintainability + * correctness * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql b/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql index 0852595d9b..88a39dd973 100644 --- a/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql +++ b/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql @@ -1,6 +1,6 @@ /** * @id c/misra/memcmp-on-inappropriate-essential-type-args - * @name RULE-21-16: The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, + * @name RULE-21-16: Do not use memcmp on pointers to characters or composite types such as structs and unions. * @description The pointer arguments to the Standard Library function memcmp shall point to either * a pointer type, an essentially signed type, an essentially unsigned type, an * essentially Boolean type or an essentially enum type @@ -8,6 +8,8 @@ * @precision very-high * @problem.severity error * @tags external/misra/id/rule-21-16 + * maintainability + * correctness * external/misra/obligation/required */ diff --git a/rule_packages/c/EssentialTypes.json b/rule_packages/c/EssentialTypes.json index 15c01100b9..412aca7fe8 100644 --- a/rule_packages/c/EssentialTypes.json +++ b/rule_packages/c/EssentialTypes.json @@ -6,22 +6,26 @@ }, "queries": [ { - "description": "", + "description": "Using an inappropriate essential type operand may lead to confusing or unexpected behavior when the operand is converted.", "kind": "problem", "name": "Operands shall not be of an inappropriate essential type", "precision": "very-high", - "severity": "error", + "severity": "warning", "short_name": "OperandsOfAnInappropriateEssentialType", - "tags": [] + "tags": [ + "maintainability" + ] }, { - "description": "", + "description": "Using pointer types with logical operators should be avoid because it can cause confusing behavior.", "kind": "problem", "name": "Logical operators should not be used with pointer types", "precision": "very-high", - "severity": "error", + "severity": "warning", "short_name": "PointerTypeOnLogicalOperator", - "tags": [] + "tags": [ + "correctness" + ] } ], "title": "Operands shall not be of an inappropriate essential type" @@ -34,11 +38,14 @@ { "description": "Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations", "kind": "problem", - "name": "Expressions of essentially character type shall not be used inappropriately in addition and", + "name": "Inappropriate use of essentially character type operands in addition and subtraction operations", "precision": "very-high", "severity": "error", "short_name": "AdditionSubtractionOnEssentiallyCharType", - "tags": [] + "tags": [ + "maintainability", + "correctness" + ] } ], "title": "Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations" @@ -51,11 +58,14 @@ { "description": "The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category", "kind": "problem", - "name": "The value of an expression shall not be assigned to an object with a narrower essential type or of a", - "precision": "high", - "severity": "error", + "name": "Do not assign to an object with a different essential type category or narrower essential type", + "precision": "very-high", + "severity": "warning", "short_name": "AssignmentOfIncompatibleEssentialType", - "tags": [] + "tags": [ + "maintainability", + "correctness" + ] } ], "title": "The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category" @@ -68,11 +78,14 @@ { "description": "Both operands of an operator in which the usual arithmetic conversions are performed shall have the same essential type category", "kind": "problem", - "name": "Both operands of an operator in which the usual arithmetic conversions are performed shall have the", + "name": "Operator with usual arithmetic conversions shall have operands with the same essential type category", "precision": "very-high", - "severity": "error", + "severity": "warning", "short_name": "OperandsWithMismatchedEssentialTypeCategory", - "tags": [] + "tags": [ + "maintainability", + "correctness" + ] } ], "title": "Both operands of an operator in which the usual arithmetic conversions are performed shall have the same essential type category" @@ -83,13 +96,16 @@ }, "queries": [ { - "description": "", + "description": "Casting the value of an expression to an inappropriate essential type may lead to confusing or unexpected behavior in the way the value is converted.", "kind": "problem", "name": "The value of an expression should not be cast to an inappropriate essential type", "precision": "very-high", - "severity": "error", + "severity": "warning", "short_name": "InappropriateEssentialTypeCast", - "tags": [] + "tags": [ + "maintainability", + "correctness" + ] } ], "title": "The value of an expression should not be cast to an inappropriate essential type" @@ -100,13 +116,16 @@ }, "queries": [ { - "description": "", + "description": "Assigning a composite expression to an object with wider essential type can cause some unexpected conversions.", "kind": "problem", "name": "The value of a composite expression shall not be assigned to an object with wider essential type", "precision": "very-high", - "severity": "error", + "severity": "warning", "short_name": "AssignmentToWiderEssentialType", - "tags": [] + "tags": [ + "maintainability", + "correctness" + ] } ], "title": "The value of a composite expression shall not be assigned to an object with wider essential type" @@ -119,11 +138,14 @@ { "description": "If a composite expression is used as one operand of an operator in which the usual arithmetic conversions are performed then the other operand shall not have wider essential type", "kind": "problem", - "name": "If a composite expression is used as one operand of an operator in which the usual arithmetic", + "name": "Implicit conversion of composite expression operand to wider essential type", "precision": "very-high", - "severity": "error", + "severity": "warning", "short_name": "ImplicitConversionOfCompositeExpression", - "tags": [] + "tags": [ + "maintainability", + "correctness" + ] } ], "title": "If a composite expression is used as one operand of an operator in which the usual arithmetic conversions are performed then the other operand shall not have wider essential type" @@ -136,11 +158,14 @@ { "description": "The value of a composite expression shall not be cast to a different essential type category or a wider essential type", "kind": "problem", - "name": "The value of a composite expression shall not be cast to a different essential type category or a", + "name": "Composite expression explicitly casted to wider or different essential type", "precision": "very-high", - "severity": "error", + "severity": "warning", "short_name": "InappropriateCastOfCompositeExpression", - "tags": [] + "tags": [ + "maintainability", + "correctness" + ] } ], "title": "The value of a composite expression shall not be cast to a different essential type category or a wider essential type" @@ -151,13 +176,16 @@ }, "queries": [ { - "description": "", + "description": "A floating point loop counter can cause confusing behavior when incremented.", "kind": "problem", "name": "A loop counter shall not have essentially floating type", - "precision": "high", - "severity": "error", + "precision": "very-high", + "severity": "warning", "short_name": "LoopOverEssentiallyFloatType", - "tags": [] + "tags": [ + "maintainability", + "correctness" + ] } ], "title": "A loop counter shall not have essentially floating type" @@ -170,11 +198,14 @@ { "description": "The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type", "kind": "problem", - "name": "The pointer arguments to the Standard Library function memcmp shall point to either a pointer type,", + "name": "Do not use memcmp on pointers to characters or composite types such as structs and unions.", "precision": "very-high", "severity": "error", "short_name": "MemcmpOnInappropriateEssentialTypeArgs", - "tags": [] + "tags": [ + "maintainability", + "correctness" + ] } ], "title": "The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type" From 326d7d3d6b70408445fcb6f6c9049483bc7773b7 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Tue, 14 Feb 2023 14:30:31 +0000 Subject: [PATCH 20/25] EssentialTypes: add . to descriptions --- .../AdditionSubtractionOnEssentiallyCharType.ql | 2 +- .../AssignmentOfIncompatibleEssentialType.ql | 2 +- .../OperandsWithMismatchedEssentialTypeCategory.ql | 2 +- .../ImplicitConversionOfCompositeExpression.ql | 2 +- .../InappropriateCastOfCompositeExpression.ql | 2 +- .../MemcmpOnInappropriateEssentialTypeArgs.ql | 2 +- rule_packages/c/EssentialTypes.json | 12 ++++++------ 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql b/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql index 7ed86b9210..ad0c630e23 100644 --- a/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql +++ b/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql @@ -2,7 +2,7 @@ * @id c/misra/addition-subtraction-on-essentially-char-type * @name RULE-10-2: Inappropriate use of essentially character type operands in addition and subtraction operations * @description Expressions of essentially character type shall not be used inappropriately in - * addition and subtraction operations + * addition and subtraction operations. * @kind problem * @precision very-high * @problem.severity error diff --git a/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql b/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql index 358c0c1a09..353f6a9c8d 100644 --- a/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql +++ b/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql @@ -2,7 +2,7 @@ * @id c/misra/assignment-of-incompatible-essential-type * @name RULE-10-3: Do not assign to an object with a different essential type category or narrower essential type * @description The value of an expression shall not be assigned to an object with a narrower - * essential type or of a different essential type category + * essential type or of a different essential type category. * @kind problem * @precision very-high * @problem.severity warning diff --git a/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql b/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql index 6619ce31e4..d5ef8b6d26 100644 --- a/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql +++ b/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql @@ -2,7 +2,7 @@ * @id c/misra/operands-with-mismatched-essential-type-category * @name RULE-10-4: Operator with usual arithmetic conversions shall have operands with the same essential type category * @description Both operands of an operator in which the usual arithmetic conversions are performed - * shall have the same essential type category + * shall have the same essential type category. * @kind problem * @precision very-high * @problem.severity warning diff --git a/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql b/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql index c1f8c1c342..1cf20378fa 100644 --- a/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql +++ b/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql @@ -3,7 +3,7 @@ * @name RULE-10-7: Implicit conversion of composite expression operand to wider essential type * @description If a composite expression is used as one operand of an operator in which the usual * arithmetic conversions are performed then the other operand shall not have wider - * essential type + * essential type. * @kind problem * @precision very-high * @problem.severity warning diff --git a/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql b/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql index a251feefa2..8e58ded416 100644 --- a/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql +++ b/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql @@ -2,7 +2,7 @@ * @id c/misra/inappropriate-cast-of-composite-expression * @name RULE-10-8: Composite expression explicitly casted to wider or different essential type * @description The value of a composite expression shall not be cast to a different essential type - * category or a wider essential type + * category or a wider essential type. * @kind problem * @precision very-high * @problem.severity warning diff --git a/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql b/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql index 88a39dd973..cfeffe16a0 100644 --- a/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql +++ b/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql @@ -3,7 +3,7 @@ * @name RULE-21-16: Do not use memcmp on pointers to characters or composite types such as structs and unions. * @description The pointer arguments to the Standard Library function memcmp shall point to either * a pointer type, an essentially signed type, an essentially unsigned type, an - * essentially Boolean type or an essentially enum type + * essentially Boolean type or an essentially enum type. * @kind problem * @precision very-high * @problem.severity error diff --git a/rule_packages/c/EssentialTypes.json b/rule_packages/c/EssentialTypes.json index 412aca7fe8..f24b49f7c2 100644 --- a/rule_packages/c/EssentialTypes.json +++ b/rule_packages/c/EssentialTypes.json @@ -36,7 +36,7 @@ }, "queries": [ { - "description": "Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations", + "description": "Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations.", "kind": "problem", "name": "Inappropriate use of essentially character type operands in addition and subtraction operations", "precision": "very-high", @@ -56,7 +56,7 @@ }, "queries": [ { - "description": "The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category", + "description": "The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category.", "kind": "problem", "name": "Do not assign to an object with a different essential type category or narrower essential type", "precision": "very-high", @@ -76,7 +76,7 @@ }, "queries": [ { - "description": "Both operands of an operator in which the usual arithmetic conversions are performed shall have the same essential type category", + "description": "Both operands of an operator in which the usual arithmetic conversions are performed shall have the same essential type category.", "kind": "problem", "name": "Operator with usual arithmetic conversions shall have operands with the same essential type category", "precision": "very-high", @@ -136,7 +136,7 @@ }, "queries": [ { - "description": "If a composite expression is used as one operand of an operator in which the usual arithmetic conversions are performed then the other operand shall not have wider essential type", + "description": "If a composite expression is used as one operand of an operator in which the usual arithmetic conversions are performed then the other operand shall not have wider essential type.", "kind": "problem", "name": "Implicit conversion of composite expression operand to wider essential type", "precision": "very-high", @@ -156,7 +156,7 @@ }, "queries": [ { - "description": "The value of a composite expression shall not be cast to a different essential type category or a wider essential type", + "description": "The value of a composite expression shall not be cast to a different essential type category or a wider essential type.", "kind": "problem", "name": "Composite expression explicitly casted to wider or different essential type", "precision": "very-high", @@ -196,7 +196,7 @@ }, "queries": [ { - "description": "The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type", + "description": "The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type.", "kind": "problem", "name": "Do not use memcmp on pointers to characters or composite types such as structs and unions.", "precision": "very-high", From 3eca5d6434bb73af3eb320e132963c1196e0aab9 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Wed, 15 Feb 2023 23:00:53 +0000 Subject: [PATCH 21/25] EssentialTypes: Ensure compatibility with C++ This query looks for use of memcmp, but previously it would not have worked if the user was using C++ and specified std::memcmp. Although this rule is targeted at C, it is one that a user might enable for C++ and expect to work. --- .../rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql b/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql index cfeffe16a0..cebc30d6be 100644 --- a/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql +++ b/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql @@ -20,7 +20,7 @@ import codingstandards.c.misra.EssentialTypes from FunctionCall memcmp, Expr arg, Type argBaseType where not isExcluded(arg, EssentialTypesPackage::memcmpOnInappropriateEssentialTypeArgsQuery()) and - memcmp.getTarget().hasGlobalName("memcmp") and + memcmp.getTarget().hasGlobalOrStdName("memcmp") and // Pointer arguments arg = memcmp.getArgument([0, 1]) and exists(DerivedType pt | From b38552c78ed7a76ca88b1361bd90479e90d011f0 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Wed, 15 Feb 2023 23:04:40 +0000 Subject: [PATCH 22/25] EssentialTypes: Implement Rule 21.14 Adds a query to detect the use of memcmp to compare null-terminated strings, using global data flow from hard-coded string literals or array literals. --- ...emcmpUsedToCompareNullTerminatedStrings.ql | 80 +++++++++++++++++++ ...sedToCompareNullTerminatedStrings.expected | 34 ++++++++ ...mpUsedToCompareNullTerminatedStrings.qlref | 1 + c/misra/test/rules/RULE-21-14/test.c | 28 +++++++ .../cpp/exclusions/c/EssentialTypes.qll | 17 ++++ rule_packages/c/EssentialTypes.json | 20 +++++ rules.csv | 2 +- 7 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql create mode 100644 c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected create mode 100644 c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.qlref create mode 100644 c/misra/test/rules/RULE-21-14/test.c diff --git a/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql b/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql new file mode 100644 index 0000000000..9bbec5c398 --- /dev/null +++ b/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql @@ -0,0 +1,80 @@ +/** + * @id c/misra/memcmp-used-to-compare-null-terminated-strings + * @name RULE-21-14: The Standard Library function memcmp shall not be used to compare null terminated strings + * @description Using memcmp to compare null terminated strings may give unexpected results because + * memcmp compares by size with no consideration for the null terminator. + * @kind path-problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-14 + * maintainability + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.misra.EssentialTypes +import semmle.code.cpp.dataflow.TaintTracking +import DataFlow::PathGraph + +// Data flow from a StringLiteral or from an array of characters, to a memcmp call +class NullTerminatedStringToMemcmpConfiguration extends TaintTracking::Configuration { + NullTerminatedStringToMemcmpConfiguration() { this = "NullTerminatedStringToMemcmpConfiguration" } + + override predicate isSource(DataFlow::Node source) { + source.asExpr() instanceof StringLiteral + or + exists(Variable v, ArrayAggregateLiteral aal | + aal = v.getInitializer().getExpr() and + // The array element type is an essentially character type + getEssentialTypeCategory(aal.getElementType()) = EssentiallyCharacterType() and + // Includes a null terminator somewhere in the array initializer + aal.getElementExpr(_).getValue().toInt() = 0 + | + // For local variables, use the array aggregate literal as the source + aal = source.asExpr() + or + // ArrayAggregateLiterals used as initializers for global variables are not viable sources + // for global data flow, so we instead report variable accesses as sources, where the variable + // is constant or is not assigned in the program + v instanceof GlobalVariable and + source.asExpr() = v.getAnAccess() and + ( + v.isConst() + or + not exists(Expr e | e = v.getAnAssignedValue() and not e = aal) + ) + ) + } + + override predicate isSink(DataFlow::Node sink) { + exists(FunctionCall memcmp | + memcmp.getTarget().hasGlobalOrStdName("memcmp") and + sink.asExpr() = memcmp.getArgument([0, 1]) + ) + } +} + +from + FunctionCall memcmp, DataFlow::PathNode source, DataFlow::PathNode sink, + DataFlow::PathNode source1, DataFlow::PathNode arg1, DataFlow::PathNode source2, + DataFlow::PathNode arg2 +where + not isExcluded(memcmp, EssentialTypesPackage::memcmpUsedToCompareNullTerminatedStringsQuery()) and + memcmp.getTarget().hasGlobalOrStdName("memcmp") and + arg1.getNode().asExpr() = memcmp.getArgument(0) and + arg2.getNode().asExpr() = memcmp.getArgument(1) and + // There is a path from a null-terminated string to each argument + exists(NullTerminatedStringToMemcmpConfiguration cfg | + cfg.hasFlowPath(source1, arg1) and + cfg.hasFlowPath(source2, arg2) + ) and + // Produce multiple paths for each result, one for each source/arg pair + ( + source = source1 and sink = arg1 + or + source = source2 and sink = arg2 + ) +select memcmp, source, sink, "memcmp used to compare $@ with $@.", source1, + "null-terminated string", source2, "null-terminated string" diff --git a/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected b/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected new file mode 100644 index 0000000000..bdfec99b4a --- /dev/null +++ b/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected @@ -0,0 +1,34 @@ +edges +| test.c:12:13:12:15 | a | test.c:14:10:14:10 | a | +| test.c:12:13:12:15 | a | test.c:23:13:23:13 | a | +| test.c:12:13:12:15 | a | test.c:24:10:24:10 | a | +| test.c:13:13:13:15 | b | test.c:14:13:14:13 | b | +| test.c:18:15:18:28 | {...} | test.c:21:10:21:10 | e | +| test.c:19:15:19:28 | {...} | test.c:21:13:21:13 | f | +nodes +| test.c:10:10:10:12 | a | semmle.label | a | +| test.c:10:15:10:17 | b | semmle.label | b | +| test.c:12:13:12:15 | a | semmle.label | a | +| test.c:13:13:13:15 | b | semmle.label | b | +| test.c:14:10:14:10 | a | semmle.label | a | +| test.c:14:13:14:13 | b | semmle.label | b | +| test.c:16:10:16:10 | c | semmle.label | c | +| test.c:16:13:16:13 | d | semmle.label | d | +| test.c:18:15:18:28 | {...} | semmle.label | {...} | +| test.c:19:15:19:28 | {...} | semmle.label | {...} | +| test.c:21:10:21:10 | e | semmle.label | e | +| test.c:21:13:21:13 | f | semmle.label | f | +| test.c:23:13:23:13 | a | semmle.label | a | +| test.c:24:10:24:10 | a | semmle.label | a | +| test.c:26:13:26:13 | c | semmle.label | c | +| test.c:27:10:27:10 | c | semmle.label | c | +subpaths +#select +| test.c:10:3:10:8 | call to memcmp | test.c:10:10:10:12 | a | test.c:10:10:10:12 | a | memcmp used to compare $@ with $@. | test.c:10:10:10:12 | a | null-terminated string | test.c:10:15:10:17 | b | null-terminated string | +| test.c:10:3:10:8 | call to memcmp | test.c:10:15:10:17 | b | test.c:10:15:10:17 | b | memcmp used to compare $@ with $@. | test.c:10:10:10:12 | a | null-terminated string | test.c:10:15:10:17 | b | null-terminated string | +| test.c:14:3:14:8 | call to memcmp | test.c:12:13:12:15 | a | test.c:14:10:14:10 | a | memcmp used to compare $@ with $@. | test.c:12:13:12:15 | a | null-terminated string | test.c:13:13:13:15 | b | null-terminated string | +| test.c:14:3:14:8 | call to memcmp | test.c:13:13:13:15 | b | test.c:14:13:14:13 | b | memcmp used to compare $@ with $@. | test.c:12:13:12:15 | a | null-terminated string | test.c:13:13:13:15 | b | null-terminated string | +| test.c:16:3:16:8 | call to memcmp | test.c:16:10:16:10 | c | test.c:16:10:16:10 | c | memcmp used to compare $@ with $@. | test.c:16:10:16:10 | c | null-terminated string | test.c:16:13:16:13 | d | null-terminated string | +| test.c:16:3:16:8 | call to memcmp | test.c:16:13:16:13 | d | test.c:16:13:16:13 | d | memcmp used to compare $@ with $@. | test.c:16:10:16:10 | c | null-terminated string | test.c:16:13:16:13 | d | null-terminated string | +| test.c:21:3:21:8 | call to memcmp | test.c:18:15:18:28 | {...} | test.c:21:10:21:10 | e | memcmp used to compare $@ with $@. | test.c:18:15:18:28 | {...} | null-terminated string | test.c:19:15:19:28 | {...} | null-terminated string | +| test.c:21:3:21:8 | call to memcmp | test.c:19:15:19:28 | {...} | test.c:21:13:21:13 | f | memcmp used to compare $@ with $@. | test.c:18:15:18:28 | {...} | null-terminated string | test.c:19:15:19:28 | {...} | null-terminated string | diff --git a/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.qlref b/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.qlref new file mode 100644 index 0000000000..99017569aa --- /dev/null +++ b/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.qlref @@ -0,0 +1 @@ +rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-14/test.c b/c/misra/test/rules/RULE-21-14/test.c new file mode 100644 index 0000000000..6ca988242e --- /dev/null +++ b/c/misra/test/rules/RULE-21-14/test.c @@ -0,0 +1,28 @@ +#include + +extern char a[10]; +extern char b[10]; + +char c[10] = {'a', 'b', 0}; +char d[10] = {'a', 'b', 0}; + +void testCmp(int *p) { + memcmp("a", "b", 1); // NON_COMPLIANT + + strcpy(a, "a"); + strcpy(b, "b"); + memcmp(a, b, 1); // NON_COMPLIANT + + memcmp(c, d, 1); // NON_COMPLIANT + + char e[10] = {'a', 'b', 0}; + char f[10] = {'a', 'b', 0}; + + memcmp(e, f, 1); // NON_COMPLIANT + + memcmp(p, a, 1); // COMPLIANT + memcmp(a, p, 1); // COMPLIANT + + memcmp(p, c, 1); // COMPLIANT + memcmp(c, p, 1); // COMPLIANT +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes.qll index 5e3be0cebb..a29e113146 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes.qll @@ -14,6 +14,7 @@ newtype EssentialTypesQuery = TImplicitConversionOfCompositeExpressionQuery() or TInappropriateCastOfCompositeExpressionQuery() or TLoopOverEssentiallyFloatTypeQuery() or + TMemcmpUsedToCompareNullTerminatedStringsQuery() or TMemcmpOnInappropriateEssentialTypeArgsQuery() predicate isEssentialTypesQueryMetadata(Query query, string queryId, string ruleId, string category) { @@ -107,6 +108,15 @@ predicate isEssentialTypesQueryMetadata(Query query, string queryId, string rule ruleId = "RULE-14-1" and category = "required" or + query = + // `Query` instance for the `memcmpUsedToCompareNullTerminatedStrings` query + EssentialTypesPackage::memcmpUsedToCompareNullTerminatedStringsQuery() and + queryId = + // `@id` for the `memcmpUsedToCompareNullTerminatedStrings` query + "c/misra/memcmp-used-to-compare-null-terminated-strings" and + ruleId = "RULE-21-14" and + category = "required" + or query = // `Query` instance for the `memcmpOnInappropriateEssentialTypeArgs` query EssentialTypesPackage::memcmpOnInappropriateEssentialTypeArgsQuery() and @@ -188,6 +198,13 @@ module EssentialTypesPackage { TQueryC(TEssentialTypesPackageQuery(TLoopOverEssentiallyFloatTypeQuery())) } + Query memcmpUsedToCompareNullTerminatedStringsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `memcmpUsedToCompareNullTerminatedStrings` query + TQueryC(TEssentialTypesPackageQuery(TMemcmpUsedToCompareNullTerminatedStringsQuery())) + } + Query memcmpOnInappropriateEssentialTypeArgsQuery() { //autogenerate `Query` type result = diff --git a/rule_packages/c/EssentialTypes.json b/rule_packages/c/EssentialTypes.json index f24b49f7c2..9bdf0a5fe7 100644 --- a/rule_packages/c/EssentialTypes.json +++ b/rule_packages/c/EssentialTypes.json @@ -190,6 +190,26 @@ ], "title": "A loop counter shall not have essentially floating type" }, + "RULE-21-14": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Using memcmp to compare null terminated strings may give unexpected results because memcmp compares by size with no consideration for the null terminator.", + "kind": "path-problem", + "name": "The Standard Library function memcmp shall not be used to compare null terminated strings", + "precision": "very-high", + "severity": "error", + "short_name": "MemcmpUsedToCompareNullTerminatedStrings", + "tags": [ + "maintainability", + "correctness" + ] + } + ], + "title": "The Standard Library function memcmp shall not be used to compare null terminated strings" + }, "RULE-21-16": { "properties": { "obligation": "required" diff --git a/rules.csv b/rules.csv index b083ee015d..6f34213f54 100644 --- a/rules.csv +++ b/rules.csv @@ -756,7 +756,7 @@ c,MISRA-C-2012,RULE-21-10,Yes,Required,,,The Standard Library time and date func c,MISRA-C-2012,RULE-21-11,Yes,Required,,,The standard header file shall not be used,,Banned,Easy, c,MISRA-C-2012,RULE-21-12,Yes,Advisory,,,The exception handling features of should not be used,,Banned,Easy, c,MISRA-C-2012,RULE-21-13,Yes,Mandatory,,,Any value passed to a function in shall be representable as an unsigned char or be the value EOF,,Types,Medium, -c,MISRA-C-2012,RULE-21-14,Yes,Required,,,The Standard Library function memcmp shall not be used to compare null terminated strings,,Types,Hard, +c,MISRA-C-2012,RULE-21-14,Yes,Required,,,The Standard Library function memcmp shall not be used to compare null terminated strings,,EssentialTypes,Hard, c,MISRA-C-2012,RULE-21-15,Yes,Required,,,"The pointer arguments to the Standard Library functions memcpy, memmove and memcmp shall be pointers to qualified or unqualified versions of compatible types",,Types,Medium, c,MISRA-C-2012,RULE-21-16,Yes,Required,,,"The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type",,EssentialTypes,Medium, c,MISRA-C-2012,RULE-21-17,Yes,Mandatory,,,Use of the string handling functions from shall not result in accesses beyond the bounds of the objects referenced by their pointer parameters,,Memory2,Hard, From 2750f695c3348dba83ae3646f55fc5c91bdce1ed Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 8 Mar 2023 10:34:16 +0000 Subject: [PATCH 23/25] EssentialTypes: Fix metadata consistency issue --- .../rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql | 2 +- rule_packages/c/EssentialTypes.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql b/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql index cebc30d6be..1a939e920c 100644 --- a/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql +++ b/c/misra/src/rules/RULE-21-16/MemcmpOnInappropriateEssentialTypeArgs.ql @@ -1,6 +1,6 @@ /** * @id c/misra/memcmp-on-inappropriate-essential-type-args - * @name RULE-21-16: Do not use memcmp on pointers to characters or composite types such as structs and unions. + * @name RULE-21-16: Do not use memcmp on pointers to characters or composite types such as structs and unions * @description The pointer arguments to the Standard Library function memcmp shall point to either * a pointer type, an essentially signed type, an essentially unsigned type, an * essentially Boolean type or an essentially enum type. diff --git a/rule_packages/c/EssentialTypes.json b/rule_packages/c/EssentialTypes.json index 9bdf0a5fe7..57c7ace1ba 100644 --- a/rule_packages/c/EssentialTypes.json +++ b/rule_packages/c/EssentialTypes.json @@ -218,7 +218,7 @@ { "description": "The pointer arguments to the Standard Library function memcmp shall point to either a pointer type, an essentially signed type, an essentially unsigned type, an essentially Boolean type or an essentially enum type.", "kind": "problem", - "name": "Do not use memcmp on pointers to characters or composite types such as structs and unions.", + "name": "Do not use memcmp on pointers to characters or composite types such as structs and unions", "precision": "very-high", "severity": "error", "short_name": "MemcmpOnInappropriateEssentialTypeArgs", From bf1ee22e9abf7817f401117212dc06433959eb75 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Wed, 8 Mar 2023 23:27:01 +0000 Subject: [PATCH 24/25] EssentialTypes: Handle boolean type defs The computation of essential type category was incorrect when the type was a typedef of a boolean. --- c/misra/src/codingstandards/c/misra/EssentialTypes.qll | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 3acb041139..697a24513f 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -78,8 +78,11 @@ private IntegralType stlr(Expr const) { */ EssentialTypeCategory getEssentialTypeCategory(Type type) { exists(Type essentialType | - // Resolve typedefs to ensure - essentialType = type.getUnspecifiedType() + if type instanceof MisraBoolType + then essentialType = type + else + // If not a bool type, resolve the typedefs to determine the actual type + essentialType = type.getUnspecifiedType() | result = EssentiallyBooleanType() and essentialType instanceof MisraBoolType or From 4e477e90f0008f47a6a2c12dec62759885c65c59 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Wed, 8 Mar 2023 23:31:04 +0000 Subject: [PATCH 25/25] EssentialTypes: Make switch cases valid Compiler testing showed that the switch cases were not valid as they required a statement. Added breaks to satisfy this condition. --- c/misra/test/rules/RULE-10-3/test.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/c/misra/test/rules/RULE-10-3/test.c b/c/misra/test/rules/RULE-10-3/test.c index 1eb065e58b..30ab2985ae 100644 --- a/c/misra/test/rules/RULE-10-3/test.c +++ b/c/misra/test/rules/RULE-10-3/test.c @@ -131,7 +131,7 @@ void testSwitchCase() { case A: // NON_COMPLIANT case 100: // NON_COMPLIANT case ((unsigned int)200): // NON_COMPLIANT - // case 1.0f: // NON_COMPILABLE + break; // case 1.0f: // NON_COMPILABLE } switch (e1) { @@ -139,7 +139,7 @@ void testSwitchCase() { case A: // COMPLIANT case 100: // NON_COMPLIANT case ((unsigned int)200): // NON_COMPLIANT - // case 1.0f: // NON_COMPILABLE + break; // case 1.0f: // NON_COMPILABLE } switch (s) { @@ -147,7 +147,7 @@ void testSwitchCase() { case A: // NON_COMPLIANT case 100: // COMPLIANT case ((unsigned int)200): // NON_COMPLIANT - // case 1.0f: // NON_COMPILABLE + break; // case 1.0f: // NON_COMPILABLE } switch (u) { @@ -155,7 +155,7 @@ void testSwitchCase() { case A: // NON_COMPLIANT case 100: // COMPLIANT - by exception 1 case ((unsigned int)200): // COMPLIANT - by exception 1 - // case 1.0f: // NON_COMPILABLE + break; // case 1.0f: // NON_COMPILABLE } }