From 758986867f64e813d153dd6863505405b8eca49a Mon Sep 17 00:00:00 2001 From: s-samadi Date: Fri, 18 Nov 2022 10:56:34 +1100 Subject: [PATCH 01/76] moved M-4-4 to common lib --- .../src/rules/M6-4-4/NestedCaseInSwitch.ql | 18 ++--- .../rules/M6-4-4/NestedCaseInSwitch.expected | 3 - .../rules/M6-4-4/NestedCaseInSwitch.qlref | 1 - .../rules/M6-4-4/NestedCaseInSwitch.testref | 1 + cpp/autosar/test/rules/M6-4-4/test.cpp | 79 ------------------ .../NestedLabelInSwitch.qll | 25 ++++++ .../NestedLabelInSwitch.expected | 1 + .../NestedLabelInSwitch.ql | 2 + .../test/rules/nestedlabelinswitch/test.cpp | 80 +++++++++++++++++++ rule_packages/cpp/Conditionals.json | 5 +- 10 files changed, 119 insertions(+), 96 deletions(-) delete mode 100644 cpp/autosar/test/rules/M6-4-4/NestedCaseInSwitch.expected delete mode 100644 cpp/autosar/test/rules/M6-4-4/NestedCaseInSwitch.qlref create mode 100644 cpp/autosar/test/rules/M6-4-4/NestedCaseInSwitch.testref delete mode 100644 cpp/autosar/test/rules/M6-4-4/test.cpp create mode 100644 cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll create mode 100644 cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected create mode 100644 cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.ql create mode 100644 cpp/common/test/rules/nestedlabelinswitch/test.cpp diff --git a/cpp/autosar/src/rules/M6-4-4/NestedCaseInSwitch.ql b/cpp/autosar/src/rules/M6-4-4/NestedCaseInSwitch.ql index 18c07b8eea..c984053464 100644 --- a/cpp/autosar/src/rules/M6-4-4/NestedCaseInSwitch.ql +++ b/cpp/autosar/src/rules/M6-4-4/NestedCaseInSwitch.ql @@ -1,8 +1,7 @@ /** * @id cpp/autosar/nested-case-in-switch * @name M6-4-4: A switch-label shall only be used when the most closely-enclosing compound statement is the body of a switch statement - * @description By default in C++, the switch structure is weak, which may lead to switch labels - * being placed anywhere in the switch block. This can cause unspecified behaviour. + * @description Nested switch labels cause undefined behaviour. * @kind problem * @precision very-high * @problem.severity recommendation @@ -16,13 +15,10 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.SwitchStatement +import codingstandards.cpp.rules.nestedlabelinswitch.NestedLabelInSwitch -from SwitchCase nestedCase, SwitchStmt switch -where - not isExcluded(nestedCase, ConditionalsPackage::nestedCaseInSwitchQuery()) and - switch.getASwitchCase() = nestedCase and - not nestedCase.getParentStmt() = switch.getChildStmt() -select nestedCase, - "Weak switch structure - the parent statement of this $@ clause does not belong to its $@ statement.", - switch, "switch", nestedCase, "case" +class NestedCaseInSwitchQuery extends NestedLabelInSwitchSharedQuery { + NestedCaseInSwitchQuery() { + this = ConditionalsPackage::nestedCaseInSwitchQuery() + } +} diff --git a/cpp/autosar/test/rules/M6-4-4/NestedCaseInSwitch.expected b/cpp/autosar/test/rules/M6-4-4/NestedCaseInSwitch.expected deleted file mode 100644 index c9fbbdcb35..0000000000 --- a/cpp/autosar/test/rules/M6-4-4/NestedCaseInSwitch.expected +++ /dev/null @@ -1,3 +0,0 @@ -| test.cpp:9:5:9:11 | case ...: | Weak switch structure - the parent statement of this $@ clause does not belong to its $@ statement. | test.cpp:6:3:17:3 | switch (...) ... | switch | test.cpp:9:5:9:11 | case ...: | case | -| test.cpp:36:5:36:11 | case ...: | Weak switch structure - the parent statement of this $@ clause does not belong to its $@ statement. | test.cpp:23:3:43:3 | switch (...) ... | switch | test.cpp:36:5:36:11 | case ...: | case | -| test.cpp:75:5:75:11 | case ...: | Weak switch structure - the parent statement of this $@ clause does not belong to its $@ statement. | test.cpp:73:3:78:3 | switch (...) ... | switch | test.cpp:75:5:75:11 | case ...: | case | diff --git a/cpp/autosar/test/rules/M6-4-4/NestedCaseInSwitch.qlref b/cpp/autosar/test/rules/M6-4-4/NestedCaseInSwitch.qlref deleted file mode 100644 index ad5727e1dc..0000000000 --- a/cpp/autosar/test/rules/M6-4-4/NestedCaseInSwitch.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M6-4-4/NestedCaseInSwitch.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-4-4/NestedCaseInSwitch.testref b/cpp/autosar/test/rules/M6-4-4/NestedCaseInSwitch.testref new file mode 100644 index 0000000000..6c5434b0e2 --- /dev/null +++ b/cpp/autosar/test/rules/M6-4-4/NestedCaseInSwitch.testref @@ -0,0 +1 @@ +cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-4-4/test.cpp b/cpp/autosar/test/rules/M6-4-4/test.cpp deleted file mode 100644 index 6ccd440de3..0000000000 --- a/cpp/autosar/test/rules/M6-4-4/test.cpp +++ /dev/null @@ -1,79 +0,0 @@ -void f(); - -void test_switch_nested_case_invalid(int expression) { - int i = 5; - int j; - switch (expression) { - case 1: // BAD - if (i > 4) { - case 2: - j = 3; - break; - } - break; - default: - j = 5; - break; - } -} - -void test_switch_nested_case_invalid_2(int expression) { - int i = 5; - int j; - switch (expression) { - case 1: - if (i > 4) { - j = 3; - } - break; - case 2: - if (i % 2 == 0) { - j = 1; - } - case 3: - if (i % 2 == 1) { - j = 8; - case 4: // BAD - j++; - } - break; - default: - j = 5; - break; - } -} - -void test_switch_valid(int expression) { - - int i = 5; - int j; - switch (expression) { - case 1: - if (i > 4) { - j = 3; - } - break; - case 2: - if (i % 2 == 0) { - j = 1; - } - break; - case 3: - if (i % 2 == 1) { - j = 8; - } - break; - default: - j = 5; - break; - } -} - -void test_singlecase_invalid(int expression) { - switch (expression) { - { - case 1: - f(); - } - } -} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll b/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll new file mode 100644 index 0000000000..a149654c5c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll @@ -0,0 +1,25 @@ +/** + * Provides a library which includes a `problems` predicate for reporting.... + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class NestedLabelInSwitchSharedQuery extends Query { } + +Query getQuery() { result instanceof NestedLabelInSwitchSharedQuery } + +query predicate problems( + SwitchCase nestedCase, string message, SwitchCase case, string caseLabel, SwitchStmt switch, + string switchLabel +) { + not isExcluded(nestedCase, getQuery()) and + switch.getASwitchCase() = nestedCase and + not nestedCase.getParentStmt() = switch.getChildStmt() and + nestedCase = case and + message = + "The switch $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement." and + caseLabel = nestedCase.toString() and + switchLabel = switch.toString() +} diff --git a/cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected b/cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.ql b/cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.ql new file mode 100644 index 0000000000..a23fe0b2f9 --- /dev/null +++ b/cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.nestedlabelinswitch.NestedLabelInSwitch diff --git a/cpp/common/test/rules/nestedlabelinswitch/test.cpp b/cpp/common/test/rules/nestedlabelinswitch/test.cpp new file mode 100644 index 0000000000..5c04578f0b --- /dev/null +++ b/cpp/common/test/rules/nestedlabelinswitch/test.cpp @@ -0,0 +1,80 @@ +void f(); + +void f1(int p1) { + int i; + int j; + switch (p1) { + case 1: // COMPLIANT + if (i) { + case 2: // NON_COMPLIANT + j; + break; + } + break; + default: // COMPLIANT + j; + break; + } +} + +void f2(int p1) { + int i; + int j; + switch (p1) { + case 1: // COMPLIANT + if (i) { + j; + } + break; + case 2: // COMPLIANT + if (i) { + j; + } + case 3: // COMPLIANT + if (i) { + j; + case 4: // NON_COMPLIANT + j; + } + break; + default: // COMPLIANT + j; + break; + } +} + +void f3(int p1) { + + int i; + int j; + switch (p1) { + case 1: // COMPLIANT + if (i) { + j; + } + break; + case 2: // COMPLIANT + if (i) { + j; + } + break; + case 3: // COMPLIANT + if (i) { + j; + } + break; + default: // COMPLIANT + j; + break; + } +} + +void f4(int p1) { + switch (p1) { + int i; + if (i) { + case 1: // NON_COMPLIANT + f(); + } + } +} diff --git a/rule_packages/cpp/Conditionals.json b/rule_packages/cpp/Conditionals.json index 4c382a06e9..5f6a120d16 100644 --- a/rule_packages/cpp/Conditionals.json +++ b/rule_packages/cpp/Conditionals.json @@ -190,12 +190,13 @@ }, "queries": [ { - "description": "By default in C++, the switch structure is weak, which may lead to switch labels being placed anywhere in the switch block. This can cause unspecified behaviour.", + "description": "Nested switch labels cause undefined behaviour.", "kind": "problem", "name": "A switch-label shall only be used when the most closely-enclosing compound statement is the body of a switch statement", "precision": "very-high", "severity": "recommendation", "short_name": "NestedCaseInSwitch", + "shared_implementation_short_name": "NestedLabelInSwitch", "tags": [ "maintainability", "readability" @@ -361,4 +362,4 @@ "title": "The continue statement shall only be used within a well-formed for loop." } } -} \ No newline at end of file +} From 32391bb8ecdf33bc03f1d0433cf434142a1732df Mon Sep 17 00:00:00 2001 From: s-samadi Date: Fri, 18 Nov 2022 16:04:54 +1100 Subject: [PATCH 02/76] added Statements1 package and generated files --- .../cpp/exclusions/c/Statements1.qll | 74 +++++++++++++++++ rule_packages/c/Statements1.json | 82 +++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Statements1.qll create mode 100644 rule_packages/c/Statements1.json diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Statements1.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements1.qll new file mode 100644 index 0000000000..566399fc44 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements1.qll @@ -0,0 +1,74 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Statements1Query = + TNestSwitchLabelInSwitchStatementQuery() or + TBreakShallTerminateSwitchClauseQuery() or + TEverySwitchShallHaveDefaultLabelQuery() or + TDefaultNotFirstOrLastOfSwitchQuery() + +predicate isStatements1QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `nestSwitchLabelInSwitchStatement` query + Statements1Package::nestSwitchLabelInSwitchStatementQuery() and + queryId = + // `@id` for the `nestSwitchLabelInSwitchStatement` query + "c/misra/nest-switch-label-in-switch-statement" and + ruleId = "RULE-16-2" + or + query = + // `Query` instance for the `breakShallTerminateSwitchClause` query + Statements1Package::breakShallTerminateSwitchClauseQuery() and + queryId = + // `@id` for the `breakShallTerminateSwitchClause` query + "c/misra/break-shall-terminate-switch-clause" and + ruleId = "RULE-16-3" + or + query = + // `Query` instance for the `everySwitchShallHaveDefaultLabel` query + Statements1Package::everySwitchShallHaveDefaultLabelQuery() and + queryId = + // `@id` for the `everySwitchShallHaveDefaultLabel` query + "c/misra/every-switch-shall-have-default-label" and + ruleId = "RULE-16-4" + or + query = + // `Query` instance for the `defaultNotFirstOrLastOfSwitch` query + Statements1Package::defaultNotFirstOrLastOfSwitchQuery() and + queryId = + // `@id` for the `defaultNotFirstOrLastOfSwitch` query + "c/misra/default-not-first-or-last-of-switch" and + ruleId = "RULE-16-5" +} + +module Statements1Package { + Query nestSwitchLabelInSwitchStatementQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nestSwitchLabelInSwitchStatement` query + TQueryC(TStatements1PackageQuery(TNestSwitchLabelInSwitchStatementQuery())) + } + + Query breakShallTerminateSwitchClauseQuery() { + //autogenerate `Query` type + result = + // `Query` type for `breakShallTerminateSwitchClause` query + TQueryC(TStatements1PackageQuery(TBreakShallTerminateSwitchClauseQuery())) + } + + Query everySwitchShallHaveDefaultLabelQuery() { + //autogenerate `Query` type + result = + // `Query` type for `everySwitchShallHaveDefaultLabel` query + TQueryC(TStatements1PackageQuery(TEverySwitchShallHaveDefaultLabelQuery())) + } + + Query defaultNotFirstOrLastOfSwitchQuery() { + //autogenerate `Query` type + result = + // `Query` type for `defaultNotFirstOrLastOfSwitch` query + TQueryC(TStatements1PackageQuery(TDefaultNotFirstOrLastOfSwitchQuery())) + } +} diff --git a/rule_packages/c/Statements1.json b/rule_packages/c/Statements1.json new file mode 100644 index 0000000000..43c88481cf --- /dev/null +++ b/rule_packages/c/Statements1.json @@ -0,0 +1,82 @@ +{ + "MISRA-C-2012": { + "RULE-16-2": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Nested switch labels cause undefined behaviour.", + "kind": "problem", + "name": "A switch label shall only be used when the most closely-enclosing compound statement is the body of", + "precision": "very-high", + "severity": "error", + "short_name": "NestSwitchLabelInSwitchStatement", + "shared_implementation_short_name": "NestedLabelInSwitch", + "tags": [ + "maintainability", + "readability" + ] + } + ], + "title": "A switch label shall only be used when the most closely-enclosing compound statement is the body of a switch statement" + }, + "RULE-16-3": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "An unterminated switch-clause occurring at the end of a switch statement may fall into switch clauses which are added later.", + "kind": "problem", + "name": "An unconditional break statement shall terminate every switch-clause", + "precision": "very-high", + "severity": "error", + "short_name": "BreakShallTerminateSwitchClause", + "tags": [ + "maintainability", + "readability" + ] + } + ], + "title": "An unconditional break statement shall terminate every switch-clause" + }, + "RULE-16-4": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The requirement for a default label is defensive programming.", + "kind": "problem", + "name": "Every switch statement shall have a default label", + "precision": "very-high", + "severity": "error", + "short_name": "EverySwitchShallHaveDefaultLabel", + "tags": [ + "maintainability", + "readability" + ] + } + ], + "title": "Every switch statement shall have a default label" + }, + "RULE-16-5": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Locating the default label is easy when it the first of last label.", + "kind": "problem", + "name": "A default label shall appear as either the first or the last switch label of a switch statement", + "precision": "very-high", + "severity": "error", + "short_name": "DefaultNotFirstOrLastOfSwitch", + "tags": [] + } + ], + "title": "A default label shall appear as either the first or the last switch label of a switch statement" + } + } +} From e98102fba319e7e1d6f28faf8128267424cf00f0 Mon Sep 17 00:00:00 2001 From: s-samadi Date: Fri, 18 Nov 2022 16:09:43 +1100 Subject: [PATCH 03/76] added RULE-16-2 --- .../NestedLabelInSwitch.expected | 3 + .../NestedLabelInSwitch.ql | 2 + .../test/rules/nestedlabelinswitch/test.c | 80 +++++++++++++++++++ .../NestSwitchLabelInSwitchStatement.ql | 22 +++++ .../NestSwitchLabelInSwitchStatement.testref | 1 + 5 files changed, 108 insertions(+) create mode 100644 c/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected create mode 100644 c/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.ql create mode 100644 c/common/test/rules/nestedlabelinswitch/test.c create mode 100644 c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql create mode 100644 c/misra/test/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.testref diff --git a/c/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected b/c/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected new file mode 100644 index 0000000000..dfc375e567 --- /dev/null +++ b/c/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected @@ -0,0 +1,3 @@ +| test.c:9:5:9:11 | case ...: | The switch $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.c:9:5:9:11 | case ...: | case ...: | test.c:6:3:17:3 | switch (...) ... | switch (...) ... | +| test.c:36:5:36:11 | case ...: | The switch $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.c:36:5:36:11 | case ...: | case ...: | test.c:23:3:43:3 | switch (...) ... | switch (...) ... | +| test.c:76:5:76:11 | case ...: | The switch $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.c:76:5:76:11 | case ...: | case ...: | test.c:73:3:79:3 | switch (...) ... | switch (...) ... | diff --git a/c/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.ql b/c/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.ql new file mode 100644 index 0000000000..a23fe0b2f9 --- /dev/null +++ b/c/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.nestedlabelinswitch.NestedLabelInSwitch diff --git a/c/common/test/rules/nestedlabelinswitch/test.c b/c/common/test/rules/nestedlabelinswitch/test.c new file mode 100644 index 0000000000..5c04578f0b --- /dev/null +++ b/c/common/test/rules/nestedlabelinswitch/test.c @@ -0,0 +1,80 @@ +void f(); + +void f1(int p1) { + int i; + int j; + switch (p1) { + case 1: // COMPLIANT + if (i) { + case 2: // NON_COMPLIANT + j; + break; + } + break; + default: // COMPLIANT + j; + break; + } +} + +void f2(int p1) { + int i; + int j; + switch (p1) { + case 1: // COMPLIANT + if (i) { + j; + } + break; + case 2: // COMPLIANT + if (i) { + j; + } + case 3: // COMPLIANT + if (i) { + j; + case 4: // NON_COMPLIANT + j; + } + break; + default: // COMPLIANT + j; + break; + } +} + +void f3(int p1) { + + int i; + int j; + switch (p1) { + case 1: // COMPLIANT + if (i) { + j; + } + break; + case 2: // COMPLIANT + if (i) { + j; + } + break; + case 3: // COMPLIANT + if (i) { + j; + } + break; + default: // COMPLIANT + j; + break; + } +} + +void f4(int p1) { + switch (p1) { + int i; + if (i) { + case 1: // NON_COMPLIANT + f(); + } + } +} diff --git a/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql b/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql new file mode 100644 index 0000000000..2c35b5a185 --- /dev/null +++ b/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/nest-switch-label-in-switch-statement + * @name RULE-16-2: A switch label shall only be used when the most closely-enclosing compound statement is the body of + * @description Nested switch labels cause undefined behaviour. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-16-2 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.nestedlabelinswitch.NestedLabelInSwitch + +class NestSwitchLabelInSwitchStatementQuery extends NestedLabelInSwitchSharedQuery { + NestSwitchLabelInSwitchStatementQuery() { + this = Statements1Package::nestSwitchLabelInSwitchStatementQuery() + } +} diff --git a/c/misra/test/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.testref b/c/misra/test/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.testref new file mode 100644 index 0000000000..329212287e --- /dev/null +++ b/c/misra/test/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.testref @@ -0,0 +1 @@ +c/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.ql \ No newline at end of file From 9e68f0bbdd63d17956c61784cf6c9863ed093208 Mon Sep 17 00:00:00 2001 From: s-samadi Date: Fri, 18 Nov 2022 16:11:23 +1100 Subject: [PATCH 04/76] updated rules.csv for Statements1 package and refactored rule 16-2 into common folder --- .../cpp/exclusions/c/RuleMetadata.qll | 3 +++ .../NestedLabelInSwitch.expected | 4 +++- rules.csv | 13 +++++++------ 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index ad05d9b737..7adcb322a9 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -31,6 +31,7 @@ import Preprocessor4 import Preprocessor5 import SideEffects1 import SideEffects2 +import Statements1 import Strings1 import Strings2 import Strings3 @@ -67,6 +68,7 @@ newtype TCQuery = TPreprocessor5PackageQuery(Preprocessor5Query q) or TSideEffects1PackageQuery(SideEffects1Query q) or TSideEffects2PackageQuery(SideEffects2Query q) or + TStatements1PackageQuery(Statements1Query q) or TStrings1PackageQuery(Strings1Query q) or TStrings2PackageQuery(Strings2Query q) or TStrings3PackageQuery(Strings3Query q) or @@ -103,6 +105,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId) { isPreprocessor5QueryMetadata(query, queryId, ruleId) or isSideEffects1QueryMetadata(query, queryId, ruleId) or isSideEffects2QueryMetadata(query, queryId, ruleId) or + isStatements1QueryMetadata(query, queryId, ruleId) or isStrings1QueryMetadata(query, queryId, ruleId) or isStrings2QueryMetadata(query, queryId, ruleId) or isStrings3QueryMetadata(query, queryId, ruleId) or diff --git a/cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected b/cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected index 2ec1a0ac6c..79c75b75e3 100644 --- a/cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected +++ b/cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected @@ -1 +1,3 @@ -No expected results have yet been specified \ No newline at end of file +| test.cpp:9:5:9:11 | case ...: | The switch $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.cpp:9:5:9:11 | case ...: | case ...: | test.cpp:6:3:17:3 | switch (...) ... | switch (...) ... | +| test.cpp:36:5:36:11 | case ...: | The switch $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.cpp:36:5:36:11 | case ...: | case ...: | test.cpp:23:3:43:3 | switch (...) ... | switch (...) ... | +| test.cpp:76:5:76:11 | case ...: | The switch $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.cpp:76:5:76:11 | case ...: | case ...: | test.cpp:73:3:79:3 | switch (...) ... | switch (...) ... | diff --git a/rules.csv b/rules.csv index ec8b29eaf9..d2f0450b32 100644 --- a/rules.csv +++ b/rules.csv @@ -511,7 +511,7 @@ c,CERT-C,ENV31-C,Yes,Rule,,,Do not rely on an environment pointer following an o c,CERT-C,ENV32-C,Yes,Rule,,,All exit handlers must return normally,,Contracts2,Medium, c,CERT-C,ENV33-C,Yes,Rule,,,Do not call system(),"RULE-21-21, M18-0-3",Banned,Easy, c,CERT-C,ENV34-C,Yes,Rule,,,Do not store pointers returned by certain functions,RULE-21-20,Contracts2,Medium, -c,CERT-C,ERR30-C,Yes,Rule,,,"Take care when reading errno",M19-3-1,Contracts4,Hard, +c,CERT-C,ERR30-C,Yes,Rule,,,Take care when reading errno,M19-3-1,Contracts4,Hard, c,CERT-C,ERR32-C,Yes,Rule,,,Do not rely on indeterminate values of errno,,Contracts,Hard, c,CERT-C,ERR33-C,Yes,Rule,,,Detect and handle standard library errors,MEM52-CPP,Contracts,Hard, c,CERT-C,ERR34-C,OutOfScope,Rule,,,Detect errors when converting a string to a number,,,, @@ -705,10 +705,10 @@ c,MISRA-C-2012,RULE-15-5,Yes,Advisory,,,A function should have a single point of c,MISRA-C-2012,RULE-15-6,Yes,Required,,,The body of an iteration-statement or a selection-statement shall be a compund-statement,M6-3-1,Statements,Import, c,MISRA-C-2012,RULE-15-7,Yes,Required,,,All if / else if constructs shall be terminated with an else statement,M6-4-2,Statements,Import, c,MISRA-C-2012,RULE-16-1,Yes,Required,,,All switch statements shall be well-formed,M6-4-3,Statements,Import, -c,MISRA-C-2012,RULE-16-2,Yes,Required,,,A switch label shall only be used when the most closely-enclosing compound statement is the body of a switch statement,M6-4-4,Statements,Import, -c,MISRA-C-2012,RULE-16-3,Yes,Required,,,An unconditional break statement shall terminate every switch-clause,M6-4-5,Statements,Import, -c,MISRA-C-2012,RULE-16-4,Yes,Required,,,Every switch statement shall have a default label,M6-4-6,Statements,Easy, -c,MISRA-C-2012,RULE-16-5,Yes,Required,,,A default label shall appear as either the first or the last switch label of a switch statement,M6-4-6,Statements,Easy, +c,MISRA-C-2012,RULE-16-2,Yes,Required,,,A switch label shall only be used when the most closely-enclosing compound statement is the body of a switch statement,M6-4-4,Statements1,Import, +c,MISRA-C-2012,RULE-16-3,Yes,Required,,,An unconditional break statement shall terminate every switch-clause,M6-4-5,Statements1,Import, +c,MISRA-C-2012,RULE-16-4,Yes,Required,,,Every switch statement shall have a default label,M6-4-6,Statements1,Easy, +c,MISRA-C-2012,RULE-16-5,Yes,Required,,,A default label shall appear as either the first or the last switch label of a switch statement,M6-4-6,Statements1,Easy, c,MISRA-C-2012,RULE-16-6,Yes,Required,,,Every switch statement shall have at least two switch-clauses,A6-4-1,Statements,Medium, c,MISRA-C-2012,RULE-16-7,Yes,Required,,,A switch-expression shall not have essentially Boolean type,M6-4-7,Statements,Medium, c,MISRA-C-2012,RULE-17-1,Yes,Required,,,The features of shall not be used,,Banned,Easy, @@ -762,7 +762,7 @@ c,MISRA-C-2012,RULE-21-16,Yes,Required,,,"The pointer arguments to the Standard 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, -c,MISRA-C-2012,RULE-21-20,Yes,Mandatory,,,"The pointer returned by the Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror shall not be used following a subsequent call to the same function","ENV34-C",Contracts2,Import, +c,MISRA-C-2012,RULE-21-20,Yes,Mandatory,,,"The pointer returned by the Standard Library functions asctime, ctime, gmtime, localtime, localeconv, getenv, setlocale or strerror shall not be used following a subsequent call to the same function",ENV34-C,Contracts2,Import, c,MISRA-C-2012,RULE-21-21,Yes,Required,,,The Standard Library function system of shall not be used,ENV33-C,Banned,Import, c,MISRA-C-2012,RULE-22-1,Yes,Required,,,All resources obtained dynamically by means of Standard Library functions shall be explicitly released,,Memory,Hard, c,MISRA-C-2012,RULE-22-2,Yes,Mandatory,,,A block of memory shall only be freed if it was allocated by means of a Standard Library function,,Memory,Hard, @@ -774,3 +774,4 @@ c,MISRA-C-2012,RULE-22-7,Yes,Required,,,The macro EOF shall only be compared wit c,MISRA-C-2012,RULE-22-8,Yes,Required,,,The value of errno shall be set to zero prior to a call to an errno-setting-function,ERR30-C,Contracts3,Medium, c,MISRA-C-2012,RULE-22-9,Yes,Required,,,The value of errno shall be tested against zero after calling an errno-setting-function,,Contracts3,Medium, c,MISRA-C-2012,RULE-22-10,Yes,Required,,,The value of errno shall only be tested when the last function to be called was an errno-setting-function,,Contracts3,Medium, +,,,,,,,,,,0, \ No newline at end of file From c90f56606dc5081d840d699304a87b90b36e1701 Mon Sep 17 00:00:00 2001 From: s-samadi Date: Sat, 19 Nov 2022 12:24:45 +1100 Subject: [PATCH 05/76] Added rules and tests for RULE-16-3, RULE-16-4, RULE-16-5 --- .../BreakShallTerminateSwitchClause.ql | 23 ++++++++ .../EverySwitchShallHaveDefaultLabel.ql | 32 ++++++++++++ .../DefaultNotFirstOrLastOfSwitch.ql | 23 ++++++++ .../BreakShallTerminateSwitchClause.expected | 3 ++ .../BreakShallTerminateSwitchClause.qlref | 1 + c/misra/test/rules/RULE-16-3/test.c | 41 +++++++++++++++ .../EverySwitchShallHaveDefaultLabel.expected | 2 + .../EverySwitchShallHaveDefaultLabel.qlref | 1 + c/misra/test/rules/RULE-16-4/test.c | 52 +++++++++++++++++++ .../DefaultNotFirstOrLastOfSwitch.expected | 1 + .../DefaultNotFirstOrLastOfSwitch.qlref | 1 + c/misra/test/rules/RULE-16-5/test.c | 34 ++++++++++++ 12 files changed, 214 insertions(+) create mode 100644 c/misra/src/rules/RULE-16-3/BreakShallTerminateSwitchClause.ql create mode 100644 c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql create mode 100644 c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql create mode 100644 c/misra/test/rules/RULE-16-3/BreakShallTerminateSwitchClause.expected create mode 100644 c/misra/test/rules/RULE-16-3/BreakShallTerminateSwitchClause.qlref create mode 100644 c/misra/test/rules/RULE-16-3/test.c create mode 100644 c/misra/test/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.expected create mode 100644 c/misra/test/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.qlref create mode 100644 c/misra/test/rules/RULE-16-4/test.c create mode 100644 c/misra/test/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.expected create mode 100644 c/misra/test/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.qlref create mode 100644 c/misra/test/rules/RULE-16-5/test.c diff --git a/c/misra/src/rules/RULE-16-3/BreakShallTerminateSwitchClause.ql b/c/misra/src/rules/RULE-16-3/BreakShallTerminateSwitchClause.ql new file mode 100644 index 0000000000..04cd95a6fe --- /dev/null +++ b/c/misra/src/rules/RULE-16-3/BreakShallTerminateSwitchClause.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/break-shall-terminate-switch-clause + * @name RULE-16-3: An unconditional break statement shall terminate every switch-clause + * @description An unterminated switch-clause occurring at the end of a switch statement may fall + * into switch clauses which are added later. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-16-3 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from SwitchCase case +where + not isExcluded(case, Statements1Package::breakShallTerminateSwitchClauseQuery()) and + not case.terminatesInBreakStmt() and + not case.getFollowingStmt() instanceof SwitchCase +select case, "The switch $@ does not terminate with a break statement.", case, "clause" diff --git a/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql b/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql new file mode 100644 index 0000000000..c857690e84 --- /dev/null +++ b/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql @@ -0,0 +1,32 @@ +/** + * @id c/misra/every-switch-shall-have-default-label + * @name RULE-16-4: Every switch statement shall have a default label + * @description The requirement for a default label is defensive programming. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-16-4 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from SwitchStmt switch, string message +where + not isExcluded(switch, Statements1Package::everySwitchShallHaveDefaultLabelQuery()) and + not switch.hasDefaultCase() and + message = "has missing default clause." + or + exists(SwitchCase case, BreakStmt break | + switch.getDefaultCase() = case and + case.getFollowingStmt() = break and + not exists(Comment comment | + break.getLocation().getEndLine() - 1 = comment.getLocation().getEndLine() + ) and + message = + "has default label that does not terminate in a statement or comment before break statement" + ) +select switch, "$@ statement " + message, switch, "Switch" diff --git a/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql b/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql new file mode 100644 index 0000000000..457fd4ba2f --- /dev/null +++ b/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/default-not-first-or-last-of-switch + * @name RULE-16-5: A default label shall appear as either the first or the last switch label of a switch statement + * @description Locating the default label is easy when it the first of last label. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-16-5 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.SwitchStatement + +from SwitchStmt switch, SwitchCase defaultCase +where + not isExcluded(switch, Statements1Package::defaultNotFirstOrLastOfSwitchQuery()) and + switch.getDefaultCase() = defaultCase and + exists(defaultCase.getPreviousSwitchCase()) and + finalClauseInSwitchNotDefault(switch) +select defaultCase, "$@ statement does not have $@ case as first or last switch label.", switch, + "Switch", defaultCase, "default" diff --git a/c/misra/test/rules/RULE-16-3/BreakShallTerminateSwitchClause.expected b/c/misra/test/rules/RULE-16-3/BreakShallTerminateSwitchClause.expected new file mode 100644 index 0000000000..3a97de439c --- /dev/null +++ b/c/misra/test/rules/RULE-16-3/BreakShallTerminateSwitchClause.expected @@ -0,0 +1,3 @@ +| test.c:11:3:11:9 | case ...: | The switch $@ does not terminate with a break statement. | test.c:11:3:11:9 | case ...: | clause | +| test.c:14:3:14:9 | case ...: | The switch $@ does not terminate with a break statement. | test.c:14:3:14:9 | case ...: | clause | +| test.c:26:3:26:10 | default: | The switch $@ does not terminate with a break statement. | test.c:26:3:26:10 | default: | clause | diff --git a/c/misra/test/rules/RULE-16-3/BreakShallTerminateSwitchClause.qlref b/c/misra/test/rules/RULE-16-3/BreakShallTerminateSwitchClause.qlref new file mode 100644 index 0000000000..9764f620d0 --- /dev/null +++ b/c/misra/test/rules/RULE-16-3/BreakShallTerminateSwitchClause.qlref @@ -0,0 +1 @@ +rules/RULE-16-3/BreakShallTerminateSwitchClause.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-16-3/test.c b/c/misra/test/rules/RULE-16-3/test.c new file mode 100644 index 0000000000..bfd21d9823 --- /dev/null +++ b/c/misra/test/rules/RULE-16-3/test.c @@ -0,0 +1,41 @@ +void f1(int p1) { + int i; + int j; + switch (p1) { + case 1: // COMPLIANT + break; + case 2: // COMPLIANT + case 3: // COMPLIANT + case 4: // COMPLIANT + break; + case 5: // NON_COMPLIANT + i = j; + j++; + case 6: // NON_COMPLIANT + if (i > j) { + j++; + i++; + break; + } + case 7: // COMPLIANT + if (i > j) { + j++; + i++; + } + break; + default: // NON_COMPLIANT + ; + } +} + +void f2(int p1) { + switch (p1) { + case 1: // COMPLIANT + break; + case 2: // COMPLIANT + case 3: // COMPLIANT + case 4: // COMPLIANT + default: // COMPLIANT + break; + } +} diff --git a/c/misra/test/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.expected b/c/misra/test/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.expected new file mode 100644 index 0000000000..008b1513e8 --- /dev/null +++ b/c/misra/test/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.expected @@ -0,0 +1,2 @@ +| test.c:4:3:12:3 | switch (...) ... | $@ statement has missing default clause. | test.c:4:3:12:3 | switch (...) ... | Switch | +| test.c:13:3:22:3 | switch (...) ... | $@ statement has default label that does not terminate in a statement or comment before break statement | test.c:13:3:22:3 | switch (...) ... | Switch | diff --git a/c/misra/test/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.qlref b/c/misra/test/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.qlref new file mode 100644 index 0000000000..394a5e941a --- /dev/null +++ b/c/misra/test/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.qlref @@ -0,0 +1 @@ +rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-16-4/test.c b/c/misra/test/rules/RULE-16-4/test.c new file mode 100644 index 0000000000..7c2f2b210d --- /dev/null +++ b/c/misra/test/rules/RULE-16-4/test.c @@ -0,0 +1,52 @@ +void f1(int p1) { + int i; + int j; + switch (p1) { // NON COMPLIANT + case 1: + i++; + j++; + break; + case 2: + case 3: + break; + } + switch (p1) { // NON_COMPLIANT + case 1: + i++; + break; + case 2: + j++; + break; + default: + break; + } + switch (p1) { // COMPLIANT + case 1: + i++; + break; + case 2: + j++; + break; + default: + // codeql + break; + } + + switch (p1) { // COMPLIANT + case 1: + i++; + break; + default: + j++; + break; + } + switch (p1) { // COMPLIANT + case 1: + i++; + break; + default: + j++; + i++; + break; + } +} diff --git a/c/misra/test/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.expected b/c/misra/test/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.expected new file mode 100644 index 0000000000..a17969c296 --- /dev/null +++ b/c/misra/test/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.expected @@ -0,0 +1 @@ +| test.c:16:3:16:10 | default: | $@ statement does not have $@ case as first or last switch label. | test.c:12:3:22:3 | switch (...) ... | Switch | test.c:16:3:16:10 | default: | default | diff --git a/c/misra/test/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.qlref b/c/misra/test/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.qlref new file mode 100644 index 0000000000..00e2e8aedf --- /dev/null +++ b/c/misra/test/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.qlref @@ -0,0 +1 @@ +rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-16-5/test.c b/c/misra/test/rules/RULE-16-5/test.c new file mode 100644 index 0000000000..37d96bb0af --- /dev/null +++ b/c/misra/test/rules/RULE-16-5/test.c @@ -0,0 +1,34 @@ +void f1(int p1) { + int i; + int j; + switch (p1) { + default: // COMPLIANT + i++; + break; + case 1: + j++; + break; + } + switch (p1) { + case 1: + i++; + break; + default: // NON_COMPLIANT + j++; + break; + case 2: + i++; + break; + } + switch (p1) { + case 1: + i++; + break; + case 2: + j++; + break; + default: // COMPLIANT + i++; + break; + } +} From 5745732a4d908e0602d1a91ff508a74b62d8dbed Mon Sep 17 00:00:00 2001 From: s-samadi Date: Sat, 19 Nov 2022 12:33:21 +1100 Subject: [PATCH 06/76] Fixed formatting issue for test RULE-16-3 --- c/misra/test/rules/RULE-16-3/test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/misra/test/rules/RULE-16-3/test.c b/c/misra/test/rules/RULE-16-3/test.c index bfd21d9823..ae009174eb 100644 --- a/c/misra/test/rules/RULE-16-3/test.c +++ b/c/misra/test/rules/RULE-16-3/test.c @@ -24,7 +24,7 @@ void f1(int p1) { } break; default: // NON_COMPLIANT - ; + i++; } } From 321aee180ae54ab350045710315b0e2ed8379c18 Mon Sep 17 00:00:00 2001 From: Shadi Samadi <68650974+s-samadi@users.noreply.github.com> Date: Tue, 21 Feb 2023 12:09:05 +1100 Subject: [PATCH 07/76] Update cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll Co-authored-by: Remco Vermeulen --- .../cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll b/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll index a149654c5c..22e977f2d3 100644 --- a/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll +++ b/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll @@ -1,5 +1,5 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library which includes a `problems` predicate for reporting nested labels in a switch statement. */ import cpp From c9a7b57b0beaacb89e3e0ff4777da232b36433ca Mon Sep 17 00:00:00 2001 From: Shadi Samadi <68650974+s-samadi@users.noreply.github.com> Date: Tue, 21 Feb 2023 12:09:25 +1100 Subject: [PATCH 08/76] Update cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll Co-authored-by: Remco Vermeulen --- .../cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll b/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll index 22e977f2d3..0e0156cb90 100644 --- a/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll +++ b/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll @@ -11,7 +11,7 @@ abstract class NestedLabelInSwitchSharedQuery extends Query { } Query getQuery() { result instanceof NestedLabelInSwitchSharedQuery } query predicate problems( - SwitchCase nestedCase, string message, SwitchCase case, string caseLabel, SwitchStmt switch, + SwitchCase case, string message, Location caseLocation, string caseLabel, SwitchStmt switch, string switchLabel ) { not isExcluded(nestedCase, getQuery()) and From 21a44326770a8d1b6e7d1fe630fc9dcb7dcbd4b7 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 21 Feb 2023 13:15:58 +1100 Subject: [PATCH 09/76] updated rule metadata based on PR feedback --- .../RULE-16-2/NestSwitchLabelInSwitchStatement.ql | 6 +++--- .../cpp/exclusions/c/RuleMetadata.qll | 1 + .../cpp/exclusions/c/Statements1.qll | 14 +++++++++----- .../nestedlabelinswitch/NestedLabelInSwitch.qll | 4 ++-- rule_packages/c/Statements1.json | 6 +++--- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql b/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql index 2c35b5a185..1cab75f6bf 100644 --- a/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql +++ b/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql @@ -1,10 +1,10 @@ /** * @id c/misra/nest-switch-label-in-switch-statement - * @name RULE-16-2: A switch label shall only be used when the most closely-enclosing compound statement is the body of - * @description Nested switch labels cause undefined behaviour. + * @name RULE-16-2: Nested switch labels shall not be used. + * @description Nested switch labels can lead to unstructured code. * @kind problem * @precision very-high - * @problem.severity error + * @problem.severity recommendation * @tags external/misra/id/rule-16-2 * maintainability * readability diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 166e8b3b59..022b57dcbf 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -138,6 +138,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isPreprocessor6QueryMetadata(query, queryId, ruleId, category) or isSideEffects1QueryMetadata(query, queryId, ruleId, category) or isSideEffects2QueryMetadata(query, queryId, ruleId, category) or + isStatements1QueryMetadata(query, queryId, ruleId, category) or isStrings1QueryMetadata(query, queryId, ruleId, category) or isStrings2QueryMetadata(query, queryId, ruleId, category) or isStrings3QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Statements1.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements1.qll index 566399fc44..88ea77c7d4 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Statements1.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements1.qll @@ -9,14 +9,15 @@ newtype Statements1Query = TEverySwitchShallHaveDefaultLabelQuery() or TDefaultNotFirstOrLastOfSwitchQuery() -predicate isStatements1QueryMetadata(Query query, string queryId, string ruleId) { +predicate isStatements1QueryMetadata(Query query, string queryId, string ruleId, string category) { query = // `Query` instance for the `nestSwitchLabelInSwitchStatement` query Statements1Package::nestSwitchLabelInSwitchStatementQuery() and queryId = // `@id` for the `nestSwitchLabelInSwitchStatement` query "c/misra/nest-switch-label-in-switch-statement" and - ruleId = "RULE-16-2" + ruleId = "RULE-16-2" and + category = "required" or query = // `Query` instance for the `breakShallTerminateSwitchClause` query @@ -24,7 +25,8 @@ predicate isStatements1QueryMetadata(Query query, string queryId, string ruleId) queryId = // `@id` for the `breakShallTerminateSwitchClause` query "c/misra/break-shall-terminate-switch-clause" and - ruleId = "RULE-16-3" + ruleId = "RULE-16-3" and + category = "required" or query = // `Query` instance for the `everySwitchShallHaveDefaultLabel` query @@ -32,7 +34,8 @@ predicate isStatements1QueryMetadata(Query query, string queryId, string ruleId) queryId = // `@id` for the `everySwitchShallHaveDefaultLabel` query "c/misra/every-switch-shall-have-default-label" and - ruleId = "RULE-16-4" + ruleId = "RULE-16-4" and + category = "required" or query = // `Query` instance for the `defaultNotFirstOrLastOfSwitch` query @@ -40,7 +43,8 @@ predicate isStatements1QueryMetadata(Query query, string queryId, string ruleId) queryId = // `@id` for the `defaultNotFirstOrLastOfSwitch` query "c/misra/default-not-first-or-last-of-switch" and - ruleId = "RULE-16-5" + ruleId = "RULE-16-5" and + category = "required" } module Statements1Package { diff --git a/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll b/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll index 0e0156cb90..a1f06734d0 100644 --- a/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll +++ b/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll @@ -11,11 +11,11 @@ abstract class NestedLabelInSwitchSharedQuery extends Query { } Query getQuery() { result instanceof NestedLabelInSwitchSharedQuery } query predicate problems( - SwitchCase case, string message, Location caseLocation, string caseLabel, SwitchStmt switch, + SwitchCase nestedCase, string message, SwitchCase case, string caseLabel, SwitchStmt switch, string switchLabel ) { not isExcluded(nestedCase, getQuery()) and - switch.getASwitchCase() = nestedCase and + switch.getASwitchCase() = case and not nestedCase.getParentStmt() = switch.getChildStmt() and nestedCase = case and message = diff --git a/rule_packages/c/Statements1.json b/rule_packages/c/Statements1.json index 43c88481cf..f8a05972c2 100644 --- a/rule_packages/c/Statements1.json +++ b/rule_packages/c/Statements1.json @@ -6,11 +6,11 @@ }, "queries": [ { - "description": "Nested switch labels cause undefined behaviour.", + "description": "Nested switch labels can lead to unstructured code.", "kind": "problem", - "name": "A switch label shall only be used when the most closely-enclosing compound statement is the body of", + "name": "Nested switch labels shall not be used.", "precision": "very-high", - "severity": "error", + "severity": "recommendation", "short_name": "NestSwitchLabelInSwitchStatement", "shared_implementation_short_name": "NestedLabelInSwitch", "tags": [ From 48175e7599a32a57f908777b4d1463a8dfe76575 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 21 Feb 2023 14:22:19 +1100 Subject: [PATCH 10/76] Added test case to 16-3 for non last default labels --- .../RULE-16-3/BreakShallTerminateSwitchClause.expected | 1 + c/misra/test/rules/RULE-16-3/test.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/c/misra/test/rules/RULE-16-3/BreakShallTerminateSwitchClause.expected b/c/misra/test/rules/RULE-16-3/BreakShallTerminateSwitchClause.expected index 3a97de439c..cac08cc449 100644 --- a/c/misra/test/rules/RULE-16-3/BreakShallTerminateSwitchClause.expected +++ b/c/misra/test/rules/RULE-16-3/BreakShallTerminateSwitchClause.expected @@ -1,3 +1,4 @@ | test.c:11:3:11:9 | case ...: | The switch $@ does not terminate with a break statement. | test.c:11:3:11:9 | case ...: | clause | | test.c:14:3:14:9 | case ...: | The switch $@ does not terminate with a break statement. | test.c:14:3:14:9 | case ...: | clause | | test.c:26:3:26:10 | default: | The switch $@ does not terminate with a break statement. | test.c:26:3:26:10 | default: | clause | +| test.c:45:3:45:10 | default: | The switch $@ does not terminate with a break statement. | test.c:45:3:45:10 | default: | clause | diff --git a/c/misra/test/rules/RULE-16-3/test.c b/c/misra/test/rules/RULE-16-3/test.c index ae009174eb..c7cae7216c 100644 --- a/c/misra/test/rules/RULE-16-3/test.c +++ b/c/misra/test/rules/RULE-16-3/test.c @@ -39,3 +39,12 @@ void f2(int p1) { break; } } + +void f3(int p1) { + switch (p1) { + default: // NON_COMPLIANT + p1++; + case 1: // COMPLIANT + break; + } +} \ No newline at end of file From 0e68e41b94b47e4fa8171413d95e20154508a28d Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 21 Feb 2023 14:23:43 +1100 Subject: [PATCH 11/76] updated metadata for 16-3 based on PR feedback --- .../src/rules/RULE-16-3/BreakShallTerminateSwitchClause.ql | 4 ++-- rule_packages/c/Statements1.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/c/misra/src/rules/RULE-16-3/BreakShallTerminateSwitchClause.ql b/c/misra/src/rules/RULE-16-3/BreakShallTerminateSwitchClause.ql index 04cd95a6fe..e62fe8c8d4 100644 --- a/c/misra/src/rules/RULE-16-3/BreakShallTerminateSwitchClause.ql +++ b/c/misra/src/rules/RULE-16-3/BreakShallTerminateSwitchClause.ql @@ -4,8 +4,8 @@ * @description An unterminated switch-clause occurring at the end of a switch statement may fall * into switch clauses which are added later. * @kind problem - * @precision very-high - * @problem.severity error + * @precision high + * @problem.severity warning * @tags external/misra/id/rule-16-3 * maintainability * readability diff --git a/rule_packages/c/Statements1.json b/rule_packages/c/Statements1.json index f8a05972c2..13798b1a3f 100644 --- a/rule_packages/c/Statements1.json +++ b/rule_packages/c/Statements1.json @@ -30,8 +30,8 @@ "description": "An unterminated switch-clause occurring at the end of a switch statement may fall into switch clauses which are added later.", "kind": "problem", "name": "An unconditional break statement shall terminate every switch-clause", - "precision": "very-high", - "severity": "error", + "precision": "high", + "severity": "warning", "short_name": "BreakShallTerminateSwitchClause", "tags": [ "maintainability", From 6b575f4a84b53840f0bad3665414557be39ca1ce Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 21 Feb 2023 15:15:27 +1100 Subject: [PATCH 12/76] updated metadata for 16-5 --- c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql | 4 ++-- rule_packages/c/Statements1.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql b/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql index 457fd4ba2f..22565b708e 100644 --- a/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql +++ b/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql @@ -1,10 +1,10 @@ /** * @id c/misra/default-not-first-or-last-of-switch - * @name RULE-16-5: A default label shall appear as either the first or the last switch label of a switch statement + * @name RULE-16-5: A default label shall appear as either the first or the last switch label or a switch statement * @description Locating the default label is easy when it the first of last label. * @kind problem * @precision very-high - * @problem.severity error + * @problem.severity recommendation * @tags external/misra/id/rule-16-5 * external/misra/obligation/required */ diff --git a/rule_packages/c/Statements1.json b/rule_packages/c/Statements1.json index 13798b1a3f..f6e377e592 100644 --- a/rule_packages/c/Statements1.json +++ b/rule_packages/c/Statements1.json @@ -69,9 +69,9 @@ { "description": "Locating the default label is easy when it the first of last label.", "kind": "problem", - "name": "A default label shall appear as either the first or the last switch label of a switch statement", + "name": "A default label shall appear as either the first or the last switch label or a switch statement", "precision": "very-high", - "severity": "error", + "severity": "recommendation", "short_name": "DefaultNotFirstOrLastOfSwitch", "tags": [] } From 9f6b224671cc5634fac6ef4e1915408272a548d3 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 21 Feb 2023 15:19:57 +1100 Subject: [PATCH 13/76] removed full stop from name property of 16-2 --- c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql | 2 +- rule_packages/c/Statements1.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql b/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql index 1cab75f6bf..df4b6fc93a 100644 --- a/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql +++ b/c/misra/src/rules/RULE-16-2/NestSwitchLabelInSwitchStatement.ql @@ -1,6 +1,6 @@ /** * @id c/misra/nest-switch-label-in-switch-statement - * @name RULE-16-2: Nested switch labels shall not be used. + * @name RULE-16-2: Nested switch labels shall not be used * @description Nested switch labels can lead to unstructured code. * @kind problem * @precision very-high diff --git a/rule_packages/c/Statements1.json b/rule_packages/c/Statements1.json index f6e377e592..903172ae51 100644 --- a/rule_packages/c/Statements1.json +++ b/rule_packages/c/Statements1.json @@ -8,7 +8,7 @@ { "description": "Nested switch labels can lead to unstructured code.", "kind": "problem", - "name": "Nested switch labels shall not be used.", + "name": "Nested switch labels shall not be used", "precision": "very-high", "severity": "recommendation", "short_name": "NestSwitchLabelInSwitchStatement", From 80b891f0472d8151a33a91a49451900e19fafdd5 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Wed, 22 Feb 2023 07:33:10 +1100 Subject: [PATCH 14/76] WIP --- .../GotoStatementCondition.expected | 1 + .../GotoStatementCondition.ql | 2 + .../test/rules/gotostatementcondition/test.c | 0 .../RULE-15-2/GotoLabelLocationCondition.ql | 20 ++++ .../RULE-15-3/GotoLabelBlockCondition.ql | 19 ++++ .../rules/RULE-15-4/LoopIterationCondition.ql | 18 ++++ .../RULE-16-6/SwitchClauseNumberCondition.ql | 18 ++++ .../SwitchExpressionBoolCondition.ql | 18 ++++ .../GotoLabelLocationCondition.expected | 1 + .../GotoLabelLocationCondition.qlref | 1 + .../GotoLabelLocationCondition.testref | 1 + .../GotoLabelBlockCondition.expected | 1 + .../RULE-15-3/GotoLabelBlockCondition.qlref | 1 + .../RULE-15-4/LoopIterationCondition.expected | 1 + .../RULE-15-4/LoopIterationCondition.qlref | 1 + .../SwitchClauseNumberCondition.expected | 1 + .../SwitchClauseNumberCondition.qlref | 1 + .../SwitchExpressionBoolCondition.expected | 1 + .../SwitchExpressionBoolCondition.qlref | 1 + .../M6-6-2/GotoStatementJumpCondition.ql | 24 ++--- .../M6-6-2/GotoStatementJumpCondition.testref | 1 + .../cpp/exclusions/c/RuleMetadata.qll | 3 + .../cpp/exclusions/c/Statements2.qll | 95 +++++++++++++++++++ .../GotoStatementCondition.qll | 52 ++++++++++ .../GotoStatementCondition.expected | 1 + .../GotoStatementCondition.ql | 2 + .../rules/gotostatementcondition/test.cpp | 0 rule_packages/c/Statements2.json | 90 ++++++++++++++++++ rule_packages/cpp/Conditionals.json | 1 + rules.csv | 10 +- 30 files changed, 363 insertions(+), 23 deletions(-) create mode 100644 c/common/test/rules/gotostatementcondition/GotoStatementCondition.expected create mode 100644 c/common/test/rules/gotostatementcondition/GotoStatementCondition.ql create mode 100644 c/common/test/rules/gotostatementcondition/test.c create mode 100644 c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql create mode 100644 c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql create mode 100644 c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql create mode 100644 c/misra/src/rules/RULE-16-6/SwitchClauseNumberCondition.ql create mode 100644 c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql create mode 100644 c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.expected create mode 100644 c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.qlref create mode 100644 c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.testref create mode 100644 c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected create mode 100644 c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.qlref create mode 100644 c/misra/test/rules/RULE-15-4/LoopIterationCondition.expected create mode 100644 c/misra/test/rules/RULE-15-4/LoopIterationCondition.qlref create mode 100644 c/misra/test/rules/RULE-16-6/SwitchClauseNumberCondition.expected create mode 100644 c/misra/test/rules/RULE-16-6/SwitchClauseNumberCondition.qlref create mode 100644 c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected create mode 100644 c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.qlref create mode 100644 cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.testref create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Statements2.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/gotostatementcondition/GotoStatementCondition.qll create mode 100644 cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.expected create mode 100644 cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.ql create mode 100644 cpp/common/test/rules/gotostatementcondition/test.cpp create mode 100644 rule_packages/c/Statements2.json diff --git a/c/common/test/rules/gotostatementcondition/GotoStatementCondition.expected b/c/common/test/rules/gotostatementcondition/GotoStatementCondition.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/c/common/test/rules/gotostatementcondition/GotoStatementCondition.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/c/common/test/rules/gotostatementcondition/GotoStatementCondition.ql b/c/common/test/rules/gotostatementcondition/GotoStatementCondition.ql new file mode 100644 index 0000000000..826a161cc6 --- /dev/null +++ b/c/common/test/rules/gotostatementcondition/GotoStatementCondition.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.gotostatementcondition.GotoStatementCondition diff --git a/c/common/test/rules/gotostatementcondition/test.c b/c/common/test/rules/gotostatementcondition/test.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql b/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql new file mode 100644 index 0000000000..36d1640d6b --- /dev/null +++ b/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql @@ -0,0 +1,20 @@ +/** + * @id c/misra/goto-label-location-condition + * @name RULE-15-2: The goto statement shall jump to a label declared later in the same function + * @description Unconstrained use of goto can lead to unstructured code + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-15-2 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.gotostatementcondition.GotoStatementCondition + +class GotoLabelLocationConditionQuery extends GotoStatementConditionSharedQuery { + GotoLabelLocationConditionQuery() { + this = Statements2Package::gotoLabelLocationConditionQuery() + } +} diff --git a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql new file mode 100644 index 0000000000..f4388a0818 --- /dev/null +++ b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql @@ -0,0 +1,19 @@ +/** + * @id c/misra/goto-label-block-condition + * @name RULE-15-3: Any label referenced by a goto statement shall be declared in the same block, or in any block + * @description Any label referenced by a goto statement shall be declared in the same block, or in + * any block enclosing the goto statement + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-15-3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from +where + not isExcluded(x, Statements2Package::gotoLabelBlockConditionQuery()) and +select diff --git a/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql b/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql new file mode 100644 index 0000000000..c9b49b5f56 --- /dev/null +++ b/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql @@ -0,0 +1,18 @@ +/** + * @id c/misra/loop-iteration-condition + * @name RULE-15-4: There should be no more than one break or goto statement used to terminate any iteration statement + * @description + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-15-4 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +from +where + not isExcluded(x, Statements2Package::loopIterationConditionQuery()) and +select diff --git a/c/misra/src/rules/RULE-16-6/SwitchClauseNumberCondition.ql b/c/misra/src/rules/RULE-16-6/SwitchClauseNumberCondition.ql new file mode 100644 index 0000000000..6b2bc9278e --- /dev/null +++ b/c/misra/src/rules/RULE-16-6/SwitchClauseNumberCondition.ql @@ -0,0 +1,18 @@ +/** + * @id c/misra/switch-clause-number-condition + * @name RULE-16-6: Every switch statement shall have at least two switch-clauses + * @description + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-16-6 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from +where + not isExcluded(x, Statements2Package::switchClauseNumberConditionQuery()) and +select diff --git a/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql b/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql new file mode 100644 index 0000000000..54b143c464 --- /dev/null +++ b/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql @@ -0,0 +1,18 @@ +/** + * @id c/misra/switch-expression-bool-condition + * @name RULE-16-7: A switch-expression shall not have essentially Boolean type + * @description + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-16-7 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from +where + not isExcluded(x, Statements2Package::switchExpressionBoolConditionQuery()) and +select diff --git a/c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.expected b/c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.qlref b/c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.qlref new file mode 100644 index 0000000000..6a35e05154 --- /dev/null +++ b/c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.qlref @@ -0,0 +1 @@ +rules/RULE-15-2/GotoLabelLocationCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.testref b/c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.testref new file mode 100644 index 0000000000..0573c85129 --- /dev/null +++ b/c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.testref @@ -0,0 +1 @@ +c/common/test/rules/gotostatementcondition/GotoStatementCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.qlref b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.qlref new file mode 100644 index 0000000000..5f430f0790 --- /dev/null +++ b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.qlref @@ -0,0 +1 @@ +rules/RULE-15-3/GotoLabelBlockCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-4/LoopIterationCondition.expected b/c/misra/test/rules/RULE-15-4/LoopIterationCondition.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/c/misra/test/rules/RULE-15-4/LoopIterationCondition.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-4/LoopIterationCondition.qlref b/c/misra/test/rules/RULE-15-4/LoopIterationCondition.qlref new file mode 100644 index 0000000000..33ff4561da --- /dev/null +++ b/c/misra/test/rules/RULE-15-4/LoopIterationCondition.qlref @@ -0,0 +1 @@ +rules/RULE-15-4/LoopIterationCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-16-6/SwitchClauseNumberCondition.expected b/c/misra/test/rules/RULE-16-6/SwitchClauseNumberCondition.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/c/misra/test/rules/RULE-16-6/SwitchClauseNumberCondition.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/c/misra/test/rules/RULE-16-6/SwitchClauseNumberCondition.qlref b/c/misra/test/rules/RULE-16-6/SwitchClauseNumberCondition.qlref new file mode 100644 index 0000000000..6502b855f9 --- /dev/null +++ b/c/misra/test/rules/RULE-16-6/SwitchClauseNumberCondition.qlref @@ -0,0 +1 @@ +rules/RULE-16-6/SwitchClauseNumberCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected b/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.qlref b/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.qlref new file mode 100644 index 0000000000..dc86fab7e9 --- /dev/null +++ b/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.qlref @@ -0,0 +1 @@ +rules/RULE-16-7/SwitchExpressionBoolCondition.ql \ No newline at end of file diff --git a/cpp/autosar/src/rules/M6-6-2/GotoStatementJumpCondition.ql b/cpp/autosar/src/rules/M6-6-2/GotoStatementJumpCondition.ql index 89e35990d5..bde6e8ddee 100644 --- a/cpp/autosar/src/rules/M6-6-2/GotoStatementJumpCondition.ql +++ b/cpp/autosar/src/rules/M6-6-2/GotoStatementJumpCondition.ql @@ -15,22 +15,10 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.gotostatementcondition.GotoStatementCondition -from GotoStmt goto, Stmt target -where - not isExcluded(goto, ConditionalsPackage::gotoStatementJumpConditionQuery()) and - target = goto.getTarget() and - exists(Location targetLoc, Location gotoLoc | - targetLoc = target.getLocation() and - gotoLoc = goto.getLocation() and - targetLoc.getFile() = gotoLoc.getFile() - | - // Starts on a previous line - targetLoc.getStartLine() < gotoLoc.getEndLine() - or - // Starts on the same line, but an earlier column - targetLoc.getStartLine() = gotoLoc.getEndLine() and - targetLoc.getEndColumn() < gotoLoc.getStartColumn() - ) -select goto, "The goto jumps to the label $@ that is not declared later in the same function.", - target, goto.getName() +class GotoStatementJumpConditionQuery extends GotoStatementConditionSharedQuery { + GotoStatementJumpConditionQuery() { + this = ConditionalsPackage::gotoStatementJumpConditionQuery() + } +} diff --git a/cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.testref b/cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.testref new file mode 100644 index 0000000000..b4f807e8e2 --- /dev/null +++ b/cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.testref @@ -0,0 +1 @@ +cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.ql \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 022b57dcbf..e480438be3 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -43,6 +43,7 @@ import Preprocessor6 import SideEffects1 import SideEffects2 import Statements1 +import Statements2 import Strings1 import Strings2 import Strings3 @@ -91,6 +92,7 @@ newtype TCQuery = TSideEffects1PackageQuery(SideEffects1Query q) or TSideEffects2PackageQuery(SideEffects2Query q) or TStatements1PackageQuery(Statements1Query q) or + TStatements2PackageQuery(Statements2Query q) or TStrings1PackageQuery(Strings1Query q) or TStrings2PackageQuery(Strings2Query q) or TStrings3PackageQuery(Strings3Query q) or @@ -139,6 +141,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isSideEffects1QueryMetadata(query, queryId, ruleId, category) or isSideEffects2QueryMetadata(query, queryId, ruleId, category) or isStatements1QueryMetadata(query, queryId, ruleId, category) or + isStatements2QueryMetadata(query, queryId, ruleId, category) or isStrings1QueryMetadata(query, queryId, ruleId, category) or isStrings2QueryMetadata(query, queryId, ruleId, category) or isStrings3QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Statements2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements2.qll new file mode 100644 index 0000000000..49dd38c316 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements2.qll @@ -0,0 +1,95 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Statements2Query = + TGotoLabelLocationConditionQuery() or + TGotoLabelBlockConditionQuery() or + TLoopIterationConditionQuery() or + TSwitchClauseNumberConditionQuery() or + TSwitchExpressionBoolConditionQuery() + +predicate isStatements2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `gotoLabelLocationCondition` query + Statements2Package::gotoLabelLocationConditionQuery() and + queryId = + // `@id` for the `gotoLabelLocationCondition` query + "c/misra/goto-label-location-condition" and + ruleId = "RULE-15-2" and + category = "required" + or + query = + // `Query` instance for the `gotoLabelBlockCondition` query + Statements2Package::gotoLabelBlockConditionQuery() and + queryId = + // `@id` for the `gotoLabelBlockCondition` query + "c/misra/goto-label-block-condition" and + ruleId = "RULE-15-3" and + category = "required" + or + query = + // `Query` instance for the `loopIterationCondition` query + Statements2Package::loopIterationConditionQuery() and + queryId = + // `@id` for the `loopIterationCondition` query + "c/misra/loop-iteration-condition" and + ruleId = "RULE-15-4" and + category = "advisory" + or + query = + // `Query` instance for the `switchClauseNumberCondition` query + Statements2Package::switchClauseNumberConditionQuery() and + queryId = + // `@id` for the `switchClauseNumberCondition` query + "c/misra/switch-clause-number-condition" and + ruleId = "RULE-16-6" and + category = "required" + or + query = + // `Query` instance for the `switchExpressionBoolCondition` query + Statements2Package::switchExpressionBoolConditionQuery() and + queryId = + // `@id` for the `switchExpressionBoolCondition` query + "c/misra/switch-expression-bool-condition" and + ruleId = "RULE-16-7" and + category = "required" +} + +module Statements2Package { + Query gotoLabelLocationConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `gotoLabelLocationCondition` query + TQueryC(TStatements2PackageQuery(TGotoLabelLocationConditionQuery())) + } + + Query gotoLabelBlockConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `gotoLabelBlockCondition` query + TQueryC(TStatements2PackageQuery(TGotoLabelBlockConditionQuery())) + } + + Query loopIterationConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `loopIterationCondition` query + TQueryC(TStatements2PackageQuery(TLoopIterationConditionQuery())) + } + + Query switchClauseNumberConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `switchClauseNumberCondition` query + TQueryC(TStatements2PackageQuery(TSwitchClauseNumberConditionQuery())) + } + + Query switchExpressionBoolConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `switchExpressionBoolCondition` query + TQueryC(TStatements2PackageQuery(TSwitchExpressionBoolConditionQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/rules/gotostatementcondition/GotoStatementCondition.qll b/cpp/common/src/codingstandards/cpp/rules/gotostatementcondition/GotoStatementCondition.qll new file mode 100644 index 0000000000..54a10b5580 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/gotostatementcondition/GotoStatementCondition.qll @@ -0,0 +1,52 @@ +/** + * Provides a library which includes a `problems` predicate for reporting.... + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class GotoStatementConditionSharedQuery extends Query { } + +Query getQuery() { result instanceof GotoStatementConditionSharedQuery } + +query predicate problems(GotoStmt goto, string message, Stmt target, string targetLabel) { + not isExcluded(goto, getQuery()) and + target = goto.getTarget() and + exists(Location targetLoc, Location gotoLoc | + targetLoc = target.getLocation() and + gotoLoc = goto.getLocation() and + targetLoc.getFile() = gotoLoc.getFile() + | + // Starts on a previous line + targetLoc.getStartLine() < gotoLoc.getEndLine() + or + // Starts on the same line, but an earlier column + targetLoc.getStartLine() = gotoLoc.getEndLine() and + targetLoc.getEndColumn() < gotoLoc.getStartColumn() + ) + and message = "The goto jumps to the label $@ that is not declared later in the same function." and targetLabel = target.toString() +} + + + + + +// from GotoStmt goto, Stmt target +// where +// not isExcluded(goto, ConditionalsPackage::gotoStatementJumpConditionQuery()) and +// target = goto.getTarget() and +// exists(Location targetLoc, Location gotoLoc | +// targetLoc = target.getLocation() and +// gotoLoc = goto.getLocation() and +// targetLoc.getFile() = gotoLoc.getFile() +// | +// // Starts on a previous line +// targetLoc.getStartLine() < gotoLoc.getEndLine() +// or +// // Starts on the same line, but an earlier column +// targetLoc.getStartLine() = gotoLoc.getEndLine() and +// targetLoc.getEndColumn() < gotoLoc.getStartColumn() +// ) +// select goto, "The goto jumps to the label $@ that is not declared later in the same function.", +// target, goto.getName() diff --git a/cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.expected b/cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.ql b/cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.ql new file mode 100644 index 0000000000..826a161cc6 --- /dev/null +++ b/cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.gotostatementcondition.GotoStatementCondition diff --git a/cpp/common/test/rules/gotostatementcondition/test.cpp b/cpp/common/test/rules/gotostatementcondition/test.cpp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/rule_packages/c/Statements2.json b/rule_packages/c/Statements2.json new file mode 100644 index 0000000000..c85c5e4404 --- /dev/null +++ b/rule_packages/c/Statements2.json @@ -0,0 +1,90 @@ +{ + "MISRA-C-2012": { + "RULE-15-2": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Unconstrained use of goto can lead to unstructured code", + "kind": "problem", + "name": "The goto statement shall jump to a label declared later in the same function", + "precision": "very-high", + "severity": "error", + "short_name": "GotoLabelLocationCondition", + "shared_implementation_short_name": "GotoStatementCondition", + "tags": [] + } + ], + "title": "The goto statement shall jump to a label declared later in the same function" + }, + "RULE-15-3": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement", + "kind": "problem", + "name": "Any label referenced by a goto statement shall be declared in the same block, or in any block", + "precision": "very-high", + "severity": "error", + "short_name": "GotoLabelBlockCondition", + "tags": [] + } + ], + "title": "Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement" + }, + "RULE-15-4": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "", + "kind": "problem", + "name": "There should be no more than one break or goto statement used to terminate any iteration statement", + "precision": "very-high", + "severity": "error", + "short_name": "LoopIterationCondition", + "tags": [] + } + ], + "title": "There should be no more than one break or goto statement used to terminate any iteration statement" + }, + "RULE-16-6": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "", + "kind": "problem", + "name": "Every switch statement shall have at least two switch-clauses", + "precision": "very-high", + "severity": "error", + "short_name": "SwitchClauseNumberCondition", + "tags": [] + } + ], + "title": "Every switch statement shall have at least two switch-clauses" + }, + "RULE-16-7": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "", + "kind": "problem", + "name": "A switch-expression shall not have essentially Boolean type", + "precision": "very-high", + "severity": "error", + "short_name": "SwitchExpressionBoolCondition", + "tags": [] + } + ], + "title": "A switch-expression shall not have essentially Boolean type" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/Conditionals.json b/rule_packages/cpp/Conditionals.json index 5f6a120d16..755a24d2aa 100644 --- a/rule_packages/cpp/Conditionals.json +++ b/rule_packages/cpp/Conditionals.json @@ -329,6 +329,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "GotoStatementJumpCondition", + "shared_implementation_short_name": "GotoStatementCondition", "tags": [ "maintainability", "readability" diff --git a/rules.csv b/rules.csv index 37140d4b2a..4029401639 100644 --- a/rules.csv +++ b/rules.csv @@ -698,9 +698,9 @@ c,MISRA-C-2012,RULE-14-2,Yes,Required,,,A for loop shall be well-formed,M6-5-1.. 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, c,MISRA-C-2012,RULE-15-1,No,Advisory,,,The goto statement should not be used,A6-6-1,,Import, -c,MISRA-C-2012,RULE-15-2,Yes,Required,,,The goto statement shall jump to a label declared later in the same function,M6-6-2,Statements,Import, -c,MISRA-C-2012,RULE-15-3,Yes,Required,,,"Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement",M6-6-1,Statements,Import, -c,MISRA-C-2012,RULE-15-4,Yes,Advisory,,,There should be no more than one break or goto statement used to terminate any iteration statement,,Statements,Medium, +c,MISRA-C-2012,RULE-15-2,Yes,Required,,,The goto statement shall jump to a label declared later in the same function,M6-6-2,Statements2,Import, +c,MISRA-C-2012,RULE-15-3,Yes,Required,,,"Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement",M6-6-1,Statements2,Import, +c,MISRA-C-2012,RULE-15-4,Yes,Advisory,,,There should be no more than one break or goto statement used to terminate any iteration statement,,Statements2,Medium, c,MISRA-C-2012,RULE-15-5,Yes,Advisory,,,A function should have a single point of exit at the end,,Statements,Medium, c,MISRA-C-2012,RULE-15-6,Yes,Required,,,The body of an iteration-statement or a selection-statement shall be a compund-statement,M6-3-1,Statements,Import, c,MISRA-C-2012,RULE-15-7,Yes,Required,,,All if / else if constructs shall be terminated with an else statement,M6-4-2,Statements,Import, @@ -709,8 +709,8 @@ c,MISRA-C-2012,RULE-16-2,Yes,Required,,,A switch label shall only be used when t c,MISRA-C-2012,RULE-16-3,Yes,Required,,,An unconditional break statement shall terminate every switch-clause,M6-4-5,Statements1,Import, c,MISRA-C-2012,RULE-16-4,Yes,Required,,,Every switch statement shall have a default label,M6-4-6,Statements1,Easy, c,MISRA-C-2012,RULE-16-5,Yes,Required,,,A default label shall appear as either the first or the last switch label of a switch statement,M6-4-6,Statements1,Easy, -c,MISRA-C-2012,RULE-16-6,Yes,Required,,,Every switch statement shall have at least two switch-clauses,A6-4-1,Statements,Medium, -c,MISRA-C-2012,RULE-16-7,Yes,Required,,,A switch-expression shall not have essentially Boolean type,M6-4-7,Statements,Medium, +c,MISRA-C-2012,RULE-16-6,Yes,Required,,,Every switch statement shall have at least two switch-clauses,A6-4-1,Statements2,Medium, +c,MISRA-C-2012,RULE-16-7,Yes,Required,,,A switch-expression shall not have essentially Boolean type,M6-4-7,Statements2,Medium, c,MISRA-C-2012,RULE-17-1,Yes,Required,,,The features of shall not be used,,Banned,Easy, c,MISRA-C-2012,RULE-17-2,Yes,Required,,,"Functions shall not call themselves, either directly or indirectly",A7-5-2,Statements,Import, c,MISRA-C-2012,RULE-17-3,Yes,Mandatory,,,A function shall not be declared implicitly,,Declarations6,Medium, From c76909cd452c4be17bafade3af036baacc380000 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Fri, 24 Feb 2023 10:00:13 +1100 Subject: [PATCH 15/76] Implementation for RULE-15-2 --- .../GotoStatementCondition.expected | 4 +- .../test/rules/gotostatementcondition/test.c | 17 +++++ .../RULE-15-2/GotoLabelLocationCondition.ql | 4 +- .../GotoStatementJumpCondition.expected | 8 +-- .../GotoStatementCondition.qll | 64 +++++++------------ rule_packages/c/Statements2.json | 7 +- 6 files changed, 56 insertions(+), 48 deletions(-) diff --git a/c/common/test/rules/gotostatementcondition/GotoStatementCondition.expected b/c/common/test/rules/gotostatementcondition/GotoStatementCondition.expected index 2ec1a0ac6c..e522289c7b 100644 --- a/c/common/test/rules/gotostatementcondition/GotoStatementCondition.expected +++ b/c/common/test/rules/gotostatementcondition/GotoStatementCondition.expected @@ -1 +1,3 @@ -No expected results have yet been specified \ No newline at end of file +| test.c:5:3:5:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.c:5:3:5:10 | goto ... | L1 | test.c:2:1:2:3 | label ...: | label ...: | +| test.c:14:3:14:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.c:14:3:14:10 | goto ... | L2 | test.c:12:1:12:3 | label ...: | label ...: | +| test.c:16:3:16:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.c:16:3:16:10 | goto ... | L1 | test.c:11:1:11:3 | label ...: | label ...: | diff --git a/c/common/test/rules/gotostatementcondition/test.c b/c/common/test/rules/gotostatementcondition/test.c index e69de29bb2..2c189cd433 100644 --- a/c/common/test/rules/gotostatementcondition/test.c +++ b/c/common/test/rules/gotostatementcondition/test.c @@ -0,0 +1,17 @@ +void f1() { +L1:; + goto L2; // COMPLIANT + ; + goto L1; // NON_COMPLIANT + +L2:; +} + +void f2() { +L1:; +L2: + goto L3; // COMPLIANT + goto L2; // NON_COMPLIANT +L3: + goto L1; // NON_COMPLIANT +} diff --git a/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql b/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql index 36d1640d6b..99940dbff2 100644 --- a/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql +++ b/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql @@ -4,8 +4,10 @@ * @description Unconstrained use of goto can lead to unstructured code * @kind problem * @precision very-high - * @problem.severity error + * @problem.severity recommendation * @tags external/misra/id/rule-15-2 + * maintainability + * readability * external/misra/obligation/required */ diff --git a/cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.expected b/cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.expected index 58df2b5ec1..dba183caaf 100644 --- a/cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.expected +++ b/cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.expected @@ -1,4 +1,4 @@ -| test.cpp:7:3:7:11 | goto ... | The goto jumps to the label $@ that is not declared later in the same function. | test.cpp:3:1:3:4 | label ...: | bad | -| test.cpp:21:3:21:11 | goto ... | The goto jumps to the label $@ that is not declared later in the same function. | test.cpp:17:1:17:4 | label ...: | bad | -| test.cpp:24:3:24:13 | goto ... | The goto jumps to the label $@ that is not declared later in the same function. | test.cpp:15:1:15:6 | label ...: | sobad | -| test.cpp:31:3:31:11 | goto ... | The goto jumps to the label $@ that is not declared later in the same function. | test.cpp:29:1:29:4 | label ...: | bad | +| test.cpp:7:3:7:11 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:7:3:7:11 | goto ... | bad | test.cpp:3:1:3:4 | label ...: | label ...: | +| test.cpp:21:3:21:11 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:21:3:21:11 | goto ... | bad | test.cpp:17:1:17:4 | label ...: | label ...: | +| test.cpp:24:3:24:13 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:24:3:24:13 | goto ... | sobad | test.cpp:15:1:15:6 | label ...: | label ...: | +| test.cpp:31:3:31:11 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:31:3:31:11 | goto ... | bad | test.cpp:29:1:29:4 | label ...: | label ...: | diff --git a/cpp/common/src/codingstandards/cpp/rules/gotostatementcondition/GotoStatementCondition.qll b/cpp/common/src/codingstandards/cpp/rules/gotostatementcondition/GotoStatementCondition.qll index 54a10b5580..74c6abbade 100644 --- a/cpp/common/src/codingstandards/cpp/rules/gotostatementcondition/GotoStatementCondition.qll +++ b/cpp/common/src/codingstandards/cpp/rules/gotostatementcondition/GotoStatementCondition.qll @@ -1,5 +1,6 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library which includes a `problems` predicate for reporting goto statements that jump to labels + * declared later in the same funciton. */ import cpp @@ -10,43 +11,26 @@ abstract class GotoStatementConditionSharedQuery extends Query { } Query getQuery() { result instanceof GotoStatementConditionSharedQuery } -query predicate problems(GotoStmt goto, string message, Stmt target, string targetLabel) { - not isExcluded(goto, getQuery()) and - target = goto.getTarget() and - exists(Location targetLoc, Location gotoLoc | - targetLoc = target.getLocation() and - gotoLoc = goto.getLocation() and - targetLoc.getFile() = gotoLoc.getFile() - | - // Starts on a previous line - targetLoc.getStartLine() < gotoLoc.getEndLine() - or - // Starts on the same line, but an earlier column - targetLoc.getStartLine() = gotoLoc.getEndLine() and - targetLoc.getEndColumn() < gotoLoc.getStartColumn() - ) - and message = "The goto jumps to the label $@ that is not declared later in the same function." and targetLabel = target.toString() +query predicate problems( + GotoStmt goto, string message, GotoStmt gotoLocation, string gotoLabel, Stmt target, + string targetLabel +) { + not isExcluded(goto, getQuery()) and + target = goto.getTarget() and + exists(Location targetLoc, Location gotoLoc | + targetLoc = target.getLocation() and + gotoLoc = goto.getLocation() and + targetLoc.getFile() = gotoLoc.getFile() + | + // Starts on a previous line + targetLoc.getStartLine() < gotoLoc.getEndLine() + or + // Starts on the same line, but an earlier column + targetLoc.getStartLine() = gotoLoc.getEndLine() and + targetLoc.getEndColumn() < gotoLoc.getStartColumn() + ) and + goto = gotoLocation and + message = "The $@ statement jumps to a $@ that is not declared later in the same function." and + gotoLabel = goto.getName() and + targetLabel = target.toString() } - - - - - -// from GotoStmt goto, Stmt target -// where -// not isExcluded(goto, ConditionalsPackage::gotoStatementJumpConditionQuery()) and -// target = goto.getTarget() and -// exists(Location targetLoc, Location gotoLoc | -// targetLoc = target.getLocation() and -// gotoLoc = goto.getLocation() and -// targetLoc.getFile() = gotoLoc.getFile() -// | -// // Starts on a previous line -// targetLoc.getStartLine() < gotoLoc.getEndLine() -// or -// // Starts on the same line, but an earlier column -// targetLoc.getStartLine() = gotoLoc.getEndLine() and -// targetLoc.getEndColumn() < gotoLoc.getStartColumn() -// ) -// select goto, "The goto jumps to the label $@ that is not declared later in the same function.", -// target, goto.getName() diff --git a/rule_packages/c/Statements2.json b/rule_packages/c/Statements2.json index c85c5e4404..b1fcf55926 100644 --- a/rule_packages/c/Statements2.json +++ b/rule_packages/c/Statements2.json @@ -10,10 +10,13 @@ "kind": "problem", "name": "The goto statement shall jump to a label declared later in the same function", "precision": "very-high", - "severity": "error", + "severity": "recommendation", "short_name": "GotoLabelLocationCondition", "shared_implementation_short_name": "GotoStatementCondition", - "tags": [] + "tags": [ + "maintainability", + "readability" + ] } ], "title": "The goto statement shall jump to a label declared later in the same function" From e71e36d67b1956e68e466e30af74fc2d21ebb9c0 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Fri, 24 Feb 2023 11:42:14 +1100 Subject: [PATCH 16/76] added fullstop to 15-2 description --- c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql | 2 +- rule_packages/c/Statements2.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql b/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql index 99940dbff2..7ad9963d14 100644 --- a/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql +++ b/c/misra/src/rules/RULE-15-2/GotoLabelLocationCondition.ql @@ -1,7 +1,7 @@ /** * @id c/misra/goto-label-location-condition * @name RULE-15-2: The goto statement shall jump to a label declared later in the same function - * @description Unconstrained use of goto can lead to unstructured code + * @description Unconstrained use of goto can lead to unstructured code. * @kind problem * @precision very-high * @problem.severity recommendation diff --git a/rule_packages/c/Statements2.json b/rule_packages/c/Statements2.json index b1fcf55926..dbf2ebb102 100644 --- a/rule_packages/c/Statements2.json +++ b/rule_packages/c/Statements2.json @@ -6,7 +6,7 @@ }, "queries": [ { - "description": "Unconstrained use of goto can lead to unstructured code", + "description": "Unconstrained use of goto can lead to unstructured code.", "kind": "problem", "name": "The goto statement shall jump to a label declared later in the same function", "precision": "very-high", From e3c2298c5e39a0a1a0fbef492a52695850b89149 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Sat, 25 Feb 2023 20:30:20 +1100 Subject: [PATCH 17/76] Added implementation for 15-3 --- .../RULE-15-3/GotoLabelBlockCondition.ql | 30 ++++++-- .../GotoLabelBlockCondition.expected | 4 +- c/misra/test/rules/RULE-15-3/test.c | 69 +++++++++++++++++++ rule_packages/c/Statements2.json | 11 +-- 4 files changed, 103 insertions(+), 11 deletions(-) create mode 100644 c/misra/test/rules/RULE-15-3/test.c diff --git a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql index f4388a0818..7b941f3669 100644 --- a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql +++ b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql @@ -1,19 +1,37 @@ /** * @id c/misra/goto-label-block-condition - * @name RULE-15-3: Any label referenced by a goto statement shall be declared in the same block, or in any block + * @name RULE-15-3: The goto statement and any of its label shall be declared or enclosed in the same block. * @description Any label referenced by a goto statement shall be declared in the same block, or in * any block enclosing the goto statement * @kind problem - * @precision very-high - * @problem.severity error + * @precision high + * @problem.severity recommendation * @tags external/misra/id/rule-15-3 + * maintainability + * readability * external/misra/obligation/required */ import cpp import codingstandards.c.misra -from +from GotoStmt goto where - not isExcluded(x, Statements2Package::gotoLabelBlockConditionQuery()) and -select + not isExcluded(goto, Statements2Package::gotoLabelBlockConditionQuery()) and + not goto.getEnclosingBlock+() = goto.getTarget().getEnclosingBlock() + or + exists(SwitchStmt switch, int caseLocation, int nextCaseLocation | + switch.getAChild*() = goto and + switch.getASwitchCase().getLocation().getStartLine() = caseLocation and + switch.getASwitchCase().getNextSwitchCase().getLocation().getStartLine() = nextCaseLocation and + goto.getLocation().getStartLine() > caseLocation and + goto.getLocation().getStartLine() < nextCaseLocation and + ( + goto.getTarget().getLocation().getStartLine() < caseLocation + or + goto.getTarget().getLocation().getStartLine() > nextCaseLocation + ) and + goto.getTarget().getLocation().getStartLine() > switch.getLocation().getStartLine() + ) +select goto, "The $@ statement and its $@ are not declared or enclosed in the same block.", goto, + "goto", goto.getTarget(), "label" diff --git a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected index 2ec1a0ac6c..9a81d6f434 100644 --- a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected +++ b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected @@ -1 +1,3 @@ -No expected results have yet been specified \ No newline at end of file +| test.c:2:3:2:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:2:3:2:10 | goto ... | goto | test.c:4:3:4:5 | label ...: | label | +| test.c:37:3:37:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:37:3:37:10 | goto ... | goto | test.c:41:3:41:5 | label ...: | label | +| test.c:52:5:52:12 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:52:5:52:12 | goto ... | goto | test.c:55:3:55:5 | label ...: | label | diff --git a/c/misra/test/rules/RULE-15-3/test.c b/c/misra/test/rules/RULE-15-3/test.c new file mode 100644 index 0000000000..666a45cb2c --- /dev/null +++ b/c/misra/test/rules/RULE-15-3/test.c @@ -0,0 +1,69 @@ +void f1() { + goto L1; + for (int i = 0; i < 100; i++) { + L1: // NON_COMPLIANT + } +} + +void f2() { + int i = 0; + if (i >= 0) { + for (int j = 0; j < 10; j++) { + goto L2; + } + } +L2: // COMPLIANT +} + +void f3() { + int i = 0; + if (i >= 0) { + for (int j = 0; j < 10; j++) { + goto L3; + L3: // COMPLIANT + } + } +} + +void f4() { + int i = 0; +L4: // COMPLIANT + if (i >= 0) { + goto L4; + } +} + +void f5(int p) { + goto L1; + + switch (p) { + case 0: + L1:; // NON_COMPLIANT + break; + default: + break; + } +} + +void f6(int p) { + + switch (p) { + case 0: + goto L1; + break; + default: + L1: // NON_COMPLIANT + break; + } +} + +void f7(int p) { +L1: // COMPLIANT + switch (p) { + case 0: + goto L1; + break; + default: + break; + } +} \ No newline at end of file diff --git a/rule_packages/c/Statements2.json b/rule_packages/c/Statements2.json index dbf2ebb102..48e6a3aaa1 100644 --- a/rule_packages/c/Statements2.json +++ b/rule_packages/c/Statements2.json @@ -29,11 +29,14 @@ { "description": "Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement", "kind": "problem", - "name": "Any label referenced by a goto statement shall be declared in the same block, or in any block", - "precision": "very-high", - "severity": "error", + "name": "The goto statement and any of its label shall be declared or enclosed in the same block. ", + "precision": "high", + "severity": "recommendation", "short_name": "GotoLabelBlockCondition", - "tags": [] + "tags": [ + "maintainability", + "readability" + ] } ], "title": "Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement" From 0ef25b2bae9de325e0a059247879784b643b8af1 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 28 Feb 2023 14:09:15 +1100 Subject: [PATCH 18/76] Added RULE 15-4 --- .../rules/RULE-15-4/LoopIterationCondition.ql | 19 ++++++-- .../RULE-15-4/LoopIterationCondition.expected | 3 +- c/misra/test/rules/RULE-15-4/test.c | 46 +++++++++++++++++++ rule_packages/c/Statements2.json | 7 ++- 4 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 c/misra/test/rules/RULE-15-4/test.c diff --git a/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql b/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql index c9b49b5f56..9176aea2e1 100644 --- a/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql +++ b/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql @@ -1,18 +1,29 @@ /** * @id c/misra/loop-iteration-condition * @name RULE-15-4: There should be no more than one break or goto statement used to terminate any iteration statement - * @description + * @description More than one break or goto statement in iteration conditions may lead to + * readability and maintainability issues. * @kind problem * @precision very-high * @problem.severity error * @tags external/misra/id/rule-15-4 + * maintainability + * readability * external/misra/obligation/advisory */ import cpp import codingstandards.c.misra -from +from Loop loop where - not isExcluded(x, Statements2Package::loopIterationConditionQuery()) and -select + not isExcluded(loop, Statements2Package::loopIterationConditionQuery()) and + count(Stmt terminationStmt | + loop.getChildStmt*() = terminationStmt and + ( + terminationStmt instanceof BreakStmt + or + terminationStmt instanceof GotoStmt + ) + ) > 1 +select loop, "$@ statement contains more than one break or goto statement", loop, "Iteration" diff --git a/c/misra/test/rules/RULE-15-4/LoopIterationCondition.expected b/c/misra/test/rules/RULE-15-4/LoopIterationCondition.expected index 2ec1a0ac6c..6a8d9bf23a 100644 --- a/c/misra/test/rules/RULE-15-4/LoopIterationCondition.expected +++ b/c/misra/test/rules/RULE-15-4/LoopIterationCondition.expected @@ -1 +1,2 @@ -No expected results have yet been specified \ No newline at end of file +| test.c:24:3:32:3 | for(...;...;...) ... | $@ statement contains more than one break or goto statement | test.c:24:3:32:3 | for(...;...;...) ... | Iteration | +| test.c:38:3:45:3 | while (...) ... | $@ statement contains more than one break or goto statement | test.c:38:3:45:3 | while (...) ... | Iteration | diff --git a/c/misra/test/rules/RULE-15-4/test.c b/c/misra/test/rules/RULE-15-4/test.c new file mode 100644 index 0000000000..382b040c55 --- /dev/null +++ b/c/misra/test/rules/RULE-15-4/test.c @@ -0,0 +1,46 @@ +void f1() { +L1:; + + for (int k = 0; k < 10; k++) { // COMPLIANT + ; + } + + for (int i = 0; i < 10; i++) { // COMPLIANT + if (i > 5) { + break; + } + } + + for (int j = 0; j < 10; j++) { // COMPLIANT + goto L1; + } +} + +void f2() { +L1:; + + int k = 0; + + for (int i = 0; i < 10; i++) { // NON_COMPLIANT + if (i > 5) { + break; + } + if (i < 10) { + break; + } + goto L1; + } + + while (k < 10) { // COMPLIANT + ; + } + + while (k < 10) { // NON_COMPLIANT + if (k > 5) { + break; + } + while (k < 3) { // COMPLIANT + goto L1; + } + } +} diff --git a/rule_packages/c/Statements2.json b/rule_packages/c/Statements2.json index 48e6a3aaa1..6406a91441 100644 --- a/rule_packages/c/Statements2.json +++ b/rule_packages/c/Statements2.json @@ -47,13 +47,16 @@ }, "queries": [ { - "description": "", + "description": "More than one break or goto statement in iteration conditions may lead to readability and maintainability issues.", "kind": "problem", "name": "There should be no more than one break or goto statement used to terminate any iteration statement", "precision": "very-high", "severity": "error", "short_name": "LoopIterationCondition", - "tags": [] + "tags": [ + "maintainability", + "readability" + ] } ], "title": "There should be no more than one break or goto statement used to terminate any iteration statement" From 094f6a02cc0678eaaf5d691129bf570714d83012 Mon Sep 17 00:00:00 2001 From: s-samadi Date: Mon, 6 Mar 2023 17:26:18 +1100 Subject: [PATCH 19/76] added RULE-16-6 --- .../RULE-15-3/GotoLabelBlockCondition.ql | 2 +- .../RULE-16-6/SwitchClauseNumberCondition.ql | 16 ++++-- .../SwitchClauseNumberCondition.expected | 4 +- c/misra/test/rules/RULE-16-6/test.c | 49 +++++++++++++++++++ rule_packages/c/Statements2.json | 11 +++-- 5 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 c/misra/test/rules/RULE-16-6/test.c diff --git a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql index 7b941f3669..d0737e659e 100644 --- a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql +++ b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql @@ -1,6 +1,6 @@ /** * @id c/misra/goto-label-block-condition - * @name RULE-15-3: The goto statement and any of its label shall be declared or enclosed in the same block. + * @name RULE-15-3: The goto statement and any of its label shall be declared or enclosed in the same block. * @description Any label referenced by a goto statement shall be declared in the same block, or in * any block enclosing the goto statement * @kind problem diff --git a/c/misra/src/rules/RULE-16-6/SwitchClauseNumberCondition.ql b/c/misra/src/rules/RULE-16-6/SwitchClauseNumberCondition.ql index 6b2bc9278e..8ddb2e49b2 100644 --- a/c/misra/src/rules/RULE-16-6/SwitchClauseNumberCondition.ql +++ b/c/misra/src/rules/RULE-16-6/SwitchClauseNumberCondition.ql @@ -1,18 +1,24 @@ /** * @id c/misra/switch-clause-number-condition * @name RULE-16-6: Every switch statement shall have at least two switch-clauses - * @description + * @description Switch Statements with a single path are redundant and may cause programming errors. * @kind problem * @precision very-high - * @problem.severity error + * @problem.severity recommendation * @tags external/misra/id/rule-16-6 + * maintainability + * readability * external/misra/obligation/required */ import cpp import codingstandards.c.misra -from +from SwitchStmt switch where - not isExcluded(x, Statements2Package::switchClauseNumberConditionQuery()) and -select + not isExcluded(switch, Statements2Package::switchClauseNumberConditionQuery()) and + count(SwitchCase case | + switch.getASwitchCase() = case and + case.getNextSwitchCase() != case.getFollowingStmt() + ) + 1 < 2 +select switch, "$@ statement has a single path.", switch, "Switch" diff --git a/c/misra/test/rules/RULE-16-6/SwitchClauseNumberCondition.expected b/c/misra/test/rules/RULE-16-6/SwitchClauseNumberCondition.expected index 2ec1a0ac6c..112d0bdd96 100644 --- a/c/misra/test/rules/RULE-16-6/SwitchClauseNumberCondition.expected +++ b/c/misra/test/rules/RULE-16-6/SwitchClauseNumberCondition.expected @@ -1 +1,3 @@ -No expected results have yet been specified \ No newline at end of file +| test.c:3:3:6:3 | switch (...) ... | $@ statement has a single path. | test.c:3:3:6:3 | switch (...) ... | Switch | +| test.c:8:3:12:3 | switch (...) ... | $@ statement has a single path. | test.c:8:3:12:3 | switch (...) ... | Switch | +| test.c:14:3:19:3 | switch (...) ... | $@ statement has a single path. | test.c:14:3:19:3 | switch (...) ... | Switch | diff --git a/c/misra/test/rules/RULE-16-6/test.c b/c/misra/test/rules/RULE-16-6/test.c new file mode 100644 index 0000000000..38a1457a61 --- /dev/null +++ b/c/misra/test/rules/RULE-16-6/test.c @@ -0,0 +1,49 @@ +void f1(int p1) { + int i = 0; + switch (p1) { // NON_COMPLIANT + default: + break; + } + + switch (p1) { // NON_COMPLIANT + case 1: + default: + break; + } + + switch (p1) { // NON_COMPLIANT + case 1: + case 2: + default: + break; + } + + switch (p1) { // COMPLIANT + case 1: + i++; + default: + i = 1; + break; + } + + switch (p1) { // COMPLIANT + case 1: + i++; + case 2: + i = 2; + default: + i = 1; + break; + } + + switch (p1) { // COMPLIANT + case 1: + i++; + case 2: + i = 2; + case 3: + default: + i = 1; + break; + } +} diff --git a/rule_packages/c/Statements2.json b/rule_packages/c/Statements2.json index 6406a91441..4bb37e2743 100644 --- a/rule_packages/c/Statements2.json +++ b/rule_packages/c/Statements2.json @@ -67,13 +67,16 @@ }, "queries": [ { - "description": "", + "description": "Switch Statements with a single path are redundant and may cause programming errors.", "kind": "problem", "name": "Every switch statement shall have at least two switch-clauses", "precision": "very-high", - "severity": "error", + "severity": "recommendation", "short_name": "SwitchClauseNumberCondition", - "tags": [] + "tags": [ + "maintainability", + "readability" + ] } ], "title": "Every switch statement shall have at least two switch-clauses" @@ -96,4 +99,4 @@ "title": "A switch-expression shall not have essentially Boolean type" } } -} \ No newline at end of file +} From 4599a7354a9eb24592374af60c0cc3f320af175f Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 7 Mar 2023 07:55:38 +1100 Subject: [PATCH 20/76] Added RULE-15-6 --- .../rules/RULE-15-6/LoopCompoundCondition.ql | 22 +++ .../RULE-15-6/SelectionCompoundCondition.ql | 22 +++ .../RULE-15-6/SwitchCompoundCondition.ql | 26 ++++ .../RULE-15-6/LoopCompoundCondition.expected | 4 + .../RULE-15-6/LoopCompoundCondition.qlref | 1 + .../SelectionCompoundCondition.expected | 4 + .../SelectionCompoundCondition.qlref | 1 + .../SwitchCompoundCondition.expected | 1 + .../RULE-15-6/SwitchCompoundCondition.qlref | 1 + c/misra/test/rules/RULE-15-6/test.c | 80 +++++++++++ .../codingstandards/cpp/SwitchStatement.qll | 24 ++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + .../cpp/exclusions/c/Statements3.qll | 129 ++++++++++++++++++ rule_packages/c/Statements3.json | 123 +++++++++++++++++ rules.csv | 10 +- 15 files changed, 446 insertions(+), 5 deletions(-) create mode 100644 c/misra/src/rules/RULE-15-6/LoopCompoundCondition.ql create mode 100644 c/misra/src/rules/RULE-15-6/SelectionCompoundCondition.ql create mode 100644 c/misra/src/rules/RULE-15-6/SwitchCompoundCondition.ql create mode 100644 c/misra/test/rules/RULE-15-6/LoopCompoundCondition.expected create mode 100644 c/misra/test/rules/RULE-15-6/LoopCompoundCondition.qlref create mode 100644 c/misra/test/rules/RULE-15-6/SelectionCompoundCondition.expected create mode 100644 c/misra/test/rules/RULE-15-6/SelectionCompoundCondition.qlref create mode 100644 c/misra/test/rules/RULE-15-6/SwitchCompoundCondition.expected create mode 100644 c/misra/test/rules/RULE-15-6/SwitchCompoundCondition.qlref create mode 100644 c/misra/test/rules/RULE-15-6/test.c create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Statements3.qll create mode 100644 rule_packages/c/Statements3.json diff --git a/c/misra/src/rules/RULE-15-6/LoopCompoundCondition.ql b/c/misra/src/rules/RULE-15-6/LoopCompoundCondition.ql new file mode 100644 index 0000000000..c596cb2970 --- /dev/null +++ b/c/misra/src/rules/RULE-15-6/LoopCompoundCondition.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/loop-compound-condition + * @name RULE-15-6: the statement forming the body of a loop shall be a compound statement + * @description if the body of a loop is not enclosed in braces, then this can lead to incorrect + * execution, and is hard for developers to maintain. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-15-6 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from Loop loop +where + not isExcluded(loop, Statements3Package::loopCompoundConditionQuery()) and + not loop.getStmt() instanceof BlockStmt +select loop, "Loop body not enclosed within braces." diff --git a/c/misra/src/rules/RULE-15-6/SelectionCompoundCondition.ql b/c/misra/src/rules/RULE-15-6/SelectionCompoundCondition.ql new file mode 100644 index 0000000000..0c97b3ea5a --- /dev/null +++ b/c/misra/src/rules/RULE-15-6/SelectionCompoundCondition.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/selection-compound-condition + * @name RULE-15-6: the statement forming the body of a loop shall be a compound statement + * @description if the body of a selection statement is not enclosed in braces, then this can lead + * to incorrect execution, and is hard for developers to maintain. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-15-6 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from IfStmt ifStmt +where + not isExcluded(ifStmt, Statements3Package::selectionCompoundConditionQuery()) and + not ifStmt.getChildStmt() instanceof BlockStmt +select ifStmt, "If statement not enclosed within braces." diff --git a/c/misra/src/rules/RULE-15-6/SwitchCompoundCondition.ql b/c/misra/src/rules/RULE-15-6/SwitchCompoundCondition.ql new file mode 100644 index 0000000000..837bfb12c1 --- /dev/null +++ b/c/misra/src/rules/RULE-15-6/SwitchCompoundCondition.ql @@ -0,0 +1,26 @@ +/** + * @id c/misra/switch-compound-condition + * @name RULE-15-6: The statement forming the body of a switch shall be a compound statement + * @description If the body of a switch is not enclosed in braces, then this can lead to incorrect + * execution, and is hard for developers to maintain. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-15-6 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.SwitchStatement + +from SwitchStmt switch +where + not isExcluded(switch, Statements3Package::switchCompoundConditionQuery()) and + ( + switch.getStmt() instanceof ArtificialBlock or + not switch.getStmt() instanceof BlockStmt + ) +select switch, "Switch body not enclosed within braces." diff --git a/c/misra/test/rules/RULE-15-6/LoopCompoundCondition.expected b/c/misra/test/rules/RULE-15-6/LoopCompoundCondition.expected new file mode 100644 index 0000000000..263fee14de --- /dev/null +++ b/c/misra/test/rules/RULE-15-6/LoopCompoundCondition.expected @@ -0,0 +1,4 @@ +| test.c:4:3:5:9 | while (...) ... | Loop body not enclosed within braces. | +| test.c:7:3:8:5 | while (...) ... | Loop body not enclosed within braces. | +| test.c:11:3:12:9 | for(...;...;...) ... | Loop body not enclosed within braces. | +| test.c:14:3:15:5 | while (...) ... | Loop body not enclosed within braces. | diff --git a/c/misra/test/rules/RULE-15-6/LoopCompoundCondition.qlref b/c/misra/test/rules/RULE-15-6/LoopCompoundCondition.qlref new file mode 100644 index 0000000000..8cd3c36d27 --- /dev/null +++ b/c/misra/test/rules/RULE-15-6/LoopCompoundCondition.qlref @@ -0,0 +1 @@ +rules/RULE-15-6/LoopCompoundCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-6/SelectionCompoundCondition.expected b/c/misra/test/rules/RULE-15-6/SelectionCompoundCondition.expected new file mode 100644 index 0000000000..661d118a69 --- /dev/null +++ b/c/misra/test/rules/RULE-15-6/SelectionCompoundCondition.expected @@ -0,0 +1,4 @@ +| test.c:29:3:32:5 | if (...) ... | If statement not enclosed within braces. | +| test.c:34:3:41:7 | if (...) ... | If statement not enclosed within braces. | +| test.c:36:8:41:7 | if (...) ... | If statement not enclosed within braces. | +| test.c:37:5:41:7 | if (...) ... | If statement not enclosed within braces. | diff --git a/c/misra/test/rules/RULE-15-6/SelectionCompoundCondition.qlref b/c/misra/test/rules/RULE-15-6/SelectionCompoundCondition.qlref new file mode 100644 index 0000000000..b62fe0b2c8 --- /dev/null +++ b/c/misra/test/rules/RULE-15-6/SelectionCompoundCondition.qlref @@ -0,0 +1 @@ +rules/RULE-15-6/SelectionCompoundCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-6/SwitchCompoundCondition.expected b/c/misra/test/rules/RULE-15-6/SwitchCompoundCondition.expected new file mode 100644 index 0000000000..eedc122cd6 --- /dev/null +++ b/c/misra/test/rules/RULE-15-6/SwitchCompoundCondition.expected @@ -0,0 +1 @@ +| test.c:75:3:79:5 | switch (...) ... | Switch body not enclosed within braces. | diff --git a/c/misra/test/rules/RULE-15-6/SwitchCompoundCondition.qlref b/c/misra/test/rules/RULE-15-6/SwitchCompoundCondition.qlref new file mode 100644 index 0000000000..c34e33fcbd --- /dev/null +++ b/c/misra/test/rules/RULE-15-6/SwitchCompoundCondition.qlref @@ -0,0 +1 @@ +rules/RULE-15-6/SwitchCompoundCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-6/test.c b/c/misra/test/rules/RULE-15-6/test.c new file mode 100644 index 0000000000..e8ed064b32 --- /dev/null +++ b/c/misra/test/rules/RULE-15-6/test.c @@ -0,0 +1,80 @@ +void f1(); + +void f2(int p1) { + while (p1) // NON_COMPLIANT + f1(); + + while (p1) // NON_COMPLIANT + ; + f1(); + + for (int i = 0; i < p1; i++) // NON_COMPLIANT + f1(); + + while (p1) + ; + { // NON_COMPLIANT + ; + } + + while (p1) { // COMPLIANT + ; + } + for (int i = 0; i < p1; i++) { // COMPLIANT + ; + } +} + +void f3(int p1) { + if (p1) // NON_COMPLIANT + ; + else + ; + + if (p1) // NON_COMPLIANT + ; + else if (p1) // NON_COMPLIANT + if (p1) // NON_COMPLIANT + + if (p1) { // COMPLIANT + ; + } + + if (p1) { // COMPLIANT + ; + } else { // COMPLIANT + ; + } + + if (p1) { // COMPLIANT + ; + } else if (p1) { // COMPLIANT + ; + } else { // COMPLIANT + ; + } +} + +void f4(int p1) { + + switch (p1) { // COMPLIANT + case 0: + while (p1) { + ; + } + break; + case 1: + if (p1) { + ; + } + break; + default: + break; + } + + switch (p1) // NON_COMPLIANT + case 0: + while (p1) { + ; + } +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/SwitchStatement.qll b/cpp/common/src/codingstandards/cpp/SwitchStatement.qll index 1f055be570..7e6686b41a 100644 --- a/cpp/common/src/codingstandards/cpp/SwitchStatement.qll +++ b/cpp/common/src/codingstandards/cpp/SwitchStatement.qll @@ -4,6 +4,30 @@ import cpp +/** + * Class to differentiate between extractor generated blockstmt and actual blockstmt. The extractor + * will generate an artificial blockstmt when there is a single case and statement, e.g. + * ``` + * switch(x) + * case 1: + * f(); + * ``` + * This is because our AST model considers the `case` to be a statement in its own right, so the + * extractor needs an aritifical block to hold both the case and the statement. + */ +class ArtificialBlock extends BlockStmt { + ArtificialBlock() { + exists(Location block, Location firstStatement | + block = getLocation() and firstStatement = getStmt(0).getLocation() + | + // We can identify artificial blocks as those where the start of the statement is at the same + // location as the start of the first statement in the block i.e. there was no opening brace. + block.getStartLine() = firstStatement.getStartLine() and + block.getStartColumn() = firstStatement.getStartColumn() + ) + } +} + /* A `SwitchCase` that contains a 'SwitchCase' inside its body */ class NestedSwitchCase extends SwitchCase { NestedSwitchCase() { diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index e480438be3..5d5e2b7189 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -44,6 +44,7 @@ import SideEffects1 import SideEffects2 import Statements1 import Statements2 +import Statements3 import Strings1 import Strings2 import Strings3 @@ -93,6 +94,7 @@ newtype TCQuery = TSideEffects2PackageQuery(SideEffects2Query q) or TStatements1PackageQuery(Statements1Query q) or TStatements2PackageQuery(Statements2Query q) or + TStatements3PackageQuery(Statements3Query q) or TStrings1PackageQuery(Strings1Query q) or TStrings2PackageQuery(Strings2Query q) or TStrings3PackageQuery(Strings3Query q) or @@ -142,6 +144,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isSideEffects2QueryMetadata(query, queryId, ruleId, category) or isStatements1QueryMetadata(query, queryId, ruleId, category) or isStatements2QueryMetadata(query, queryId, ruleId, category) or + isStatements3QueryMetadata(query, queryId, ruleId, category) or isStrings1QueryMetadata(query, queryId, ruleId, category) or isStrings2QueryMetadata(query, queryId, ruleId, category) or isStrings3QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Statements3.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements3.qll new file mode 100644 index 0000000000..25c1a82ea2 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements3.qll @@ -0,0 +1,129 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Statements3Query = + TSwitchCompoundConditionQuery() or + TLoopCompoundConditionQuery() or + TSelectionCompoundConditionQuery() or + TIfElseEndConditionQuery() or + TSwitchCaseStartConditionQuery() or + TSwitchStmtNotWellFormedQuery() or + TRecursiveFunctionConditionQuery() + +predicate isStatements3QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `switchCompoundCondition` query + Statements3Package::switchCompoundConditionQuery() and + queryId = + // `@id` for the `switchCompoundCondition` query + "c/misra/switch-compound-condition" and + ruleId = "RULE-15-6" and + category = "required" + or + query = + // `Query` instance for the `loopCompoundCondition` query + Statements3Package::loopCompoundConditionQuery() and + queryId = + // `@id` for the `loopCompoundCondition` query + "c/misra/loop-compound-condition" and + ruleId = "RULE-15-6" and + category = "required" + or + query = + // `Query` instance for the `selectionCompoundCondition` query + Statements3Package::selectionCompoundConditionQuery() and + queryId = + // `@id` for the `selectionCompoundCondition` query + "c/misra/selection-compound-condition" and + ruleId = "RULE-15-6" and + category = "required" + or + query = + // `Query` instance for the `ifElseEndCondition` query + Statements3Package::ifElseEndConditionQuery() and + queryId = + // `@id` for the `ifElseEndCondition` query + "c/misra/if-else-end-condition" and + ruleId = "RULE-15-7" and + category = "required" + or + query = + // `Query` instance for the `switchCaseStartCondition` query + Statements3Package::switchCaseStartConditionQuery() and + queryId = + // `@id` for the `switchCaseStartCondition` query + "c/misra/switch-case-start-condition" and + ruleId = "RULE-16-1" and + category = "required" + or + query = + // `Query` instance for the `switchStmtNotWellFormed` query + Statements3Package::switchStmtNotWellFormedQuery() and + queryId = + // `@id` for the `switchStmtNotWellFormed` query + "c/misra/switch-stmt-not-well-formed" and + ruleId = "RULE-16-1" and + category = "required" + or + query = + // `Query` instance for the `recursiveFunctionCondition` query + Statements3Package::recursiveFunctionConditionQuery() and + queryId = + // `@id` for the `recursiveFunctionCondition` query + "c/misra/recursive-function-condition" and + ruleId = "RULE-17-2" and + category = "required" +} + +module Statements3Package { + Query switchCompoundConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `switchCompoundCondition` query + TQueryC(TStatements3PackageQuery(TSwitchCompoundConditionQuery())) + } + + Query loopCompoundConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `loopCompoundCondition` query + TQueryC(TStatements3PackageQuery(TLoopCompoundConditionQuery())) + } + + Query selectionCompoundConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `selectionCompoundCondition` query + TQueryC(TStatements3PackageQuery(TSelectionCompoundConditionQuery())) + } + + Query ifElseEndConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `ifElseEndCondition` query + TQueryC(TStatements3PackageQuery(TIfElseEndConditionQuery())) + } + + Query switchCaseStartConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `switchCaseStartCondition` query + TQueryC(TStatements3PackageQuery(TSwitchCaseStartConditionQuery())) + } + + Query switchStmtNotWellFormedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `switchStmtNotWellFormed` query + TQueryC(TStatements3PackageQuery(TSwitchStmtNotWellFormedQuery())) + } + + Query recursiveFunctionConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `recursiveFunctionCondition` query + TQueryC(TStatements3PackageQuery(TRecursiveFunctionConditionQuery())) + } +} diff --git a/rule_packages/c/Statements3.json b/rule_packages/c/Statements3.json new file mode 100644 index 0000000000..d6259ba8a1 --- /dev/null +++ b/rule_packages/c/Statements3.json @@ -0,0 +1,123 @@ +{ + "MISRA-C-2012": { + "RULE-15-6": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "If the body of a switch is not enclosed in braces, then this can lead to incorrect execution, and is hard for developers to maintain.", + "kind": "problem", + "name": "The statement forming the body of a switch shall be a compound statement", + "precision": "very-high", + "severity": "recommendation", + "short_name": "SwitchCompoundCondition", + "tags": [ + "maintainability", + "readability" + ] + }, + { + "description": "if the body of a loop is not enclosed in braces, then this can lead to incorrect execution, and is hard for developers to maintain.", + "kind": "problem", + "name": "the statement forming the body of a loop shall be a compound statement", + "precision": "very-high", + "severity": "recommendation", + "short_name": "LoopCompoundCondition", + "tags": [ + "maintainability", + "readability" + ] + }, + { + "description": "if the body of a selection statement is not enclosed in braces, then this can lead to incorrect execution, and is hard for developers to maintain.", + "kind": "problem", + "name": "the statement forming the body of a loop shall be a compound statement", + "precision": "very-high", + "severity": "recommendation", + "short_name": "SelectionCompoundCondition", + "tags": [ + "maintainability", + "readability" + ] + } + ], + "title": "The body of an iteration-statement or a selection-statement shall be a compund-statement" + }, + "RULE-15-7": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Terminating an `if...else`construct is a defensive programming technique.", + "kind": "problem", + "name": "All if / else if constructs shall be terminated with an else statement", + "precision": "very-high", + "severity": "recommendation", + "shared_implementation_short_name": "IfElseTerminationConstruct", + "short_name": "IfElseEndCondition", + "tags": [ + "readability", + "maintainability" + ] + } + ], + "title": "All if / else if constructs shall be terminated with an else statement" + }, + "RULE-16-1": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The switch statement syntax is weak and may lead to unspecified behaviour.", + "kind": "problem", + "name": "A well formed switch statement must start with a case clause", + "precision": "very-high", + "severity": "recommendation", + "shared_implementation_short_name": "SwitchCasePositionCondition", + "short_name": "SwitchCaseStartCondition", + "tags": [ + "maintainability", + "readability" + ] + }, + { + "description": "The switch statement syntax is weak and may lead to unspecified behaviour.", + "kind": "problem", + "name": "A well formed switch statement should only have expression, compound, selection, iteration or try statements within its body", + "precision": "very-high", + "severity": "recommendation", + "shared_implementation_short_name": "SwitchNotWellFormed", + "short_name": "SwitchStmtNotWellFormed", + "tags": [ + "maintainability", + "readability" + ] + } + ], + "title": "All switch statements shall be well-formed" + }, + "RULE-17-2": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Recursive function may cause memory and system failure issues.", + "kind": "problem", + "name": "Functions shall not call themselves, either directly or indirectly", + "precision": "very-high", + "severity": "error", + "short_name": "RecursiveFunctionCondition", + "tags": [ + "maintainability", + "correctness" + ] + } + ], + "title": "Functions shall not call themselves, either directly or indirectly" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index 4029401639..96da89354d 100644 --- a/rules.csv +++ b/rules.csv @@ -692,7 +692,7 @@ c,MISRA-C-2012,RULE-13-2,Yes,Required,,,The value of an expression and its persi c,MISRA-C-2012,RULE-13-3,Yes,Advisory,,,A full expression containing an increment (++) or decrement (--) operator should have no other potential side effects other than that caused by the increment or decrement operator,,SideEffects2,Medium, 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-13-6,Yes,Mandatory,,,The operand of the sizeof operator shall not contain any expressiosn 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-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, @@ -702,9 +702,9 @@ c,MISRA-C-2012,RULE-15-2,Yes,Required,,,The goto statement shall jump to a label c,MISRA-C-2012,RULE-15-3,Yes,Required,,,"Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement",M6-6-1,Statements2,Import, c,MISRA-C-2012,RULE-15-4,Yes,Advisory,,,There should be no more than one break or goto statement used to terminate any iteration statement,,Statements2,Medium, c,MISRA-C-2012,RULE-15-5,Yes,Advisory,,,A function should have a single point of exit at the end,,Statements,Medium, -c,MISRA-C-2012,RULE-15-6,Yes,Required,,,The body of an iteration-statement or a selection-statement shall be a compund-statement,M6-3-1,Statements,Import, -c,MISRA-C-2012,RULE-15-7,Yes,Required,,,All if / else if constructs shall be terminated with an else statement,M6-4-2,Statements,Import, -c,MISRA-C-2012,RULE-16-1,Yes,Required,,,All switch statements shall be well-formed,M6-4-3,Statements,Import, +c,MISRA-C-2012,RULE-15-6,Yes,Required,,,The body of an iteration-statement or a selection-statement shall be a compund-statement,M6-3-1,Statements3,Import, +c,MISRA-C-2012,RULE-15-7,Yes,Required,,,All if / else if constructs shall be terminated with an else statement,M6-4-2,Statements3,Import, +c,MISRA-C-2012,RULE-16-1,Yes,Required,,,All switch statements shall be well-formed,M6-4-3,Statements3,Import, c,MISRA-C-2012,RULE-16-2,Yes,Required,,,A switch label shall only be used when the most closely-enclosing compound statement is the body of a switch statement,M6-4-4,Statements1,Import, c,MISRA-C-2012,RULE-16-3,Yes,Required,,,An unconditional break statement shall terminate every switch-clause,M6-4-5,Statements1,Import, c,MISRA-C-2012,RULE-16-4,Yes,Required,,,Every switch statement shall have a default label,M6-4-6,Statements1,Easy, @@ -712,7 +712,7 @@ c,MISRA-C-2012,RULE-16-5,Yes,Required,,,A default label shall appear as either t c,MISRA-C-2012,RULE-16-6,Yes,Required,,,Every switch statement shall have at least two switch-clauses,A6-4-1,Statements2,Medium, c,MISRA-C-2012,RULE-16-7,Yes,Required,,,A switch-expression shall not have essentially Boolean type,M6-4-7,Statements2,Medium, c,MISRA-C-2012,RULE-17-1,Yes,Required,,,The features of shall not be used,,Banned,Easy, -c,MISRA-C-2012,RULE-17-2,Yes,Required,,,"Functions shall not call themselves, either directly or indirectly",A7-5-2,Statements,Import, +c,MISRA-C-2012,RULE-17-2,Yes,Required,,,"Functions shall not call themselves, either directly or indirectly",A7-5-2,Statements3,Import, c,MISRA-C-2012,RULE-17-3,Yes,Mandatory,,,A function shall not be declared implicitly,,Declarations6,Medium, c,MISRA-C-2012,RULE-17-4,Yes,Mandatory,,,All exit paths from a function with non-void return type shall have an explicit return statement with an expression,MSC52-CPP,Statements,Medium, c,MISRA-C-2012,RULE-17-5,Yes,Advisory,,,The function argument corresponding to a parameter declared to have an array type shall have an appropriate number of elements,,Contracts,Hard, From 3b86205f6b50cb667ae97a555e6b9c2bbb6d89e4 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 7 Mar 2023 07:58:08 +1100 Subject: [PATCH 21/76] RULE-15-3 WIP --- .../src/rules/RULE-15-3/GotoLabelBlockCondition.ql | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql index 7b941f3669..cfe5634688 100644 --- a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql +++ b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql @@ -15,6 +15,16 @@ import cpp import codingstandards.c.misra +int statementDepth(Stmt statement) { + statement.getParent() = statement.getEnclosingFunction().getBlock() and result = 1 + or + statementDepth(statement.getParent()) + 1 = result +} + +predicate test(GotoStmt goto, Stmt target, int m, int n) { + statementDepth(goto) = m and target = goto.getTarget() and statementDepth(target) = n +} + from GotoStmt goto where not isExcluded(goto, Statements2Package::gotoLabelBlockConditionQuery()) and @@ -33,5 +43,5 @@ where ) and goto.getTarget().getLocation().getStartLine() > switch.getLocation().getStartLine() ) -select goto, "The $@ statement and its $@ are not declared or enclosed in the same block.", goto, - "goto", goto.getTarget(), "label" +select goto, "The $@ statement and its $@ are not declared or enclosed in the same block. test", + goto, "goto", goto.getTarget(), "label" From 490b3fe0b885744b2547506eda641954e0b99a6d Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 7 Mar 2023 09:47:38 +1100 Subject: [PATCH 22/76] Added RULE-15-7 and moved M6-4-2 to shared folder --- .../IfElseTerminationConstruct.expected | 3 + .../IfElseTerminationConstruct.ql | 2 + .../rules/ifelseterminationconstruct/test.c | 56 +++++++++++++++++++ .../src/rules/RULE-15-7/IfElseEndCondition.ql | 22 ++++++++ .../M6-4-2/IfElseTerminationCondition.ql | 12 ++-- .../IfElseTerminationCondition.expected | 3 - .../M6-4-2/IfElseTerminationCondition.qlref | 1 - .../M6-4-2/IfElseTerminationCondition.testref | 1 + .../IfElseTerminationConstruct.qll | 22 ++++++++ .../IfElseTerminationConstruct.expected | 3 + .../IfElseTerminationConstruct.ql | 2 + .../ifelseterminationconstruct}/test.cpp | 1 + rule_packages/c/Statements3.json | 2 +- rule_packages/cpp/Conditionals.json | 3 +- 14 files changed, 121 insertions(+), 12 deletions(-) create mode 100644 c/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.expected create mode 100644 c/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.ql create mode 100644 c/common/test/rules/ifelseterminationconstruct/test.c create mode 100644 c/misra/src/rules/RULE-15-7/IfElseEndCondition.ql delete mode 100644 cpp/autosar/test/rules/M6-4-2/IfElseTerminationCondition.expected delete mode 100644 cpp/autosar/test/rules/M6-4-2/IfElseTerminationCondition.qlref create mode 100644 cpp/autosar/test/rules/M6-4-2/IfElseTerminationCondition.testref create mode 100644 cpp/common/src/codingstandards/cpp/rules/ifelseterminationconstruct/IfElseTerminationConstruct.qll create mode 100644 cpp/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.expected create mode 100644 cpp/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.ql rename cpp/{autosar/test/rules/M6-4-2 => common/test/rules/ifelseterminationconstruct}/test.cpp (99%) diff --git a/c/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.expected b/c/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.expected new file mode 100644 index 0000000000..910ea55bab --- /dev/null +++ b/c/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.expected @@ -0,0 +1,3 @@ +| test.c:16:3:20:3 | if (...) ... | The $@ construct does not terminate with else statement. | test.c:16:3:20:3 | if (...) ... | `if...else` | +| test.c:33:5:37:5 | if (...) ... | The $@ construct does not terminate with else statement. | test.c:33:5:37:5 | if (...) ... | `if...else` | +| test.c:45:3:55:3 | if (...) ... | The $@ construct does not terminate with else statement. | test.c:45:3:55:3 | if (...) ... | `if...else` | diff --git a/c/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.ql b/c/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.ql new file mode 100644 index 0000000000..d96cb456ce --- /dev/null +++ b/c/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.ifelseterminationconstruct.IfElseTerminationConstruct diff --git a/c/common/test/rules/ifelseterminationconstruct/test.c b/c/common/test/rules/ifelseterminationconstruct/test.c new file mode 100644 index 0000000000..c3fb95df15 --- /dev/null +++ b/c/common/test/rules/ifelseterminationconstruct/test.c @@ -0,0 +1,56 @@ +void f1(int p1) { + + if (p1) { // COMPLIANT + ; + } else if (p1) { + ; + } else { + ; + } +} + +void f2(int p1) { + if (p1) { // COMPLIANT + ; + } + if (p1) { // NON_COMPLIANT + ; + } else if (p1) { + ; + } +} + +void f3(int p1) { + + if (p1) { // COMPLIANT + ; + } else { + ; + } + if (p1) { // COMPLIANT + ; + } else if (p1) { + if (p1) { // NON_COMPLIANT + ; + } else if (p1) { + ; + } + } else { + ; + } +} + +void f4(int p1) { + + if (p1) { // NON_COMPLIANT + ; + } else if (p1) { + if (p1) { // COMPLIANT + ; + } else if (p1) { + ; + } else { + ; + } + } +} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-15-7/IfElseEndCondition.ql b/c/misra/src/rules/RULE-15-7/IfElseEndCondition.ql new file mode 100644 index 0000000000..96132d3deb --- /dev/null +++ b/c/misra/src/rules/RULE-15-7/IfElseEndCondition.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/if-else-end-condition + * @name RULE-15-7: All if / else if constructs shall be terminated with an else statement + * @description Terminating an `if...else` construct is a defensive programming technique. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-15-7 + * readability + * maintainability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.ifelseterminationconstruct.IfElseTerminationConstruct + +class IfElseEndConditionQuery extends IfElseTerminationConstructSharedQuery { + IfElseEndConditionQuery() { + this = Statements3Package::ifElseEndConditionQuery() + } +} diff --git a/cpp/autosar/src/rules/M6-4-2/IfElseTerminationCondition.ql b/cpp/autosar/src/rules/M6-4-2/IfElseTerminationCondition.ql index 1435ed2281..e75d365461 100644 --- a/cpp/autosar/src/rules/M6-4-2/IfElseTerminationCondition.ql +++ b/cpp/autosar/src/rules/M6-4-2/IfElseTerminationCondition.ql @@ -15,10 +15,10 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.ifelseterminationconstruct.IfElseTerminationConstruct -from IfStmt ifStmt, IfStmt ifElse -where - not isExcluded(ifStmt, ConditionalsPackage::ifElseTerminationConditionQuery()) and - ifStmt.getElse() = ifElse and - not ifElse.hasElse() -select ifStmt, "The $@ if statement does not terminate with an else construct.", ifElse, "if...else" +class IfElseTerminationConditionQuery extends IfElseTerminationConstructSharedQuery { + IfElseTerminationConditionQuery() { + this = ConditionalsPackage::ifElseTerminationConditionQuery() + } +} diff --git a/cpp/autosar/test/rules/M6-4-2/IfElseTerminationCondition.expected b/cpp/autosar/test/rules/M6-4-2/IfElseTerminationCondition.expected deleted file mode 100644 index 7716b684af..0000000000 --- a/cpp/autosar/test/rules/M6-4-2/IfElseTerminationCondition.expected +++ /dev/null @@ -1,3 +0,0 @@ -| test.cpp:22:3:26:3 | if (...) ... | The $@ if statement does not terminate with an else construct. | test.cpp:24:10:26:3 | if (...) ... | if...else | -| test.cpp:42:5:46:5 | if (...) ... | The $@ if statement does not terminate with an else construct. | test.cpp:44:12:46:5 | if (...) ... | if...else | -| test.cpp:56:3:66:3 | if (...) ... | The $@ if statement does not terminate with an else construct. | test.cpp:58:10:66:3 | if (...) ... | if...else | diff --git a/cpp/autosar/test/rules/M6-4-2/IfElseTerminationCondition.qlref b/cpp/autosar/test/rules/M6-4-2/IfElseTerminationCondition.qlref deleted file mode 100644 index 28420bff1a..0000000000 --- a/cpp/autosar/test/rules/M6-4-2/IfElseTerminationCondition.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M6-4-2/IfElseTerminationCondition.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-4-2/IfElseTerminationCondition.testref b/cpp/autosar/test/rules/M6-4-2/IfElseTerminationCondition.testref new file mode 100644 index 0000000000..d7ca04a26e --- /dev/null +++ b/cpp/autosar/test/rules/M6-4-2/IfElseTerminationCondition.testref @@ -0,0 +1 @@ +cpp/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.ql \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/ifelseterminationconstruct/IfElseTerminationConstruct.qll b/cpp/common/src/codingstandards/cpp/rules/ifelseterminationconstruct/IfElseTerminationConstruct.qll new file mode 100644 index 0000000000..5755ed8f38 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/ifelseterminationconstruct/IfElseTerminationConstruct.qll @@ -0,0 +1,22 @@ +/** + * Provides a library which includes a `problems` predicate for reporting.... + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class IfElseTerminationConstructSharedQuery extends Query { } + +Query getQuery() { result instanceof IfElseTerminationConstructSharedQuery } + +query predicate problems(IfStmt ifStmt, string message, IfStmt ifLocation, string ifElseString) { + not isExcluded(ifStmt, getQuery()) and + exists(IfStmt ifElse | + ifStmt.getElse() = ifElse and + not ifElse.hasElse() + ) and + ifLocation = ifStmt and + message = "The $@ construct does not terminate with else statement." and + ifElseString = "`if...else`" +} diff --git a/cpp/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.expected b/cpp/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.expected new file mode 100644 index 0000000000..0d14bfa016 --- /dev/null +++ b/cpp/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.expected @@ -0,0 +1,3 @@ +| test.cpp:23:3:27:3 | if (...) ... | The $@ construct does not terminate with else statement. | test.cpp:23:3:27:3 | if (...) ... | `if...else` | +| test.cpp:43:5:47:5 | if (...) ... | The $@ construct does not terminate with else statement. | test.cpp:43:5:47:5 | if (...) ... | `if...else` | +| test.cpp:57:3:67:3 | if (...) ... | The $@ construct does not terminate with else statement. | test.cpp:57:3:67:3 | if (...) ... | `if...else` | diff --git a/cpp/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.ql b/cpp/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.ql new file mode 100644 index 0000000000..d96cb456ce --- /dev/null +++ b/cpp/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.ifelseterminationconstruct.IfElseTerminationConstruct diff --git a/cpp/autosar/test/rules/M6-4-2/test.cpp b/cpp/common/test/rules/ifelseterminationconstruct/test.cpp similarity index 99% rename from cpp/autosar/test/rules/M6-4-2/test.cpp rename to cpp/common/test/rules/ifelseterminationconstruct/test.cpp index 8689771d8e..bf8d1d6da3 100644 --- a/cpp/autosar/test/rules/M6-4-2/test.cpp +++ b/cpp/common/test/rules/ifelseterminationconstruct/test.cpp @@ -1,3 +1,4 @@ + void test_ifelse_valid(int expression) { int i = 3; int j = 4; diff --git a/rule_packages/c/Statements3.json b/rule_packages/c/Statements3.json index d6259ba8a1..41463415a6 100644 --- a/rule_packages/c/Statements3.json +++ b/rule_packages/c/Statements3.json @@ -50,7 +50,7 @@ }, "queries": [ { - "description": "Terminating an `if...else`construct is a defensive programming technique.", + "description": "Terminating an `if...else` construct is a defensive programming technique.", "kind": "problem", "name": "All if / else if constructs shall be terminated with an else statement", "precision": "very-high", diff --git a/rule_packages/cpp/Conditionals.json b/rule_packages/cpp/Conditionals.json index 755a24d2aa..549f3440e3 100644 --- a/rule_packages/cpp/Conditionals.json +++ b/rule_packages/cpp/Conditionals.json @@ -136,6 +136,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "IfElseTerminationCondition", + "shared_implementation_short_name": "IfElseTerminationConstruct", "tags": [ "maintainability", "readability" @@ -363,4 +364,4 @@ "title": "The continue statement shall only be used within a well-formed for loop." } } -} +} \ No newline at end of file From d327596ee8473fc98f9f2711a913d29a34bd9e9a Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 7 Mar 2023 10:46:58 +1100 Subject: [PATCH 23/76] added RULE-16-1 and moved M6-4-3 to shared folder --- .../SwitchCasePositionCondition.expected | 1 + .../SwitchCasePositionCondition.ql | 2 + .../rules/switchcasepositioncondition/test.c | 42 +++++++++ .../SwitchNotWellFormed.expected | 3 + .../SwitchNotWellFormed.ql | 2 + .../test/rules/switchnotwellformed/test.c | 40 ++++++++ .../RULE-16-1/SwitchCaseStartCondition.ql | 22 +++++ .../RULE-16-1/SwitchStmtNotWellFormed.ql | 22 +++++ .../M6-4-3/SwitchDoesNotStartWithCase.ql | 15 ++- .../M6-4-3/SwitchStatementNotWellFormed.ql | 15 ++- .../SwitchDoesNotStartWithCase.expected | 1 - .../M6-4-3/SwitchDoesNotStartWithCase.qlref | 1 - .../M6-4-3/SwitchDoesNotStartWithCase.testref | 1 + .../SwitchStatementNotWellFormed.expected | 3 - .../M6-4-3/SwitchStatementNotWellFormed.qlref | 1 - .../SwitchStatementNotWellFormed.testref | 1 + cpp/autosar/test/rules/M6-4-3/test.cpp | 92 ------------------- .../SwitchCasePositionCondition.qll | 32 +++++++ .../SwitchNotWellFormed.qll | 26 ++++++ .../SwitchCasePositionCondition.expected | 1 + .../SwitchCasePositionCondition.ql | 2 + .../switchcasepositioncondition/test.cpp | 42 +++++++++ .../SwitchNotWellFormed.expected | 3 + .../SwitchNotWellFormed.ql | 2 + .../test/rules/switchnotwellformed/test.cpp | 40 ++++++++ rule_packages/cpp/Conditionals.json | 2 + 26 files changed, 298 insertions(+), 116 deletions(-) create mode 100644 c/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.expected create mode 100644 c/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.ql create mode 100644 c/common/test/rules/switchcasepositioncondition/test.c create mode 100644 c/common/test/rules/switchnotwellformed/SwitchNotWellFormed.expected create mode 100644 c/common/test/rules/switchnotwellformed/SwitchNotWellFormed.ql create mode 100644 c/common/test/rules/switchnotwellformed/test.c create mode 100644 c/misra/src/rules/RULE-16-1/SwitchCaseStartCondition.ql create mode 100644 c/misra/src/rules/RULE-16-1/SwitchStmtNotWellFormed.ql delete mode 100644 cpp/autosar/test/rules/M6-4-3/SwitchDoesNotStartWithCase.expected delete mode 100644 cpp/autosar/test/rules/M6-4-3/SwitchDoesNotStartWithCase.qlref create mode 100644 cpp/autosar/test/rules/M6-4-3/SwitchDoesNotStartWithCase.testref delete mode 100644 cpp/autosar/test/rules/M6-4-3/SwitchStatementNotWellFormed.expected delete mode 100644 cpp/autosar/test/rules/M6-4-3/SwitchStatementNotWellFormed.qlref create mode 100644 cpp/autosar/test/rules/M6-4-3/SwitchStatementNotWellFormed.testref delete mode 100644 cpp/autosar/test/rules/M6-4-3/test.cpp create mode 100644 cpp/common/src/codingstandards/cpp/rules/switchcasepositioncondition/SwitchCasePositionCondition.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/switchnotwellformed/SwitchNotWellFormed.qll create mode 100644 cpp/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.expected create mode 100644 cpp/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.ql create mode 100644 cpp/common/test/rules/switchcasepositioncondition/test.cpp create mode 100644 cpp/common/test/rules/switchnotwellformed/SwitchNotWellFormed.expected create mode 100644 cpp/common/test/rules/switchnotwellformed/SwitchNotWellFormed.ql create mode 100644 cpp/common/test/rules/switchnotwellformed/test.cpp diff --git a/c/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.expected b/c/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.expected new file mode 100644 index 0000000000..14cc8431da --- /dev/null +++ b/c/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.expected @@ -0,0 +1 @@ +| test.c:5:3:24:3 | switch (...) ... | $@ statement not well formed because the first statement in a well formed switch statement must be a case clause. | test.c:5:3:24:3 | switch (...) ... | Switch | diff --git a/c/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.ql b/c/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.ql new file mode 100644 index 0000000000..65188d04f7 --- /dev/null +++ b/c/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.switchcasepositioncondition.SwitchCasePositionCondition diff --git a/c/common/test/rules/switchcasepositioncondition/test.c b/c/common/test/rules/switchcasepositioncondition/test.c new file mode 100644 index 0000000000..bbdbddfb80 --- /dev/null +++ b/c/common/test/rules/switchcasepositioncondition/test.c @@ -0,0 +1,42 @@ +void f1(int p1); + +void f2(int p1) { + + switch (p1) { + start:; // NON_COMPLIANT + case 1: + if (p1) { + ; + }; + break; + case 2: + if (p1) { + ; + } + break; + case 3: + if (p1) { + ; + } + break; + default:; + break; + } +} +void f3(int p1) { + + switch (p1) { // COMPLIANT + case 2: + if (p1) { + ; + } + break; + case 3: + if (p1) { + ; + } + break; + default:; + break; + } +} diff --git a/c/common/test/rules/switchnotwellformed/SwitchNotWellFormed.expected b/c/common/test/rules/switchnotwellformed/SwitchNotWellFormed.expected new file mode 100644 index 0000000000..a9062b5fd4 --- /dev/null +++ b/c/common/test/rules/switchnotwellformed/SwitchNotWellFormed.expected @@ -0,0 +1,3 @@ +| test.c:4:3:10:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.c:4:3:10:3 | switch (...) ... | Switch | test.c:5:3:5:9 | case ...: | case | +| test.c:13:3:20:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.c:13:3:20:3 | switch (...) ... | Switch | test.c:14:3:14:10 | case ...: | case | +| test.c:25:3:30:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.c:25:3:30:3 | switch (...) ... | Switch | test.c:26:3:26:9 | case ...: | case | diff --git a/c/common/test/rules/switchnotwellformed/SwitchNotWellFormed.ql b/c/common/test/rules/switchnotwellformed/SwitchNotWellFormed.ql new file mode 100644 index 0000000000..0a398a99a9 --- /dev/null +++ b/c/common/test/rules/switchnotwellformed/SwitchNotWellFormed.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.switchnotwellformed.SwitchNotWellFormed diff --git a/c/common/test/rules/switchnotwellformed/test.c b/c/common/test/rules/switchnotwellformed/test.c new file mode 100644 index 0000000000..d1fe00d5af --- /dev/null +++ b/c/common/test/rules/switchnotwellformed/test.c @@ -0,0 +1,40 @@ + +void f1(); +void f2(int p1) { + switch (p1) { + case 1: + int y = p1; // NON_COMPLIANT - `DeclStmt` whose parent + // statement is the switch body + f1(); + break; + } +} +void f3(int p1) { + switch (p1) { + case 10: + f1(); + goto L1; // NON_COMPLIANT - `JumpStmt` whose parent statement is the// + // switch// body + case 2: + break; + } +L1:; +} + +void f4(int p1) { + switch (p1) { + case 1: + L1:; // NON_COMPLIANT - `LabelStmt` whose parent statement is the + // switch body + break; + } +} + +void f5(int p1) { + switch (p1) { + case 1: // COMPLIANT + default: + p1 = 0; + break; + } +} diff --git a/c/misra/src/rules/RULE-16-1/SwitchCaseStartCondition.ql b/c/misra/src/rules/RULE-16-1/SwitchCaseStartCondition.ql new file mode 100644 index 0000000000..32d390e33e --- /dev/null +++ b/c/misra/src/rules/RULE-16-1/SwitchCaseStartCondition.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/switch-case-start-condition + * @name RULE-16-1: A well formed switch statement must start with a case clause + * @description The switch statement syntax is weak and may lead to unspecified behaviour. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-16-1 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.switchcasepositioncondition.SwitchCasePositionCondition + +class SwitchCaseStartConditionQuery extends SwitchCasePositionConditionSharedQuery { + SwitchCaseStartConditionQuery() { + this = Statements3Package::switchCaseStartConditionQuery() + } +} diff --git a/c/misra/src/rules/RULE-16-1/SwitchStmtNotWellFormed.ql b/c/misra/src/rules/RULE-16-1/SwitchStmtNotWellFormed.ql new file mode 100644 index 0000000000..30293e41dd --- /dev/null +++ b/c/misra/src/rules/RULE-16-1/SwitchStmtNotWellFormed.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/switch-stmt-not-well-formed + * @name RULE-16-1: A well formed switch statement should only have expression, compound, selection, iteration or try statements within its body + * @description The switch statement syntax is weak and may lead to unspecified behaviour. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-16-1 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.switchnotwellformed.SwitchNotWellFormed + +class SwitchStmtNotWellFormedQuery extends SwitchNotWellFormedSharedQuery { + SwitchStmtNotWellFormedQuery() { + this = Statements3Package::switchStmtNotWellFormedQuery() + } +} diff --git a/cpp/autosar/src/rules/M6-4-3/SwitchDoesNotStartWithCase.ql b/cpp/autosar/src/rules/M6-4-3/SwitchDoesNotStartWithCase.ql index d56bf1da0f..07953dd9f1 100644 --- a/cpp/autosar/src/rules/M6-4-3/SwitchDoesNotStartWithCase.ql +++ b/cpp/autosar/src/rules/M6-4-3/SwitchDoesNotStartWithCase.ql @@ -16,13 +16,10 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.SwitchStatement +import codingstandards.cpp.rules.switchcasepositioncondition.SwitchCasePositionCondition -from SwitchStmt switch, SwitchCase case -where - not isExcluded(switch, ConditionalsPackage::switchDoesNotStartWithCaseQuery()) and - case = switch.getASwitchCase() and - switchWithCaseNotFirst(switch) -select switch, - "$@ statement not well formed because the first statement in a well formed switch statement must be a case clause.", - switch, "Switch" +class SwitchDoesNotStartWithCaseQuery extends SwitchCasePositionConditionSharedQuery { + SwitchDoesNotStartWithCaseQuery() { + this = ConditionalsPackage::switchDoesNotStartWithCaseQuery() + } +} diff --git a/cpp/autosar/src/rules/M6-4-3/SwitchStatementNotWellFormed.ql b/cpp/autosar/src/rules/M6-4-3/SwitchStatementNotWellFormed.ql index 83d4c2017f..24ac2298b5 100644 --- a/cpp/autosar/src/rules/M6-4-3/SwitchStatementNotWellFormed.ql +++ b/cpp/autosar/src/rules/M6-4-3/SwitchStatementNotWellFormed.ql @@ -16,13 +16,10 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.SwitchStatement +import codingstandards.cpp.rules.switchnotwellformed.SwitchNotWellFormed -from SwitchStmt switch, SwitchCase case -where - not isExcluded(switch, ConditionalsPackage::switchStatementNotWellFormedQuery()) and - case = switch.getASwitchCase() and - switchCaseNotWellFormed(case) -select switch, - "$@ statement not well formed because this $@ block uses a statement that is not allowed.", - switch, "Switch", case, "case" +class SwitchStatementNotWellFormedQuery extends SwitchNotWellFormedSharedQuery { + SwitchStatementNotWellFormedQuery() { + this = ConditionalsPackage::switchStatementNotWellFormedQuery() + } +} diff --git a/cpp/autosar/test/rules/M6-4-3/SwitchDoesNotStartWithCase.expected b/cpp/autosar/test/rules/M6-4-3/SwitchDoesNotStartWithCase.expected deleted file mode 100644 index 58fffdcdbb..0000000000 --- a/cpp/autosar/test/rules/M6-4-3/SwitchDoesNotStartWithCase.expected +++ /dev/null @@ -1 +0,0 @@ -| test.cpp:6:3:28:3 | switch (...) ... | $@ statement not well formed because the first statement in a well formed switch statement must be a case clause. | test.cpp:6:3:28:3 | switch (...) ... | Switch | diff --git a/cpp/autosar/test/rules/M6-4-3/SwitchDoesNotStartWithCase.qlref b/cpp/autosar/test/rules/M6-4-3/SwitchDoesNotStartWithCase.qlref deleted file mode 100644 index 6cd5c459fb..0000000000 --- a/cpp/autosar/test/rules/M6-4-3/SwitchDoesNotStartWithCase.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M6-4-3/SwitchDoesNotStartWithCase.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-4-3/SwitchDoesNotStartWithCase.testref b/cpp/autosar/test/rules/M6-4-3/SwitchDoesNotStartWithCase.testref new file mode 100644 index 0000000000..4dd98ccfb9 --- /dev/null +++ b/cpp/autosar/test/rules/M6-4-3/SwitchDoesNotStartWithCase.testref @@ -0,0 +1 @@ +cpp/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-4-3/SwitchStatementNotWellFormed.expected b/cpp/autosar/test/rules/M6-4-3/SwitchStatementNotWellFormed.expected deleted file mode 100644 index 6985297c15..0000000000 --- a/cpp/autosar/test/rules/M6-4-3/SwitchStatementNotWellFormed.expected +++ /dev/null @@ -1,3 +0,0 @@ -| test.cpp:51:3:57:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.cpp:51:3:57:3 | switch (...) ... | Switch | test.cpp:52:3:52:9 | case ...: | case | -| test.cpp:61:3:70:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.cpp:61:3:70:3 | switch (...) ... | Switch | test.cpp:62:3:62:10 | case ...: | case | -| test.cpp:76:3:82:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.cpp:76:3:82:3 | switch (...) ... | Switch | test.cpp:77:3:77:9 | case ...: | case | diff --git a/cpp/autosar/test/rules/M6-4-3/SwitchStatementNotWellFormed.qlref b/cpp/autosar/test/rules/M6-4-3/SwitchStatementNotWellFormed.qlref deleted file mode 100644 index d71f5220bc..0000000000 --- a/cpp/autosar/test/rules/M6-4-3/SwitchStatementNotWellFormed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M6-4-3/SwitchStatementNotWellFormed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-4-3/SwitchStatementNotWellFormed.testref b/cpp/autosar/test/rules/M6-4-3/SwitchStatementNotWellFormed.testref new file mode 100644 index 0000000000..7695dc2772 --- /dev/null +++ b/cpp/autosar/test/rules/M6-4-3/SwitchStatementNotWellFormed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/switchnotwellformed/SwitchNotWellFormed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-4-3/test.cpp b/cpp/autosar/test/rules/M6-4-3/test.cpp deleted file mode 100644 index 4156053457..0000000000 --- a/cpp/autosar/test/rules/M6-4-3/test.cpp +++ /dev/null @@ -1,92 +0,0 @@ -void f(int y); - -void test_caseclausenotfirst_invalid(int expression) { - int i = 5; - int j; - switch (expression) { - start: - expression = 4; // NON_COMPLIANT - first statement must be case clause - case 1: - if (i > 4) { - j = 3; - } - i = 3; - break; - case 2: - if (i % 2 == 0) { - j = 1; - } - break; - case 3: - if (i % 2 == 1) { - j = 8; - } - break; - default: - j = 5; - break; - } -} -void test_switch_caseclausefirst_valid(int expression) { - int i = 5; - int j; - switch (expression) { - case 2: - if (i % 2 == 0) { - j = 1; - } - break; - case 3: - if (i % 2 == 1) { - j = 8; - } - break; - default: - j = 5; - break; - } -} - -void test_notwellformedswitch_expr(int expression) { - switch (expression) { - case 1: - int y = expression + 1; // NON_COMPLIANT - `DeclStmt` whose parent - // statementis the switch body - f(y); - break; - } -} -void test_notwellformedswitch_jmp(int expression) { - int y = 2; - switch (expression) { - case 10: - f(y); - goto end; // NON_COMPLIANT - `JumpStmt` whose parent statement is the - // switch - // body - - case 2: - break; - } -end: - expression = 3; -} - -void test_notwellformedswitch_labelStmt(int expression) { - switch (expression) { - case 1: - start: - expression = 4; // NON_COMPLIANT - `LabelStmt` whose parent statement is the - // switch body - break; - } -} - -void test_emptyfallthrough(int expression) { - switch (expression) { - case 1: // COMPLIANT - default: - expression = 0; - break; - } -} diff --git a/cpp/common/src/codingstandards/cpp/rules/switchcasepositioncondition/SwitchCasePositionCondition.qll b/cpp/common/src/codingstandards/cpp/rules/switchcasepositioncondition/SwitchCasePositionCondition.qll new file mode 100644 index 0000000000..68ba9850af --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/switchcasepositioncondition/SwitchCasePositionCondition.qll @@ -0,0 +1,32 @@ +/** + * Provides a library which includes a `problems` predicate for reporting.... + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.SwitchStatement + +abstract class SwitchCasePositionConditionSharedQuery extends Query { } + +Query getQuery() { result instanceof SwitchCasePositionConditionSharedQuery } + +//from SwitchStmt switch, SwitchCase case +//where +//not isExcluded(switch, ConditionalsPackage::switchDoesNotStartWithCaseQuery()) and +//case = switch.getASwitchCase() and +//switchWithCaseNotFirst(switch) +//select switch, +//"$@ statement not well formed because the first statement in a well formed switch statement must be a case clause.", +//switch, "Switch" +query predicate problems( + SwitchStmt switch, string message, SwitchStmt switchLocation, string switchMessage +) { + not isExcluded(switch, getQuery()) and + exists(SwitchCase case | case = switch.getASwitchCase()) and + switchWithCaseNotFirst(switch) and + switchLocation = switch and + switchMessage = "Switch" and + message = + "$@ statement not well formed because the first statement in a well formed switch statement must be a case clause." +} diff --git a/cpp/common/src/codingstandards/cpp/rules/switchnotwellformed/SwitchNotWellFormed.qll b/cpp/common/src/codingstandards/cpp/rules/switchnotwellformed/SwitchNotWellFormed.qll new file mode 100644 index 0000000000..ee04228a95 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/switchnotwellformed/SwitchNotWellFormed.qll @@ -0,0 +1,26 @@ +/** + * Provides a library which includes a `problems` predicate for reporting.... + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.SwitchStatement + +abstract class SwitchNotWellFormedSharedQuery extends Query { } + +Query getQuery() { result instanceof SwitchNotWellFormedSharedQuery } + +query predicate problems( + SwitchStmt switch, string message, SwitchStmt switchLocation, string switchMessage, + SwitchCase case, string caseMessage +) { + not isExcluded(switch, getQuery()) and + case = switch.getASwitchCase() and + switchCaseNotWellFormed(case) and + switch = switchLocation and + message = + "$@ statement not well formed because this $@ block uses a statement that is not allowed." and + switchMessage = "Switch" and + caseMessage = "case" +} diff --git a/cpp/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.expected b/cpp/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.expected new file mode 100644 index 0000000000..9bad1dc42e --- /dev/null +++ b/cpp/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.expected @@ -0,0 +1 @@ +| test.cpp:5:3:24:3 | switch (...) ... | $@ statement not well formed because the first statement in a well formed switch statement must be a case clause. | test.cpp:5:3:24:3 | switch (...) ... | Switch | diff --git a/cpp/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.ql b/cpp/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.ql new file mode 100644 index 0000000000..65188d04f7 --- /dev/null +++ b/cpp/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.switchcasepositioncondition.SwitchCasePositionCondition diff --git a/cpp/common/test/rules/switchcasepositioncondition/test.cpp b/cpp/common/test/rules/switchcasepositioncondition/test.cpp new file mode 100644 index 0000000000..bbdbddfb80 --- /dev/null +++ b/cpp/common/test/rules/switchcasepositioncondition/test.cpp @@ -0,0 +1,42 @@ +void f1(int p1); + +void f2(int p1) { + + switch (p1) { + start:; // NON_COMPLIANT + case 1: + if (p1) { + ; + }; + break; + case 2: + if (p1) { + ; + } + break; + case 3: + if (p1) { + ; + } + break; + default:; + break; + } +} +void f3(int p1) { + + switch (p1) { // COMPLIANT + case 2: + if (p1) { + ; + } + break; + case 3: + if (p1) { + ; + } + break; + default:; + break; + } +} diff --git a/cpp/common/test/rules/switchnotwellformed/SwitchNotWellFormed.expected b/cpp/common/test/rules/switchnotwellformed/SwitchNotWellFormed.expected new file mode 100644 index 0000000000..0353e68531 --- /dev/null +++ b/cpp/common/test/rules/switchnotwellformed/SwitchNotWellFormed.expected @@ -0,0 +1,3 @@ +| test.cpp:4:3:10:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.cpp:4:3:10:3 | switch (...) ... | Switch | test.cpp:5:3:5:9 | case ...: | case | +| test.cpp:13:3:20:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.cpp:13:3:20:3 | switch (...) ... | Switch | test.cpp:14:3:14:10 | case ...: | case | +| test.cpp:25:3:30:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.cpp:25:3:30:3 | switch (...) ... | Switch | test.cpp:26:3:26:9 | case ...: | case | diff --git a/cpp/common/test/rules/switchnotwellformed/SwitchNotWellFormed.ql b/cpp/common/test/rules/switchnotwellformed/SwitchNotWellFormed.ql new file mode 100644 index 0000000000..0a398a99a9 --- /dev/null +++ b/cpp/common/test/rules/switchnotwellformed/SwitchNotWellFormed.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.switchnotwellformed.SwitchNotWellFormed diff --git a/cpp/common/test/rules/switchnotwellformed/test.cpp b/cpp/common/test/rules/switchnotwellformed/test.cpp new file mode 100644 index 0000000000..d1fe00d5af --- /dev/null +++ b/cpp/common/test/rules/switchnotwellformed/test.cpp @@ -0,0 +1,40 @@ + +void f1(); +void f2(int p1) { + switch (p1) { + case 1: + int y = p1; // NON_COMPLIANT - `DeclStmt` whose parent + // statement is the switch body + f1(); + break; + } +} +void f3(int p1) { + switch (p1) { + case 10: + f1(); + goto L1; // NON_COMPLIANT - `JumpStmt` whose parent statement is the// + // switch// body + case 2: + break; + } +L1:; +} + +void f4(int p1) { + switch (p1) { + case 1: + L1:; // NON_COMPLIANT - `LabelStmt` whose parent statement is the + // switch body + break; + } +} + +void f5(int p1) { + switch (p1) { + case 1: // COMPLIANT + default: + p1 = 0; + break; + } +} diff --git a/rule_packages/cpp/Conditionals.json b/rule_packages/cpp/Conditionals.json index 549f3440e3..dba9341493 100644 --- a/rule_packages/cpp/Conditionals.json +++ b/rule_packages/cpp/Conditionals.json @@ -161,6 +161,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "SwitchDoesNotStartWithCase", + "shared_implementation_short_name": "SwitchCasePositionCondition", "tags": [ "maintainability", "readability" @@ -173,6 +174,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "SwitchStatementNotWellFormed", + "shared_implementation_short_name": "SwitchNotWellFormed", "tags": [ "maintainability", "readability" From 12da78003c426b9b7f94b723bab611983ec18936 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 7 Mar 2023 10:58:20 +1100 Subject: [PATCH 24/76] added image of rule condition to RULE-16-1 --- .../src/rules/RULE-16-1/6-4-3_grammar_1.png | Bin 0 -> 213564 bytes .../src/rules/RULE-16-1/6-4-3_grammar_2.png | Bin 0 -> 26933 bytes .../src/rules/RULE-16-1/6-4-3_grammar_3.png | Bin 0 -> 58008 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 c/misra/src/rules/RULE-16-1/6-4-3_grammar_1.png create mode 100644 c/misra/src/rules/RULE-16-1/6-4-3_grammar_2.png create mode 100644 c/misra/src/rules/RULE-16-1/6-4-3_grammar_3.png diff --git a/c/misra/src/rules/RULE-16-1/6-4-3_grammar_1.png b/c/misra/src/rules/RULE-16-1/6-4-3_grammar_1.png new file mode 100644 index 0000000000000000000000000000000000000000..d6adfd06c1335fbc7f370fcfb37862f5be316ed6 GIT binary patch literal 213564 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�ocYq6-AWv8d221Et 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%0DeX@D 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 GgZ~10AO02q literal 0 HcmV?d00001 diff --git a/c/misra/src/rules/RULE-16-1/6-4-3_grammar_2.png b/c/misra/src/rules/RULE-16-1/6-4-3_grammar_2.png new file mode 100644 index 0000000000000000000000000000000000000000..4a7ae673e8c771fb9b84964abd03d0550fa85000 GIT binary patch literal 26933 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�_My7uE&wemvPP6{RSP@<|l$}U;?;~m@t20Xa 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 Nfv2mV%Q~loCIGUx= Date: Tue, 7 Mar 2023 11:00:41 +1100 Subject: [PATCH 25/76] Added tests for RULE-16-1 --- c/misra/test/rules/RULE-16-1/SwitchCaseStartCondition.testref | 1 + c/misra/test/rules/RULE-16-1/SwitchStmtNotWellFormed.testref | 1 + 2 files changed, 2 insertions(+) create mode 100644 c/misra/test/rules/RULE-16-1/SwitchCaseStartCondition.testref create mode 100644 c/misra/test/rules/RULE-16-1/SwitchStmtNotWellFormed.testref diff --git a/c/misra/test/rules/RULE-16-1/SwitchCaseStartCondition.testref b/c/misra/test/rules/RULE-16-1/SwitchCaseStartCondition.testref new file mode 100644 index 0000000000..5d2b2ff0d1 --- /dev/null +++ b/c/misra/test/rules/RULE-16-1/SwitchCaseStartCondition.testref @@ -0,0 +1 @@ +c/common/test/rules/switchcasepositioncondition/SwitchCasePositionCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-16-1/SwitchStmtNotWellFormed.testref b/c/misra/test/rules/RULE-16-1/SwitchStmtNotWellFormed.testref new file mode 100644 index 0000000000..e37234ee4b --- /dev/null +++ b/c/misra/test/rules/RULE-16-1/SwitchStmtNotWellFormed.testref @@ -0,0 +1 @@ +c/common/test/rules/switchnotwellformed/SwitchNotWellFormed.ql \ No newline at end of file From 2b76aad5ea13a71b9c4a99c703b66e39eae14ba4 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 7 Mar 2023 12:02:59 +1100 Subject: [PATCH 26/76] Added RULE-17-2 --- .../RULE-17-2/RecursiveFunctionCondition.ql | 27 +++++++++++++++++++ .../RecursiveFunctionCondition.expected | 4 +++ .../RecursiveFunctionCondition.qlref | 1 + c/misra/test/rules/RULE-17-2/test.c | 19 +++++++++++++ 4 files changed, 51 insertions(+) create mode 100644 c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql create mode 100644 c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.expected create mode 100644 c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.qlref create mode 100644 c/misra/test/rules/RULE-17-2/test.c diff --git a/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql b/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql new file mode 100644 index 0000000000..e1f8180aee --- /dev/null +++ b/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql @@ -0,0 +1,27 @@ +/** + * @id c/misra/recursive-function-condition + * @name RULE-17-2: Functions shall not call themselves, either directly or indirectly + * @description Recursive function may cause memory and system failure issues. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-17-2 + * maintainability + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from FunctionCall call, string msg, FunctionCall fc +where + not isExcluded(fc, Statements3Package::recursiveFunctionConditionQuery()) and + fc.getTarget() = call.getTarget() and + call.getTarget().calls*(call.getEnclosingFunction()) and + if fc.getTarget() = fc.getEnclosingFunction() + then msg = "This call directly invokes its containing function $@." + else + msg = + "The function " + fc.getEnclosingFunction() + " is indirectly recursive via this call to $@." +select fc, msg, fc.getTarget(), fc.getTarget().getName() diff --git a/c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.expected b/c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.expected new file mode 100644 index 0000000000..5c40b93b1c --- /dev/null +++ b/c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.expected @@ -0,0 +1,4 @@ +| test.c:8:3:8:4 | call to f3 | This call directly invokes its containing function $@. | test.c:7:6:7:7 | f3 | f3 | +| test.c:11:3:11:4 | call to f3 | The function f6 is indirectly recursive via this call to $@. | test.c:7:6:7:7 | f3 | f3 | +| test.c:15:3:15:4 | call to f2 | The function f5 is indirectly recursive via this call to $@. | test.c:17:6:17:7 | f2 | f2 | +| test.c:18:3:18:4 | call to f5 | The function f2 is indirectly recursive via this call to $@. | test.c:14:6:14:7 | f5 | f5 | diff --git a/c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.qlref b/c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.qlref new file mode 100644 index 0000000000..da361b35f4 --- /dev/null +++ b/c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.qlref @@ -0,0 +1 @@ +rules/RULE-17-2/RecursiveFunctionCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-2/test.c b/c/misra/test/rules/RULE-17-2/test.c new file mode 100644 index 0000000000..800921c1e2 --- /dev/null +++ b/c/misra/test/rules/RULE-17-2/test.c @@ -0,0 +1,19 @@ +void f1(); +void f2(); +void f4(int p1) { // COMPLIANT + f1(); +} + +void f3() { + f3(); // NON_COMPLIANT +} +void f6() { + f3(); // NON_COMPLIANT +} + +void f5() { + f2(); // NON_COMPLIANT +} +void f2() { + f5(); // NON_COMPLIANT +} \ No newline at end of file From 34fb54a9a15691b11fcd0b3bdf54e5f88a93272b Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 7 Mar 2023 12:56:57 +1100 Subject: [PATCH 27/76] Added Tests for RULE-15-7 --- c/misra/test/rules/RULE-15-7/IfElseEndCondition.testref | 1 + 1 file changed, 1 insertion(+) create mode 100644 c/misra/test/rules/RULE-15-7/IfElseEndCondition.testref diff --git a/c/misra/test/rules/RULE-15-7/IfElseEndCondition.testref b/c/misra/test/rules/RULE-15-7/IfElseEndCondition.testref new file mode 100644 index 0000000000..89caf8f257 --- /dev/null +++ b/c/misra/test/rules/RULE-15-7/IfElseEndCondition.testref @@ -0,0 +1 @@ +c/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.ql \ No newline at end of file From 755fc4692c300852ca3b123cb0c6ea448cfeb4ec Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 7 Mar 2023 14:21:38 +1100 Subject: [PATCH 28/76] added FLP30-C --- .../FLP30-C/FloatingPointLoopCounters.md | 106 ++++++++++++++++++ .../FLP30-C/FloatingPointLoopCounters.ql | 30 +++++ .../FloatingPointLoopCounters.expected | 2 + .../FLP30-C/FloatingPointLoopCounters.qlref | 1 + c/cert/test/rules/FLP30-C/test.c | 15 +++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + .../cpp/exclusions/c/Statements4.qll | 78 +++++++++++++ rule_packages/c/Statements4.json | 81 +++++++++++++ rules.csv | 6 +- 9 files changed, 319 insertions(+), 3 deletions(-) create mode 100644 c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.md create mode 100644 c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql create mode 100644 c/cert/test/rules/FLP30-C/FloatingPointLoopCounters.expected create mode 100644 c/cert/test/rules/FLP30-C/FloatingPointLoopCounters.qlref create mode 100644 c/cert/test/rules/FLP30-C/test.c create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Statements4.qll create mode 100644 rule_packages/c/Statements4.json diff --git a/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.md b/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.md new file mode 100644 index 0000000000..52e2c70fce --- /dev/null +++ b/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.md @@ -0,0 +1,106 @@ +# FLP30-C: Do not use floating-point variables as loop counters + +This query implements the CERT-C rule FLP30-C: + +> Do not use floating-point variables as loop counters + + +## Description + +Because floating-point numbers represent real numbers, it is often mistakenly assumed that they can represent any simple fraction exactly. Floating-point numbers are subject to representational limitations just as integers are, and binary floating-point numbers cannot represent all real numbers exactly, even if they can be represented in a small number of decimal digits. + +In addition, because floating-point numbers can represent large values, it is often mistakenly assumed that they can represent all significant digits of those values. To gain a large dynamic range, floating-point numbers maintain a fixed number of precision bits (also called the significand) and an exponent, which limit the number of significant digits they can represent. + +Different implementations have different precision limitations, and to keep code portable, floating-point variables must not be used as the loop induction variable. See Goldberg's work for an introduction to this topic \[[Goldberg 1991](https://www.securecoding.cert.org/confluence/display/java/Rule+AA.+References#RuleAA.References-Goldberg91)\]. + +For the purpose of this rule, a *loop counter* is an induction variable that is used as an operand of a comparison expression that is used as the controlling expression of a `do`, `while`, or `for` loop. An *induction variable* is a variable that gets increased or decreased by a fixed amount on every iteration of a loop \[[Aho 1986](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-Aho1986)\]. Furthermore, the change to the variable must occur directly in the loop body (rather than inside a function executed within the loop). + +## Noncompliant Code Example + +In this noncompliant code example, a floating-point variable is used as a loop counter. The decimal number `0.1` is a repeating fraction in binary and cannot be exactly represented as a binary floating-point number. Depending on the implementation, the loop may iterate 9 or 10 times. + +```cpp +void func(void) { + for (float x = 0.1f; x <= 1.0f; x += 0.1f) { + /* Loop may iterate 9 or 10 times */ + } +} +``` +For example, when compiled with GCC or Microsoft Visual Studio 2013 and executed on an x86 processor, the loop is evaluated only nine times. + +## Compliant Solution + +In this compliant solution, the loop counter is an integer from which the floating-point value is derived: + +```cpp +#include + +void func(void) { + for (size_t count = 1; count <= 10; ++count) { + float x = count / 10.0f; + /* Loop iterates exactly 10 times */ + } +} +``` + +## Noncompliant Code Example + +In this noncompliant code example, a floating-point loop counter is incremented by an amount that is too small to change its value given its precision: + +```cpp +void func(void) { + for (float x = 100000001.0f; x <= 100000010.0f; x += 1.0f) { + /* Loop may not terminate */ + } +} +``` +On many implementations, this produces an infinite loop. + +## Compliant Solution + +In this compliant solution, the loop counter is an integer from which the floating-point value is derived. The variable `x` is assigned a computed value to reduce compounded rounding errors that are present in the noncompliant code example. + +```cpp +void func(void) { + for (size_t count = 1; count <= 10; ++count) { + float x = 100000000.0f + (count * 1.0f); + /* Loop iterates exactly 10 times */ + } +} +``` + +## Risk Assessment + +The use of floating-point variables as loop counters can result in [unexpected behavior ](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior). + +
Rule Severity Likelihood Remediation Cost Priority Level
FLP30-C Low Probable Low P6 L2
+ + +## Automated Detection + +
Tool Version Checker Description
Astrée 22.04 for-loop-float Fully checked
Axivion Bauhaus Suite 7.2.0 CertC-FLP30 Fully implemented
Clang 3.9 cert-flp30-c Checked by clang-tidy
CodeSonar 7.2p0 LANG.STRUCT.LOOP.FPC Float-typed loop counter
Compass/ROSE
Coverity 2017.07 MISRA C 2004 Rule 13.4 MISRA C 2012 Rule 14.1 Implemented
ECLAIR 1.2 CC2.FLP30 Fully implemented
Helix QAC 2022.4 C3339, C3340, C3342 C++4234
Klocwork 2022.4 MISRA.FOR.COUNTER.FLT
LDRA tool suite 9.7.1 39 S Fully implemented
Parasoft C/C++test 2022.2 CERT_C-FLP30-a Do not use floating point variables as loop counters
PC-lint Plus 1.4 9009 Fully supported
Polyspace Bug Finder R2022b CERT C: Rule FLP30-C Checks for use of float variable as loop counter (rule fully covered)
PRQA QA-C 9.7 3339, 3340, 3342 Partially implemented
PRQA QA-C++ 4.4 4234
PVS-Studio 7.23 V1034
RuleChecker 22.04 for-loop-float Fully checked
SonarQube C/C++ Plugin 3.11 S2193 Fully implemented
TrustInSoft Analyzer 1.38 non-terminating Exhaustively detects non-terminating statements (see one compliant and one non-compliant example ).
+ + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+FLP30-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
Taxonomy Taxonomy item Relationship
CERT C FLP30-CPP. Do not use floating-point variables as loop counters Prior to 2018-01-12: CERT: Unspecified Relationship
CERT Oracle Secure Coding Standard for Java NUM09-J. Do not use floating-point variables as loop counters Prior to 2018-01-12: CERT: Unspecified Relationship
ISO/IEC TR 24772:2013 Floating-Point Arithmetic \[PLF\] Prior to 2018-01-12: CERT: Unspecified Relationship
MISRA C:2012 Directive 1.1 (required) Prior to 2018-01-12: CERT: Unspecified Relationship
MISRA C:2012 Rule 14.1 (required) Prior to 2018-01-12: CERT: Unspecified Relationship
+ + +## Bibliography + +
\[ Aho 1986 \]
\[ Goldberg 1991 \]
\[ Lockheed Martin 05 \] AV Rule 197
+ + +## Implementation notes + +None + +## References + +* CERT-C: [FLP30-C: Do not use floating-point variables as loop counters](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql b/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql new file mode 100644 index 0000000000..1f99006866 --- /dev/null +++ b/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql @@ -0,0 +1,30 @@ +/** + * @id c/cert/floating-point-loop-counters + * @name FLP30-C: Do not use floating-point variables as loop counters + * @description Loop counters should not use floating-point variables to keep code portable. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/cert/id/flp30-c + * maintainability + * readability + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.Loops + +from Loop loop +where + not isExcluded(loop, Statements4Package::floatingPointLoopCountersQuery()) and + exists(WhileStmt while | + while.getCondition().getType() instanceof FloatType and + loop = while + ) + or + exists(ForStmt for, Variable counter | + isForLoopWithFloatingPointCounters(for, counter) and for = loop + ) +select loop, "Loop $@ has a floating-point type.", loop.getControllingExpr(), "counter" diff --git a/c/cert/test/rules/FLP30-C/FloatingPointLoopCounters.expected b/c/cert/test/rules/FLP30-C/FloatingPointLoopCounters.expected new file mode 100644 index 0000000000..964df7c2b7 --- /dev/null +++ b/c/cert/test/rules/FLP30-C/FloatingPointLoopCounters.expected @@ -0,0 +1,2 @@ +| test.c:3:3:4:3 | for(...;...;...) ... | Loop $@ has a floating-point type. | test.c:3:18:3:26 | ... < ... | counter | +| test.c:5:3:6:3 | while (...) ... | Loop $@ has a floating-point type. | test.c:5:10:5:17 | ... - ... | counter | diff --git a/c/cert/test/rules/FLP30-C/FloatingPointLoopCounters.qlref b/c/cert/test/rules/FLP30-C/FloatingPointLoopCounters.qlref new file mode 100644 index 0000000000..1ada999730 --- /dev/null +++ b/c/cert/test/rules/FLP30-C/FloatingPointLoopCounters.qlref @@ -0,0 +1 @@ +rules/FLP30-C/FloatingPointLoopCounters.ql \ No newline at end of file diff --git a/c/cert/test/rules/FLP30-C/test.c b/c/cert/test/rules/FLP30-C/test.c new file mode 100644 index 0000000000..9ec460953b --- /dev/null +++ b/c/cert/test/rules/FLP30-C/test.c @@ -0,0 +1,15 @@ +void f1() { + float f = 0.0F; + for (f = 0.0F; f < 10.0F; f += 0.2F) { // NON_COMPLIANT + } + while (f - 0.0F) { // NON_COMPLIANT + } +} + +void f2() { + + for (int i = 0; i < 10; i++) { // COMPLIANT + } + while (4 - 4) { // COMPLIANT + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 5d5e2b7189..80c09f4c5f 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -45,6 +45,7 @@ import SideEffects2 import Statements1 import Statements2 import Statements3 +import Statements4 import Strings1 import Strings2 import Strings3 @@ -95,6 +96,7 @@ newtype TCQuery = TStatements1PackageQuery(Statements1Query q) or TStatements2PackageQuery(Statements2Query q) or TStatements3PackageQuery(Statements3Query q) or + TStatements4PackageQuery(Statements4Query q) or TStrings1PackageQuery(Strings1Query q) or TStrings2PackageQuery(Strings2Query q) or TStrings3PackageQuery(Strings3Query q) or @@ -145,6 +147,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isStatements1QueryMetadata(query, queryId, ruleId, category) or isStatements2QueryMetadata(query, queryId, ruleId, category) or isStatements3QueryMetadata(query, queryId, ruleId, category) or + isStatements4QueryMetadata(query, queryId, ruleId, category) or isStrings1QueryMetadata(query, queryId, ruleId, category) or isStrings2QueryMetadata(query, queryId, ruleId, category) or isStrings3QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Statements4.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements4.qll new file mode 100644 index 0000000000..b46cd2207b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements4.qll @@ -0,0 +1,78 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Statements4Query = + TFloatingPointLoopCountersQuery() or + TForLoopNotWellFormedQuery() or + TNonBooleanIfConditionQuery() or + TNonBooleanIterationConditionQuery() + +predicate isStatements4QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `floatingPointLoopCounters` query + Statements4Package::floatingPointLoopCountersQuery() and + queryId = + // `@id` for the `floatingPointLoopCounters` query + "c/cert/floating-point-loop-counters" and + ruleId = "FLP30-C" and + category = "rule" + or + query = + // `Query` instance for the `forLoopNotWellFormed` query + Statements4Package::forLoopNotWellFormedQuery() and + queryId = + // `@id` for the `forLoopNotWellFormed` query + "c/misra/for-loop-not-well-formed" and + ruleId = "RULE-14-2" and + category = "required" + or + query = + // `Query` instance for the `nonBooleanIfCondition` query + Statements4Package::nonBooleanIfConditionQuery() and + queryId = + // `@id` for the `nonBooleanIfCondition` query + "c/misra/non-boolean-if-condition" and + ruleId = "RULE-14-4" and + category = "required" + or + query = + // `Query` instance for the `nonBooleanIterationCondition` query + Statements4Package::nonBooleanIterationConditionQuery() and + queryId = + // `@id` for the `nonBooleanIterationCondition` query + "c/misra/non-boolean-iteration-condition" and + ruleId = "RULE-14-4" and + category = "required" +} + +module Statements4Package { + Query floatingPointLoopCountersQuery() { + //autogenerate `Query` type + result = + // `Query` type for `floatingPointLoopCounters` query + TQueryC(TStatements4PackageQuery(TFloatingPointLoopCountersQuery())) + } + + Query forLoopNotWellFormedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `forLoopNotWellFormed` query + TQueryC(TStatements4PackageQuery(TForLoopNotWellFormedQuery())) + } + + Query nonBooleanIfConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonBooleanIfCondition` query + TQueryC(TStatements4PackageQuery(TNonBooleanIfConditionQuery())) + } + + Query nonBooleanIterationConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonBooleanIterationCondition` query + TQueryC(TStatements4PackageQuery(TNonBooleanIterationConditionQuery())) + } +} diff --git a/rule_packages/c/Statements4.json b/rule_packages/c/Statements4.json new file mode 100644 index 0000000000..e76c984f76 --- /dev/null +++ b/rule_packages/c/Statements4.json @@ -0,0 +1,81 @@ +{ + "CERT-C": { + "FLP30-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Loop counters should not use floating-point variables to keep code portable.", + "kind": "problem", + "name": "Do not use floating-point variables as loop counters", + "precision": "very-high", + "severity": "recommendation", + "short_name": "FloatingPointLoopCounters", + "tags": [ + "maintainability", + "readability", + "correctness" + ] + } + ], + "title": "Do not use floating-point variables as loop counters" + } + }, + "MISRA-C-2012": { + "RULE-14-2": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "A well-formed for loop makes code easier to review.", + "kind": "problem", + "name": "A for loop shall be well-formed", + "precision": "very-high", + "severity": "recommendation", + "short_name": "ForLoopNotWellFormed", + "tags": [ + "readability", + "maintainability" + ] + } + ], + "title": "A for loop shall be well-formed" + }, + "RULE-14-4": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Non boolean conditions can be confusing for developers.", + "kind": "problem", + "name": "The condition of an if-statement shall have type bool", + "precision": "very-high", + "severity": "recommendation", + "short_name": "NonBooleanIfCondition", + "shared_implementation_short_name": "NonBooleanIfStmt", + "tags": [ + "maintainability", + "readability" + ] + }, + { + "description": "Non boolean conditions can be confusing for developers.", + "kind": "problem", + "name": "The condition of an iteration statement shall have type bool", + "precision": "very-high", + "severity": "recommendation", + "short_name": "NonBooleanIterationCondition", + "shared_implementation_short_name": "NonBooleanIterationStmt", + "tags": [ + "maintainability", + "readability" + ] + } + ], + "title": "The controlling expression of an if statement and the controlling expression of an iteration-statement shall have essentially Boolean type" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index 96da89354d..81ef255764 100644 --- a/rules.csv +++ b/rules.csv @@ -543,7 +543,7 @@ c,CERT-C,FIO44-C,Yes,Rule,,,Only use values for fsetpos() that are returned from c,CERT-C,FIO45-C,Yes,Rule,,,Avoid TOCTOU race conditions while accessing files,,IO4,Medium, c,CERT-C,FIO46-C,Yes,Rule,,,Do not access a closed file,FIO51-CPP,IO1,Hard, c,CERT-C,FIO47-C,Yes,Rule,,,Use valid format strings,,IO4,Hard, -c,CERT-C,FLP30-C,Yes,Rule,,,Do not use floating-point variables as loop counters,,Statements,Easy, +c,CERT-C,FLP30-C,Yes,Rule,,,Do not use floating-point variables as loop counters,,Statements4,Easy, c,CERT-C,FLP32-C,Yes,Rule,,,Prevent or detect domain and range errors in math functions,A0-4-4,Types,Medium, c,CERT-C,FLP34-C,Yes,Rule,,,Ensure that floating-point conversions are within range of the new type,,Types,Medium, c,CERT-C,FLP36-C,Yes,Rule,,,Preserve precision when converting integral values to floating-point type,,Types,Medium, @@ -694,9 +694,9 @@ c,MISRA-C-2012,RULE-13-4,Yes,Advisory,,,The result of an assignment operator sho 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 expressiosn 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-2,Yes,Required,,,A for loop shall be well-formed,M6-5-1...M6-5-6,Statements,Medium, +c,MISRA-C-2012,RULE-14-2,Yes,Required,,,A for loop shall be well-formed,M6-5-1...M6-5-6,Statements4,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, +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,Statements4,Medium, c,MISRA-C-2012,RULE-15-1,No,Advisory,,,The goto statement should not be used,A6-6-1,,Import, c,MISRA-C-2012,RULE-15-2,Yes,Required,,,The goto statement shall jump to a label declared later in the same function,M6-6-2,Statements2,Import, c,MISRA-C-2012,RULE-15-3,Yes,Required,,,"Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement",M6-6-1,Statements2,Import, From d89c8cb91f55cb6c5f11671b293453286df2812d Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 7 Mar 2023 15:08:17 +1100 Subject: [PATCH 29/76] added RULE-14-2 --- .../rules/RULE-14-2/ForLoopNotWellFormed.ql | 22 ++++++ .../RULE-14-2/ForLoopNotWellFormed.expected | 1 + .../RULE-14-2/ForLoopNotWellFormed.qlref | 1 + c/misra/test/rules/RULE-14-2/test.c | 68 +++++++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 c/misra/src/rules/RULE-14-2/ForLoopNotWellFormed.ql create mode 100644 c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.expected create mode 100644 c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.qlref create mode 100644 c/misra/test/rules/RULE-14-2/test.c diff --git a/c/misra/src/rules/RULE-14-2/ForLoopNotWellFormed.ql b/c/misra/src/rules/RULE-14-2/ForLoopNotWellFormed.ql new file mode 100644 index 0000000000..a454d90505 --- /dev/null +++ b/c/misra/src/rules/RULE-14-2/ForLoopNotWellFormed.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/for-loop-not-well-formed + * @name RULE-14-2: A for loop shall be well-formed + * @description A well-formed for loop makes code easier to review. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-14-2 + * readability + * maintainability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Loops + +from ForStmt for +where + not isExcluded(for, Statements4Package::forLoopNotWellFormedQuery()) and + isInvalidLoop(for) +select for, "For loop is not well formed." diff --git a/c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.expected b/c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.qlref b/c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.qlref new file mode 100644 index 0000000000..f65068dfb2 --- /dev/null +++ b/c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.qlref @@ -0,0 +1 @@ +rules/RULE-14-2/ForLoopNotWellFormed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-14-2/test.c b/c/misra/test/rules/RULE-14-2/test.c new file mode 100644 index 0000000000..c1ce23dd11 --- /dev/null +++ b/c/misra/test/rules/RULE-14-2/test.c @@ -0,0 +1,68 @@ + +#include "stdbool.h" +int g1 = 10; +int f1() { return g1++; } + +void f2() { + for (float f = 0.0F; f < 10.0F; f += 0.2F) { // NON_COMPLIANT + } + for (int i = 0; i < 10; i++) { // COMPLIANT + } +} + +void f3() { + for (int i = 0, j = 0; i < j; i++, j++) { // NON_COMPLIANT + } +} + +void f4() { + int i, j; + for (i = 0, j = 0; i < j; i++, j++) { // NON_COMPLIANT + } +} + +void f5() { + for (int i = 0; i != 10; i += 3) { // NON_COMPLIANT + } + + for (int i = 0; i != 10; i++) { // COMPLIANT + } +} + +void f7() { + for (int i = 0; i < 100; i += g1) { // COMPLIANT + } +} + +void f8() { + for (int x = 0; x < 5; x += f1()) { // NON_COMPLIANT + } +} + +void f9() { + bool l1 = true; + for (int x = 0; (x < 5) && l1; ++x) { // COMPLIANT + l1 = false; + } +} + +bool f10(int p1) { return false; } +void f11() { + bool p1 = true; + for (int x = 0; (x < 5); p1 = f10(++x)) { // NON_COMPLIANT + } +} + +void f12() { + bool l1 = true; + for (int x = 0; (x < 5) && l1; ++x) { // COMPLIANT + } +} + +void f13() { + int l1 = 1; + for (int x = 0; x < 5 && l1 == 9; ++x) { // NON_COMPLIANT + x = x + 2; + g1--; + } +} From df09cc189ffbe13ac907c98863f0ce19b9377428 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 7 Mar 2023 15:09:23 +1100 Subject: [PATCH 30/76] test results for RULE-14-2 --- .../test/rules/RULE-14-2/ForLoopNotWellFormed.expected | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.expected b/c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.expected index 2ec1a0ac6c..c084d2d0ad 100644 --- a/c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.expected +++ b/c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.expected @@ -1 +1,7 @@ -No expected results have yet been specified \ No newline at end of file +| test.c:7:3:8:3 | for(...;...;...) ... | For loop is not well formed. | +| test.c:14:3:15:3 | for(...;...;...) ... | For loop is not well formed. | +| test.c:20:3:21:3 | for(...;...;...) ... | For loop is not well formed. | +| test.c:25:3:26:3 | for(...;...;...) ... | For loop is not well formed. | +| test.c:38:3:39:3 | for(...;...;...) ... | For loop is not well formed. | +| test.c:52:3:53:3 | for(...;...;...) ... | For loop is not well formed. | +| test.c:64:3:67:3 | for(...;...;...) ... | For loop is not well formed. | From 9748585e5560a12dc3b0e684a620821a4059bace Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 7 Mar 2023 16:22:55 +1100 Subject: [PATCH 31/76] added RULE-14-4 and moved A5-0-2 to shared folder --- .../NonBooleanIfStmt.expected | 3 ++ .../nonbooleanifstmt/NonBooleanIfStmt.ql | 2 + c/common/test/rules/nonbooleanifstmt/test.c | 24 +++++++++ .../NonBooleanIterationStmt.expected | 3 ++ .../NonBooleanIterationStmt.ql | 2 + .../test/rules/nonbooleaniterationstmt/test.c | 15 ++++++ .../rules/RULE-14-4/NonBooleanIfCondition.ql | 22 ++++++++ .../RULE-14-4/NonBooleanIterationCondition.ql | 22 ++++++++ .../RULE-14-4/NonBooleanIfCondition.testref | 1 + .../NonBooleanIterationCondition.testref | 1 + .../src/rules/A5-0-2/NonBooleanIfCondition.ql | 14 +++-- .../A5-0-2/NonBooleanIterationCondition.ql | 13 +++-- .../A5-0-2/NonBooleanIfCondition.expected | 3 -- .../rules/A5-0-2/NonBooleanIfCondition.qlref | 1 - .../A5-0-2/NonBooleanIfCondition.testref | 1 + .../NonBooleanIterationCondition.expected | 2 - .../A5-0-2/NonBooleanIterationCondition.qlref | 1 - .../NonBooleanIterationCondition.testref | 1 + .../nonbooleanifstmt/NonBooleanIfStmt.qll | 22 ++++++++ .../NonBooleanIterationStmt.qll | 21 ++++++++ .../NonBooleanIfStmt.expected | 3 ++ .../nonbooleanifstmt/NonBooleanIfStmt.ql | 2 + .../test/rules/nonbooleanifstmt}/test.cpp | 54 +------------------ .../NonBooleanIterationStmt.expected | 2 + .../NonBooleanIterationStmt.ql | 2 + .../rules/nonbooleaniterationstmt/test.cpp | 44 +++++++++++++++ rule_packages/cpp/Conditionals.json | 2 + 27 files changed, 208 insertions(+), 75 deletions(-) create mode 100644 c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.expected create mode 100644 c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql create mode 100644 c/common/test/rules/nonbooleanifstmt/test.c create mode 100644 c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.expected create mode 100644 c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql create mode 100644 c/common/test/rules/nonbooleaniterationstmt/test.c create mode 100644 c/misra/src/rules/RULE-14-4/NonBooleanIfCondition.ql create mode 100644 c/misra/src/rules/RULE-14-4/NonBooleanIterationCondition.ql create mode 100644 c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.testref create mode 100644 c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.testref delete mode 100644 cpp/autosar/test/rules/A5-0-2/NonBooleanIfCondition.expected delete mode 100644 cpp/autosar/test/rules/A5-0-2/NonBooleanIfCondition.qlref create mode 100644 cpp/autosar/test/rules/A5-0-2/NonBooleanIfCondition.testref delete mode 100644 cpp/autosar/test/rules/A5-0-2/NonBooleanIterationCondition.expected delete mode 100644 cpp/autosar/test/rules/A5-0-2/NonBooleanIterationCondition.qlref create mode 100644 cpp/autosar/test/rules/A5-0-2/NonBooleanIterationCondition.testref create mode 100644 cpp/common/src/codingstandards/cpp/rules/nonbooleanifstmt/NonBooleanIfStmt.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.qll create mode 100644 cpp/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.expected create mode 100644 cpp/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql rename cpp/{autosar/test/rules/A5-0-2 => common/test/rules/nonbooleanifstmt}/test.cpp (52%) create mode 100644 cpp/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.expected create mode 100644 cpp/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql create mode 100644 cpp/common/test/rules/nonbooleaniterationstmt/test.cpp diff --git a/c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.expected b/c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.expected new file mode 100644 index 0000000000..490b14b9bf --- /dev/null +++ b/c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.expected @@ -0,0 +1,3 @@ +| test.c:7:7:7:8 | l1 | If condition has non boolean type int. | +| test.c:9:7:9:8 | call to f1 | If condition has non boolean type int. | +| test.c:12:7:12:8 | l2 | If condition has non boolean type void *. | diff --git a/c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql b/c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql new file mode 100644 index 0000000000..da907fcf9e --- /dev/null +++ b/c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.nonbooleanifstmt.NonBooleanIfStmt diff --git a/c/common/test/rules/nonbooleanifstmt/test.c b/c/common/test/rules/nonbooleanifstmt/test.c new file mode 100644 index 0000000000..ca71348a5b --- /dev/null +++ b/c/common/test/rules/nonbooleanifstmt/test.c @@ -0,0 +1,24 @@ +#include "stdbool.h" +int f1(); +void *f2(); + +void f3() { + int l1 = 1; + if (l1) { // NON_COMPLIANT + } + if (f1()) { // NON_COMPLIANT + } + void *l2 = f2(); + if (l2) { // NON_COMPLIANT + } +} + +void f4() { + int l1 = 1; + if ((bool)l1) { // COMPLIANT + } + + int l2 = 1; + if ((const bool)l2) { // COMPLIANT + } +} \ No newline at end of file diff --git a/c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.expected b/c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.expected new file mode 100644 index 0000000000..3d3aa974dd --- /dev/null +++ b/c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.expected @@ -0,0 +1,3 @@ +| test.c:5:3:6:3 | for(...;...;...) ... | Iteration condition has non boolean type int. | +| test.c:7:3:8:3 | while (...) ... | Iteration condition has non boolean type int. | +| test.c:13:3:14:3 | for(...;...;...) ... | Iteration condition has non boolean type int. | diff --git a/c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql b/c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql new file mode 100644 index 0000000000..ffe3f351c6 --- /dev/null +++ b/c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.nonbooleaniterationstmt.NonBooleanIterationStmt diff --git a/c/common/test/rules/nonbooleaniterationstmt/test.c b/c/common/test/rules/nonbooleaniterationstmt/test.c new file mode 100644 index 0000000000..8ecbb1c1fd --- /dev/null +++ b/c/common/test/rules/nonbooleaniterationstmt/test.c @@ -0,0 +1,15 @@ + + +void f1() { + int l1; + for (int i = 10; i; i++) { // NON_COMPLIANT + } + while (l1) { // NON_COMPLIANT + } +} + +void f2() { + int j = 0; + for (int i = 0; i < 10; i++) { // COMPLIANT + } +} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-14-4/NonBooleanIfCondition.ql b/c/misra/src/rules/RULE-14-4/NonBooleanIfCondition.ql new file mode 100644 index 0000000000..ab5144fbc2 --- /dev/null +++ b/c/misra/src/rules/RULE-14-4/NonBooleanIfCondition.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/non-boolean-if-condition + * @name RULE-14-4: The condition of an if-statement shall have type bool + * @description Non boolean conditions can be confusing for developers. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-14-4 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.nonbooleanifstmt.NonBooleanIfStmt + +class NonBooleanIfConditionQuery extends NonBooleanIfStmtSharedQuery { + NonBooleanIfConditionQuery() { + this = Statements4Package::nonBooleanIfConditionQuery() + } +} diff --git a/c/misra/src/rules/RULE-14-4/NonBooleanIterationCondition.ql b/c/misra/src/rules/RULE-14-4/NonBooleanIterationCondition.ql new file mode 100644 index 0000000000..01482c5e0e --- /dev/null +++ b/c/misra/src/rules/RULE-14-4/NonBooleanIterationCondition.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/non-boolean-iteration-condition + * @name RULE-14-4: The condition of an iteration statement shall have type bool + * @description Non boolean conditions can be confusing for developers. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-14-4 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.nonbooleaniterationstmt.NonBooleanIterationStmt + +class NonBooleanIterationConditionQuery extends NonBooleanIterationStmtSharedQuery { + NonBooleanIterationConditionQuery() { + this = Statements4Package::nonBooleanIterationConditionQuery() + } +} diff --git a/c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.testref b/c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.testref new file mode 100644 index 0000000000..e586a8d8ec --- /dev/null +++ b/c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.testref @@ -0,0 +1 @@ +c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.testref b/c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.testref new file mode 100644 index 0000000000..15f5d0713f --- /dev/null +++ b/c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.testref @@ -0,0 +1 @@ +c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql \ No newline at end of file diff --git a/cpp/autosar/src/rules/A5-0-2/NonBooleanIfCondition.ql b/cpp/autosar/src/rules/A5-0-2/NonBooleanIfCondition.ql index 45b130e184..134ded1651 100644 --- a/cpp/autosar/src/rules/A5-0-2/NonBooleanIfCondition.ql +++ b/cpp/autosar/src/rules/A5-0-2/NonBooleanIfCondition.ql @@ -15,12 +15,10 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.nonbooleanifstmt.NonBooleanIfStmt -from IfStmt ifStmt, Expr condition, Type explicitConversionType -where - not isExcluded(ifStmt, ConditionalsPackage::nonBooleanIfConditionQuery()) and - condition = ifStmt.getCondition() and - not ifStmt.isFromUninstantiatedTemplate(_) and - explicitConversionType = condition.getExplicitlyConverted().getType().getUnspecifiedType() and - not explicitConversionType instanceof BoolType -select condition, "If condition has non boolean type " + explicitConversionType + "." +class NonBooleanIfConditionQuery extends NonBooleanIfStmtSharedQuery { + NonBooleanIfConditionQuery() { + this = ConditionalsPackage::nonBooleanIfConditionQuery() + } +} diff --git a/cpp/autosar/src/rules/A5-0-2/NonBooleanIterationCondition.ql b/cpp/autosar/src/rules/A5-0-2/NonBooleanIterationCondition.ql index 07f8f4de3c..c52c100df8 100644 --- a/cpp/autosar/src/rules/A5-0-2/NonBooleanIterationCondition.ql +++ b/cpp/autosar/src/rules/A5-0-2/NonBooleanIterationCondition.ql @@ -15,11 +15,10 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.nonbooleaniterationstmt.NonBooleanIterationStmt -from Loop loopStmt, Expr condition, Type explicitConversionType -where - not isExcluded(loopStmt, ConditionalsPackage::nonBooleanIterationConditionQuery()) and - condition = loopStmt.getCondition() and - explicitConversionType = condition.getExplicitlyConverted().getType().getUnspecifiedType() and - not explicitConversionType instanceof BoolType -select condition, "Iteration condition has non boolean type " + explicitConversionType + "." +class NonBooleanIterationConditionQuery extends NonBooleanIterationStmtSharedQuery { + NonBooleanIterationConditionQuery() { + this = ConditionalsPackage::nonBooleanIterationConditionQuery() + } +} diff --git a/cpp/autosar/test/rules/A5-0-2/NonBooleanIfCondition.expected b/cpp/autosar/test/rules/A5-0-2/NonBooleanIfCondition.expected deleted file mode 100644 index 655e5571e1..0000000000 --- a/cpp/autosar/test/rules/A5-0-2/NonBooleanIfCondition.expected +++ /dev/null @@ -1,3 +0,0 @@ -| test.cpp:8:7:8:7 | i | If condition has non boolean type int. | -| test.cpp:10:7:10:7 | call to f | If condition has non boolean type int. | -| test.cpp:13:7:13:7 | a | If condition has non boolean type void *. | diff --git a/cpp/autosar/test/rules/A5-0-2/NonBooleanIfCondition.qlref b/cpp/autosar/test/rules/A5-0-2/NonBooleanIfCondition.qlref deleted file mode 100644 index a2280d92c6..0000000000 --- a/cpp/autosar/test/rules/A5-0-2/NonBooleanIfCondition.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A5-0-2/NonBooleanIfCondition.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A5-0-2/NonBooleanIfCondition.testref b/cpp/autosar/test/rules/A5-0-2/NonBooleanIfCondition.testref new file mode 100644 index 0000000000..5f106ce750 --- /dev/null +++ b/cpp/autosar/test/rules/A5-0-2/NonBooleanIfCondition.testref @@ -0,0 +1 @@ +cpp/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A5-0-2/NonBooleanIterationCondition.expected b/cpp/autosar/test/rules/A5-0-2/NonBooleanIterationCondition.expected deleted file mode 100644 index 091087b3a1..0000000000 --- a/cpp/autosar/test/rules/A5-0-2/NonBooleanIterationCondition.expected +++ /dev/null @@ -1,2 +0,0 @@ -| test.cpp:51:20:51:20 | i | Iteration condition has non boolean type int. | -| test.cpp:55:10:55:10 | j | Iteration condition has non boolean type int. | diff --git a/cpp/autosar/test/rules/A5-0-2/NonBooleanIterationCondition.qlref b/cpp/autosar/test/rules/A5-0-2/NonBooleanIterationCondition.qlref deleted file mode 100644 index 535235d198..0000000000 --- a/cpp/autosar/test/rules/A5-0-2/NonBooleanIterationCondition.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A5-0-2/NonBooleanIterationCondition.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A5-0-2/NonBooleanIterationCondition.testref b/cpp/autosar/test/rules/A5-0-2/NonBooleanIterationCondition.testref new file mode 100644 index 0000000000..36a500fcf8 --- /dev/null +++ b/cpp/autosar/test/rules/A5-0-2/NonBooleanIterationCondition.testref @@ -0,0 +1 @@ +cpp/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/nonbooleanifstmt/NonBooleanIfStmt.qll b/cpp/common/src/codingstandards/cpp/rules/nonbooleanifstmt/NonBooleanIfStmt.qll new file mode 100644 index 0000000000..f2933f755a --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/nonbooleanifstmt/NonBooleanIfStmt.qll @@ -0,0 +1,22 @@ +/** + * Provides a library which includes a `problems` predicate for reporting.... + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class NonBooleanIfStmtSharedQuery extends Query { } + +Query getQuery() { result instanceof NonBooleanIfStmtSharedQuery } + +query predicate problems(Expr condition, string message) { + not isExcluded(condition, getQuery()) and + exists(IfStmt ifStmt, Type explicitConversionType | + condition = ifStmt.getCondition() and + not ifStmt.isFromUninstantiatedTemplate(_) and + explicitConversionType = condition.getExplicitlyConverted().getUnderlyingType() and + not explicitConversionType instanceof BoolType and + message = "If condition has non boolean type " + explicitConversionType + "." + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.qll b/cpp/common/src/codingstandards/cpp/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.qll new file mode 100644 index 0000000000..f1ee555406 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.qll @@ -0,0 +1,21 @@ +/** + * Provides a library which includes a `problems` predicate for reporting.... + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class NonBooleanIterationStmtSharedQuery extends Query { } + +Query getQuery() { result instanceof NonBooleanIterationStmtSharedQuery } + +query predicate problems(Loop loopStmt, string message) { + not isExcluded(loopStmt, getQuery()) and + exists(Expr condition, Type explicitConversionType | + condition = loopStmt.getCondition() and + explicitConversionType = condition.getExplicitlyConverted().getType().getUnspecifiedType() and + not explicitConversionType instanceof BoolType and + message = "Iteration condition has non boolean type " + explicitConversionType + "." + ) +} diff --git a/cpp/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.expected b/cpp/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.expected new file mode 100644 index 0000000000..f3899bf81c --- /dev/null +++ b/cpp/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.expected @@ -0,0 +1,3 @@ +| test.cpp:9:7:9:7 | i | If condition has non boolean type int. | +| test.cpp:11:7:11:7 | call to f | If condition has non boolean type int. | +| test.cpp:14:7:14:7 | a | If condition has non boolean type void *. | diff --git a/cpp/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql b/cpp/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql new file mode 100644 index 0000000000..da907fcf9e --- /dev/null +++ b/cpp/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.nonbooleanifstmt.NonBooleanIfStmt diff --git a/cpp/autosar/test/rules/A5-0-2/test.cpp b/cpp/common/test/rules/nonbooleanifstmt/test.cpp similarity index 52% rename from cpp/autosar/test/rules/A5-0-2/test.cpp rename to cpp/common/test/rules/nonbooleanifstmt/test.cpp index 00fc281605..b10cd7034e 100644 --- a/cpp/autosar/test/rules/A5-0-2/test.cpp +++ b/cpp/common/test/rules/nonbooleanifstmt/test.cpp @@ -1,3 +1,4 @@ + #include int f(); @@ -45,56 +46,3 @@ void test_boolean_conditions() { if (a) { // COMPLIANT - a has an explicit operator bool() } } - -void test_non_boolean_iterations() { - int j; - for (int i = 10; i; i++) { // NON_COMPLIANT - j = 3; - } - - while (j) { // NON_COMPLIANT - int k = 3; - } -} - -void test_boolean_iterations() { - int j = 0; - for (int i = 0; i < 10; i++) { // COMPLIANT - j = i + j; - } - - int boolean = 0; - while (bool(boolean)) { // COMPLIANT - j = 5; - } - - while (int i = 0) { // COMPLIANT - due to exception - } - - ClassA a; - while (a) { // COMPLIANT - a has an explicit operator bool() - } -} - -template class ClassB { -public: - std::deque d; - void f() { - if (d.empty()) { // COMPLIANT - } - } -}; - -void class_b_test() { - ClassB b; - - b.f(); -} - -class ClassC { - void run() { - std::deque d; - if (!d.empty()) { // COMPLIANT - } - } -}; \ No newline at end of file diff --git a/cpp/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.expected b/cpp/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.expected new file mode 100644 index 0000000000..05dfadc1f7 --- /dev/null +++ b/cpp/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.expected @@ -0,0 +1,2 @@ +| test.cpp:7:3:9:3 | for(...;...;...) ... | Iteration condition has non boolean type int. | +| test.cpp:11:3:13:3 | while (...) ... | Iteration condition has non boolean type int. | diff --git a/cpp/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql b/cpp/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql new file mode 100644 index 0000000000..ffe3f351c6 --- /dev/null +++ b/cpp/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.nonbooleaniterationstmt.NonBooleanIterationStmt diff --git a/cpp/common/test/rules/nonbooleaniterationstmt/test.cpp b/cpp/common/test/rules/nonbooleaniterationstmt/test.cpp new file mode 100644 index 0000000000..ed25cad311 --- /dev/null +++ b/cpp/common/test/rules/nonbooleaniterationstmt/test.cpp @@ -0,0 +1,44 @@ +#include + +int f(); +void *g(); +void test_non_boolean_iterations() { + int j; + for (int i = 10; i; i++) { // NON_COMPLIANT + j = 3; + } + + while (j) { // NON_COMPLIANT + int k = 3; + } +} + +void test_boolean_iterations() { + int j = 0; + for (int i = 0; i < 10; i++) { // COMPLIANT + j = i + j; + } +} + +template class ClassB { +public: + std::deque d; + void f() { + if (d.empty()) { // COMPLIANT + } + } +}; + +void class_b_test() { + ClassB b; + + b.f(); +} + +class ClassC { + void run() { + std::deque d; + if (!d.empty()) { // COMPLIANT + } + } +}; \ No newline at end of file diff --git a/rule_packages/cpp/Conditionals.json b/rule_packages/cpp/Conditionals.json index dba9341493..c2afb626e4 100644 --- a/rule_packages/cpp/Conditionals.json +++ b/rule_packages/cpp/Conditionals.json @@ -16,6 +16,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "NonBooleanIfCondition", + "shared_implementation_short_name": "NonBooleanIfStmt", "tags": [ "maintainability", "readability" @@ -28,6 +29,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "NonBooleanIterationCondition", + "shared_implementation_short_name": "NonBooleanIterationStmt", "tags": [ "maintainability", "readability" From 88febcb317869b563b936f7b1543aa8abdfc46a8 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 7 Mar 2023 17:56:50 +1100 Subject: [PATCH 32/76] added RULE-15-5 --- .../RULE-15-5/FunctionReturnCondition.ql | 26 +++++++ .../FunctionReturnCondition.expected | 4 ++ .../RULE-15-5/FunctionReturnCondition.qlref | 1 + c/misra/test/rules/RULE-15-5/test.c | 27 ++++++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + .../cpp/exclusions/c/Statements5.qll | 61 +++++++++++++++++ rule_packages/c/Statements5.json | 67 +++++++++++++++++++ rules.csv | 6 +- 8 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql create mode 100644 c/misra/test/rules/RULE-15-5/FunctionReturnCondition.expected create mode 100644 c/misra/test/rules/RULE-15-5/FunctionReturnCondition.qlref create mode 100644 c/misra/test/rules/RULE-15-5/test.c create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Statements5.qll create mode 100644 rule_packages/c/Statements5.json diff --git a/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql b/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql new file mode 100644 index 0000000000..b26de24322 --- /dev/null +++ b/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql @@ -0,0 +1,26 @@ +/** + * @id c/misra/function-return-condition + * @name RULE-15-5: A function should have a single point of exit at the end + * @description Not having a single point of exit in a function can lead to unintentional behaviour. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-15-5 + * maintainability + * readability + * correctness + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +from Function func, string message +where + not isExcluded(func, Statements5Package::functionReturnConditionQuery()) and + count(ReturnStmt return | return.getEnclosingFunction() = func) > 1 and + message = "Function has more than on return statement." + or + not func.getBlock().getLastStmt() instanceof ReturnStmt and + message = "The last statement of the function is not a return statement." +select func, message diff --git a/c/misra/test/rules/RULE-15-5/FunctionReturnCondition.expected b/c/misra/test/rules/RULE-15-5/FunctionReturnCondition.expected new file mode 100644 index 0000000000..48ee45bfdd --- /dev/null +++ b/c/misra/test/rules/RULE-15-5/FunctionReturnCondition.expected @@ -0,0 +1,4 @@ +| test.c:1:6:1:7 | f1 | Function has more than on return statement. | +| test.c:14:6:14:7 | f3 | The last statement of the function is not a return statement. | +| test.c:21:6:21:7 | f4 | Function has more than on return statement. | +| test.c:21:6:21:7 | f4 | The last statement of the function is not a return statement. | diff --git a/c/misra/test/rules/RULE-15-5/FunctionReturnCondition.qlref b/c/misra/test/rules/RULE-15-5/FunctionReturnCondition.qlref new file mode 100644 index 0000000000..fef14a8d42 --- /dev/null +++ b/c/misra/test/rules/RULE-15-5/FunctionReturnCondition.qlref @@ -0,0 +1 @@ +rules/RULE-15-5/FunctionReturnCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-5/test.c b/c/misra/test/rules/RULE-15-5/test.c new file mode 100644 index 0000000000..80667338a2 --- /dev/null +++ b/c/misra/test/rules/RULE-15-5/test.c @@ -0,0 +1,27 @@ +void f1(int p1) { // NON_COMPLIANT + if (p1) { + return; + } + return; +} + +void f2(int p1) { // COMPLIANT + if (p1) { + } + return; +} + +void f3(int p1) { // NON_COMPLIANT + if (p1) { + } + return; + p1++; +} + +void f4(int p1) { // NON_COMPLIANT + if (p1) { + return; + } + return; + p1++; +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 80c09f4c5f..b7c763c9d8 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -46,6 +46,7 @@ import Statements1 import Statements2 import Statements3 import Statements4 +import Statements5 import Strings1 import Strings2 import Strings3 @@ -97,6 +98,7 @@ newtype TCQuery = TStatements2PackageQuery(Statements2Query q) or TStatements3PackageQuery(Statements3Query q) or TStatements4PackageQuery(Statements4Query q) or + TStatements5PackageQuery(Statements5Query q) or TStrings1PackageQuery(Strings1Query q) or TStrings2PackageQuery(Strings2Query q) or TStrings3PackageQuery(Strings3Query q) or @@ -148,6 +150,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isStatements2QueryMetadata(query, queryId, ruleId, category) or isStatements3QueryMetadata(query, queryId, ruleId, category) or isStatements4QueryMetadata(query, queryId, ruleId, category) or + isStatements5QueryMetadata(query, queryId, ruleId, category) or isStrings1QueryMetadata(query, queryId, ruleId, category) or isStrings2QueryMetadata(query, queryId, ruleId, category) or isStrings3QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Statements5.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements5.qll new file mode 100644 index 0000000000..cb0eeeff90 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements5.qll @@ -0,0 +1,61 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Statements5Query = + TControllingExpInvariantConditionQuery() or + TFunctionReturnConditionQuery() or + TNonVoidFunctionReturnConditionQuery() + +predicate isStatements5QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `controllingExpInvariantCondition` query + Statements5Package::controllingExpInvariantConditionQuery() and + queryId = + // `@id` for the `controllingExpInvariantCondition` query + "c/misra/controlling-exp-invariant-condition" and + ruleId = "RULE-14-3" and + category = "required" + or + query = + // `Query` instance for the `functionReturnCondition` query + Statements5Package::functionReturnConditionQuery() and + queryId = + // `@id` for the `functionReturnCondition` query + "c/misra/function-return-condition" and + ruleId = "RULE-15-5" and + category = "advisory" + or + query = + // `Query` instance for the `nonVoidFunctionReturnCondition` query + Statements5Package::nonVoidFunctionReturnConditionQuery() and + queryId = + // `@id` for the `nonVoidFunctionReturnCondition` query + "c/misra/non-void-function-return-condition" and + ruleId = "RULE-17-4" and + category = "mandatory" +} + +module Statements5Package { + Query controllingExpInvariantConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `controllingExpInvariantCondition` query + TQueryC(TStatements5PackageQuery(TControllingExpInvariantConditionQuery())) + } + + Query functionReturnConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `functionReturnCondition` query + TQueryC(TStatements5PackageQuery(TFunctionReturnConditionQuery())) + } + + Query nonVoidFunctionReturnConditionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonVoidFunctionReturnCondition` query + TQueryC(TStatements5PackageQuery(TNonVoidFunctionReturnConditionQuery())) + } +} diff --git a/rule_packages/c/Statements5.json b/rule_packages/c/Statements5.json new file mode 100644 index 0000000000..c32f0f4968 --- /dev/null +++ b/rule_packages/c/Statements5.json @@ -0,0 +1,67 @@ +{ + "MISRA-C-2012": { + "RULE-14-3": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "If a controlling expression has an invariant value then it is possible that there is a programming error.", + "kind": "problem", + "name": "Controlling expressions shall not be invariant", + "precision": "very-high", + "severity": "error", + "short_name": "ControllingExpInvariantCondition", + "tags": [ + "correctness", + "maintainability", + "readability" + ] + } + ], + "title": "Controlling expressions shall not be invariant" + }, + "RULE-15-5": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Not having a single point of exit in a function can lead to unintentional behaviour.", + "kind": "problem", + "name": "A function should have a single point of exit at the end", + "precision": "very-high", + "severity": "recommendation", + "short_name": "FunctionReturnCondition", + "tags": [ + "maintainability", + "readability", + "correctness" + ] + } + ], + "title": "A function should have a single point of exit at the end" + }, + "RULE-17-4": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Not returning with an expression from a non-void function can lead to undefined behaviour.", + "kind": "problem", + "name": "All exit paths from a function with non-void return type shall have an explicit return statement", + "precision": "very-high", + "severity": "error", + "short_name": "NonVoidFunctionReturnCondition", + "tags": [ + "correctness", + "maintainability", + "readability" + ] + } + ], + "title": "All exit paths from a function with non-void return type shall have an explicit return statement with an expression" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index 81ef255764..33f5df22b1 100644 --- a/rules.csv +++ b/rules.csv @@ -695,13 +695,13 @@ c,MISRA-C-2012,RULE-13-5,Yes,Required,,,The right hand operand of a logical && o c,MISRA-C-2012,RULE-13-6,Yes,Mandatory,,,The operand of the sizeof operator shall not contain any expressiosn 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-2,Yes,Required,,,A for loop shall be well-formed,M6-5-1...M6-5-6,Statements4,Medium, -c,MISRA-C-2012,RULE-14-3,Yes,Required,,,Controlling expressions shall not be invariant,,Statements,Medium, +c,MISRA-C-2012,RULE-14-3,Yes,Required,,,Controlling expressions shall not be invariant,,Statements5,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,Statements4,Medium, c,MISRA-C-2012,RULE-15-1,No,Advisory,,,The goto statement should not be used,A6-6-1,,Import, c,MISRA-C-2012,RULE-15-2,Yes,Required,,,The goto statement shall jump to a label declared later in the same function,M6-6-2,Statements2,Import, c,MISRA-C-2012,RULE-15-3,Yes,Required,,,"Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement",M6-6-1,Statements2,Import, c,MISRA-C-2012,RULE-15-4,Yes,Advisory,,,There should be no more than one break or goto statement used to terminate any iteration statement,,Statements2,Medium, -c,MISRA-C-2012,RULE-15-5,Yes,Advisory,,,A function should have a single point of exit at the end,,Statements,Medium, +c,MISRA-C-2012,RULE-15-5,Yes,Advisory,,,A function should have a single point of exit at the end,,Statements5,Medium, c,MISRA-C-2012,RULE-15-6,Yes,Required,,,The body of an iteration-statement or a selection-statement shall be a compund-statement,M6-3-1,Statements3,Import, c,MISRA-C-2012,RULE-15-7,Yes,Required,,,All if / else if constructs shall be terminated with an else statement,M6-4-2,Statements3,Import, c,MISRA-C-2012,RULE-16-1,Yes,Required,,,All switch statements shall be well-formed,M6-4-3,Statements3,Import, @@ -714,7 +714,7 @@ c,MISRA-C-2012,RULE-16-7,Yes,Required,,,A switch-expression shall not have essen c,MISRA-C-2012,RULE-17-1,Yes,Required,,,The features of shall not be used,,Banned,Easy, c,MISRA-C-2012,RULE-17-2,Yes,Required,,,"Functions shall not call themselves, either directly or indirectly",A7-5-2,Statements3,Import, c,MISRA-C-2012,RULE-17-3,Yes,Mandatory,,,A function shall not be declared implicitly,,Declarations6,Medium, -c,MISRA-C-2012,RULE-17-4,Yes,Mandatory,,,All exit paths from a function with non-void return type shall have an explicit return statement with an expression,MSC52-CPP,Statements,Medium, +c,MISRA-C-2012,RULE-17-4,Yes,Mandatory,,,All exit paths from a function with non-void return type shall have an explicit return statement with an expression,MSC52-CPP,Statements5,Medium, c,MISRA-C-2012,RULE-17-5,Yes,Advisory,,,The function argument corresponding to a parameter declared to have an array type shall have an appropriate number of elements,,Contracts,Hard, c,MISRA-C-2012,RULE-17-6,No,Mandatory,,,The declaration of an array parameter shall not contain the static keyword between the [ ],,,, c,MISRA-C-2012,RULE-17-7,Yes,Required,,,The value returned by a function having non-void return type shall be used,A0-1-2,Contracts,Import, From 307173253815c1c596e128e0a4de872f7abb4aa3 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 7 Mar 2023 18:34:16 +1100 Subject: [PATCH 33/76] added RULE-17-4 --- .../NonVoidFunctionReturnCondition.ql | 24 +++++++++++++++++++ .../NonVoidFunctionReturnCondition.testref | 1 + rule_packages/c/Statements5.json | 1 + 3 files changed, 26 insertions(+) create mode 100644 c/misra/src/rules/RULE-17-4/NonVoidFunctionReturnCondition.ql create mode 100644 c/misra/test/rules/RULE-17-4/NonVoidFunctionReturnCondition.testref diff --git a/c/misra/src/rules/RULE-17-4/NonVoidFunctionReturnCondition.ql b/c/misra/src/rules/RULE-17-4/NonVoidFunctionReturnCondition.ql new file mode 100644 index 0000000000..24329e5ab5 --- /dev/null +++ b/c/misra/src/rules/RULE-17-4/NonVoidFunctionReturnCondition.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/non-void-function-return-condition + * @name RULE-17-4: All exit paths from a function with non-void return type shall have an explicit return statement + * @description Not returning with an expression from a non-void function can lead to undefined + * behaviour. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-17-4 + * correctness + * maintainability + * readability + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.nonvoidfunctiondoesnotreturn.NonVoidFunctionDoesNotReturn + +class NonVoidFunctionReturnConditionQuery extends NonVoidFunctionDoesNotReturnSharedQuery { + NonVoidFunctionReturnConditionQuery() { + this = Statements5Package::nonVoidFunctionReturnConditionQuery() + } +} diff --git a/c/misra/test/rules/RULE-17-4/NonVoidFunctionReturnCondition.testref b/c/misra/test/rules/RULE-17-4/NonVoidFunctionReturnCondition.testref new file mode 100644 index 0000000000..6ddd134ce3 --- /dev/null +++ b/c/misra/test/rules/RULE-17-4/NonVoidFunctionReturnCondition.testref @@ -0,0 +1 @@ +c/common/test/rules/nonvoidfunctiondoesnotreturn/NonVoidFunctionDoesNotReturn.ql \ No newline at end of file diff --git a/rule_packages/c/Statements5.json b/rule_packages/c/Statements5.json index c32f0f4968..96c0f9a0f5 100644 --- a/rule_packages/c/Statements5.json +++ b/rule_packages/c/Statements5.json @@ -54,6 +54,7 @@ "precision": "very-high", "severity": "error", "short_name": "NonVoidFunctionReturnCondition", + "shared_implementation_short_name": "NonVoidFunctionDoesNotReturn", "tags": [ "correctness", "maintainability", From 88be9693acb80df3eeae1d0045e8db6b48cb2947 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Tue, 7 Mar 2023 21:23:14 +1100 Subject: [PATCH 34/76] Added RULE-14-3 --- .../ControllingExpInvariantCondition.ql | 54 +++++++++++++++++++ .../ControllingExpInvariantCondition.expected | 3 ++ .../ControllingExpInvariantCondition.qlref | 1 + c/misra/test/rules/RULE-14-3/test.c | 17 ++++++ 4 files changed, 75 insertions(+) create mode 100644 c/misra/src/rules/RULE-14-3/ControllingExpInvariantCondition.ql create mode 100644 c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.expected create mode 100644 c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.qlref create mode 100644 c/misra/test/rules/RULE-14-3/test.c diff --git a/c/misra/src/rules/RULE-14-3/ControllingExpInvariantCondition.ql b/c/misra/src/rules/RULE-14-3/ControllingExpInvariantCondition.ql new file mode 100644 index 0000000000..ba74a7b9e9 --- /dev/null +++ b/c/misra/src/rules/RULE-14-3/ControllingExpInvariantCondition.ql @@ -0,0 +1,54 @@ +/** + * @id c/misra/controlling-exp-invariant-condition + * @name RULE-14-3: Controlling expressions shall not be invariant + * @description If a controlling expression has an invariant value then it is possible that there is + * a programming error. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-14-3 + * correctness + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from ControlFlowNode expr, string message +where + not isExcluded(expr, Statements5Package::controllingExpInvariantConditionQuery()) and + ( + exists(IfStmt ifStmt | + ( + ifStmt.getControllingExpr() = expr and + ( + conditionAlwaysFalse(expr) + or + conditionAlwaysTrue(expr) + ) + ) + ) and + message = "Controlling expression in if statement has invariant value." + ) + or + exists(Loop loop | + loop.getControllingExpr() = expr and + ( + conditionAlwaysFalse(expr) + or + conditionAlwaysTrue(expr) + ) + ) and + message = "Controlling expression in loop statement has invariant value." + or + exists(SwitchStmt switch | + switch.getControllingExpr() = expr and + ( + conditionAlwaysFalse(expr) and + conditionAlwaysTrue(expr) + ) + ) and + message = "Controlling expression in switch statement has invariant value." +select expr, message diff --git a/c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.expected b/c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.expected new file mode 100644 index 0000000000..b328b45d37 --- /dev/null +++ b/c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.expected @@ -0,0 +1,3 @@ +| test.c:2:7:2:11 | ... > ... | Controlling expression in if statement has invariant value. | +| test.c:13:10:13:16 | ... > ... | Controlling expression in loop statement has invariant value. | +| test.c:14:9:14:13 | ... > ... | Controlling expression in if statement has invariant value. | diff --git a/c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.qlref b/c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.qlref new file mode 100644 index 0000000000..807b93cb30 --- /dev/null +++ b/c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.qlref @@ -0,0 +1 @@ +rules/RULE-14-3/ControllingExpInvariantCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-14-3/test.c b/c/misra/test/rules/RULE-14-3/test.c new file mode 100644 index 0000000000..9d3ea0088f --- /dev/null +++ b/c/misra/test/rules/RULE-14-3/test.c @@ -0,0 +1,17 @@ +void f1(int p1) { + if (2 > 3) { // NON_COMPLIANT + } + + if (p1 > 0) { // COMPLIANT + } + + if (p1 < 10 && p1 > 20) { // NON_COMPLIANT[FALSE_NEGATIVE] + } +} + +void f2(int p1) { + while (20 > 10) { // NON_COMPLIANT + if (1 > 2) { + } // NON_COMPLIANT + } +} \ No newline at end of file From 1a1dbba84428440b687f4bf23504d9ed5ef7371c Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Wed, 8 Mar 2023 21:47:37 +1100 Subject: [PATCH 35/76] WIP 15-3 --- .../RULE-15-3/GotoLabelBlockCondition.ql | 66 ++++++++++++++----- c/misra/test/rules/RULE-15-3/test.c | 15 ++++- 2 files changed, 64 insertions(+), 17 deletions(-) diff --git a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql index c5980557ba..646d0fb439 100644 --- a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql +++ b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql @@ -1,6 +1,6 @@ /** * @id c/misra/goto-label-block-condition - * @name RULE-15-3: The goto statement and any of its label shall be declared or enclosed in the same block. + * @name RULE-15-3: The goto statement and any of its label shall be declared or enclosed in the same block. * @description Any label referenced by a goto statement shall be declared in the same block, or in * any block enclosing the goto statement * @kind problem @@ -15,6 +15,37 @@ import cpp import codingstandards.c.misra +predicate isPartOfSwitch(Stmt goto) { + exists(SwitchStmt switch | switch.getStmt() = goto.getParent()) +} + +Stmt getNextStmt(ControlFlowNode node) { + node.getASuccessor() = result + or + exists(ControlFlowNode other | + node.getASuccessor() = other and other != result and result = getNextStmt(other) + ) +} + +Stmt getPreviousStmt(Stmt s) { s = getNextStmt(result) } + +SwitchCase getSwitchCase(Stmt stmt) { + exists(int index, SwitchStmt switch | + getStmtInSwitch(switch, stmt, index) and getStmtInSwitch(switch, result, index - 1) + ) + or + exists(int index, SwitchStmt switch, Stmt other | + getStmtInSwitch(switch, stmt, index) and + getStmtInSwitch(switch, other, index - 1) and + not other instanceof SwitchCase and + result = getSwitchCase(other) + ) +} + +predicate getStmtInSwitch(SwitchStmt switch, Stmt s, int index) { + switch.getStmt().(BlockStmt).getStmt(index) = s +} + int statementDepth(Stmt statement) { statement.getParent() = statement.getEnclosingFunction().getBlock() and result = 1 or @@ -22,26 +53,29 @@ int statementDepth(Stmt statement) { } predicate test(GotoStmt goto, Stmt target, int m, int n) { - statementDepth(goto) = m and target = goto.getTarget() and statementDepth(target) = n + statementDepth(goto) = m and + target = goto.getTarget() and + statementDepth(target) = n and + isPartOfSwitch(goto) and + getSwitchCase(goto) = getSwitchCase(target) and + m = n } -from GotoStmt goto +from GotoStmt goto, Stmt target, int gotoDepth, int targetDepth where not isExcluded(goto, Statements2Package::gotoLabelBlockConditionQuery()) and - not goto.getEnclosingBlock+() = goto.getTarget().getEnclosingBlock() - or - exists(SwitchStmt switch, int caseLocation, int nextCaseLocation | - switch.getAChild*() = goto and - switch.getASwitchCase().getLocation().getStartLine() = caseLocation and - switch.getASwitchCase().getNextSwitchCase().getLocation().getStartLine() = nextCaseLocation and - goto.getLocation().getStartLine() > caseLocation and - goto.getLocation().getStartLine() < nextCaseLocation and + goto.getTarget() = target and + gotoDepth = statementDepth(goto) and + targetDepth = statementDepth(target) and + targetDepth >= gotoDepth and + ( + targetDepth = gotoDepth + implies ( - goto.getTarget().getLocation().getStartLine() < caseLocation + not isPartOfSwitch(goto) and not goto.getParent() = target.getParent() or - goto.getTarget().getLocation().getStartLine() > nextCaseLocation - ) and - goto.getTarget().getLocation().getStartLine() > switch.getLocation().getStartLine() + isPartOfSwitch(goto) and not getSwitchCase(goto) = getSwitchCase(target) + ) ) select goto, "The $@ statement and its $@ are not declared or enclosed in the same block. test", - goto, "goto", goto.getTarget(), "label" + goto, "goto", target, "label" diff --git a/c/misra/test/rules/RULE-15-3/test.c b/c/misra/test/rules/RULE-15-3/test.c index 666a45cb2c..82b149b326 100644 --- a/c/misra/test/rules/RULE-15-3/test.c +++ b/c/misra/test/rules/RULE-15-3/test.c @@ -66,4 +66,17 @@ void f7(int p) { default: break; } -} \ No newline at end of file +} + +void f8(int p) { + + switch (p) { + case 0: + goto L1; + ; + L1:; // COMPLIANT + break; + default: + break; + } +} From ddc2892280037c7bf5a889018b0cdc80dda66462 Mon Sep 17 00:00:00 2001 From: s-samadi Date: Thu, 9 Mar 2023 14:03:20 +1100 Subject: [PATCH 36/76] WIP 16-7 --- .../SwitchExpressionBoolCondition.ql | 12 ++++--- .../SwitchExpressionBoolCondition.expected | 1 - c/misra/test/rules/RULE-16-7/test.c | 36 +++++++++++++++++++ rule_packages/c/Statements2.json | 11 +++--- 4 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 c/misra/test/rules/RULE-16-7/test.c diff --git a/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql b/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql index 54b143c464..0bc891fe6e 100644 --- a/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql +++ b/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql @@ -1,18 +1,20 @@ /** * @id c/misra/switch-expression-bool-condition * @name RULE-16-7: A switch-expression shall not have essentially Boolean type - * @description + * @description An `if-else` construct is more appropriate for boolean controlled expression. * @kind problem * @precision very-high * @problem.severity error * @tags external/misra/id/rule-16-7 + * readability + * maintainability * external/misra/obligation/required */ import cpp import codingstandards.c.misra +import codingstandards.cpp.SwitchStatement -from -where - not isExcluded(x, Statements2Package::switchExpressionBoolConditionQuery()) and -select +from BooleanSwitchStmt boolSwitch +where not isExcluded(boolSwitch, Statements2Package::switchExpressionBoolConditionQuery()) +select boolSwitch, "Boolean expression used in switch." diff --git a/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected b/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected index 2ec1a0ac6c..e69de29bb2 100644 --- a/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected +++ b/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected @@ -1 +0,0 @@ -No expected results have yet been specified \ No newline at end of file diff --git a/c/misra/test/rules/RULE-16-7/test.c b/c/misra/test/rules/RULE-16-7/test.c new file mode 100644 index 0000000000..31e0a27821 --- /dev/null +++ b/c/misra/test/rules/RULE-16-7/test.c @@ -0,0 +1,36 @@ +void f1(int p1) { + + switch (p1) // COMPLIANT + { + case 1:; + break; + case 2:; + break; + default: + break; + } +} + +void f2(int p1) { + switch (p1 == 1) // NON_COMPLIANT + { + case 0: + break; + case 1: + break; + default: + break; + } +} + +void f3(char *p1) { + switch (p1 == "CODEQL") // NON_COMPLIANT + { + case 0: + break; + case 1: + break; + default: + break; + } +} diff --git a/rule_packages/c/Statements2.json b/rule_packages/c/Statements2.json index 4bb37e2743..8aa44c5091 100644 --- a/rule_packages/c/Statements2.json +++ b/rule_packages/c/Statements2.json @@ -27,9 +27,9 @@ }, "queries": [ { - "description": "Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement", + "description": "Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement.", "kind": "problem", - "name": "The goto statement and any of its label shall be declared or enclosed in the same block. ", + "name": "The goto statement and any of its label shall be declared or enclosed in the same block", "precision": "high", "severity": "recommendation", "short_name": "GotoLabelBlockCondition", @@ -87,13 +87,16 @@ }, "queries": [ { - "description": "", + "description": "An `if-else` construct is more appropriate for boolean controlled expression.", "kind": "problem", "name": "A switch-expression shall not have essentially Boolean type", "precision": "very-high", "severity": "error", "short_name": "SwitchExpressionBoolCondition", - "tags": [] + "tags": [ + "readability", + "maintainability" + ] } ], "title": "A switch-expression shall not have essentially Boolean type" From 5afb8a0db4773c56231fe1c97bbf64693bfac82b Mon Sep 17 00:00:00 2001 From: s-samadi Date: Thu, 9 Mar 2023 14:09:32 +1100 Subject: [PATCH 37/76] formatted 15-3 --- c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql index 646d0fb439..30b72b441e 100644 --- a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql +++ b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql @@ -1,8 +1,8 @@ /** * @id c/misra/goto-label-block-condition - * @name RULE-15-3: The goto statement and any of its label shall be declared or enclosed in the same block. + * @name RULE-15-3: The goto statement and any of its label shall be declared or enclosed in the same block * @description Any label referenced by a goto statement shall be declared in the same block, or in - * any block enclosing the goto statement + * any block enclosing the goto statement. * @kind problem * @precision high * @problem.severity recommendation From d50b84d80bec55bb02d7af1ebd40c2c777911bd1 Mon Sep 17 00:00:00 2001 From: s-samadi Date: Thu, 9 Mar 2023 14:16:41 +1100 Subject: [PATCH 38/76] formatted 16-7 --- c/misra/test/rules/RULE-16-3/test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/c/misra/test/rules/RULE-16-3/test.c b/c/misra/test/rules/RULE-16-3/test.c index c7cae7216c..ade65474f2 100644 --- a/c/misra/test/rules/RULE-16-3/test.c +++ b/c/misra/test/rules/RULE-16-3/test.c @@ -43,8 +43,8 @@ void f2(int p1) { void f3(int p1) { switch (p1) { default: // NON_COMPLIANT - p1++; - case 1: // COMPLIANT + p1++; + case 1: // COMPLIANT break; } -} \ No newline at end of file +} From 8a83f84e01ab6ede611a583283f1de1a9861ab90 Mon Sep 17 00:00:00 2001 From: s-samadi Date: Thu, 9 Mar 2023 15:35:51 +1100 Subject: [PATCH 39/76] Renamed query RULE-14-3 --- ...tCondition.ql => ControllingExprInvariant.ql} | 6 ++++-- .../ControllingExpInvariantCondition.qlref | 1 - ...xpected => ControllingExprInvariant.expected} | 1 + .../RULE-14-3/ControllingExprInvariant.qlref | 1 + c/misra/test/rules/RULE-14-3/test.c | 7 +++++-- .../cpp/exclusions/c/Statements5.qll | 16 ++++++++-------- rule_packages/c/Statements5.json | 4 ++-- 7 files changed, 21 insertions(+), 15 deletions(-) rename c/misra/src/rules/RULE-14-3/{ControllingExpInvariantCondition.ql => ControllingExprInvariant.ql} (88%) delete mode 100644 c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.qlref rename c/misra/test/rules/RULE-14-3/{ControllingExpInvariantCondition.expected => ControllingExprInvariant.expected} (74%) create mode 100644 c/misra/test/rules/RULE-14-3/ControllingExprInvariant.qlref diff --git a/c/misra/src/rules/RULE-14-3/ControllingExpInvariantCondition.ql b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql similarity index 88% rename from c/misra/src/rules/RULE-14-3/ControllingExpInvariantCondition.ql rename to c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql index ba74a7b9e9..436cde3f1c 100644 --- a/c/misra/src/rules/RULE-14-3/ControllingExpInvariantCondition.ql +++ b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql @@ -1,5 +1,5 @@ /** - * @id c/misra/controlling-exp-invariant-condition + * @id c/misra/controlling-expr-invariant * @name RULE-14-3: Controlling expressions shall not be invariant * @description If a controlling expression has an invariant value then it is possible that there is * a programming error. @@ -15,10 +15,12 @@ import cpp import codingstandards.c.misra +import cpp +import codingstandards.c.misra from ControlFlowNode expr, string message where - not isExcluded(expr, Statements5Package::controllingExpInvariantConditionQuery()) and + not isExcluded(expr, Statements5Package::controllingExprInvariantQuery()) and ( exists(IfStmt ifStmt | ( diff --git a/c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.qlref b/c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.qlref deleted file mode 100644 index 807b93cb30..0000000000 --- a/c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-14-3/ControllingExpInvariantCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.expected b/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected similarity index 74% rename from c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.expected rename to c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected index b328b45d37..7543929f91 100644 --- a/c/misra/test/rules/RULE-14-3/ControllingExpInvariantCondition.expected +++ b/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected @@ -1,3 +1,4 @@ | test.c:2:7:2:11 | ... > ... | Controlling expression in if statement has invariant value. | | test.c:13:10:13:16 | ... > ... | Controlling expression in loop statement has invariant value. | | test.c:14:9:14:13 | ... > ... | Controlling expression in if statement has invariant value. | +| test.c:18:20:18:24 | ... < ... | Controlling expression in loop statement has invariant value. | diff --git a/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.qlref b/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.qlref new file mode 100644 index 0000000000..dcee0a35ac --- /dev/null +++ b/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.qlref @@ -0,0 +1 @@ +rules/RULE-14-3/ControllingExprInvariant.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-14-3/test.c b/c/misra/test/rules/RULE-14-3/test.c index 9d3ea0088f..56383beb4e 100644 --- a/c/misra/test/rules/RULE-14-3/test.c +++ b/c/misra/test/rules/RULE-14-3/test.c @@ -9,9 +9,12 @@ void f1(int p1) { } } -void f2(int p1) { +void f2() { while (20 > 10) { // NON_COMPLIANT if (1 > 2) { } // NON_COMPLIANT } -} \ No newline at end of file + + for (int i = 10; i < 5; i++) { // NON_COMPLIANT + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Statements5.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements5.qll index cb0eeeff90..d8312d11d7 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Statements5.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements5.qll @@ -4,17 +4,17 @@ import RuleMetadata import codingstandards.cpp.exclusions.RuleMetadata newtype Statements5Query = - TControllingExpInvariantConditionQuery() or + TControllingExprInvariantQuery() or TFunctionReturnConditionQuery() or TNonVoidFunctionReturnConditionQuery() predicate isStatements5QueryMetadata(Query query, string queryId, string ruleId, string category) { query = - // `Query` instance for the `controllingExpInvariantCondition` query - Statements5Package::controllingExpInvariantConditionQuery() and + // `Query` instance for the `controllingExprInvariant` query + Statements5Package::controllingExprInvariantQuery() and queryId = - // `@id` for the `controllingExpInvariantCondition` query - "c/misra/controlling-exp-invariant-condition" and + // `@id` for the `controllingExprInvariant` query + "c/misra/controlling-expr-invariant" and ruleId = "RULE-14-3" and category = "required" or @@ -38,11 +38,11 @@ predicate isStatements5QueryMetadata(Query query, string queryId, string ruleId, } module Statements5Package { - Query controllingExpInvariantConditionQuery() { + Query controllingExprInvariantQuery() { //autogenerate `Query` type result = - // `Query` type for `controllingExpInvariantCondition` query - TQueryC(TStatements5PackageQuery(TControllingExpInvariantConditionQuery())) + // `Query` type for `controllingExprInvariant` query + TQueryC(TStatements5PackageQuery(TControllingExprInvariantQuery())) } Query functionReturnConditionQuery() { diff --git a/rule_packages/c/Statements5.json b/rule_packages/c/Statements5.json index 96c0f9a0f5..93a533939b 100644 --- a/rule_packages/c/Statements5.json +++ b/rule_packages/c/Statements5.json @@ -11,7 +11,7 @@ "name": "Controlling expressions shall not be invariant", "precision": "very-high", "severity": "error", - "short_name": "ControllingExpInvariantCondition", + "short_name": "ControllingExprInvariant", "tags": [ "correctness", "maintainability", @@ -65,4 +65,4 @@ "title": "All exit paths from a function with non-void return type shall have an explicit return statement with an expression" } } -} \ No newline at end of file +} From 94a33f6b57d980c3eb559008ad38c19a7f52cb87 Mon Sep 17 00:00:00 2001 From: s-samadi Date: Thu, 9 Mar 2023 15:37:06 +1100 Subject: [PATCH 40/76] fixed logical error in RULE-14-3 --- c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql index 436cde3f1c..d372d587a4 100644 --- a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql +++ b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql @@ -48,7 +48,7 @@ where exists(SwitchStmt switch | switch.getControllingExpr() = expr and ( - conditionAlwaysFalse(expr) and + conditionAlwaysFalse(expr) or conditionAlwaysTrue(expr) ) ) and From 8dc56be78a28bc44c23afe5e5911307660c62e8c Mon Sep 17 00:00:00 2001 From: s-samadi Date: Thu, 9 Mar 2023 15:55:30 +1100 Subject: [PATCH 41/76] added change notes for alert message formatting --- change_notes/2023-03-09-changed-alert-messages.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change_notes/2023-03-09-changed-alert-messages.md diff --git a/change_notes/2023-03-09-changed-alert-messages.md b/change_notes/2023-03-09-changed-alert-messages.md new file mode 100644 index 0000000000..4756d7822f --- /dev/null +++ b/change_notes/2023-03-09-changed-alert-messages.md @@ -0,0 +1,2 @@ + - `M6-6-2`: Changed formatting of the alert message. + - `M6-4-2`: Changed formatting of alert message. From 1161be02bb9a9a1799d966a647240ff097033fb0 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Fri, 10 Mar 2023 11:17:44 +1100 Subject: [PATCH 42/76] fixed formatting issues --- ...opriateThreadObjectStorageDurations.md.tmp | 364 ++++++++++++++++++ .../RULE-15-3/GotoLabelBlockCondition.ql | 11 - .../SwitchExpressionBoolCondition.ql | 10 +- .../GotoLabelBlockCondition.expected | 6 +- .../SwitchExpressionBoolCondition.expected | 1 - c/misra/test/rules/RULE-16-7/test.c | 37 ++ .../GotoStatementJumpCondition.expected | 4 - .../M6-6-2/GotoStatementJumpCondition.qlref | 1 - cpp/autosar/test/rules/M6-6-2/test.cpp | 32 -- .../GotoStatementCondition.expected | 5 +- .../rules/gotostatementcondition/test.cpp | 27 ++ .../IfElseTerminationConstruct.expected | 6 +- .../rules/ifelseterminationconstruct/test.cpp | 93 +++-- 13 files changed, 489 insertions(+), 108 deletions(-) create mode 100644 c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.md.tmp create mode 100644 c/misra/test/rules/RULE-16-7/test.c delete mode 100644 cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.expected delete mode 100644 cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.qlref delete mode 100644 cpp/autosar/test/rules/M6-6-2/test.cpp diff --git a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.md.tmp b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.md.tmp new file mode 100644 index 0000000000..5ade8c902a --- /dev/null +++ b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.md.tmp @@ -0,0 +1,364 @@ + +## Description +Accessing the automatic or thread-local variables of one thread from another thread is [implementation-defined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation-definedbehavior) and can cause invalid memory accesses because the execution of threads can be interwoven within the constraints of the synchronization model. As a result, the referenced stack frame or thread-local variable may no longer be valid when another thread tries to access it. Shared static variables can be protected by thread synchronization mechanisms. + +However, automatic (local) variables cannot be shared in the same manner because the referenced stack frame's thread would need to stop executing, or some other mechanism must be employed to ensure that the referenced stack frame is still valid. Do not access automatic or thread-local objects from a thread other than the one with which the object is associated. See [DCL30-C. Declare objects with appropriate storage durations](https://wiki.sei.cmu.edu/confluence/display/c/DCL30-C.+Declare+objects+with+appropriate+storage+durations) for information on how to declare objects with appropriate storage durations when data is not being shared between threads. + +Noncompliant Code Example (Automatic Storage Duration) + +This noncompliant code example passes the address of a variable to a child thread, which prints it out. The variable has automatic storage duration. Depending on the execution order, the child thread might reference the variable after the variable's lifetime in the parent thread. This would cause the child thread to access an invalid memory location. + +```cpp +#include +#include + +int child_thread(void *val) { + int *res = (int *)val; + printf("Result: %d\n", *res); + return 0; +} + +void create_thread(thrd_t *tid) { + int val = 1; + if (thrd_success != thrd_create(tid, child_thread, &val)) { + /* Handle error */ + } +} + +int main(void) { + thrd_t tid; + create_thread(&tid); + + if (thrd_success != thrd_join(tid, NULL)) { + /* Handle error */ + } + return 0; +} + +``` + +## Noncompliant Code Example (Automatic Storage Duration) +One practice is to ensure that all objects with automatic storage duration shared between threads are declared such that their lifetime extends past the lifetime of the threads. This can be accomplished using a thread synchronization mechanism, such as `thrd_join()`. In this code example, `val` is declared in `main()`, where `thrd_join()` is called. Because the parent thread waits until the child thread completes before continuing its execution, the shared objects have a lifetime at least as great as the thread. + +```cpp +#include +#include + +int child_thread(void *val) { + int *result = (int *)val; + printf("Result: %d\n", *result); /* Correctly prints 1 */ + return 0; +} + +void create_thread(thrd_t *tid, int *val) { + if (thrd_success != thrd_create(tid, child_thread, val)) { + /* Handle error */ + } +} + +int main(void) { + int val = 1; + thrd_t tid; + create_thread(&tid, &val); + if (thrd_success != thrd_join(tid, NULL)) { + /* Handle error */ + } + return 0; +} +``` + +## +However, the C Standard, 6.2.4 paragraphs 4 and 5 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography)\], states: + +> The result of attempting to indirectly access an object with thread storage duration from a thread other than the one with which the object is associated is implementation-defined. . . . + + +The result of attempting to indirectly access an object with automatic storage duration from a thread other than the one with which the object is associated is implementation-defined. + +Therefore this example relies on [implementation-defined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation-definedbehavior) and is nonportable. + +## Compliant Solution (Static Storage Duration) +This compliant solution stores the value in an object having static storage duration. The lifetime of this object is the entire execution of the program; consequently, it can be safely accessed by any thread. + +```cpp +#include +#include + +int child_thread(void *v) { + int *result = (int *)v; + printf("Result: %d\n", *result); /* Correctly prints 1 */ + return 0; +} + +void create_thread(thrd_t *tid) { + static int val = 1; + if (thrd_success != thrd_create(tid, child_thread, &val)) { + /* Handle error */ + } +} + +int main(void) { + thrd_t tid; + create_thread(&tid); + if (thrd_success != thrd_join(tid, NULL)) { + /* Handle error */ + } + return 0; +} + +``` + +## Compliant Solution (Allocated Storage Duration) +This compliant solution stores the value passed to the child thread in a dynamically allocated object. Because this object will persist until explicitly freed, the child thread can safely access its value. + +```cpp +#include +#include +#include + +int child_thread(void *val) { + int *result = (int *)val; + printf("Result: %d\n", *result); /* Correctly prints 1 */ + return 0; +} + +void create_thread(thrd_t *tid, int *value) { + *value = 1; + if (thrd_success != thrd_create(tid, child_thread, + value)) { + /* Handle error */ + } +} + +int main(void) { + thrd_t tid; + int *value = (int *)malloc(sizeof(int)); + if (!value) { + /* Handle error */ + } + create_thread(&tid, value); + if (thrd_success != thrd_join(tid, NULL)) { + /* Handle error */ + } + free(value); + return 0; +} + +``` + +## Noncompliant Code Example (Thread-Specific Storage) +In this noncompliant code example, the value is stored in thread-specific storage of the parent thread. However, because thread-specific data is available only to the thread that stores it, the `child_thread()` function will set `result` to a null value. + +```cpp +#include +#include +#include + +static tss_t key; + +int child_thread(void *v) { + void *result = tss_get(*(tss_t *)v); + printf("Result: %d\n", *(int *)result); + return 0; +} + +int create_thread(void *thrd) { + int *val = (int *)malloc(sizeof(int)); + if (val == NULL) { + /* Handle error */ + } + *val = 1; + if (thrd_success != tss_set(key, val)) { + /* Handle error */ + } + if (thrd_success != thrd_create((thrd_t *)thrd, + child_thread, &key)) { + /* Handle error */ + } + return 0; +} + +int main(void) { + thrd_t parent_tid, child_tid; + + if (thrd_success != tss_create(&key, free)) { + /* Handle error */ + } + if (thrd_success != thrd_create(&parent_tid, create_thread, + &child_tid)) { + /* Handle error */ + } + if (thrd_success != thrd_join(parent_tid, NULL)) { + /* Handle error */ + } + if (thrd_success != thrd_join(child_tid, NULL)) { + /* Handle error */ + } + tss_delete(key); + return 0; +} +``` + +## Compliant Solution (Thread-Specific Storage) +This compliant solution illustrates how thread-specific storage can be combined with a call to a thread synchronization mechanism, such as `thrd_join()`. Because the parent thread waits until the child thread completes before continuing its execution, the child thread is guaranteed to access a valid live object. + +```cpp +#include +#include +#include + +static tss_t key; + +int child_thread(void *v) { + int *result = v; + printf("Result: %d\n", *result); /* Correctly prints 1 */ + return 0; +} + +int create_thread(void *thrd) { + int *val = (int *)malloc(sizeof(int)); + if (val == NULL) { + /* Handle error */ + } + *val = 1; + if (thrd_success != tss_set(key, val)) { + /* Handle error */ + } + /* ... */ + void *v = tss_get(key); + if (thrd_success != thrd_create((thrd_t *)thrd, + child_thread, v)) { + /* Handle error */ + } + return 0; +} + +int main(void) { + thrd_t parent_tid, child_tid; + + if (thrd_success != tss_create(&key, free)) { + /* Handle error */ + } + if (thrd_success != thrd_create(&parent_tid, create_thread, + &child_tid)) { + /* Handle error */ + } + if (thrd_success != thrd_join(parent_tid, NULL)) { + /* Handle error */ + } + if (thrd_success != thrd_join(child_tid, NULL)) { + /* Handle error */ + } + tss_delete(key); +return 0; +} +``` +This compliant solution uses pointer-to-integer and integer-to-pointer conversions, which have implementation-defined behavior. (See [INT36-C. Converting a pointer to integer or integer to pointer](https://wiki.sei.cmu.edu/confluence/display/c/INT36-C.+Converting+a+pointer+to+integer+or+integer+to+pointer).) + +## Compliant Solution (Thread-Local Storage, Windows, Visual Studio) +Similar to the preceding compliant solution, this compliant solution uses thread-local storage combined with thread synchronization to ensure the child thread is accessing a valid live object. It uses the Visual Studio–specific [__declspec(thread)](http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx) language extension to provide the thread-local storage and the `[WaitForSingleObject()](http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx)` API to provide the synchronization. + +```cpp +#include +#include + +DWORD WINAPI child_thread(LPVOID v) { + int *result = (int *)v; + printf("Result: %d\n", *result); /* Correctly prints 1 */ + return NULL; +} + +int create_thread(HANDLE *tid) { + /* Declare val as a thread-local value */ + __declspec(thread) int val = 1; + *tid = create_thread(NULL, 0, child_thread, &val, 0, NULL); + return *tid == NULL; +} + +int main(void) { + HANDLE tid; + + if (create_thread(&tid)) { + /* Handle error */ + } + + if (WAIT_OBJECT_0 != WaitForSingleObject(tid, INFINITE)) { + /* Handle error */ + } + CloseHandle(tid); + + return 0; +} + +``` + +## Noncompliant Code Example (OpenMP, parallel) +It is important to note that local data can be used securely with threads when using other thread interfaces, so the programmer need not always copy data into nonlocal memory when sharing data with threads. For example, the `shared` keyword in *®The OpenMP API Specification for Parallel Programming* \[[OpenMP](http://openmp.org/wp/)\] can be used in combination with OpenMP's threading interface to share local memory without having to worry about whether local automatic variables remain valid. + +In this noncompliant code example, a variable `j` is declared outside a `parallel` `#pragma` and not listed as a private variable. In OpenMP, variables outside a `parallel #pragma` are shared unless designated as `private`. + +```cpp +#include +#include + +int main(void) { + int j = 0; + #pragma omp parallel + { + int t = omp_get_thread_num(); + printf("Running thread - %d\n", t); + for (int i = 0; i < 5050; i++) { + j++; /* j not private; could be a race condition */ + } + printf("Just ran thread - %d\n", t); + printf("loop count %d\n", j); + } +return 0; +} +``` + +## Compliant Solution (OpenMP, parallel, private) +In this compliant solution, the variable `j` is declared outside of the `parallel` `#pragma` but is explicitly labeled as `private`: + +```cpp +#include +#include + +int main(void) { + int j = 0; + #pragma omp parallel private(j) + { + int t = omp_get_thread_num(); + printf("Running thread - %d\n", t); + for (int i = 0; i < 5050; i++) { + j++; + } + printf("Just ran thread - %d\n", t); + printf("loop count %d\n", j); + } +return 0; +} +``` + +## Risk Assessment +Threads that reference the stack of other threads can potentially overwrite important information on the stack, such as function pointers and return addresses. The compiler may not generate warnings if the programmer allows one thread to access another thread's local variables, so a programmer may not catch a potential error at compile time. The remediation cost for this error is high because analysis tools have difficulty diagnosing problems with concurrency and race conditions. + +
Recommendation Severity Likelihood Remediation Cost Priority Level
CON34-C Medium Probable High P4 L3
+ + +## Automated Detection +
Tool Version Checker Description
CodeSonar 7.2p0 CONCURRENCY.LOCALARG Local Variable Passed to Thread
Helix QAC 2022.4 DF4926, DF4927, DF4928
Parasoft C/C++test 2022.2 CERT_C-CON34-a Declare objects shared between POSIX threads with appropriate storage durations
Polyspace Bug Finder R2022b CERT C: Rule CON34-C Checks for automatic or thread local variable escaping from a C11 thread (rule fully covered)
PRQA QA-C 9.7 4926, 4927, 4928 Enforced by QAC
+ + +## Related Vulnerabilities +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+CON34-C). + +## Related Guidelines +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
Taxonomy Taxonomy item Relationship
CERT C Secure Coding Standard DCL30-C. Declare objects with appropriate storage durations Prior to 2018-01-12: CERT: Unspecified Relationship
+ + +## Bibliography +
\[ ISO/IEC 9899:2011 \] 6.2.4, "Storage Durations of Objects"
\[ OpenMP \] ® The OpenMP API Specification for Parallel Programming
+ diff --git a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql index 646d0fb439..38dc16bcd2 100644 --- a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql +++ b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql @@ -27,8 +27,6 @@ Stmt getNextStmt(ControlFlowNode node) { ) } -Stmt getPreviousStmt(Stmt s) { s = getNextStmt(result) } - SwitchCase getSwitchCase(Stmt stmt) { exists(int index, SwitchStmt switch | getStmtInSwitch(switch, stmt, index) and getStmtInSwitch(switch, result, index - 1) @@ -52,15 +50,6 @@ int statementDepth(Stmt statement) { statementDepth(statement.getParent()) + 1 = result } -predicate test(GotoStmt goto, Stmt target, int m, int n) { - statementDepth(goto) = m and - target = goto.getTarget() and - statementDepth(target) = n and - isPartOfSwitch(goto) and - getSwitchCase(goto) = getSwitchCase(target) and - m = n -} - from GotoStmt goto, Stmt target, int gotoDepth, int targetDepth where not isExcluded(goto, Statements2Package::gotoLabelBlockConditionQuery()) and diff --git a/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql b/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql index 54b143c464..8366f5f60e 100644 --- a/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql +++ b/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql @@ -1,7 +1,7 @@ /** * @id c/misra/switch-expression-bool-condition * @name RULE-16-7: A switch-expression shall not have essentially Boolean type - * @description + * @description * @kind problem * @precision very-high * @problem.severity error @@ -11,8 +11,8 @@ import cpp import codingstandards.c.misra +import codingstandards.cpp.SwitchStatement -from -where - not isExcluded(x, Statements2Package::switchExpressionBoolConditionQuery()) and -select +from BooleanSwitchStmt switch +where not isExcluded(switch, Statements2Package::switchExpressionBoolConditionQuery()) +select switch, "The condition of this $@ statement has boolean type", switch, "switch" diff --git a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected index 9a81d6f434..7ddb3fe509 100644 --- a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected +++ b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected @@ -1,3 +1,3 @@ -| test.c:2:3:2:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:2:3:2:10 | goto ... | goto | test.c:4:3:4:5 | label ...: | label | -| test.c:37:3:37:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:37:3:37:10 | goto ... | goto | test.c:41:3:41:5 | label ...: | label | -| test.c:52:5:52:12 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:52:5:52:12 | goto ... | goto | test.c:55:3:55:5 | label ...: | label | +| test.c:2:3:2:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. test | test.c:2:3:2:10 | goto ... | goto | test.c:4:3:4:5 | label ...: | label | +| test.c:37:3:37:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. test | test.c:37:3:37:10 | goto ... | goto | test.c:41:3:41:5 | label ...: | label | +| test.c:52:5:52:12 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. test | test.c:52:5:52:12 | goto ... | goto | test.c:55:3:55:5 | label ...: | label | diff --git a/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected b/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected index 2ec1a0ac6c..e69de29bb2 100644 --- a/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected +++ b/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected @@ -1 +0,0 @@ -No expected results have yet been specified \ No newline at end of file diff --git a/c/misra/test/rules/RULE-16-7/test.c b/c/misra/test/rules/RULE-16-7/test.c new file mode 100644 index 0000000000..74b394bc6d --- /dev/null +++ b/c/misra/test/rules/RULE-16-7/test.c @@ -0,0 +1,37 @@ + +void f1(int p1) { + + switch (p1) // COMPLIANT + { + case 1: + break; + case 2: + break; + default: + break; + } +} + +void f2(int p1) { + switch (p1 == 1) // NON_COMPLIANT + { + case 0: + break; + case 1: + break; + default: + break; + } +} + +void f3(char *p1) { + switch (p1 == "CODEQL") // NON_COMPLIANT + { + case 0: + break; + case 1: + break; + default: + break; + } +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.expected b/cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.expected deleted file mode 100644 index dba183caaf..0000000000 --- a/cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.expected +++ /dev/null @@ -1,4 +0,0 @@ -| test.cpp:7:3:7:11 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:7:3:7:11 | goto ... | bad | test.cpp:3:1:3:4 | label ...: | label ...: | -| test.cpp:21:3:21:11 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:21:3:21:11 | goto ... | bad | test.cpp:17:1:17:4 | label ...: | label ...: | -| test.cpp:24:3:24:13 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:24:3:24:13 | goto ... | sobad | test.cpp:15:1:15:6 | label ...: | label ...: | -| test.cpp:31:3:31:11 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:31:3:31:11 | goto ... | bad | test.cpp:29:1:29:4 | label ...: | label ...: | diff --git a/cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.qlref b/cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.qlref deleted file mode 100644 index d66c789012..0000000000 --- a/cpp/autosar/test/rules/M6-6-2/GotoStatementJumpCondition.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M6-6-2/GotoStatementJumpCondition.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/M6-6-2/test.cpp b/cpp/autosar/test/rules/M6-6-2/test.cpp deleted file mode 100644 index e942077efd..0000000000 --- a/cpp/autosar/test/rules/M6-6-2/test.cpp +++ /dev/null @@ -1,32 +0,0 @@ -void test_goto_jump_forward_back() { - int i = 5; -bad: - if (i < 10) { - goto good; // GOOD - } - goto bad; // BAD - -good: - i++; -} - -void test_goto_mix_validity() { - int i = 5; -sobad: - i = i * i; -bad: - if (i < 10) { - goto good; // GOOD - } - goto bad; // BAD -good: - i++; - goto sobad; // BAD -} - -void test_goto_jumpsameline_invalid() { - int i = 3; -bad: - i = 4; - goto bad; // BAD -} \ No newline at end of file diff --git a/cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.expected b/cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.expected index 2ec1a0ac6c..c1b2f35eda 100644 --- a/cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.expected +++ b/cpp/common/test/rules/gotostatementcondition/GotoStatementCondition.expected @@ -1 +1,4 @@ -No expected results have yet been specified \ No newline at end of file +| test.cpp:7:3:7:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:7:3:7:10 | goto ... | l1 | test.cpp:3:1:3:3 | label ...: | label ...: | +| test.cpp:19:3:19:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:19:3:19:10 | goto ... | l2 | test.cpp:15:1:15:3 | label ...: | label ...: | +| test.cpp:21:3:21:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:21:3:21:10 | goto ... | l1 | test.cpp:14:1:14:3 | label ...: | label ...: | +| test.cpp:26:3:26:10 | goto ... | The $@ statement jumps to a $@ that is not declared later in the same function. | test.cpp:26:3:26:10 | goto ... | l1 | test.cpp:25:1:25:3 | label ...: | label ...: | diff --git a/cpp/common/test/rules/gotostatementcondition/test.cpp b/cpp/common/test/rules/gotostatementcondition/test.cpp index e69de29bb2..225c1b32f6 100644 --- a/cpp/common/test/rules/gotostatementcondition/test.cpp +++ b/cpp/common/test/rules/gotostatementcondition/test.cpp @@ -0,0 +1,27 @@ +void f1(int p1) { + +l1: + if (p1) { + goto l2; // COMPLIANT + } + goto l1; // NON_COMPLIANT + +l2:; +} + +void f2(int p1) { + +l1:; +l2: + if (p1) { + goto l3; // COMPLIANT + } + goto l2; // NON_COMPLIANT +l3: + goto l1; // NON_COMPLIANT +} + +void f3() { +l1: + goto l1; // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.expected b/cpp/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.expected index 0d14bfa016..bcbc388ca6 100644 --- a/cpp/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.expected +++ b/cpp/common/test/rules/ifelseterminationconstruct/IfElseTerminationConstruct.expected @@ -1,3 +1,3 @@ -| test.cpp:23:3:27:3 | if (...) ... | The $@ construct does not terminate with else statement. | test.cpp:23:3:27:3 | if (...) ... | `if...else` | -| test.cpp:43:5:47:5 | if (...) ... | The $@ construct does not terminate with else statement. | test.cpp:43:5:47:5 | if (...) ... | `if...else` | -| test.cpp:57:3:67:3 | if (...) ... | The $@ construct does not terminate with else statement. | test.cpp:57:3:67:3 | if (...) ... | `if...else` | +| test.cpp:21:5:25:5 | if (...) ... | The $@ construct does not terminate with else statement. | test.cpp:21:5:25:5 | if (...) ... | `if...else` | +| test.cpp:41:7:45:7 | if (...) ... | The $@ construct does not terminate with else statement. | test.cpp:41:7:45:7 | if (...) ... | `if...else` | +| test.cpp:55:5:65:5 | if (...) ... | The $@ construct does not terminate with else statement. | test.cpp:55:5:65:5 | if (...) ... | `if...else` | diff --git a/cpp/common/test/rules/ifelseterminationconstruct/test.cpp b/cpp/common/test/rules/ifelseterminationconstruct/test.cpp index bf8d1d6da3..ccb59b6ca0 100644 --- a/cpp/common/test/rules/ifelseterminationconstruct/test.cpp +++ b/cpp/common/test/rules/ifelseterminationconstruct/test.cpp @@ -10,59 +10,58 @@ void test_ifelse_valid(int expression) { } else { k = j * j; } -} - -void test_ifelse_mix_validity(int expression) { - int i = 4; - int j = 7; - int k; + void test_ifelse_mix_validity(int expression) { + int i = 4; + int j = 7; + int k; - if (expression > 0) { // GOOD - k = i * i; - } - if (expression > 10) { // BAD - k = i + j; - } else if (expression < 0) { - k = i * 2; + if (expression > 0) { // GOOD + k = i * i; + } + if (expression > 10) { // BAD + k = i + j; + } else if (expression < 0) { + k = i * 2; + } } -} -void test_ifelse_nested_invalid(int expression) { - int i = 5; - int j = 7; - int k; + void test_ifelse_nested_invalid(int expression) { + int i = 5; + int j = 7; + int k; - if (expression > 0) { // GOOD - k = i * i * i; - } else { - k = i * j; - } - if (expression > 10) { // GOOD - k = i; - } else if (expression < 0) { - if (expression < -10) { // BAD - k = 5 + j; - } else if (expression < -20) { - k = i * 3; + if (expression > 0) { // GOOD + k = i * i * i; + } else { + k = i * j; + } + if (expression > 10) { // GOOD + k = i; + } else if (expression < 0) { + if (expression < -10) { // BAD + k = 5 + j; + } else if (expression < -20) { + k = i * 3; + } + } else { + k = 3; } - } else { - k = 3; } -} -void test_ifelse_nested_valid(int expression) { - int i = 3; - int j = 1; - int k; - if (expression > 10) { // BAD - k = i + j; - } else if (expression < 0) { - if (i > 3) { // GOOD - k = j; - } else if (i < 10) { - k = i % 3; - } else { - i = i % 2; + void test_ifelse_nested_valid(int expression) { + int i = 3; + int j = 1; + int k; + if (expression > 10) { // BAD + k = i + j; + } else if (expression < 0) { + if (i > 3) { // GOOD + k = j; + } else if (i < 10) { + k = i % 3; + } else { + i = i % 2; + } } } -} \ No newline at end of file +} From 07b86c7e1807ed59a41168454ec53ec1e0e29a5f Mon Sep 17 00:00:00 2001 From: Shadi Samadi <68650974+s-samadi@users.noreply.github.com> Date: Fri, 10 Mar 2023 11:29:00 +1100 Subject: [PATCH 43/76] Delete AppropriateThreadObjectStorageDurations.md.tmp --- ...opriateThreadObjectStorageDurations.md.tmp | 364 ------------------ 1 file changed, 364 deletions(-) delete mode 100644 c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.md.tmp diff --git a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.md.tmp b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.md.tmp deleted file mode 100644 index 5ade8c902a..0000000000 --- a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.md.tmp +++ /dev/null @@ -1,364 +0,0 @@ - -## Description -Accessing the automatic or thread-local variables of one thread from another thread is [implementation-defined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation-definedbehavior) and can cause invalid memory accesses because the execution of threads can be interwoven within the constraints of the synchronization model. As a result, the referenced stack frame or thread-local variable may no longer be valid when another thread tries to access it. Shared static variables can be protected by thread synchronization mechanisms. - -However, automatic (local) variables cannot be shared in the same manner because the referenced stack frame's thread would need to stop executing, or some other mechanism must be employed to ensure that the referenced stack frame is still valid. Do not access automatic or thread-local objects from a thread other than the one with which the object is associated. See [DCL30-C. Declare objects with appropriate storage durations](https://wiki.sei.cmu.edu/confluence/display/c/DCL30-C.+Declare+objects+with+appropriate+storage+durations) for information on how to declare objects with appropriate storage durations when data is not being shared between threads. - -Noncompliant Code Example (Automatic Storage Duration) - -This noncompliant code example passes the address of a variable to a child thread, which prints it out. The variable has automatic storage duration. Depending on the execution order, the child thread might reference the variable after the variable's lifetime in the parent thread. This would cause the child thread to access an invalid memory location. - -```cpp -#include -#include - -int child_thread(void *val) { - int *res = (int *)val; - printf("Result: %d\n", *res); - return 0; -} - -void create_thread(thrd_t *tid) { - int val = 1; - if (thrd_success != thrd_create(tid, child_thread, &val)) { - /* Handle error */ - } -} - -int main(void) { - thrd_t tid; - create_thread(&tid); - - if (thrd_success != thrd_join(tid, NULL)) { - /* Handle error */ - } - return 0; -} - -``` - -## Noncompliant Code Example (Automatic Storage Duration) -One practice is to ensure that all objects with automatic storage duration shared between threads are declared such that their lifetime extends past the lifetime of the threads. This can be accomplished using a thread synchronization mechanism, such as `thrd_join()`. In this code example, `val` is declared in `main()`, where `thrd_join()` is called. Because the parent thread waits until the child thread completes before continuing its execution, the shared objects have a lifetime at least as great as the thread. - -```cpp -#include -#include - -int child_thread(void *val) { - int *result = (int *)val; - printf("Result: %d\n", *result); /* Correctly prints 1 */ - return 0; -} - -void create_thread(thrd_t *tid, int *val) { - if (thrd_success != thrd_create(tid, child_thread, val)) { - /* Handle error */ - } -} - -int main(void) { - int val = 1; - thrd_t tid; - create_thread(&tid, &val); - if (thrd_success != thrd_join(tid, NULL)) { - /* Handle error */ - } - return 0; -} -``` - -## -However, the C Standard, 6.2.4 paragraphs 4 and 5 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography)\], states: - -> The result of attempting to indirectly access an object with thread storage duration from a thread other than the one with which the object is associated is implementation-defined. . . . - - -The result of attempting to indirectly access an object with automatic storage duration from a thread other than the one with which the object is associated is implementation-defined. - -Therefore this example relies on [implementation-defined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation-definedbehavior) and is nonportable. - -## Compliant Solution (Static Storage Duration) -This compliant solution stores the value in an object having static storage duration. The lifetime of this object is the entire execution of the program; consequently, it can be safely accessed by any thread. - -```cpp -#include -#include - -int child_thread(void *v) { - int *result = (int *)v; - printf("Result: %d\n", *result); /* Correctly prints 1 */ - return 0; -} - -void create_thread(thrd_t *tid) { - static int val = 1; - if (thrd_success != thrd_create(tid, child_thread, &val)) { - /* Handle error */ - } -} - -int main(void) { - thrd_t tid; - create_thread(&tid); - if (thrd_success != thrd_join(tid, NULL)) { - /* Handle error */ - } - return 0; -} - -``` - -## Compliant Solution (Allocated Storage Duration) -This compliant solution stores the value passed to the child thread in a dynamically allocated object. Because this object will persist until explicitly freed, the child thread can safely access its value. - -```cpp -#include -#include -#include - -int child_thread(void *val) { - int *result = (int *)val; - printf("Result: %d\n", *result); /* Correctly prints 1 */ - return 0; -} - -void create_thread(thrd_t *tid, int *value) { - *value = 1; - if (thrd_success != thrd_create(tid, child_thread, - value)) { - /* Handle error */ - } -} - -int main(void) { - thrd_t tid; - int *value = (int *)malloc(sizeof(int)); - if (!value) { - /* Handle error */ - } - create_thread(&tid, value); - if (thrd_success != thrd_join(tid, NULL)) { - /* Handle error */ - } - free(value); - return 0; -} - -``` - -## Noncompliant Code Example (Thread-Specific Storage) -In this noncompliant code example, the value is stored in thread-specific storage of the parent thread. However, because thread-specific data is available only to the thread that stores it, the `child_thread()` function will set `result` to a null value. - -```cpp -#include -#include -#include - -static tss_t key; - -int child_thread(void *v) { - void *result = tss_get(*(tss_t *)v); - printf("Result: %d\n", *(int *)result); - return 0; -} - -int create_thread(void *thrd) { - int *val = (int *)malloc(sizeof(int)); - if (val == NULL) { - /* Handle error */ - } - *val = 1; - if (thrd_success != tss_set(key, val)) { - /* Handle error */ - } - if (thrd_success != thrd_create((thrd_t *)thrd, - child_thread, &key)) { - /* Handle error */ - } - return 0; -} - -int main(void) { - thrd_t parent_tid, child_tid; - - if (thrd_success != tss_create(&key, free)) { - /* Handle error */ - } - if (thrd_success != thrd_create(&parent_tid, create_thread, - &child_tid)) { - /* Handle error */ - } - if (thrd_success != thrd_join(parent_tid, NULL)) { - /* Handle error */ - } - if (thrd_success != thrd_join(child_tid, NULL)) { - /* Handle error */ - } - tss_delete(key); - return 0; -} -``` - -## Compliant Solution (Thread-Specific Storage) -This compliant solution illustrates how thread-specific storage can be combined with a call to a thread synchronization mechanism, such as `thrd_join()`. Because the parent thread waits until the child thread completes before continuing its execution, the child thread is guaranteed to access a valid live object. - -```cpp -#include -#include -#include - -static tss_t key; - -int child_thread(void *v) { - int *result = v; - printf("Result: %d\n", *result); /* Correctly prints 1 */ - return 0; -} - -int create_thread(void *thrd) { - int *val = (int *)malloc(sizeof(int)); - if (val == NULL) { - /* Handle error */ - } - *val = 1; - if (thrd_success != tss_set(key, val)) { - /* Handle error */ - } - /* ... */ - void *v = tss_get(key); - if (thrd_success != thrd_create((thrd_t *)thrd, - child_thread, v)) { - /* Handle error */ - } - return 0; -} - -int main(void) { - thrd_t parent_tid, child_tid; - - if (thrd_success != tss_create(&key, free)) { - /* Handle error */ - } - if (thrd_success != thrd_create(&parent_tid, create_thread, - &child_tid)) { - /* Handle error */ - } - if (thrd_success != thrd_join(parent_tid, NULL)) { - /* Handle error */ - } - if (thrd_success != thrd_join(child_tid, NULL)) { - /* Handle error */ - } - tss_delete(key); -return 0; -} -``` -This compliant solution uses pointer-to-integer and integer-to-pointer conversions, which have implementation-defined behavior. (See [INT36-C. Converting a pointer to integer or integer to pointer](https://wiki.sei.cmu.edu/confluence/display/c/INT36-C.+Converting+a+pointer+to+integer+or+integer+to+pointer).) - -## Compliant Solution (Thread-Local Storage, Windows, Visual Studio) -Similar to the preceding compliant solution, this compliant solution uses thread-local storage combined with thread synchronization to ensure the child thread is accessing a valid live object. It uses the Visual Studio–specific [__declspec(thread)](http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx) language extension to provide the thread-local storage and the `[WaitForSingleObject()](http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032(v=vs.85).aspx)` API to provide the synchronization. - -```cpp -#include -#include - -DWORD WINAPI child_thread(LPVOID v) { - int *result = (int *)v; - printf("Result: %d\n", *result); /* Correctly prints 1 */ - return NULL; -} - -int create_thread(HANDLE *tid) { - /* Declare val as a thread-local value */ - __declspec(thread) int val = 1; - *tid = create_thread(NULL, 0, child_thread, &val, 0, NULL); - return *tid == NULL; -} - -int main(void) { - HANDLE tid; - - if (create_thread(&tid)) { - /* Handle error */ - } - - if (WAIT_OBJECT_0 != WaitForSingleObject(tid, INFINITE)) { - /* Handle error */ - } - CloseHandle(tid); - - return 0; -} - -``` - -## Noncompliant Code Example (OpenMP, parallel) -It is important to note that local data can be used securely with threads when using other thread interfaces, so the programmer need not always copy data into nonlocal memory when sharing data with threads. For example, the `shared` keyword in *®The OpenMP API Specification for Parallel Programming* \[[OpenMP](http://openmp.org/wp/)\] can be used in combination with OpenMP's threading interface to share local memory without having to worry about whether local automatic variables remain valid. - -In this noncompliant code example, a variable `j` is declared outside a `parallel` `#pragma` and not listed as a private variable. In OpenMP, variables outside a `parallel #pragma` are shared unless designated as `private`. - -```cpp -#include -#include - -int main(void) { - int j = 0; - #pragma omp parallel - { - int t = omp_get_thread_num(); - printf("Running thread - %d\n", t); - for (int i = 0; i < 5050; i++) { - j++; /* j not private; could be a race condition */ - } - printf("Just ran thread - %d\n", t); - printf("loop count %d\n", j); - } -return 0; -} -``` - -## Compliant Solution (OpenMP, parallel, private) -In this compliant solution, the variable `j` is declared outside of the `parallel` `#pragma` but is explicitly labeled as `private`: - -```cpp -#include -#include - -int main(void) { - int j = 0; - #pragma omp parallel private(j) - { - int t = omp_get_thread_num(); - printf("Running thread - %d\n", t); - for (int i = 0; i < 5050; i++) { - j++; - } - printf("Just ran thread - %d\n", t); - printf("loop count %d\n", j); - } -return 0; -} -``` - -## Risk Assessment -Threads that reference the stack of other threads can potentially overwrite important information on the stack, such as function pointers and return addresses. The compiler may not generate warnings if the programmer allows one thread to access another thread's local variables, so a programmer may not catch a potential error at compile time. The remediation cost for this error is high because analysis tools have difficulty diagnosing problems with concurrency and race conditions. - -
Recommendation Severity Likelihood Remediation Cost Priority Level
CON34-C Medium Probable High P4 L3
- - -## Automated Detection -
Tool Version Checker Description
CodeSonar 7.2p0 CONCURRENCY.LOCALARG Local Variable Passed to Thread
Helix QAC 2022.4 DF4926, DF4927, DF4928
Parasoft C/C++test 2022.2 CERT_C-CON34-a Declare objects shared between POSIX threads with appropriate storage durations
Polyspace Bug Finder R2022b CERT C: Rule CON34-C Checks for automatic or thread local variable escaping from a C11 thread (rule fully covered)
PRQA QA-C 9.7 4926, 4927, 4928 Enforced by QAC
- - -## Related Vulnerabilities -Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+CON34-C). - -## Related Guidelines -[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) - -
Taxonomy Taxonomy item Relationship
CERT C Secure Coding Standard DCL30-C. Declare objects with appropriate storage durations Prior to 2018-01-12: CERT: Unspecified Relationship
- - -## Bibliography -
\[ ISO/IEC 9899:2011 \] 6.2.4, "Storage Durations of Objects"
\[ OpenMP \] ® The OpenMP API Specification for Parallel Programming
- From 96a2682d81f2173575c0121e09dfb313d36101b2 Mon Sep 17 00:00:00 2001 From: Shadi Samadi Date: Fri, 10 Mar 2023 12:23:17 +1100 Subject: [PATCH 44/76] added temporary expected for RULE-15-2 --- c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.expected | 1 - 1 file changed, 1 deletion(-) diff --git a/c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.expected b/c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.expected index 2ec1a0ac6c..e69de29bb2 100644 --- a/c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.expected +++ b/c/misra/test/rules/RULE-15-2/GotoLabelLocationCondition.expected @@ -1 +0,0 @@ -No expected results have yet been specified \ No newline at end of file From b0014caae1f6445a5dd05feccbe63438335f2543 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Mon, 13 Mar 2023 16:59:50 -0700 Subject: [PATCH 45/76] Use loop counter definition from CERT --- .../FLP30-C/FloatingPointLoopCounters.ql | 41 ++++++++++++++----- .../FloatingPointLoopCounters.expected | 5 ++- c/cert/test/rules/FLP30-C/test.c | 15 ++++++- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql b/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql index 1f99006866..a26736707c 100644 --- a/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql +++ b/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql @@ -16,15 +16,36 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Loops -from Loop loop +/* + * A variable that is increased or decreased by a fixed amount on each iteration. + */ + +class InductionVariable extends Variable { + Loop loop; + Expr update; + + InductionVariable() { + update.getParent+() = loop and + ( + update.(AssignArithmeticOperation).getRValue().isConstant() and + update.(AssignArithmeticOperation).getLValue() = this.getAnAccess() + or + exists(BinaryArithmeticOperation binop | + update.(Assignment).getLValue() = this.getAnAccess() and + update.(Assignment).getRValue() = binop and + binop.getAnOperand() = this.getAnAccess() and + binop.getAnOperand().isConstant() + ) + or + update.(CrementOperation).getOperand() = this.getAnAccess() + ) + } +} + +from Loop loop, InductionVariable loopCounter, ComparisonOperation comparison where not isExcluded(loop, Statements4Package::floatingPointLoopCountersQuery()) and - exists(WhileStmt while | - while.getCondition().getType() instanceof FloatType and - loop = while - ) - or - exists(ForStmt for, Variable counter | - isForLoopWithFloatingPointCounters(for, counter) and for = loop - ) -select loop, "Loop $@ has a floating-point type.", loop.getControllingExpr(), "counter" + loop.getControllingExpr() = comparison and + comparison.getAnOperand() = loopCounter.getAnAccess() and + loopCounter.getType() instanceof FloatingPointType +select loop, "Loop using a $@ of type floating-point.", loopCounter, "loop counter" diff --git a/c/cert/test/rules/FLP30-C/FloatingPointLoopCounters.expected b/c/cert/test/rules/FLP30-C/FloatingPointLoopCounters.expected index 964df7c2b7..43f8a04a66 100644 --- a/c/cert/test/rules/FLP30-C/FloatingPointLoopCounters.expected +++ b/c/cert/test/rules/FLP30-C/FloatingPointLoopCounters.expected @@ -1,2 +1,3 @@ -| test.c:3:3:4:3 | for(...;...;...) ... | Loop $@ has a floating-point type. | test.c:3:18:3:26 | ... < ... | counter | -| test.c:5:3:6:3 | while (...) ... | Loop $@ has a floating-point type. | test.c:5:10:5:17 | ... - ... | counter | +| test.c:3:3:4:3 | for(...;...;...) ... | Loop using a $@ of type floating-point. | test.c:2:9:2:9 | f | loop counter | +| test.c:5:3:7:3 | while (...) ... | Loop using a $@ of type floating-point. | test.c:2:9:2:9 | f | loop counter | +| test.c:9:3:11:22 | do (...) ... | Loop using a $@ of type floating-point. | test.c:2:9:2:9 | f | loop counter | diff --git a/c/cert/test/rules/FLP30-C/test.c b/c/cert/test/rules/FLP30-C/test.c index 9ec460953b..c56519a70e 100644 --- a/c/cert/test/rules/FLP30-C/test.c +++ b/c/cert/test/rules/FLP30-C/test.c @@ -2,14 +2,25 @@ void f1() { float f = 0.0F; for (f = 0.0F; f < 10.0F; f += 0.2F) { // NON_COMPLIANT } - while (f - 0.0F) { // NON_COMPLIANT + while (f < 10.0F) { // NON_COMPLIANT + f = f * 2.0F; } + + do { + f *= 2.0F; + } while (f < 10.0F); // NON_COMPLIANT } void f2() { for (int i = 0; i < 10; i++) { // COMPLIANT } - while (4 - 4) { // COMPLIANT + int j = 0; + while (j < 10) { // COMPLIANT + j = j * 2; } + + do { + j++; + } while (j < 10); // COMPLIANT } From 7fe93961123e543b4110b0656b17e2a93f6cb455 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Tue, 14 Mar 2023 17:11:15 -0700 Subject: [PATCH 46/76] Add `isInvalidLoop` predicate that provides a reason --- cpp/common/src/codingstandards/cpp/Loops.qll | 101 ++++++++++++++----- 1 file changed, 74 insertions(+), 27 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Loops.qll b/cpp/common/src/codingstandards/cpp/Loops.qll index 599b229771..b83a79851e 100644 --- a/cpp/common/src/codingstandards/cpp/Loops.qll +++ b/cpp/common/src/codingstandards/cpp/Loops.qll @@ -37,13 +37,14 @@ predicate isForLoopWithFloatingPointCounters(ForStmt forLoop, Variable v) { * Holds if for loop `forLoop` contains an invalid for loop incrementation. * M6-5-2 */ -predicate isInvalidForLoopIncrementation(ForStmt forLoop, LoopControlVariable v) { - v.getAnAccess() = forLoop.getCondition().getAChild*() and - exists(VariableAccess va | - va = v.getAnAccess() and - va = forLoop.getUpdate().getAChild*() and - not exists(CrementOperation cop | cop.getOperand() = va) and - not exists(Call c | c.getQualifier() = va and c.getTarget() instanceof UserCrementOperator) +predicate isInvalidForLoopIncrementation(ForStmt forLoop, Variable v, VariableAccess modification) { + v = getAnIterationVariable(forLoop) and + modification = v.getAnAccess() and + modification = forLoop.getUpdate().getAChild*() and + modification.isModified() and + not exists(CrementOperation cop | cop.getOperand() = modification) and + not exists(Call c | + c.getQualifier() = modification and c.getTarget() instanceof UserCrementOperator ) and exists(VariableAccess va | va = forLoop.getCondition().getAChild*() and va = v.getAnAccess() | exists(EqualityOperation eop | eop.getAnOperand() = va) @@ -163,26 +164,72 @@ predicate isLoopControlVarModifiedInLoopExpr( predicate isNonBoolLoopControlVar( ForStmt forLoop, LoopControlVariable loopControlVariable, VariableAccess loopControlVariableAccess ) { - // get a loop control variable that is not a loop counter - loopControlVariableAccess = loopControlVariable.getVariableAccessInLoop(forLoop) and - not loopControlVariable = getAnIterationVariable(forLoop) and - loopControlVariableAccess.getEnclosingStmt() = forLoop.getStmt().getAChild*() and - // filter only loop control variables that are modified - ( - loopControlVariableAccess.isModified() or - loopControlVariableAccess.isAddressOfAccess() - ) and - // check if the variable type is anything but bool - not loopControlVariable.getType() instanceof BoolType + exists(Variable loopCounter, ComparisonOperation terminationCheck | + loopCounter = getAnIterationVariable(forLoop) and + forLoop.getCondition() = terminationCheck.getParent*() + | + // get a loop control variable that is not a loop counter + loopControlVariableAccess = loopControlVariable.getVariableAccessInLoop(forLoop) and + not loopControlVariable = getAnIterationVariable(forLoop) and + // filter only loop control variables that are modified + ( + loopControlVariableAccess.isModified() or + loopControlVariableAccess.isAddressOfAccess() + ) and + // check if the variable type is anything but bool + not loopControlVariable.getType() instanceof BoolType and + // check if the control variable is part of the termination check, but is not compared to the loop counter + terminationCheck.getAnOperand() = loopControlVariable.getAnAccess().getParent*() and + not terminationCheck.getAnOperand() = loopCounter.getAnAccess().getParent*() + ) } -predicate isInvalidLoop(ForStmt forLoop) { - isInvalidForLoopIncrementation(forLoop, _) or - isForLoopWithMulipleCounters(forLoop) or - isForLoopWithFloatingPointCounters(forLoop, _) or - isLoopCounterModifiedInCondition(forLoop, _) or - isLoopCounterModifiedInStatement(forLoop, _, _) or - isIrregularLoopCounterModification(forLoop, _, _) or - isLoopControlVarModifiedInLoopExpr(forLoop, _, _) or - isNonBoolLoopControlVar(forLoop, _, _) +predicate isInvalidLoop(ForStmt forLoop) { isInvalidLoop(forLoop, _, _, _) } + +predicate isInvalidLoop(ForStmt forLoop, string reason, Locatable reasonLocation, string reasonLabel) { + exists(Variable loopCounter | + isInvalidForLoopIncrementation(forLoop, loopCounter, reasonLocation) and + reason = + "it $@ its loop counter '" + loopCounter.getName() + + "' with an operation that is not an increment or decrement" and + reasonLabel = "updates" + ) + or + isForLoopWithMulipleCounters(forLoop) and + reason = "it uses multiple loop counters$@" and + reasonLabel = "" and + reasonLocation.getLocation() instanceof UnknownExprLocation + or + isForLoopWithFloatingPointCounters(forLoop, reasonLocation) and + reason = "it uses a loop counter '$@' of type floating-point" and + reasonLabel = reasonLocation.(Variable).getName() + or + isLoopCounterModifiedInCondition(forLoop, reasonLocation) and + reason = + "it $@ the loop counter '" + reasonLocation.(VariableAccess).getTarget().getName() + + "' in the condition" and + reasonLabel = "updates" + or + exists(Variable loopCounter | + isLoopCounterModifiedInStatement(forLoop, loopCounter, reasonLocation) and + reason = "it $@ the loop counter '" + loopCounter.getName() + "' in the body of the loop" and + reasonLabel = "updates" + ) + or + exists(Variable loopCounter | + isIrregularLoopCounterModification(forLoop, loopCounter, reasonLocation) and + reason = "it $@ the loop counter '" + loopCounter.getName() + "' irregularly" and + reasonLabel = "updates" + ) + or + exists(Variable loopControlVariable | + isLoopControlVarModifiedInLoopExpr(forLoop, loopControlVariable, reasonLocation) and + reason = + "it updates $@, a loop control variable other than the loop counter, in the update expression of the loop" and + reasonLabel = loopControlVariable.getName() + ) + or + isNonBoolLoopControlVar(forLoop, reasonLocation, _) and + reason = "its $@ is not a boolean" and + reasonLabel = "loop control variable" } From bac2291aabd3b72b8b6abac659bc7471a430f75b Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Tue, 14 Mar 2023 17:11:50 -0700 Subject: [PATCH 47/76] Add reason to alert message --- .../src/rules/RULE-14-2/ForLoopNotWellFormed.ql | 6 +++--- .../rules/RULE-14-2/ForLoopNotWellFormed.expected | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/c/misra/src/rules/RULE-14-2/ForLoopNotWellFormed.ql b/c/misra/src/rules/RULE-14-2/ForLoopNotWellFormed.ql index a454d90505..106bd9b5c6 100644 --- a/c/misra/src/rules/RULE-14-2/ForLoopNotWellFormed.ql +++ b/c/misra/src/rules/RULE-14-2/ForLoopNotWellFormed.ql @@ -15,8 +15,8 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.Loops -from ForStmt for +from ForStmt for, Element reasonLocation, string reason, string reasonLabel where not isExcluded(for, Statements4Package::forLoopNotWellFormedQuery()) and - isInvalidLoop(for) -select for, "For loop is not well formed." + isInvalidLoop(for, reason, reasonLocation, reasonLabel) +select for, "For loop is not well formed, " + reason + ".", reasonLocation, reasonLabel diff --git a/c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.expected b/c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.expected index c084d2d0ad..fc7fbc7c5f 100644 --- a/c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.expected +++ b/c/misra/test/rules/RULE-14-2/ForLoopNotWellFormed.expected @@ -1,7 +1,7 @@ -| test.c:7:3:8:3 | for(...;...;...) ... | For loop is not well formed. | -| test.c:14:3:15:3 | for(...;...;...) ... | For loop is not well formed. | -| test.c:20:3:21:3 | for(...;...;...) ... | For loop is not well formed. | -| test.c:25:3:26:3 | for(...;...;...) ... | For loop is not well formed. | -| test.c:38:3:39:3 | for(...;...;...) ... | For loop is not well formed. | -| test.c:52:3:53:3 | for(...;...;...) ... | For loop is not well formed. | -| test.c:64:3:67:3 | for(...;...;...) ... | For loop is not well formed. | +| test.c:7:3:8:3 | for(...;...;...) ... | For loop is not well formed, it uses a loop counter '$@' of type floating-point. | test.c:7:14:7:14 | f | f | +| test.c:14:3:15:3 | for(...;...;...) ... | For loop is not well formed, it uses multiple loop counters$@. | file://:0:0:0:0 | | | +| test.c:20:3:21:3 | for(...;...;...) ... | For loop is not well formed, it uses multiple loop counters$@. | file://:0:0:0:0 | | | +| test.c:25:3:26:3 | for(...;...;...) ... | For loop is not well formed, it $@ its loop counter 'i' with an operation that is not an increment or decrement. | test.c:25:28:25:28 | i | updates | +| test.c:38:3:39:3 | for(...;...;...) ... | For loop is not well formed, it $@ the loop counter 'x' irregularly. | test.c:38:26:38:26 | x | updates | +| test.c:52:3:53:3 | for(...;...;...) ... | For loop is not well formed, it updates $@, a loop control variable other than the loop counter, in the update expression of the loop. | test.c:52:28:52:29 | p1 | p1 | +| test.c:64:3:67:3 | for(...;...;...) ... | For loop is not well formed, it $@ the loop counter 'x' in the body of the loop. | test.c:65:5:65:5 | x | updates | From 71eb2445d3f6a98f855f71b3fc14add37e260a9e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 22 Mar 2023 22:30:07 +0000 Subject: [PATCH 48/76] Statements: Implement Rule 15.1 Adds a query to find uses of goto in the program. This was originally marked as compiler implemented, but even though it is true that the compiler can check this case we can still provide a query for it. --- .../src/rules/RULE-15-1/GotoStatementUsed.ql | 21 +++++++++++++++ .../RULE-15-1/GotoStatementUsed.expected | 1 + .../rules/RULE-15-1/GotoStatementUsed.qlref | 1 + c/misra/test/rules/RULE-15-1/test.c | 9 +++++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 +++ .../cpp/exclusions/c/Statements6.qll | 26 +++++++++++++++++++ rule_packages/c/Statements6.json | 24 +++++++++++++++++ rules.csv | 2 +- 8 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 c/misra/src/rules/RULE-15-1/GotoStatementUsed.ql create mode 100644 c/misra/test/rules/RULE-15-1/GotoStatementUsed.expected create mode 100644 c/misra/test/rules/RULE-15-1/GotoStatementUsed.qlref create mode 100644 c/misra/test/rules/RULE-15-1/test.c create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Statements6.qll create mode 100644 rule_packages/c/Statements6.json diff --git a/c/misra/src/rules/RULE-15-1/GotoStatementUsed.ql b/c/misra/src/rules/RULE-15-1/GotoStatementUsed.ql new file mode 100644 index 0000000000..ddc85c305c --- /dev/null +++ b/c/misra/src/rules/RULE-15-1/GotoStatementUsed.ql @@ -0,0 +1,21 @@ +/** + * @id c/misra/goto-statement-used + * @name RULE-15-1: The goto statement should not be used + * @description The goto statement shall not be used. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-15-1 + * correctness + * security + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +from Stmt s +where + not isExcluded(s, Statements6Package::gotoStatementUsedQuery()) and + (s instanceof GotoStmt or s instanceof ComputedGotoStmt) +select s, "Use of goto." diff --git a/c/misra/test/rules/RULE-15-1/GotoStatementUsed.expected b/c/misra/test/rules/RULE-15-1/GotoStatementUsed.expected new file mode 100644 index 0000000000..7e06759159 --- /dev/null +++ b/c/misra/test/rules/RULE-15-1/GotoStatementUsed.expected @@ -0,0 +1 @@ +| test.c:4:3:4:14 | goto ... | Use of goto. | diff --git a/c/misra/test/rules/RULE-15-1/GotoStatementUsed.qlref b/c/misra/test/rules/RULE-15-1/GotoStatementUsed.qlref new file mode 100644 index 0000000000..338455d28f --- /dev/null +++ b/c/misra/test/rules/RULE-15-1/GotoStatementUsed.qlref @@ -0,0 +1 @@ +rules/RULE-15-1/GotoStatementUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-15-1/test.c b/c/misra/test/rules/RULE-15-1/test.c new file mode 100644 index 0000000000..d13f01961c --- /dev/null +++ b/c/misra/test/rules/RULE-15-1/test.c @@ -0,0 +1,9 @@ +void test_goto() { + int x = 1; + + goto label1; // NON_COMPLIANT + +label1: + + x = 2; +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index aef4c1285c..6110876f6e 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -51,6 +51,7 @@ import Statements2 import Statements3 import Statements4 import Statements5 +import Statements6 import Strings1 import Strings2 import Strings3 @@ -107,6 +108,7 @@ newtype TCQuery = TStatements3PackageQuery(Statements3Query q) or TStatements4PackageQuery(Statements4Query q) or TStatements5PackageQuery(Statements5Query q) or + TStatements6PackageQuery(Statements6Query q) or TStrings1PackageQuery(Strings1Query q) or TStrings2PackageQuery(Strings2Query q) or TStrings3PackageQuery(Strings3Query q) or @@ -163,6 +165,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isStatements3QueryMetadata(query, queryId, ruleId, category) or isStatements4QueryMetadata(query, queryId, ruleId, category) or isStatements5QueryMetadata(query, queryId, ruleId, category) or + isStatements6QueryMetadata(query, queryId, ruleId, category) or isStrings1QueryMetadata(query, queryId, ruleId, category) or isStrings2QueryMetadata(query, queryId, ruleId, category) or isStrings3QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Statements6.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements6.qll new file mode 100644 index 0000000000..7261d0980a --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Statements6.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Statements6Query = TGotoStatementUsedQuery() + +predicate isStatements6QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `gotoStatementUsed` query + Statements6Package::gotoStatementUsedQuery() and + queryId = + // `@id` for the `gotoStatementUsed` query + "c/misra/goto-statement-used" and + ruleId = "RULE-15-1" and + category = "advisory" +} + +module Statements6Package { + Query gotoStatementUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `gotoStatementUsed` query + TQueryC(TStatements6PackageQuery(TGotoStatementUsedQuery())) + } +} diff --git a/rule_packages/c/Statements6.json b/rule_packages/c/Statements6.json new file mode 100644 index 0000000000..101987f9c3 --- /dev/null +++ b/rule_packages/c/Statements6.json @@ -0,0 +1,24 @@ +{ + "MISRA-C-2012": { + "RULE-15-1": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "The goto statement shall not be used.", + "kind": "problem", + "name": "The goto statement should not be used", + "precision": "very-high", + "severity": "error", + "short_name": "GotoStatementUsed", + "tags": [ + "correctness", + "security" + ] + } + ], + "title": "The goto statement should not be used" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index e1aa314525..8d6547ec40 100644 --- a/rules.csv +++ b/rules.csv @@ -697,7 +697,7 @@ c,MISRA-C-2012,RULE-14-1,Yes,Required,,,A loop counter shall not have essentiall c,MISRA-C-2012,RULE-14-2,Yes,Required,,,A for loop shall be well-formed,M6-5-1...M6-5-6,Statements4,Medium, c,MISRA-C-2012,RULE-14-3,Yes,Required,,,Controlling expressions shall not be invariant,,Statements5,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,Statements4,Medium, -c,MISRA-C-2012,RULE-15-1,No,Advisory,,,The goto statement should not be used,A6-6-1,,Import, +c,MISRA-C-2012,RULE-15-1,Yes,Advisory,,,The goto statement should not be used,A6-6-1,Statements6,Import, c,MISRA-C-2012,RULE-15-2,Yes,Required,,,The goto statement shall jump to a label declared later in the same function,M6-6-2,Statements2,Import, c,MISRA-C-2012,RULE-15-3,Yes,Required,,,"Any label referenced by a goto statement shall be declared in the same block, or in any block enclosing the goto statement",M6-6-1,Statements2,Import, c,MISRA-C-2012,RULE-15-4,Yes,Advisory,,,There should be no more than one break or goto statement used to terminate any iteration statement,,Statements2,Medium, From 23b36b4567311fbfb603acd5e5d752a03a427115 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 22 Mar 2023 22:35:20 +0000 Subject: [PATCH 49/76] FLP30-C: Fix NON_COMPLIANT tag Loop starts on Line 9. --- c/cert/test/rules/FLP30-C/test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/c/cert/test/rules/FLP30-C/test.c b/c/cert/test/rules/FLP30-C/test.c index c56519a70e..e63dc5d1ed 100644 --- a/c/cert/test/rules/FLP30-C/test.c +++ b/c/cert/test/rules/FLP30-C/test.c @@ -6,9 +6,9 @@ void f1() { f = f * 2.0F; } - do { + do { // NON_COMPLIANT f *= 2.0F; - } while (f < 10.0F); // NON_COMPLIANT + } while (f < 10.0F); } void f2() { From 584d94c14d22efbc10f7fc4cc4183d29d90b0c12 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 22 Mar 2023 23:37:34 +0000 Subject: [PATCH 50/76] Rule 14.2: Recognise loop counters * Identify loop counters that are not initialized in the loop * Identify loop counters that are increment/decremented by += or -= --- c/misra/test/rules/RULE-14-2/test.c | 5 ++ cpp/common/src/codingstandards/cpp/Loops.qll | 85 +++++++++++++++++++- 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/c/misra/test/rules/RULE-14-2/test.c b/c/misra/test/rules/RULE-14-2/test.c index c1ce23dd11..fbeb4be21f 100644 --- a/c/misra/test/rules/RULE-14-2/test.c +++ b/c/misra/test/rules/RULE-14-2/test.c @@ -66,3 +66,8 @@ void f13() { g1--; } } + +void f14() { + for (int i = 0; i < 10; i += 3) { // COMPLIANT + } +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Loops.qll b/cpp/common/src/codingstandards/cpp/Loops.qll index b83a79851e..f2b5f1e539 100644 --- a/cpp/common/src/codingstandards/cpp/Loops.qll +++ b/cpp/common/src/codingstandards/cpp/Loops.qll @@ -5,6 +5,88 @@ import cpp import Operator +// ******* COPIED FROM semmle.code.cpp.Iteration ******* // +/** + * Holds if `child` is in the condition `forCondition` of a 'for' + * statement. + * + * For example, if a program includes + * ``` + * for (i = 0; i < 10; i++) { j++; } + * ``` + * then this predicate will hold with `forCondition` as `i < 10`, + * and `child` as any of `i`, `10` and `i < 10`. + */ +pragma[noopt] +private predicate inForCondition(Expr forCondition, Expr child) { + exists(ForStmt for | + forCondition = for.getCondition() and + child = forCondition and + for instanceof ForStmt + ) + or + exists(Expr mid | + inForCondition(forCondition, mid) and + child.getParent() = mid + ) +} + +// ******* COPIED FROM semmle.code.cpp.Iteration ******* // +/** + * Holds if `child` is in the update `forUpdate` of a 'for' statement. + * + * For example, if a program includes + * ``` + * for (i = 0; i < 10; i += 1) { j++; } + * ``` + * then this predicate will hold with `forUpdate` as `i += 1`, + * and `child` as any of `i`, `1` and `i += 1`. + */ +pragma[noopt] +private predicate inForUpdate(Expr forUpdate, Expr child) { + exists(ForStmt for | forUpdate = for.getUpdate() and child = forUpdate) + or + exists(Expr mid | inForUpdate(forUpdate, mid) and child.getParent() = mid) +} + +/** + * Gets a LoopCounter for the given `ForStmt`. + * + * Equivalent to ForStmt.getAnIterationVariable(), but handles += and -= as well. + */ +pragma[noopt] +Variable getALoopCounter(ForStmt fs) { + // check that it is assigned to, incremented or decremented in the update + exists(Expr updateOpRoot, Expr updateOp | + updateOpRoot = fs.getUpdate() and + inForUpdate(updateOpRoot, updateOp) + | + exists(CrementOperation op, VariableAccess va | + op = updateOp and + op instanceof CrementOperation and + op.getOperand() = va and + va = result.getAnAccess() + ) + or + exists(AssignArithmeticOperation op, VariableAccess va | + op = updateOp and + op instanceof AssignArithmeticOperation and + op.getOperator() = ["+=", "-="] and + op.getLValue() = va and + va = result.getAnAccess() + ) + or + updateOp = result.getAnAssignedValue() + ) and + result instanceof Variable and + // checked or used in the condition + exists(Expr e, VariableAccess va | + va = result.getAnAccess() and + inForCondition(e, va) and + e = fs.getCondition() + ) +} + /** * Gets an iteration variable as identified by the initialization statement for the loop. */ @@ -148,7 +230,8 @@ predicate isLoopControlVarModifiedInLoopExpr( ForStmt forLoop, LoopControlVariable loopControlVariable, VariableAccess loopControlVariableAccess ) { loopControlVariableAccess = loopControlVariable.getVariableAccessInLoop(forLoop) and - not loopControlVariable = getAnIterationVariable(forLoop) and + // Not a standard loop counter for this loop + not loopControlVariable = getALoopCounter(forLoop) and loopControlVariableAccess = forLoop.getUpdate().getAChild() and ( loopControlVariableAccess.isModified() or From 7dab9571b830feb02a3199cc830139ec8dc2e82a Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 22 Mar 2023 23:41:49 +0000 Subject: [PATCH 51/76] Rule 14.3: Correct bracketing Exclusions would otherwise not be correctly applied. --- .../RULE-14-3/ControllingExprInvariant.ql | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql index d372d587a4..04bc02935c 100644 --- a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql +++ b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql @@ -33,24 +33,24 @@ where ) ) and message = "Controlling expression in if statement has invariant value." + or + exists(Loop loop | + loop.getControllingExpr() = expr and + ( + conditionAlwaysFalse(expr) + or + conditionAlwaysTrue(expr) + ) + ) and + message = "Controlling expression in loop statement has invariant value." + or + exists(SwitchStmt switch | + switch.getControllingExpr() = expr and + ( + conditionAlwaysFalse(expr) or + conditionAlwaysTrue(expr) + ) + ) and + message = "Controlling expression in switch statement has invariant value." ) - or - exists(Loop loop | - loop.getControllingExpr() = expr and - ( - conditionAlwaysFalse(expr) - or - conditionAlwaysTrue(expr) - ) - ) and - message = "Controlling expression in loop statement has invariant value." - or - exists(SwitchStmt switch | - switch.getControllingExpr() = expr and - ( - conditionAlwaysFalse(expr) or - conditionAlwaysTrue(expr) - ) - ) and - message = "Controlling expression in switch statement has invariant value." select expr, message From 944f7271e1198d68e3d162b0994349016630c826 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 22 Mar 2023 23:42:53 +0000 Subject: [PATCH 52/76] Rule 14.3: Exclude results in macro expansions Expansions of macros may have expressions which are seemingly invariant, but are different per invocation. We therefore exclude all such results. --- c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql index 04bc02935c..816dfd8037 100644 --- a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql +++ b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql @@ -52,5 +52,7 @@ where ) ) and message = "Controlling expression in switch statement has invariant value." - ) + ) and + // Exclude macros, which may generate seemingly invariant expressions + not expr.isAffectedByMacro() select expr, message From 654700ff7ebda3385dcf7c5e06f9d52d739e220c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 22 Mar 2023 23:49:31 +0000 Subject: [PATCH 53/76] Rule 14.3: Permit infinite loops using literals --- c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql | 7 +++++-- .../rules/RULE-14-3/ControllingExprInvariant.expected | 9 +++++---- c/misra/test/rules/RULE-14-3/test.c | 9 +++++++++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql index 816dfd8037..367bf54905 100644 --- a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql +++ b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql @@ -39,7 +39,9 @@ where ( conditionAlwaysFalse(expr) or - conditionAlwaysTrue(expr) + conditionAlwaysTrue(expr) and + // Exception allows for infinite loops, but we only permit that for literals like `true` + not expr instanceof Literal ) ) and message = "Controlling expression in loop statement has invariant value." @@ -53,6 +55,7 @@ where ) and message = "Controlling expression in switch statement has invariant value." ) and - // Exclude macros, which may generate seemingly invariant expressions + // Exclude cases where the controlling expressions is affected by a macro, because they can appear + // invariant in a particular invocation, but be variant between invocations. not expr.isAffectedByMacro() select expr, message diff --git a/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected b/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected index 7543929f91..8cde7027fc 100644 --- a/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected +++ b/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected @@ -1,4 +1,5 @@ -| test.c:2:7:2:11 | ... > ... | Controlling expression in if statement has invariant value. | -| test.c:13:10:13:16 | ... > ... | Controlling expression in loop statement has invariant value. | -| test.c:14:9:14:13 | ... > ... | Controlling expression in if statement has invariant value. | -| test.c:18:20:18:24 | ... < ... | Controlling expression in loop statement has invariant value. | +| test.c:4:7:4:11 | ... > ... | Controlling expression in if statement has invariant value. | +| test.c:15:10:15:16 | ... > ... | Controlling expression in loop statement has invariant value. | +| test.c:16:9:16:13 | ... > ... | Controlling expression in if statement has invariant value. | +| test.c:20:20:20:24 | ... < ... | Controlling expression in loop statement has invariant value. | +| test.c:27:10:27:14 | ... < ... | Controlling expression in loop statement has invariant value. | diff --git a/c/misra/test/rules/RULE-14-3/test.c b/c/misra/test/rules/RULE-14-3/test.c index 56383beb4e..fa93c1ef4d 100644 --- a/c/misra/test/rules/RULE-14-3/test.c +++ b/c/misra/test/rules/RULE-14-3/test.c @@ -1,3 +1,5 @@ +#include + void f1(int p1) { if (2 > 3) { // NON_COMPLIANT } @@ -18,3 +20,10 @@ void f2() { for (int i = 10; i < 5; i++) { // NON_COMPLIANT } } + +void f3() { + while (true) { // Permitted by exception + } + while (1 < 2) { // NON_COMPLIANT - likely an indication of a bug + } +} \ No newline at end of file From beaf279709ead31563cb3f28b3fbd7be6778aafe Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 22 Mar 2023 23:50:17 +0000 Subject: [PATCH 54/76] Rule 14.3: Remove redundant imports --- c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql | 2 -- 1 file changed, 2 deletions(-) diff --git a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql index 367bf54905..dbea8b1541 100644 --- a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql +++ b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql @@ -15,8 +15,6 @@ import cpp import codingstandards.c.misra -import cpp -import codingstandards.c.misra from ControlFlowNode expr, string message where From 235eeded8f27940999c0828c7c8958536aa864ab Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 22 Mar 2023 23:55:28 +0000 Subject: [PATCH 55/76] Rule 14.3: Handle do..while exception --- c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql | 9 +++++++-- c/misra/test/rules/RULE-14-3/test.c | 7 ++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql index dbea8b1541..54d7b805e7 100644 --- a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql +++ b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql @@ -15,8 +15,9 @@ import cpp import codingstandards.c.misra +import codingstandards.c.misra.EssentialTypes -from ControlFlowNode expr, string message +from Expr expr, string message where not isExcluded(expr, Statements5Package::controllingExprInvariantQuery()) and ( @@ -35,7 +36,11 @@ where exists(Loop loop | loop.getControllingExpr() = expr and ( - conditionAlwaysFalse(expr) + conditionAlwaysFalse(expr) and + not ( + getEssentialTypeCategory(getEssentialType(expr)) instanceof EssentiallyBooleanType and + expr.getValue() = "0" + ) or conditionAlwaysTrue(expr) and // Exception allows for infinite loops, but we only permit that for literals like `true` diff --git a/c/misra/test/rules/RULE-14-3/test.c b/c/misra/test/rules/RULE-14-3/test.c index fa93c1ef4d..b9e4ab1303 100644 --- a/c/misra/test/rules/RULE-14-3/test.c +++ b/c/misra/test/rules/RULE-14-3/test.c @@ -22,8 +22,13 @@ void f2() { } void f3() { - while (true) { // Permitted by exception + while (true) { // COMPLIANT - permitted by exception 1 } while (1 < 2) { // NON_COMPLIANT - likely an indication of a bug } +} + +void f4() { + do { + } while (0u == 1u); // COMPLIANT - by exception 2 } \ No newline at end of file From 743b70772c6185747b6290de17b9493f360a88c0 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 23 Mar 2023 00:11:25 +0000 Subject: [PATCH 56/76] Rule 14.3: Support conditonal expressions --- .../rules/RULE-14-3/ControllingExprInvariant.ql | 17 ++++++++++++++++- .../RULE-14-3/ControllingExprInvariant.expected | 2 ++ c/misra/test/rules/RULE-14-3/test.c | 6 ++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql index 54d7b805e7..2c762b09ad 100644 --- a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql +++ b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql @@ -57,8 +57,23 @@ where ) ) and message = "Controlling expression in switch statement has invariant value." + or + exists(ConditionalExpr conditional | + conditional.getCondition() = expr and + ( + conditionAlwaysFalse(expr) or + conditionAlwaysTrue(expr) + ) + ) and + message = "Controlling expression in conditional statement has invariant value." ) and // Exclude cases where the controlling expressions is affected by a macro, because they can appear // invariant in a particular invocation, but be variant between invocations. - not expr.isAffectedByMacro() + not ( + expr.isAffectedByMacro() and + // Permit boolean literal macros + not expr instanceof BooleanLiteral + ) and + // Exclude template variables, because they can be instantiated with different values. + not expr = any(TemplateVariable tv).getAnInstantiation().getAnAccess() select expr, message diff --git a/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected b/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected index 8cde7027fc..537fc7d4e5 100644 --- a/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected +++ b/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected @@ -3,3 +3,5 @@ | test.c:16:9:16:13 | ... > ... | Controlling expression in if statement has invariant value. | | test.c:20:20:20:24 | ... < ... | Controlling expression in loop statement has invariant value. | | test.c:27:10:27:14 | ... < ... | Controlling expression in loop statement has invariant value. | +| test.c:37:3:37:6 | 1 | Controlling expression in conditional statement has invariant value. | +| test.c:38:3:38:3 | 1 | Controlling expression in conditional statement has invariant value. | diff --git a/c/misra/test/rules/RULE-14-3/test.c b/c/misra/test/rules/RULE-14-3/test.c index b9e4ab1303..38db3e1286 100644 --- a/c/misra/test/rules/RULE-14-3/test.c +++ b/c/misra/test/rules/RULE-14-3/test.c @@ -31,4 +31,10 @@ void f3() { void f4() { do { } while (0u == 1u); // COMPLIANT - by exception 2 +} + +void f5(bool b1) { + true ? 1 : 2; // NON_COMPLIANT + 1 ? 1 : 2; // NON_COMPLIANT + b1 ? 1 : 2; // COMPLIANT } \ No newline at end of file From e462d66a6b83a9e39bedd77270c2b756814c8a2e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 23 Mar 2023 00:27:01 +0000 Subject: [PATCH 57/76] Rule 15.3: Fix message, remove dead code --- .../src/rules/RULE-15-3/GotoLabelBlockCondition.ql | 12 ++---------- .../rules/RULE-15-3/GotoLabelBlockCondition.expected | 6 +++--- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql index 82de7f9a39..aeb356b501 100644 --- a/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql +++ b/c/misra/src/rules/RULE-15-3/GotoLabelBlockCondition.ql @@ -19,14 +19,6 @@ predicate isPartOfSwitch(Stmt goto) { exists(SwitchStmt switch | switch.getStmt() = goto.getParent()) } -Stmt getNextStmt(ControlFlowNode node) { - node.getASuccessor() = result - or - exists(ControlFlowNode other | - node.getASuccessor() = other and other != result and result = getNextStmt(other) - ) -} - SwitchCase getSwitchCase(Stmt stmt) { exists(int index, SwitchStmt switch | getStmtInSwitch(switch, stmt, index) and getStmtInSwitch(switch, result, index - 1) @@ -66,5 +58,5 @@ where isPartOfSwitch(goto) and not getSwitchCase(goto) = getSwitchCase(target) ) ) -select goto, "The $@ statement and its $@ are not declared or enclosed in the same block. test", - goto, "goto", target, "label" +select goto, "The $@ statement and its $@ are not declared or enclosed in the same block.", goto, + "goto", target, "label" diff --git a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected index 7ddb3fe509..9a81d6f434 100644 --- a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected +++ b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected @@ -1,3 +1,3 @@ -| test.c:2:3:2:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. test | test.c:2:3:2:10 | goto ... | goto | test.c:4:3:4:5 | label ...: | label | -| test.c:37:3:37:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. test | test.c:37:3:37:10 | goto ... | goto | test.c:41:3:41:5 | label ...: | label | -| test.c:52:5:52:12 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. test | test.c:52:5:52:12 | goto ... | goto | test.c:55:3:55:5 | label ...: | label | +| test.c:2:3:2:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:2:3:2:10 | goto ... | goto | test.c:4:3:4:5 | label ...: | label | +| test.c:37:3:37:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:37:3:37:10 | goto ... | goto | test.c:41:3:41:5 | label ...: | label | +| test.c:52:5:52:12 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:52:5:52:12 | goto ... | goto | test.c:55:3:55:5 | label ...: | label | From 298db28b7300691bb36e4225e791bf0ae614fbd5 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 23 Mar 2023 15:06:33 +0000 Subject: [PATCH 58/76] Rule 17.2: Address performance/corretness issues Simplify the query to only refer to one function call, which improves performance and addresses a correctness issue when a function calls a recursive function. --- .../rules/RULE-17-2/RecursiveFunctionCondition.ql | 12 +++++------- .../RULE-17-2/RecursiveFunctionCondition.expected | 1 - 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql b/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql index e1f8180aee..cad5a95236 100644 --- a/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql +++ b/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql @@ -14,14 +14,12 @@ import cpp import codingstandards.c.misra -from FunctionCall call, string msg, FunctionCall fc +from FunctionCall fc, Function f, string msg where not isExcluded(fc, Statements3Package::recursiveFunctionConditionQuery()) and - fc.getTarget() = call.getTarget() and - call.getTarget().calls*(call.getEnclosingFunction()) and - if fc.getTarget() = fc.getEnclosingFunction() + fc.getEnclosingFunction() = f and + fc.getTarget().calls*(f) and + if fc.getTarget() = f then msg = "This call directly invokes its containing function $@." - else - msg = - "The function " + fc.getEnclosingFunction() + " is indirectly recursive via this call to $@." + else msg = "The function " + f + " is indirectly recursive via this call to $@." select fc, msg, fc.getTarget(), fc.getTarget().getName() diff --git a/c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.expected b/c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.expected index 5c40b93b1c..39f173fa8d 100644 --- a/c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.expected +++ b/c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.expected @@ -1,4 +1,3 @@ | test.c:8:3:8:4 | call to f3 | This call directly invokes its containing function $@. | test.c:7:6:7:7 | f3 | f3 | -| test.c:11:3:11:4 | call to f3 | The function f6 is indirectly recursive via this call to $@. | test.c:7:6:7:7 | f3 | f3 | | test.c:15:3:15:4 | call to f2 | The function f5 is indirectly recursive via this call to $@. | test.c:17:6:17:7 | f2 | f2 | | test.c:18:3:18:4 | call to f5 | The function f2 is indirectly recursive via this call to $@. | test.c:14:6:14:7 | f5 | f5 | From 1dffd73af749fcb18dac6e1a62234a0ad032d6c9 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 23 Mar 2023 15:10:01 +0000 Subject: [PATCH 59/76] Rule 17.2: Simplify alert message. --- c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql | 4 ++-- .../rules/RULE-17-2/RecursiveFunctionCondition.expected | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql b/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql index cad5a95236..b6f13c4d1f 100644 --- a/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql +++ b/c/misra/src/rules/RULE-17-2/RecursiveFunctionCondition.ql @@ -20,6 +20,6 @@ where fc.getEnclosingFunction() = f and fc.getTarget().calls*(f) and if fc.getTarget() = f - then msg = "This call directly invokes its containing function $@." - else msg = "The function " + f + " is indirectly recursive via this call to $@." + then msg = f + " calls itself directly." + else msg = f + " is indirectly recursive via this call to $@." select fc, msg, fc.getTarget(), fc.getTarget().getName() diff --git a/c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.expected b/c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.expected index 39f173fa8d..06b8b5b762 100644 --- a/c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.expected +++ b/c/misra/test/rules/RULE-17-2/RecursiveFunctionCondition.expected @@ -1,3 +1,3 @@ -| test.c:8:3:8:4 | call to f3 | This call directly invokes its containing function $@. | test.c:7:6:7:7 | f3 | f3 | -| test.c:15:3:15:4 | call to f2 | The function f5 is indirectly recursive via this call to $@. | test.c:17:6:17:7 | f2 | f2 | -| test.c:18:3:18:4 | call to f5 | The function f2 is indirectly recursive via this call to $@. | test.c:14:6:14:7 | f5 | f5 | +| test.c:8:3:8:4 | call to f3 | f3 calls itself directly. | test.c:7:6:7:7 | f3 | f3 | +| test.c:15:3:15:4 | call to f2 | f5 is indirectly recursive via this call to $@. | test.c:17:6:17:7 | f2 | f2 | +| test.c:18:3:18:4 | call to f5 | f2 is indirectly recursive via this call to $@. | test.c:14:6:14:7 | f5 | f5 | From 71f6d17da5c03ae257703323aaf268633b02697e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 23 Mar 2023 17:34:31 +0000 Subject: [PATCH 60/76] Rule 15.5: Exclude functions without user bodies * Fix bracketing * Exclude compiler generated functions and functions without bodies. --- .../src/rules/RULE-15-5/FunctionReturnCondition.ql | 14 +++++++++----- c/misra/test/rules/RULE-15-5/test.c | 4 +++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql b/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql index b26de24322..806ab55ebd 100644 --- a/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql +++ b/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql @@ -18,9 +18,13 @@ import codingstandards.c.misra from Function func, string message where not isExcluded(func, Statements5Package::functionReturnConditionQuery()) and - count(ReturnStmt return | return.getEnclosingFunction() = func) > 1 and - message = "Function has more than on return statement." - or - not func.getBlock().getLastStmt() instanceof ReturnStmt and - message = "The last statement of the function is not a return statement." + func.hasDefinition() and + not func.isCompilerGenerated() and + ( + count(ReturnStmt return | return.getEnclosingFunction() = func) > 1 and + message = "Function has more than on return statement." + or + not func.getBlock().getLastStmt() instanceof ReturnStmt and + message = "The last statement of the function is not a return statement." + ) select func, message diff --git a/c/misra/test/rules/RULE-15-5/test.c b/c/misra/test/rules/RULE-15-5/test.c index 80667338a2..cbe36668f5 100644 --- a/c/misra/test/rules/RULE-15-5/test.c +++ b/c/misra/test/rules/RULE-15-5/test.c @@ -24,4 +24,6 @@ void f4(int p1) { // NON_COMPLIANT } return; p1++; -} \ No newline at end of file +} + +void f5(); // Ignored - no body \ No newline at end of file From aaa1044dc6caf6bb561bc95c0e5127a384ba6c79 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 23 Mar 2023 18:11:36 +0000 Subject: [PATCH 61/76] Rule 15.5: Improvements * Exclude compiler generated return statements * Exclude functions with more than one block * Improve alert message * Only report that the last statement is not a return, if there's at least one return statement in the block. --- .../RULE-15-5/FunctionReturnCondition.ql | 25 ++++++++++++++----- .../FunctionReturnCondition.expected | 9 ++++--- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql b/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql index 806ab55ebd..2fb5ad9d65 100644 --- a/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql +++ b/c/misra/src/rules/RULE-15-5/FunctionReturnCondition.ql @@ -15,16 +15,29 @@ import cpp import codingstandards.c.misra -from Function func, string message +class UserWrittenReturnStmt extends ReturnStmt { + UserWrittenReturnStmt() { not this.isCompilerGenerated() } +} + +from Function func, string message, UserWrittenReturnStmt returnStmt where not isExcluded(func, Statements5Package::functionReturnConditionQuery()) and func.hasDefinition() and + // Ignore functions which have multiple bodies + count(func.getBlock()) = 1 and + // Ignore functions which are compiler generated not func.isCompilerGenerated() and + // Report all the return statements in the function + returnStmt.getEnclosingFunction() = func and ( - count(ReturnStmt return | return.getEnclosingFunction() = func) > 1 and - message = "Function has more than on return statement." + // There is more than one return statement + count(UserWrittenReturnStmt return | return.getEnclosingFunction() = func) > 1 and + message = "Function has more than one $@." or - not func.getBlock().getLastStmt() instanceof ReturnStmt and - message = "The last statement of the function is not a return statement." + // There is exactly one return statement + count(UserWrittenReturnStmt return | return.getEnclosingFunction() = func) = 1 and + // But it is not the last statement in the function + not func.getBlock().getLastStmt() instanceof UserWrittenReturnStmt and + message = "The $@ is not the last statement of the function." ) -select func, message +select func, message, returnStmt, "return statement" diff --git a/c/misra/test/rules/RULE-15-5/FunctionReturnCondition.expected b/c/misra/test/rules/RULE-15-5/FunctionReturnCondition.expected index 48ee45bfdd..dde5d709dd 100644 --- a/c/misra/test/rules/RULE-15-5/FunctionReturnCondition.expected +++ b/c/misra/test/rules/RULE-15-5/FunctionReturnCondition.expected @@ -1,4 +1,5 @@ -| test.c:1:6:1:7 | f1 | Function has more than on return statement. | -| test.c:14:6:14:7 | f3 | The last statement of the function is not a return statement. | -| test.c:21:6:21:7 | f4 | Function has more than on return statement. | -| test.c:21:6:21:7 | f4 | The last statement of the function is not a return statement. | +| test.c:1:6:1:7 | f1 | Function has more than one $@. | test.c:3:5:3:11 | return ... | return statement | +| test.c:1:6:1:7 | f1 | Function has more than one $@. | test.c:5:3:5:9 | return ... | return statement | +| test.c:14:6:14:7 | f3 | The $@ is not the last statement of the function. | test.c:17:3:17:9 | return ... | return statement | +| test.c:21:6:21:7 | f4 | Function has more than one $@. | test.c:23:5:23:11 | return ... | return statement | +| test.c:21:6:21:7 | f4 | Function has more than one $@. | test.c:25:3:25:9 | return ... | return statement | From 501e8dae365615636c577a53a285ac99e3dc84b8 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 23 Mar 2023 22:42:08 +0000 Subject: [PATCH 62/76] Rule 15.4: Improve query * Accurately determine which loops each `break` and `goto` statement breaks out of. - `break` breaks out of the nearest enclosing breakable, which could be a switch. - `goto` depends on the target, and which breakables are shared between both the goto and target. * Add a placeholder location for the break or goto (so that it can be more easily verified). * Include more tests. --- .../rules/RULE-15-4/LoopIterationCondition.ql | 46 +++++++++++++++---- .../RULE-15-4/LoopIterationCondition.expected | 9 +++- c/misra/test/rules/RULE-15-4/test.c | 45 ++++++++++++++++++ 3 files changed, 88 insertions(+), 12 deletions(-) diff --git a/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql b/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql index 9176aea2e1..ed541a68d0 100644 --- a/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql +++ b/c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql @@ -15,15 +15,41 @@ import cpp import codingstandards.c.misra -from Loop loop +/** + * A breaking statement. + */ +class BreakOrGotoStmt extends JumpStmt { + BreakOrGotoStmt() { + this instanceof BreakStmt or + this instanceof GotoStmt + } + + /** + * Gets a loop this breaks out of, if any. + * + * - This can produce no results if this is a `break` and the enclosing breakable is a switch statement. + * - This can produce no result if this is a `goto`, and the target is within the same nearest enclosing loop. + * - This can produce multiple results if this is a `goto`, and the target is outside multiple enclosing loops. + */ + Loop getABrokenLoop() { + result = this.(BreakStmt).getBreakable() + or + exists(GotoStmt goto | + goto = this and + // Find any loop that encloses this goto + result.getChildStmt*() = goto and + // But does not enclose the target of the goto i.e. the goto breaks out of it + not result.getChildStmt*() = goto.getTarget() + ) + } +} + +from Loop loop, BreakOrGotoStmt breakOrGoto where not isExcluded(loop, Statements2Package::loopIterationConditionQuery()) and - count(Stmt terminationStmt | - loop.getChildStmt*() = terminationStmt and - ( - terminationStmt instanceof BreakStmt - or - terminationStmt instanceof GotoStmt - ) - ) > 1 -select loop, "$@ statement contains more than one break or goto statement", loop, "Iteration" + // More than one break or goto statement in the loop + count(BreakOrGotoStmt terminationStmt | terminationStmt.getABrokenLoop() = loop) > 1 and + // Report a break or goto statement + breakOrGoto.getABrokenLoop() = loop +select loop, "Iteration statement contains more than one $@.", breakOrGoto, + "break or goto statement" diff --git a/c/misra/test/rules/RULE-15-4/LoopIterationCondition.expected b/c/misra/test/rules/RULE-15-4/LoopIterationCondition.expected index 6a8d9bf23a..a8dae0f411 100644 --- a/c/misra/test/rules/RULE-15-4/LoopIterationCondition.expected +++ b/c/misra/test/rules/RULE-15-4/LoopIterationCondition.expected @@ -1,2 +1,7 @@ -| test.c:24:3:32:3 | for(...;...;...) ... | $@ statement contains more than one break or goto statement | test.c:24:3:32:3 | for(...;...;...) ... | Iteration | -| test.c:38:3:45:3 | while (...) ... | $@ statement contains more than one break or goto statement | test.c:38:3:45:3 | while (...) ... | Iteration | +| test.c:24:3:32:3 | for(...;...;...) ... | Iteration statement contains more than one $@. | test.c:26:7:26:12 | break; | break or goto statement | +| test.c:24:3:32:3 | for(...;...;...) ... | Iteration statement contains more than one $@. | test.c:29:7:29:12 | break; | break or goto statement | +| test.c:24:3:32:3 | for(...;...;...) ... | Iteration statement contains more than one $@. | test.c:31:5:31:12 | goto ... | break or goto statement | +| test.c:38:3:45:3 | while (...) ... | Iteration statement contains more than one $@. | test.c:40:7:40:12 | break; | break or goto statement | +| test.c:38:3:45:3 | while (...) ... | Iteration statement contains more than one $@. | test.c:43:7:43:14 | goto ... | break or goto statement | +| test.c:61:3:72:3 | while (...) ... | Iteration statement contains more than one $@. | test.c:64:7:64:12 | break; | break or goto statement | +| test.c:61:3:72:3 | while (...) ... | Iteration statement contains more than one $@. | test.c:68:7:68:14 | goto ... | break or goto statement | diff --git a/c/misra/test/rules/RULE-15-4/test.c b/c/misra/test/rules/RULE-15-4/test.c index 382b040c55..6c0693be01 100644 --- a/c/misra/test/rules/RULE-15-4/test.c +++ b/c/misra/test/rules/RULE-15-4/test.c @@ -43,4 +43,49 @@ L1:; goto L1; } } + + while (k < 10) { // COMPLIANT - the nested goto + // only applies to the nested loop + if (k > 5) { + break; + } + while (k < 3) { // COMPLIANT + break; + } + } +} + +void f3(int k) { +L3: + k++; + while (k < 10) { // NON_COMPLIANT - the nested goto + // only applies to the switch + if (k > 5) { + break; + } + switch (k) { + case 1: + goto L3; + case 2: + break; + } + } +} + +void f4(int k) { + k++; + while (k < 10) { // COMPLIANT + if (k > 5) { + break; + } + switch (k) { + case 1: + goto L4; + case 2: + k += 1; + L4: + k += 2; + break; + } + } } From 745d04cf6a6f230dd34e6d3711b95881608b05da Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 23 Mar 2023 23:16:27 +0000 Subject: [PATCH 63/76] Rule 16.7: Use the essential type Relational operations do not have boolean type in C, so we need to use the essential type library to identify them. --- .../rules/RULE-16-7/SwitchExpressionBoolCondition.ql | 11 +++++++---- .../RULE-16-7/SwitchExpressionBoolCondition.expected | 2 ++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql b/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql index 8e579d5914..9aeb50d26e 100644 --- a/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql +++ b/c/misra/src/rules/RULE-16-7/SwitchExpressionBoolCondition.ql @@ -13,8 +13,11 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.SwitchStatement +import codingstandards.c.misra.EssentialTypes -from BooleanSwitchStmt switch -where not isExcluded(switch, Statements2Package::switchExpressionBoolConditionQuery()) -select switch, "The condition of this $@ statement has boolean type", switch, "switch" +from SwitchStmt switch, Expr controllingExpr +where + not isExcluded(switch, Statements2Package::switchExpressionBoolConditionQuery()) and + controllingExpr = switch.getControllingExpr() and + getEssentialTypeCategory(getEssentialType(controllingExpr)) = EssentiallyBooleanType() +select controllingExpr, "The condition of this $@ statement has boolean type", switch, "switch" diff --git a/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected b/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected index e69de29bb2..ac74217dc3 100644 --- a/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected +++ b/c/misra/test/rules/RULE-16-7/SwitchExpressionBoolCondition.expected @@ -0,0 +1,2 @@ +| test.c:16:11:16:17 | ... == ... | The condition of this $@ statement has boolean type | test.c:16:3:24:3 | switch (...) ... | switch | +| test.c:28:11:28:24 | ... == ... | The condition of this $@ statement has boolean type | test.c:28:3:36:3 | switch (...) ... | switch | From 16c0a8c677dc47124aaba995cc6aeeedd9ccd487 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 23 Mar 2023 23:53:32 +0000 Subject: [PATCH 64/76] Rule 14.4: Convert to non-shared queries This rule requires the use of the MISRA only essential types library. This is because in C comparison expressions do not natively have boolean type. --- .../NonBooleanIfStmt.expected | 3 --- .../nonbooleanifstmt/NonBooleanIfStmt.ql | 2 -- .../NonBooleanIterationStmt.expected | 3 --- .../NonBooleanIterationStmt.ql | 2 -- .../rules/RULE-14-4/NonBooleanIfCondition.ql | 17 ++++++++----- .../RULE-14-4/NonBooleanIterationCondition.ql | 24 +++++++++++++++---- .../RULE-14-4/NonBooleanIfCondition.expected | 3 +++ .../RULE-14-4/NonBooleanIfCondition.qlref | 1 + .../RULE-14-4/NonBooleanIfCondition.testref | 1 - .../NonBooleanIterationCondition.expected | 2 ++ .../NonBooleanIterationCondition.qlref | 1 + .../NonBooleanIterationCondition.testref | 1 - .../test/rules/RULE-14-4}/test.c | 8 ++++++- .../test/rules/RULE-14-4/test_iteration.c} | 0 .../nonbooleanifstmt/NonBooleanIfStmt.qll | 2 +- rule_packages/c/Statements4.json | 2 -- 16 files changed, 45 insertions(+), 27 deletions(-) delete mode 100644 c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.expected delete mode 100644 c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql delete mode 100644 c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.expected delete mode 100644 c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql create mode 100644 c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.expected create mode 100644 c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.qlref delete mode 100644 c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.testref create mode 100644 c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.expected create mode 100644 c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.qlref delete mode 100644 c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.testref rename c/{common/test/rules/nonbooleanifstmt => misra/test/rules/RULE-14-4}/test.c (76%) rename c/{common/test/rules/nonbooleaniterationstmt/test.c => misra/test/rules/RULE-14-4/test_iteration.c} (100%) diff --git a/c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.expected b/c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.expected deleted file mode 100644 index 490b14b9bf..0000000000 --- a/c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.expected +++ /dev/null @@ -1,3 +0,0 @@ -| test.c:7:7:7:8 | l1 | If condition has non boolean type int. | -| test.c:9:7:9:8 | call to f1 | If condition has non boolean type int. | -| test.c:12:7:12:8 | l2 | If condition has non boolean type void *. | diff --git a/c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql b/c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql deleted file mode 100644 index da907fcf9e..0000000000 --- a/c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql +++ /dev/null @@ -1,2 +0,0 @@ -// GENERATED FILE - DO NOT MODIFY -import codingstandards.cpp.rules.nonbooleanifstmt.NonBooleanIfStmt diff --git a/c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.expected b/c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.expected deleted file mode 100644 index 3d3aa974dd..0000000000 --- a/c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.expected +++ /dev/null @@ -1,3 +0,0 @@ -| test.c:5:3:6:3 | for(...;...;...) ... | Iteration condition has non boolean type int. | -| test.c:7:3:8:3 | while (...) ... | Iteration condition has non boolean type int. | -| test.c:13:3:14:3 | for(...;...;...) ... | Iteration condition has non boolean type int. | diff --git a/c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql b/c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql deleted file mode 100644 index ffe3f351c6..0000000000 --- a/c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql +++ /dev/null @@ -1,2 +0,0 @@ -// GENERATED FILE - DO NOT MODIFY -import codingstandards.cpp.rules.nonbooleaniterationstmt.NonBooleanIterationStmt diff --git a/c/misra/src/rules/RULE-14-4/NonBooleanIfCondition.ql b/c/misra/src/rules/RULE-14-4/NonBooleanIfCondition.ql index ab5144fbc2..87d9d31512 100644 --- a/c/misra/src/rules/RULE-14-4/NonBooleanIfCondition.ql +++ b/c/misra/src/rules/RULE-14-4/NonBooleanIfCondition.ql @@ -13,10 +13,15 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.rules.nonbooleanifstmt.NonBooleanIfStmt +import codingstandards.c.misra.EssentialTypes -class NonBooleanIfConditionQuery extends NonBooleanIfStmtSharedQuery { - NonBooleanIfConditionQuery() { - this = Statements4Package::nonBooleanIfConditionQuery() - } -} +from Expr condition, Type essentialType +where + not isExcluded(condition, Statements4Package::nonBooleanIfConditionQuery()) and + exists(IfStmt ifStmt | + not ifStmt.isFromUninstantiatedTemplate(_) and + condition = ifStmt.getCondition() and + essentialType = getEssentialType(ifStmt.getCondition()) and + not getEssentialTypeCategory(essentialType) = EssentiallyBooleanType() + ) +select condition, "If condition has non boolean essential type " + essentialType + "." diff --git a/c/misra/src/rules/RULE-14-4/NonBooleanIterationCondition.ql b/c/misra/src/rules/RULE-14-4/NonBooleanIterationCondition.ql index 01482c5e0e..b2644a7a92 100644 --- a/c/misra/src/rules/RULE-14-4/NonBooleanIterationCondition.ql +++ b/c/misra/src/rules/RULE-14-4/NonBooleanIterationCondition.ql @@ -13,10 +13,24 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.rules.nonbooleaniterationstmt.NonBooleanIterationStmt +import codingstandards.c.misra.EssentialTypes -class NonBooleanIterationConditionQuery extends NonBooleanIterationStmtSharedQuery { - NonBooleanIterationConditionQuery() { - this = Statements4Package::nonBooleanIterationConditionQuery() - } +/** A macro within the source location of this project. */ +class UserProvidedMacro extends Macro { + UserProvidedMacro() { exists(this.getFile().getRelativePath()) } } + +/** A macro defined within a library used by this project. */ +class LibraryMacro extends Macro { + LibraryMacro() { not this instanceof UserProvidedMacro } +} + +from Expr condition, Loop l, Type essentialType +where + not isExcluded(condition, Statements4Package::nonBooleanIterationConditionQuery()) and + // Exclude loops generated from library macros + not l = any(LibraryMacro lm).getAnInvocation().getAGeneratedElement() and + condition = l.getCondition() and + essentialType = getEssentialType(condition) and + not getEssentialTypeCategory(essentialType) = EssentiallyBooleanType() +select condition, "Iteration condition has non boolean type " + essentialType + "." diff --git a/c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.expected b/c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.expected new file mode 100644 index 0000000000..c8a7508f2b --- /dev/null +++ b/c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.expected @@ -0,0 +1,3 @@ +| test.c:7:7:7:8 | l1 | If condition has non boolean essential type int. | +| test.c:9:7:9:8 | call to f1 | If condition has non boolean essential type int. | +| test.c:12:7:12:8 | l2 | If condition has non boolean essential type void *. | diff --git a/c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.qlref b/c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.qlref new file mode 100644 index 0000000000..cdfd3b5ea3 --- /dev/null +++ b/c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.qlref @@ -0,0 +1 @@ +rules/RULE-14-4/NonBooleanIfCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.testref b/c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.testref deleted file mode 100644 index e586a8d8ec..0000000000 --- a/c/misra/test/rules/RULE-14-4/NonBooleanIfCondition.testref +++ /dev/null @@ -1 +0,0 @@ -c/common/test/rules/nonbooleanifstmt/NonBooleanIfStmt.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.expected b/c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.expected new file mode 100644 index 0000000000..daf7a4be85 --- /dev/null +++ b/c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.expected @@ -0,0 +1,2 @@ +| test_iteration.c:5:20:5:20 | i | Iteration condition has non boolean type int. | +| test_iteration.c:7:10:7:11 | l1 | Iteration condition has non boolean type int. | diff --git a/c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.qlref b/c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.qlref new file mode 100644 index 0000000000..b7483581b4 --- /dev/null +++ b/c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.qlref @@ -0,0 +1 @@ +rules/RULE-14-4/NonBooleanIterationCondition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.testref b/c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.testref deleted file mode 100644 index 15f5d0713f..0000000000 --- a/c/misra/test/rules/RULE-14-4/NonBooleanIterationCondition.testref +++ /dev/null @@ -1 +0,0 @@ -c/common/test/rules/nonbooleaniterationstmt/NonBooleanIterationStmt.ql \ No newline at end of file diff --git a/c/common/test/rules/nonbooleanifstmt/test.c b/c/misra/test/rules/RULE-14-4/test.c similarity index 76% rename from c/common/test/rules/nonbooleanifstmt/test.c rename to c/misra/test/rules/RULE-14-4/test.c index ca71348a5b..faf7efd83b 100644 --- a/c/common/test/rules/nonbooleanifstmt/test.c +++ b/c/misra/test/rules/RULE-14-4/test.c @@ -1,4 +1,4 @@ -#include "stdbool.h" +#include int f1(); void *f2(); @@ -21,4 +21,10 @@ void f4() { int l2 = 1; if ((const bool)l2) { // COMPLIANT } + + if (l2 < 3) { // COMPLIANT + } + + if (true) { // COMPLIANT + } } \ No newline at end of file diff --git a/c/common/test/rules/nonbooleaniterationstmt/test.c b/c/misra/test/rules/RULE-14-4/test_iteration.c similarity index 100% rename from c/common/test/rules/nonbooleaniterationstmt/test.c rename to c/misra/test/rules/RULE-14-4/test_iteration.c diff --git a/cpp/common/src/codingstandards/cpp/rules/nonbooleanifstmt/NonBooleanIfStmt.qll b/cpp/common/src/codingstandards/cpp/rules/nonbooleanifstmt/NonBooleanIfStmt.qll index f2933f755a..18346a8159 100644 --- a/cpp/common/src/codingstandards/cpp/rules/nonbooleanifstmt/NonBooleanIfStmt.qll +++ b/cpp/common/src/codingstandards/cpp/rules/nonbooleanifstmt/NonBooleanIfStmt.qll @@ -1,5 +1,5 @@ /** - * Provides a library which includes a `problems` predicate for reporting.... + * Provides a library which includes a `problems` predicate for reporting if statements which have non boolean conditions. */ import cpp diff --git a/rule_packages/c/Statements4.json b/rule_packages/c/Statements4.json index e76c984f76..56e13c9de6 100644 --- a/rule_packages/c/Statements4.json +++ b/rule_packages/c/Statements4.json @@ -55,7 +55,6 @@ "precision": "very-high", "severity": "recommendation", "short_name": "NonBooleanIfCondition", - "shared_implementation_short_name": "NonBooleanIfStmt", "tags": [ "maintainability", "readability" @@ -68,7 +67,6 @@ "precision": "very-high", "severity": "recommendation", "short_name": "NonBooleanIterationCondition", - "shared_implementation_short_name": "NonBooleanIterationStmt", "tags": [ "maintainability", "readability" From 3cd69084193544678f03222c23598646d55f7c59 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Fri, 17 Mar 2023 17:43:38 -0700 Subject: [PATCH 65/76] Address incorrect call of isInvalidForLoopIncrementation --- cpp/autosar/src/rules/M6-5-2/NotEqualsInLoopCondition.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/autosar/src/rules/M6-5-2/NotEqualsInLoopCondition.ql b/cpp/autosar/src/rules/M6-5-2/NotEqualsInLoopCondition.ql index 8729c948dd..8d20712021 100644 --- a/cpp/autosar/src/rules/M6-5-2/NotEqualsInLoopCondition.ql +++ b/cpp/autosar/src/rules/M6-5-2/NotEqualsInLoopCondition.ql @@ -19,7 +19,7 @@ import codingstandards.cpp.Loops from ForStmt fs, LoopControlVariable v where not isExcluded(fs, LoopsPackage::notEqualsInLoopConditionQuery()) and - isInvalidForLoopIncrementation(fs, v) + isInvalidForLoopIncrementation(fs, v, _) select fs, "For-loop counter $@ is updated by an increment larger than 1 and tested in the condition using == or !=.", v, v.getName() From 7221dc4d651d32d8595556acf2a0717b76137873 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 24 Mar 2023 00:13:29 +0000 Subject: [PATCH 66/76] Rule 14.3: Improve alert message --- .../rules/RULE-14-3/ControllingExprInvariant.ql | 8 ++++---- .../RULE-14-3/ControllingExprInvariant.expected | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql index 2c762b09ad..eb8e9ede82 100644 --- a/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql +++ b/c/misra/src/rules/RULE-14-3/ControllingExprInvariant.ql @@ -31,7 +31,7 @@ where ) ) ) and - message = "Controlling expression in if statement has invariant value." + message = "Controlling expression in if statement has an invariant value." or exists(Loop loop | loop.getControllingExpr() = expr and @@ -47,7 +47,7 @@ where not expr instanceof Literal ) ) and - message = "Controlling expression in loop statement has invariant value." + message = "Controlling expression in loop statement has an invariant value." or exists(SwitchStmt switch | switch.getControllingExpr() = expr and @@ -56,7 +56,7 @@ where conditionAlwaysTrue(expr) ) ) and - message = "Controlling expression in switch statement has invariant value." + message = "Controlling expression in switch statement has an invariant value." or exists(ConditionalExpr conditional | conditional.getCondition() = expr and @@ -65,7 +65,7 @@ where conditionAlwaysTrue(expr) ) ) and - message = "Controlling expression in conditional statement has invariant value." + message = "Controlling expression in conditional statement has an invariant value." ) and // Exclude cases where the controlling expressions is affected by a macro, because they can appear // invariant in a particular invocation, but be variant between invocations. diff --git a/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected b/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected index 537fc7d4e5..c03c04d6cc 100644 --- a/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected +++ b/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected @@ -1,7 +1,7 @@ -| test.c:4:7:4:11 | ... > ... | Controlling expression in if statement has invariant value. | -| test.c:15:10:15:16 | ... > ... | Controlling expression in loop statement has invariant value. | -| test.c:16:9:16:13 | ... > ... | Controlling expression in if statement has invariant value. | -| test.c:20:20:20:24 | ... < ... | Controlling expression in loop statement has invariant value. | -| test.c:27:10:27:14 | ... < ... | Controlling expression in loop statement has invariant value. | -| test.c:37:3:37:6 | 1 | Controlling expression in conditional statement has invariant value. | -| test.c:38:3:38:3 | 1 | Controlling expression in conditional statement has invariant value. | +| test.c:4:7:4:11 | ... > ... | Controlling expression in if statement has an invariant value. | +| test.c:15:10:15:16 | ... > ... | Controlling expression in loop statement has an invariant value. | +| test.c:16:9:16:13 | ... > ... | Controlling expression in if statement has an invariant value. | +| test.c:20:20:20:24 | ... < ... | Controlling expression in loop statement has an invariant value. | +| test.c:27:10:27:14 | ... < ... | Controlling expression in loop statement has an invariant value. | +| test.c:37:3:37:6 | 1 | Controlling expression in conditional statement has an invariant value. | +| test.c:38:3:38:3 | 1 | Controlling expression in conditional statement has an invariant value. | From 3b548fe54e36fd8469093b3b766bd2a0d8daba88 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 26 Mar 2023 22:08:48 +0100 Subject: [PATCH 67/76] M6-5-2: Expand definition of modification Identify calls to non-const functions as "modifying" the local variable. --- cpp/common/src/codingstandards/cpp/Loops.qll | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/Loops.qll b/cpp/common/src/codingstandards/cpp/Loops.qll index f2b5f1e539..bc156584da 100644 --- a/cpp/common/src/codingstandards/cpp/Loops.qll +++ b/cpp/common/src/codingstandards/cpp/Loops.qll @@ -123,7 +123,19 @@ predicate isInvalidForLoopIncrementation(ForStmt forLoop, Variable v, VariableAc v = getAnIterationVariable(forLoop) and modification = v.getAnAccess() and modification = forLoop.getUpdate().getAChild*() and - modification.isModified() and + // Is modified + ( + // Variable directly modified + modification.isModified() + or + // Has a call to a member function on the variable, where the target is non-const, + // i.e. can modify the state of the object + exists(Call c | + c.getQualifier() = modification and + not c.getTarget() instanceof ConstMemberFunction + ) + ) and + // And not by a call to a crement operator not exists(CrementOperation cop | cop.getOperand() = modification) and not exists(Call c | c.getQualifier() = modification and c.getTarget() instanceof UserCrementOperator From 585ebbb9934e06be3cdb72cdac7b6d0e20d48e5a Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 26 Mar 2023 22:20:48 +0100 Subject: [PATCH 68/76] Rule 15.4: Update test comment --- c/misra/test/rules/RULE-15-4/test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/misra/test/rules/RULE-15-4/test.c b/c/misra/test/rules/RULE-15-4/test.c index 6c0693be01..2d4a0677a7 100644 --- a/c/misra/test/rules/RULE-15-4/test.c +++ b/c/misra/test/rules/RULE-15-4/test.c @@ -59,7 +59,7 @@ void f3(int k) { L3: k++; while (k < 10) { // NON_COMPLIANT - the nested goto - // only applies to the switch + // is an additional exit point for the while loop if (k > 5) { break; } From 74a5d7a3d11f55d786364fcec1189dfb29c423c9 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 26 Mar 2023 22:48:42 +0100 Subject: [PATCH 69/76] Loops: Handle user crement/assignment --- cpp/common/src/codingstandards/cpp/Loops.qll | 29 ++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/cpp/common/src/codingstandards/cpp/Loops.qll b/cpp/common/src/codingstandards/cpp/Loops.qll index bc156584da..82746b036c 100644 --- a/cpp/common/src/codingstandards/cpp/Loops.qll +++ b/cpp/common/src/codingstandards/cpp/Loops.qll @@ -49,6 +49,20 @@ private predicate inForUpdate(Expr forUpdate, Expr child) { exists(Expr mid | inForUpdate(forUpdate, mid) and child.getParent() = mid) } +class MemberCrementOperation extends FunctionCall { + MemberCrementOperation() { this.getTarget() instanceof UserCrementOperator } + + Expr getOperand() { result = this.getQualifier() } +} + +class MemberAssignmentOperation extends FunctionCall { + MemberAssignmentOperation() { this.getTarget() instanceof AssignmentOperator } + + Expr getLValue() { result = this.getQualifier() } + + string getOperator() { result = this.getTarget().getName().regexpCapture("operator(.+)", 1) } +} + /** * Gets a LoopCounter for the given `ForStmt`. * @@ -68,6 +82,21 @@ Variable getALoopCounter(ForStmt fs) { va = result.getAnAccess() ) or + exists(MemberCrementOperation op, VariableAccess va | + op = updateOp and + op instanceof MemberCrementOperation and + op.getOperand() = va and + va = result.getAnAccess() + ) + or + exists(MemberAssignmentOperation op, VariableAccess va | + op = updateOp and + op instanceof MemberAssignmentOperation and + op.getOperator() = ["+=", "-="] and + op.getLValue() = va and + va = result.getAnAccess() + ) + or exists(AssignArithmeticOperation op, VariableAccess va | op = updateOp and op instanceof AssignArithmeticOperation and From 5edcade137fd44627c63f0155592713f1d14dc46 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 26 Mar 2023 22:51:43 +0100 Subject: [PATCH 70/76] SwitchNotWellFormed: Address compiler compat Declarations cannot appear just after case labels. --- .../rules/switchnotwellformed/SwitchNotWellFormed.expected | 6 +++--- c/common/test/rules/switchnotwellformed/test.c | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/c/common/test/rules/switchnotwellformed/SwitchNotWellFormed.expected b/c/common/test/rules/switchnotwellformed/SwitchNotWellFormed.expected index a9062b5fd4..6843b78cd9 100644 --- a/c/common/test/rules/switchnotwellformed/SwitchNotWellFormed.expected +++ b/c/common/test/rules/switchnotwellformed/SwitchNotWellFormed.expected @@ -1,3 +1,3 @@ -| test.c:4:3:10:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.c:4:3:10:3 | switch (...) ... | Switch | test.c:5:3:5:9 | case ...: | case | -| test.c:13:3:20:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.c:13:3:20:3 | switch (...) ... | Switch | test.c:14:3:14:10 | case ...: | case | -| test.c:25:3:30:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.c:25:3:30:3 | switch (...) ... | Switch | test.c:26:3:26:9 | case ...: | case | +| test.c:4:3:11:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.c:4:3:11:3 | switch (...) ... | Switch | test.c:5:3:5:9 | case ...: | case | +| test.c:14:3:21:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.c:14:3:21:3 | switch (...) ... | Switch | test.c:15:3:15:10 | case ...: | case | +| test.c:26:3:31:3 | switch (...) ... | $@ statement not well formed because this $@ block uses a statement that is not allowed. | test.c:26:3:31:3 | switch (...) ... | Switch | test.c:27:3:27:9 | case ...: | case | diff --git a/c/common/test/rules/switchnotwellformed/test.c b/c/common/test/rules/switchnotwellformed/test.c index d1fe00d5af..1082ee405c 100644 --- a/c/common/test/rules/switchnotwellformed/test.c +++ b/c/common/test/rules/switchnotwellformed/test.c @@ -3,6 +3,7 @@ void f1(); void f2(int p1) { switch (p1) { case 1: + f1(); int y = p1; // NON_COMPLIANT - `DeclStmt` whose parent // statement is the switch body f1(); From d6ac6dfdd32ad114d0f3b1a337f6718963033439 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 26 Mar 2023 22:54:53 +0100 Subject: [PATCH 71/76] Rule 15.3: Address compiler compatibility issues Labels must be before a statement. --- c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected | 4 ++-- c/misra/test/rules/RULE-15-3/test.c | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected index 9a81d6f434..730403cbd7 100644 --- a/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected +++ b/c/misra/test/rules/RULE-15-3/GotoLabelBlockCondition.expected @@ -1,3 +1,3 @@ | test.c:2:3:2:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:2:3:2:10 | goto ... | goto | test.c:4:3:4:5 | label ...: | label | -| test.c:37:3:37:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:37:3:37:10 | goto ... | goto | test.c:41:3:41:5 | label ...: | label | -| test.c:52:5:52:12 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:52:5:52:12 | goto ... | goto | test.c:55:3:55:5 | label ...: | label | +| test.c:40:3:40:10 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:40:3:40:10 | goto ... | goto | test.c:44:3:44:5 | label ...: | label | +| test.c:55:5:55:12 | goto ... | The $@ statement and its $@ are not declared or enclosed in the same block. | test.c:55:5:55:12 | goto ... | goto | test.c:58:3:58:5 | label ...: | label | diff --git a/c/misra/test/rules/RULE-15-3/test.c b/c/misra/test/rules/RULE-15-3/test.c index 82b149b326..739affcfc1 100644 --- a/c/misra/test/rules/RULE-15-3/test.c +++ b/c/misra/test/rules/RULE-15-3/test.c @@ -2,6 +2,7 @@ void f1() { goto L1; for (int i = 0; i < 100; i++) { L1: // NON_COMPLIANT + break; } } @@ -13,6 +14,7 @@ void f2() { } } L2: // COMPLIANT + return; } void f3() { @@ -21,6 +23,7 @@ void f3() { for (int j = 0; j < 10; j++) { goto L3; L3: // COMPLIANT + break; } } } From dec57edc6c6a02cc09b80f11fb0e5e13f898c6bb Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 26 Mar 2023 23:00:37 +0100 Subject: [PATCH 72/76] Statements: Improve var naming and alert message. --- change_notes/2023-03-26-nested-switch-case.md | 1 + .../nestedlabelinswitch/NestedLabelInSwitch.qll | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) create mode 100644 change_notes/2023-03-26-nested-switch-case.md diff --git a/change_notes/2023-03-26-nested-switch-case.md b/change_notes/2023-03-26-nested-switch-case.md new file mode 100644 index 0000000000..0265f46954 --- /dev/null +++ b/change_notes/2023-03-26-nested-switch-case.md @@ -0,0 +1 @@ + * `M6-4-4` - alert message updated for clarity. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll b/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll index a1f06734d0..d6e75d6faf 100644 --- a/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll +++ b/cpp/common/src/codingstandards/cpp/rules/nestedlabelinswitch/NestedLabelInSwitch.qll @@ -11,15 +11,15 @@ abstract class NestedLabelInSwitchSharedQuery extends Query { } Query getQuery() { result instanceof NestedLabelInSwitchSharedQuery } query predicate problems( - SwitchCase nestedCase, string message, SwitchCase case, string caseLabel, SwitchStmt switch, + SwitchCase case, string message, SwitchCase caseLocation, string caseLabel, SwitchStmt switch, string switchLabel ) { - not isExcluded(nestedCase, getQuery()) and - switch.getASwitchCase() = case and - not nestedCase.getParentStmt() = switch.getChildStmt() and - nestedCase = case and + not isExcluded(case, getQuery()) and + switch.getASwitchCase() = caseLocation and + not case.getParentStmt() = switch.getChildStmt() and + case = caseLocation and message = - "The switch $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement." and - caseLabel = nestedCase.toString() and + "The case $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement." and + caseLabel = case.toString() and switchLabel = switch.toString() } From 575f42e8bda27b72527c303c70c507971469a753 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 26 Mar 2023 23:05:44 +0100 Subject: [PATCH 73/76] Rule 16.4: Simplify query --- .../src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql b/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql index c857690e84..a90bcc52dc 100644 --- a/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql +++ b/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql @@ -23,9 +23,7 @@ where exists(SwitchCase case, BreakStmt break | switch.getDefaultCase() = case and case.getFollowingStmt() = break and - not exists(Comment comment | - break.getLocation().getEndLine() - 1 = comment.getLocation().getEndLine() - ) and + not exists(Comment comment | comment.getCommentedElement() = break) and message = "has default label that does not terminate in a statement or comment before break statement" ) From 250e06fc834f577e84a31072e99ee8305c9122ee Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 26 Mar 2023 23:20:39 +0100 Subject: [PATCH 74/76] Rule 16.4: Consider nested blocks. --- .../EverySwitchShallHaveDefaultLabel.ql | 16 +++++++++++++++- .../EverySwitchShallHaveDefaultLabel.expected | 1 + c/misra/test/rules/RULE-16-4/test.c | 9 +++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql b/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql index a90bcc52dc..bf199a84e1 100644 --- a/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql +++ b/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql @@ -14,6 +14,20 @@ import cpp import codingstandards.c.misra +Stmt getFirstNonBlockStatement(BlockStmt bs) { + exists(Stmt nextStmt | nextStmt = bs.getStmt(0) | + if nextStmt instanceof BlockStmt + then result = getFirstNonBlockStatement(nextStmt) + else result = nextStmt + ) +} + +Stmt getFirstStatement(DefaultCase case) { + exists(Stmt next | next = case.getFollowingStmt() | + if next instanceof BlockStmt then result = getFirstNonBlockStatement(next) else result = next + ) +} + from SwitchStmt switch, string message where not isExcluded(switch, Statements1Package::everySwitchShallHaveDefaultLabelQuery()) and @@ -22,7 +36,7 @@ where or exists(SwitchCase case, BreakStmt break | switch.getDefaultCase() = case and - case.getFollowingStmt() = break and + getFirstStatement(case) = break and not exists(Comment comment | comment.getCommentedElement() = break) and message = "has default label that does not terminate in a statement or comment before break statement" diff --git a/c/misra/test/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.expected b/c/misra/test/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.expected index 008b1513e8..6ecfe62c3e 100644 --- a/c/misra/test/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.expected +++ b/c/misra/test/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.expected @@ -1,2 +1,3 @@ | test.c:4:3:12:3 | switch (...) ... | $@ statement has missing default clause. | test.c:4:3:12:3 | switch (...) ... | Switch | | test.c:13:3:22:3 | switch (...) ... | $@ statement has default label that does not terminate in a statement or comment before break statement | test.c:13:3:22:3 | switch (...) ... | Switch | +| test.c:53:3:60:3 | switch (...) ... | $@ statement has default label that does not terminate in a statement or comment before break statement | test.c:53:3:60:3 | switch (...) ... | Switch | diff --git a/c/misra/test/rules/RULE-16-4/test.c b/c/misra/test/rules/RULE-16-4/test.c index 7c2f2b210d..45fa298fc6 100644 --- a/c/misra/test/rules/RULE-16-4/test.c +++ b/c/misra/test/rules/RULE-16-4/test.c @@ -49,4 +49,13 @@ void f1(int p1) { i++; break; } + + switch (p1) { // NON_COMPLIANT + case 1: + i++; + break; + default: { + break; + } + } } From d8b3facece1f51f5e3bb89783010ea489cf426c3 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 26 Mar 2023 23:22:49 +0100 Subject: [PATCH 75/76] Statements: Improve metadata. --- .../rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql | 6 ++++-- .../src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql | 2 +- rule_packages/c/Statements1.json | 8 ++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql b/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql index bf199a84e1..a5d7c3cf2c 100644 --- a/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql +++ b/c/misra/src/rules/RULE-16-4/EverySwitchShallHaveDefaultLabel.ql @@ -1,10 +1,12 @@ /** * @id c/misra/every-switch-shall-have-default-label * @name RULE-16-4: Every switch statement shall have a default label - * @description The requirement for a default label is defensive programming. + * @description A default label that has no statements or a comment explaining why this is correct + * indicates a missing implementation that may result in unexpected behavior when the + * default case is executed. * @kind problem * @precision very-high - * @problem.severity error + * @problem.severity warning * @tags external/misra/id/rule-16-4 * maintainability * readability diff --git a/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql b/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql index 22565b708e..f86e242ee3 100644 --- a/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql +++ b/c/misra/src/rules/RULE-16-5/DefaultNotFirstOrLastOfSwitch.ql @@ -1,7 +1,7 @@ /** * @id c/misra/default-not-first-or-last-of-switch * @name RULE-16-5: A default label shall appear as either the first or the last switch label or a switch statement - * @description Locating the default label is easy when it the first of last label. + * @description Locating the default label is easier when it is the first or last label. * @kind problem * @precision very-high * @problem.severity recommendation diff --git a/rule_packages/c/Statements1.json b/rule_packages/c/Statements1.json index 903172ae51..a8dc1b55ea 100644 --- a/rule_packages/c/Statements1.json +++ b/rule_packages/c/Statements1.json @@ -47,11 +47,11 @@ }, "queries": [ { - "description": "The requirement for a default label is defensive programming.", + "description": "A default label that has no statements or a comment explaining why this is correct indicates a missing implementation that may result in unexpected behavior when the default case is executed.", "kind": "problem", "name": "Every switch statement shall have a default label", "precision": "very-high", - "severity": "error", + "severity": "warning", "short_name": "EverySwitchShallHaveDefaultLabel", "tags": [ "maintainability", @@ -67,7 +67,7 @@ }, "queries": [ { - "description": "Locating the default label is easy when it the first of last label.", + "description": "Locating the default label is easier when it is the first or last label.", "kind": "problem", "name": "A default label shall appear as either the first or the last switch label or a switch statement", "precision": "very-high", @@ -79,4 +79,4 @@ "title": "A default label shall appear as either the first or the last switch label of a switch statement" } } -} +} \ No newline at end of file From d5750b094eb59686171ff81d8557626b3feef246 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 27 Mar 2023 00:50:14 +0100 Subject: [PATCH 76/76] NestedLabelInSwitch: Update expected after alert msg change --- .../rules/nestedlabelinswitch/NestedLabelInSwitch.expected | 6 +++--- .../rules/nestedlabelinswitch/NestedLabelInSwitch.expected | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/c/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected b/c/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected index dfc375e567..3adeecc903 100644 --- a/c/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected +++ b/c/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected @@ -1,3 +1,3 @@ -| test.c:9:5:9:11 | case ...: | The switch $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.c:9:5:9:11 | case ...: | case ...: | test.c:6:3:17:3 | switch (...) ... | switch (...) ... | -| test.c:36:5:36:11 | case ...: | The switch $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.c:36:5:36:11 | case ...: | case ...: | test.c:23:3:43:3 | switch (...) ... | switch (...) ... | -| test.c:76:5:76:11 | case ...: | The switch $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.c:76:5:76:11 | case ...: | case ...: | test.c:73:3:79:3 | switch (...) ... | switch (...) ... | +| test.c:9:5:9:11 | case ...: | The case $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.c:9:5:9:11 | case ...: | case ...: | test.c:6:3:17:3 | switch (...) ... | switch (...) ... | +| test.c:36:5:36:11 | case ...: | The case $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.c:36:5:36:11 | case ...: | case ...: | test.c:23:3:43:3 | switch (...) ... | switch (...) ... | +| test.c:76:5:76:11 | case ...: | The case $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.c:76:5:76:11 | case ...: | case ...: | test.c:73:3:79:3 | switch (...) ... | switch (...) ... | diff --git a/cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected b/cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected index 79c75b75e3..58a238dbc4 100644 --- a/cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected +++ b/cpp/common/test/rules/nestedlabelinswitch/NestedLabelInSwitch.expected @@ -1,3 +1,3 @@ -| test.cpp:9:5:9:11 | case ...: | The switch $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.cpp:9:5:9:11 | case ...: | case ...: | test.cpp:6:3:17:3 | switch (...) ... | switch (...) ... | -| test.cpp:36:5:36:11 | case ...: | The switch $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.cpp:36:5:36:11 | case ...: | case ...: | test.cpp:23:3:43:3 | switch (...) ... | switch (...) ... | -| test.cpp:76:5:76:11 | case ...: | The switch $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.cpp:76:5:76:11 | case ...: | case ...: | test.cpp:73:3:79:3 | switch (...) ... | switch (...) ... | +| test.cpp:9:5:9:11 | case ...: | The case $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.cpp:9:5:9:11 | case ...: | case ...: | test.cpp:6:3:17:3 | switch (...) ... | switch (...) ... | +| test.cpp:36:5:36:11 | case ...: | The case $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.cpp:36:5:36:11 | case ...: | case ...: | test.cpp:23:3:43:3 | switch (...) ... | switch (...) ... | +| test.cpp:76:5:76:11 | case ...: | The case $@ does not appear at the outermost level of the compound statement forming the body of the $@ statement. | test.cpp:76:5:76:11 | case ...: | case ...: | test.cpp:73:3:79:3 | switch (...) ... | switch (...) ... |