From 104bdc7535c8c983cbde5832ab55a093e59c6def Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 24 Sep 2024 13:04:17 -0700 Subject: [PATCH 01/10] Implement Misra-c Noreturn rule package. Covers rules 17-9 through 17-11, regarding the use of the _Noreturn attribute. --- .../NonVoidReturnTypeOfNoreturnFunction.ql | 23 ++++++ ...onWithNoReturningBranchShouldBeNoreturn.ql | 24 ++++++ .../ReturnStatementInNoreturnFunction.ql | 24 ++++++ ...nVoidReturnTypeOfNoreturnFunction.expected | 1 + .../NonVoidReturnTypeOfNoreturnFunction.qlref | 1 + c/misra/test/rules/RULE-17-10/test.c | 24 ++++++ ...NoReturningBranchShouldBeNoreturn.expected | 4 + ...ithNoReturningBranchShouldBeNoreturn.qlref | 1 + c/misra/test/rules/RULE-17-11/test.c | 80 +++++++++++++++++++ ...ReturnStatementInNoreturnFunction.expected | 2 + .../ReturnStatementInNoreturnFunction.qlref | 1 + c/misra/test/rules/RULE-17-9/test.c | 45 +++++++++++ .../cpp/exclusions/c/NoReturn.qll | 61 ++++++++++++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + rule_packages/c/NoReturn.json | 55 +++++++++++++ 15 files changed, 349 insertions(+) create mode 100644 c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql create mode 100644 c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql create mode 100644 c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql create mode 100644 c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.expected create mode 100644 c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.qlref create mode 100644 c/misra/test/rules/RULE-17-10/test.c create mode 100644 c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected create mode 100644 c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.qlref create mode 100644 c/misra/test/rules/RULE-17-11/test.c create mode 100644 c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.expected create mode 100644 c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.qlref create mode 100644 c/misra/test/rules/RULE-17-9/test.c create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/NoReturn.qll create mode 100644 rule_packages/c/NoReturn.json diff --git a/c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql b/c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql new file mode 100644 index 0000000000..162403f579 --- /dev/null +++ b/c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/non-void-return-type-of-noreturn-function + * @name RULE-17-10: A function declared with _noreturn shall have a return type of void + * @description Function declared with _noreturn will by definition not return a value, and should + * be declared to return void. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-17-10 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from Function f, Type returnType +where + not isExcluded(f, NoReturnPackage::nonVoidReturnTypeOfNoreturnFunctionQuery()) and + f.getASpecifier().getName() = "noreturn" and + returnType = f.getType() and + not returnType instanceof VoidType +select + f, "The function " + f.getName() + " is declared _noreturn but has a return type of " + returnType.toString() + "." diff --git a/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql b/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql new file mode 100644 index 0000000000..a711658fcc --- /dev/null +++ b/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/function-with-no-returning-branch-should-be-noreturn + * @name RULE-17-11: A function without a branch that returns shall be declared with _Noreturn + * @description Functions which cannot return should be declared with _Noreturn. + * @kind problem + * @precision high + * @problem.severity recommendation + * @tags external/misra/id/rule-17-11 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +from Function f +where + not isExcluded(f, NoReturnPackage::returnStatementInNoreturnFunctionQuery()) and + not f.getASpecifier().getName() = "noreturn" and + not exists(ReturnStmt s | + f = s.getEnclosingFunction() and + s.getBasicBlock().isReachable() + ) +select + f, "The function " + f.getName() + " cannot return and should be declared attribute _Noreturn." diff --git a/c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql b/c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql new file mode 100644 index 0000000000..0c291c20af --- /dev/null +++ b/c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/return-statement-in-noreturn-function + * @name RULE-17-9: Verify that a function declared with _Noreturn does not return + * @description Returning inside a function declared with _Noreturn is undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-17-9 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra + +from Function f +where + not isExcluded(f, NoReturnPackage::returnStatementInNoreturnFunctionQuery()) and + f.getASpecifier().getName() = "noreturn" and + exists(ReturnStmt s | + f = s.getEnclosingFunction() and + s.getBasicBlock().isReachable() + ) +select + f, "The function " + f.getName() + " declared with attribute _Noreturn returns a value." diff --git a/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.expected b/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.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-17-10/NonVoidReturnTypeOfNoreturnFunction.qlref b/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.qlref new file mode 100644 index 0000000000..6726b6957a --- /dev/null +++ b/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.qlref @@ -0,0 +1 @@ +rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-10/test.c b/c/misra/test/rules/RULE-17-10/test.c new file mode 100644 index 0000000000..5e3aadf165 --- /dev/null +++ b/c/misra/test/rules/RULE-17-10/test.c @@ -0,0 +1,24 @@ +#include "stdlib.h" + +void f1(); // COMPLIANT +int f2(); // COMPLIANT +_Noreturn void f3(); // COMPLIANT +_Noreturn int f4(); // NON-COMPLIANT + +void f5() { // COMPLIANT +} + +int f6() { // COMPLIANT + return 0; +} + +_Noreturn void f7() { // COMPLIANT + abort(); +} + +_Noreturn int f8() { // NON-COMPLIANT + abort(); + return 0; +} + +_Noreturn void* f9(); // NON-COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected b/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected new file mode 100644 index 0000000000..5141f0c9c3 --- /dev/null +++ b/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected @@ -0,0 +1,4 @@ +| test.c:7:6:7:21 | test_noreturn_f2 | The function test_noreturn_f2 cannot return and should be declared attribute _Noreturn. | +| test.c:19:6:19:21 | test_noreturn_f4 | The function test_noreturn_f4 cannot return and should be declared attribute _Noreturn. | +| test.c:48:6:48:21 | test_noreturn_f8 | The function test_noreturn_f8 cannot return and should be declared attribute _Noreturn. | +| test.c:64:6:64:22 | test_noreturn_f10 | The function test_noreturn_f10 cannot return and should be declared attribute _Noreturn. | diff --git a/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.qlref b/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.qlref new file mode 100644 index 0000000000..feb6f40804 --- /dev/null +++ b/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.qlref @@ -0,0 +1 @@ +rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-11/test.c b/c/misra/test/rules/RULE-17-11/test.c new file mode 100644 index 0000000000..3d0144d6f0 --- /dev/null +++ b/c/misra/test/rules/RULE-17-11/test.c @@ -0,0 +1,80 @@ +#include "stdlib.h" + +_Noreturn void test_noreturn_f1(int i) { // COMPLIANT + abort(); +} + +void test_noreturn_f2(int i) { // NON_COMPLIANT + abort(); +} + + +_Noreturn void test_noreturn_f3(int i) { // COMPLIANT + if (i > 0) { + abort(); + } + exit(1); +} + +void test_noreturn_f4(int i) { // NON_COMPLIANT + if (i > 0) { + abort(); + } + exit(1); +} + +void test_noreturn_f5(int i) { // COMPLIANT + if (i > 0) { + return; + } + exit(1); +} + +void test_noreturn_f6(int i) { // COMPLIANT + if (i > 0) { + abort(); + } + if (i < 0) { + abort(); + } +} + +void test_noreturn_f7(int i) { // COMPLIANT + if (i > 0) { + abort(); + } +} + +void test_noreturn_f8(int i) { // NON_COMPLIANT + if (i > 0) { + abort(); + } else { + abort(); + } +} + +_Noreturn void test_noreturn_f9(int i) { // COMPLIANT + if (i > 0) { + abort(); + } else { + abort(); + } +} + +void test_noreturn_f10(int i) { // NON_COMPLIANT + if (i > 0) { + abort(); + } + while (1) { + i = 5; + } +} + +_Noreturn void test_noreturn_f11(int i) { // COMPLIANT + if (i > 0) { + abort(); + } + while (1) { + i = 5; + } +} diff --git a/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.expected b/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.expected new file mode 100644 index 0000000000..1e6a6ab180 --- /dev/null +++ b/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.expected @@ -0,0 +1,2 @@ +| test.c:7:16:7:31 | test_noreturn_f2 | The function test_noreturn_f2 declared with attribute _Noreturn returns a value. | +| test.c:32:16:32:31 | test_noreturn_f5 | The function test_noreturn_f5 declared with attribute _Noreturn returns a value. | diff --git a/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.qlref b/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.qlref new file mode 100644 index 0000000000..eaa647d8a4 --- /dev/null +++ b/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.qlref @@ -0,0 +1 @@ +rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-9/test.c b/c/misra/test/rules/RULE-17-9/test.c new file mode 100644 index 0000000000..c3ff575672 --- /dev/null +++ b/c/misra/test/rules/RULE-17-9/test.c @@ -0,0 +1,45 @@ +#include "stdlib.h" + +_Noreturn void test_noreturn_f1(int i) { // COMPLIANT + abort(); +} + +_Noreturn void test_noreturn_f2(int i) { // NON_COMPLIANT + if (i > 0) { + abort(); + } + if (i < 0) { + abort(); + } +} + +_Noreturn void test_noreturn_f3(int i) { // COMPLIANT + if (i > 0) { + abort(); + } + exit(1); +} + +void test_noreturn_f4(int i) { // COMPLIANT + if (i > 0) { + abort(); + } + if (i < 0) { + abort(); + } +} + +_Noreturn void test_noreturn_f5(int i) { // NON_COMPLIANT + if (i > 0) { + abort(); + } +} + +_Noreturn void test_noreturn_f6(int i) { // COMPLIANT + if (i > 0) { + abort(); + } + while (1) { + i = 5; + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/NoReturn.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/NoReturn.qll new file mode 100644 index 0000000000..07b9360213 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/NoReturn.qll @@ -0,0 +1,61 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype NoReturnQuery = + TNonVoidReturnTypeOfNoreturnFunctionQuery() or + TFunctionWithNoReturningBranchShouldBeNoreturnQuery() or + TReturnStatementInNoreturnFunctionQuery() + +predicate isNoReturnQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `nonVoidReturnTypeOfNoreturnFunction` query + NoReturnPackage::nonVoidReturnTypeOfNoreturnFunctionQuery() and + queryId = + // `@id` for the `nonVoidReturnTypeOfNoreturnFunction` query + "c/misra/non-void-return-type-of-noreturn-function" and + ruleId = "RULE-17-10" and + category = "required" + or + query = + // `Query` instance for the `functionWithNoReturningBranchShouldBeNoreturn` query + NoReturnPackage::functionWithNoReturningBranchShouldBeNoreturnQuery() and + queryId = + // `@id` for the `functionWithNoReturningBranchShouldBeNoreturn` query + "c/misra/function-with-no-returning-branch-should-be-noreturn" and + ruleId = "RULE-17-11" and + category = "advisory" + or + query = + // `Query` instance for the `returnStatementInNoreturnFunction` query + NoReturnPackage::returnStatementInNoreturnFunctionQuery() and + queryId = + // `@id` for the `returnStatementInNoreturnFunction` query + "c/misra/return-statement-in-noreturn-function" and + ruleId = "RULE-17-9" and + category = "mandatory" +} + +module NoReturnPackage { + Query nonVoidReturnTypeOfNoreturnFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonVoidReturnTypeOfNoreturnFunction` query + TQueryC(TNoReturnPackageQuery(TNonVoidReturnTypeOfNoreturnFunctionQuery())) + } + + Query functionWithNoReturningBranchShouldBeNoreturnQuery() { + //autogenerate `Query` type + result = + // `Query` type for `functionWithNoReturningBranchShouldBeNoreturn` query + TQueryC(TNoReturnPackageQuery(TFunctionWithNoReturningBranchShouldBeNoreturnQuery())) + } + + Query returnStatementInNoreturnFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `returnStatementInNoreturnFunction` query + TQueryC(TNoReturnPackageQuery(TReturnStatementInNoreturnFunctionQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index c2771f4171..b3ed02f204 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -42,6 +42,7 @@ import Memory1 import Memory2 import Memory3 import Misc +import NoReturn import OutOfBounds import Pointers1 import Pointers2 @@ -113,6 +114,7 @@ newtype TCQuery = TMemory2PackageQuery(Memory2Query q) or TMemory3PackageQuery(Memory3Query q) or TMiscPackageQuery(MiscQuery q) or + TNoReturnPackageQuery(NoReturnQuery q) or TOutOfBoundsPackageQuery(OutOfBoundsQuery q) or TPointers1PackageQuery(Pointers1Query q) or TPointers2PackageQuery(Pointers2Query q) or @@ -184,6 +186,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isMemory2QueryMetadata(query, queryId, ruleId, category) or isMemory3QueryMetadata(query, queryId, ruleId, category) or isMiscQueryMetadata(query, queryId, ruleId, category) or + isNoReturnQueryMetadata(query, queryId, ruleId, category) or isOutOfBoundsQueryMetadata(query, queryId, ruleId, category) or isPointers1QueryMetadata(query, queryId, ruleId, category) or isPointers2QueryMetadata(query, queryId, ruleId, category) or diff --git a/rule_packages/c/NoReturn.json b/rule_packages/c/NoReturn.json new file mode 100644 index 0000000000..1cb4d02ab4 --- /dev/null +++ b/rule_packages/c/NoReturn.json @@ -0,0 +1,55 @@ +{ + "MISRA-C-2012": { + "RULE-17-10": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Function declared with _noreturn will by definition not return a value, and should be declared to return void.", + "kind": "problem", + "name": "A function declared with _noreturn shall have a return type of void", + "precision": "very-high", + "severity": "recommendation", + "short_name": "NonVoidReturnTypeOfNoreturnFunction", + "tags": [] + } + ], + "title": "A function declared with _noreturn shall have a return type of void" + }, + "RULE-17-11": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Functions which cannot return should be declared with _Noreturn.", + "kind": "problem", + "name": "A function without a branch that returns shall be declared with _Noreturn", + "precision": "high", + "severity": "recommendation", + "short_name": "FunctionWithNoReturningBranchShouldBeNoreturn", + "tags": [] + } + ], + "title": "A function without a branch that returns shall be declared with _Noreturn" + }, + "RULE-17-9": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Returning inside a function declared with _Noreturn is undefined behavior.", + "kind": "problem", + "name": "Verify that a function declared with _Noreturn does not return", + "precision": "very-high", + "severity": "error", + "short_name": "ReturnStatementInNoreturnFunction", + "tags": [] + } + ], + "title": "Verify that a function declared with _Noreturn does not return" + } + } +} \ No newline at end of file From 778db73655fbbaebbcec2ec0a18958c1ae566e28 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 24 Sep 2024 13:43:47 -0700 Subject: [PATCH 02/10] Fix false positives by supporting __attribute__((noreturn)), format. Use shared qll to avoid duplicating logic of detecting noreturn across both specifiers and attributes, and to detect a possible returning stmt. --- c/common/src/codingstandards/c/Noreturn.qll | 22 +++++++++++++++++++ .../NonVoidReturnTypeOfNoreturnFunction.ql | 9 ++++---- ...onWithNoReturningBranchShouldBeNoreturn.ql | 14 ++++++------ .../ReturnStatementInNoreturnFunction.ql | 12 ++++------ ...nVoidReturnTypeOfNoreturnFunction.expected | 5 ++++- c/misra/test/rules/RULE-17-10/test.c | 10 +++++---- ...NoReturningBranchShouldBeNoreturn.expected | 6 ++--- c/misra/test/rules/RULE-17-11/test.c | 13 ++++++++++- ...ReturnStatementInNoreturnFunction.expected | 1 + c/misra/test/rules/RULE-17-9/test.c | 10 +++++++++ 10 files changed, 74 insertions(+), 28 deletions(-) create mode 100644 c/common/src/codingstandards/c/Noreturn.qll diff --git a/c/common/src/codingstandards/c/Noreturn.qll b/c/common/src/codingstandards/c/Noreturn.qll new file mode 100644 index 0000000000..eabe86b56e --- /dev/null +++ b/c/common/src/codingstandards/c/Noreturn.qll @@ -0,0 +1,22 @@ +import cpp + +/** + * A function marked with _Noreturn or __attribute((noreturn)) + */ +class NoreturnFunction extends Function { + NoreturnFunction() { + this.getASpecifier().getName() = "noreturn" or + this.getAnAttribute().getName() = "noreturn" + } +} + +/** + * A function that may complete normally, and/or contains an explicit reachable + * return statement. + */ +predicate mayReturn(Function function) { + exists(ReturnStmt s | + function = s.getEnclosingFunction() and + s.getBasicBlock().isReachable() + ) +} diff --git a/c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql b/c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql index 162403f579..3e6f2340fd 100644 --- a/c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql +++ b/c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql @@ -12,12 +12,13 @@ import cpp import codingstandards.c.misra +import codingstandards.c.Noreturn -from Function f, Type returnType +from NoreturnFunction f, Type returnType where not isExcluded(f, NoReturnPackage::nonVoidReturnTypeOfNoreturnFunctionQuery()) and - f.getASpecifier().getName() = "noreturn" and returnType = f.getType() and not returnType instanceof VoidType -select - f, "The function " + f.getName() + " is declared _noreturn but has a return type of " + returnType.toString() + "." +select f, + "The function " + f.getName() + " is declared _noreturn but has a return type of " + + returnType.toString() + "." diff --git a/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql b/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql index a711658fcc..c5d342c015 100644 --- a/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql +++ b/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql @@ -11,14 +11,14 @@ import cpp import codingstandards.c.misra +import codingstandards.c.Noreturn from Function f where not isExcluded(f, NoReturnPackage::returnStatementInNoreturnFunctionQuery()) and - not f.getASpecifier().getName() = "noreturn" and - not exists(ReturnStmt s | - f = s.getEnclosingFunction() and - s.getBasicBlock().isReachable() - ) -select - f, "The function " + f.getName() + " cannot return and should be declared attribute _Noreturn." + not f instanceof NoreturnFunction and + not mayReturn(f) and + f.hasDefinition() and + f.getName() != "main" // Allowed exception; _Noreturn main() is undefined behavior. +select f, + "The function " + f.getName() + " cannot return and should be declared attribute _Noreturn." diff --git a/c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql b/c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql index 0c291c20af..7c23cf306f 100644 --- a/c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql +++ b/c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql @@ -11,14 +11,10 @@ import cpp import codingstandards.c.misra +import codingstandards.c.Noreturn -from Function f +from NoreturnFunction f where not isExcluded(f, NoReturnPackage::returnStatementInNoreturnFunctionQuery()) and - f.getASpecifier().getName() = "noreturn" and - exists(ReturnStmt s | - f = s.getEnclosingFunction() and - s.getBasicBlock().isReachable() - ) -select - f, "The function " + f.getName() + " declared with attribute _Noreturn returns a value." + mayReturn(f) +select f, "The function " + f.getName() + " declared with attribute _Noreturn returns a value." diff --git a/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.expected b/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.expected index 2ec1a0ac6c..a94e37baa4 100644 --- a/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.expected +++ b/c/misra/test/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.expected @@ -1 +1,4 @@ -No expected results have yet been specified \ No newline at end of file +| test.c:6:15:6:16 | f4 | The function f4 is declared _noreturn but has a return type of int. | +| test.c:19:15:19:16 | f8 | The function f8 is declared _noreturn but has a return type of int. | +| test.c:24:17:24:18 | f9 | The function f9 is declared _noreturn but has a return type of void *. | +| test.c:26:31:26:33 | f10 | The function f10 is declared _noreturn but has a return type of int. | diff --git a/c/misra/test/rules/RULE-17-10/test.c b/c/misra/test/rules/RULE-17-10/test.c index 5e3aadf165..b5fc988af2 100644 --- a/c/misra/test/rules/RULE-17-10/test.c +++ b/c/misra/test/rules/RULE-17-10/test.c @@ -1,9 +1,9 @@ #include "stdlib.h" -void f1(); // COMPLIANT -int f2(); // COMPLIANT +void f1(); // COMPLIANT +int f2(); // COMPLIANT _Noreturn void f3(); // COMPLIANT -_Noreturn int f4(); // NON-COMPLIANT +_Noreturn int f4(); // NON-COMPLIANT void f5() { // COMPLIANT } @@ -21,4 +21,6 @@ _Noreturn int f8() { // NON-COMPLIANT return 0; } -_Noreturn void* f9(); // NON-COMPLIANT \ No newline at end of file +_Noreturn void *f9(); // NON-COMPLIANT + +__attribute__((noreturn)) int f10(); // NON-COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected b/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected index 5141f0c9c3..15389bfcdd 100644 --- a/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected +++ b/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected @@ -1,4 +1,4 @@ | test.c:7:6:7:21 | test_noreturn_f2 | The function test_noreturn_f2 cannot return and should be declared attribute _Noreturn. | -| test.c:19:6:19:21 | test_noreturn_f4 | The function test_noreturn_f4 cannot return and should be declared attribute _Noreturn. | -| test.c:48:6:48:21 | test_noreturn_f8 | The function test_noreturn_f8 cannot return and should be declared attribute _Noreturn. | -| test.c:64:6:64:22 | test_noreturn_f10 | The function test_noreturn_f10 cannot return and should be declared attribute _Noreturn. | +| test.c:18:6:18:21 | test_noreturn_f4 | The function test_noreturn_f4 cannot return and should be declared attribute _Noreturn. | +| test.c:47:6:47:21 | test_noreturn_f8 | The function test_noreturn_f8 cannot return and should be declared attribute _Noreturn. | +| test.c:63:6:63:22 | test_noreturn_f10 | The function test_noreturn_f10 cannot return and should be declared attribute _Noreturn. | diff --git a/c/misra/test/rules/RULE-17-11/test.c b/c/misra/test/rules/RULE-17-11/test.c index 3d0144d6f0..1ecc2b1c44 100644 --- a/c/misra/test/rules/RULE-17-11/test.c +++ b/c/misra/test/rules/RULE-17-11/test.c @@ -8,7 +8,6 @@ void test_noreturn_f2(int i) { // NON_COMPLIANT abort(); } - _Noreturn void test_noreturn_f3(int i) { // COMPLIANT if (i > 0) { abort(); @@ -78,3 +77,15 @@ _Noreturn void test_noreturn_f11(int i) { // COMPLIANT i = 5; } } + +void test_noreturn_f12(); // COMPLIANT + +__attribute__((noreturn)) void test_noreturn_f13(int i) { // COMPLIANT + abort(); +} + +// Allowed by exception. It is undefined behavior for main() to be declared with +// noreturn. +int main(char **argv, int argc) { // COMPLIANT + abort(); +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.expected b/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.expected index 1e6a6ab180..9775f797de 100644 --- a/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.expected +++ b/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.expected @@ -1,2 +1,3 @@ | test.c:7:16:7:31 | test_noreturn_f2 | The function test_noreturn_f2 declared with attribute _Noreturn returns a value. | | test.c:32:16:32:31 | test_noreturn_f5 | The function test_noreturn_f5 declared with attribute _Noreturn returns a value. | +| test.c:47:32:47:47 | test_noreturn_f7 | The function test_noreturn_f7 declared with attribute _Noreturn returns a value. | diff --git a/c/misra/test/rules/RULE-17-9/test.c b/c/misra/test/rules/RULE-17-9/test.c index c3ff575672..05ff410562 100644 --- a/c/misra/test/rules/RULE-17-9/test.c +++ b/c/misra/test/rules/RULE-17-9/test.c @@ -43,3 +43,13 @@ _Noreturn void test_noreturn_f6(int i) { // COMPLIANT i = 5; } } + +__attribute__((noreturn)) void test_noreturn_f7(int i) { // NON_COMPLIANT + if (i > 0) { + abort(); + } +} + +__attribute__((noreturn)) void test_noreturn_f8(int i) { // COMPLIANT + abort(); +} \ No newline at end of file From c8e50910bb1c292dbb395078aec2aef2f7f078b3 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 27 Sep 2024 13:29:11 -0700 Subject: [PATCH 03/10] Address feedback --- ...unctionNoReturnAttributeCondition.expected | 3 ++ .../FunctionNoReturnAttributeCondition.ql | 4 +++ .../test.c | 28 +++++++++++++++++++ .../NonVoidReturnTypeOfNoreturnFunction.ql | 6 ++-- ...onWithNoReturningBranchShouldBeNoreturn.ql | 6 ++-- .../ReturnStatementInNoreturnFunction.ql | 13 +++++---- ...NoReturningBranchShouldBeNoreturn.expected | 2 ++ c/misra/test/rules/RULE-17-11/test.c | 13 +++++++++ ...ReturnStatementInNoreturnFunction.expected | 3 -- .../ReturnStatementInNoreturnFunction.testref | 1 + .../src/codingstandards/cpp}/Noreturn.qll | 0 .../FunctionNoReturnAttributeCondition.qll | 23 ++++++++++----- rule_packages/c/NoReturn.json | 7 +++-- 13 files changed, 86 insertions(+), 23 deletions(-) create mode 100644 c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.expected create mode 100644 c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.ql rename c/{misra/test/rules/RULE-17-9 => common/test/rules/functionnoreturnattributecondition}/test.c (61%) delete mode 100644 c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.expected create mode 100644 c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.testref rename {c/common/src/codingstandards/c => cpp/common/src/codingstandards/cpp}/Noreturn.qll (100%) diff --git a/c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.expected b/c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.expected new file mode 100644 index 0000000000..5aede0a5ba --- /dev/null +++ b/c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.expected @@ -0,0 +1,3 @@ +| test.c:9:16:9:31 | test_noreturn_f2 | The function test_noreturn_f2 declared with attribute _Noreturn returns a value. | +| test.c:34:16:34:31 | test_noreturn_f5 | The function test_noreturn_f5 declared with attribute _Noreturn returns a value. | +| test.c:49:32:49:47 | test_noreturn_f7 | The function test_noreturn_f7 declared with attribute _Noreturn returns a value. | diff --git a/c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.ql b/c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.ql new file mode 100644 index 0000000000..4af4aeceaf --- /dev/null +++ b/c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.functionnoreturnattributecondition.FunctionNoReturnAttributeCondition + +class TestFileQuery extends FunctionNoReturnAttributeConditionSharedQuery, TestQuery { } diff --git a/c/misra/test/rules/RULE-17-9/test.c b/c/common/test/rules/functionnoreturnattributecondition/test.c similarity index 61% rename from c/misra/test/rules/RULE-17-9/test.c rename to c/common/test/rules/functionnoreturnattributecondition/test.c index 05ff410562..8299c0cc89 100644 --- a/c/misra/test/rules/RULE-17-9/test.c +++ b/c/common/test/rules/functionnoreturnattributecondition/test.c @@ -1,4 +1,6 @@ #include "stdlib.h" +#include "threads.h" +#include "setjmp.h" _Noreturn void test_noreturn_f1(int i) { // COMPLIANT abort(); @@ -52,4 +54,30 @@ __attribute__((noreturn)) void test_noreturn_f7(int i) { // NON_COMPLIANT __attribute__((noreturn)) void test_noreturn_f8(int i) { // COMPLIANT abort(); +} + +_Noreturn void test_noreturn_f9(int i) { // COMPLIANT + test_noreturn_f1(i); +} + +_Noreturn void test_noreturn_f10(int i) { // COMPLIANT + switch(i) { + case 0: + abort(); break; + case 1: + exit(0); break; + case 2: + _Exit(0); break; + case 3: + quick_exit(0); break; + case 4: + thrd_exit(0); break; + default: + jmp_buf jb; + longjmp(jb, 0); + } +} + +_Noreturn void test_noreturn_f11(int i) { // COMPLIANT + return test_noreturn_f11(i); } \ No newline at end of file diff --git a/c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql b/c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql index 3e6f2340fd..68c5faeb1b 100644 --- a/c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql +++ b/c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql @@ -7,18 +7,20 @@ * @precision very-high * @problem.severity recommendation * @tags external/misra/id/rule-17-10 + * correctness * external/misra/obligation/required */ import cpp import codingstandards.c.misra -import codingstandards.c.Noreturn +import codingstandards.cpp.Noreturn from NoreturnFunction f, Type returnType where not isExcluded(f, NoReturnPackage::nonVoidReturnTypeOfNoreturnFunctionQuery()) and returnType = f.getType() and - not returnType instanceof VoidType + not returnType instanceof VoidType and + not f.isCompilerGenerated() select f, "The function " + f.getName() + " is declared _noreturn but has a return type of " + returnType.toString() + "." diff --git a/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql b/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql index c5d342c015..5563822f9c 100644 --- a/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql +++ b/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql @@ -6,12 +6,13 @@ * @precision high * @problem.severity recommendation * @tags external/misra/id/rule-17-11 + * correctness * external/misra/obligation/advisory */ import cpp import codingstandards.c.misra -import codingstandards.c.Noreturn +import codingstandards.cpp.Noreturn from Function f where @@ -19,6 +20,7 @@ where not f instanceof NoreturnFunction and not mayReturn(f) and f.hasDefinition() and - f.getName() != "main" // Allowed exception; _Noreturn main() is undefined behavior. + not f.getName() = "main" and // Allowed exception; _Noreturn main() is undefined behavior. + not f.isCompilerGenerated() select f, "The function " + f.getName() + " cannot return and should be declared attribute _Noreturn." diff --git a/c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql b/c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql index 7c23cf306f..360be01b7c 100644 --- a/c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql +++ b/c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql @@ -6,15 +6,16 @@ * @precision very-high * @problem.severity error * @tags external/misra/id/rule-17-9 + * correctness * external/misra/obligation/mandatory */ import cpp import codingstandards.c.misra -import codingstandards.c.Noreturn +import codingstandards.cpp.rules.functionnoreturnattributecondition.FunctionNoReturnAttributeCondition -from NoreturnFunction f -where - not isExcluded(f, NoReturnPackage::returnStatementInNoreturnFunctionQuery()) and - mayReturn(f) -select f, "The function " + f.getName() + " declared with attribute _Noreturn returns a value." +class ReturnStatementInNoreturnFunctionQuery extends FunctionNoReturnAttributeConditionSharedQuery { + ReturnStatementInNoreturnFunctionQuery() { + this = NoReturnPackage::returnStatementInNoreturnFunctionQuery() + } +} diff --git a/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected b/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected index 15389bfcdd..fe275e9497 100644 --- a/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected +++ b/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected @@ -2,3 +2,5 @@ | test.c:18:6:18:21 | test_noreturn_f4 | The function test_noreturn_f4 cannot return and should be declared attribute _Noreturn. | | test.c:47:6:47:21 | test_noreturn_f8 | The function test_noreturn_f8 cannot return and should be declared attribute _Noreturn. | | test.c:63:6:63:22 | test_noreturn_f10 | The function test_noreturn_f10 cannot return and should be declared attribute _Noreturn. | +| test.c:97:6:97:22 | test_noreturn_f15 | The function test_noreturn_f15 cannot return and should be declared attribute _Noreturn. | +| test.c:101:6:101:22 | test_noreturn_f16 | The function test_noreturn_f16 cannot return and should be declared attribute _Noreturn. | diff --git a/c/misra/test/rules/RULE-17-11/test.c b/c/misra/test/rules/RULE-17-11/test.c index 1ecc2b1c44..7baaea5821 100644 --- a/c/misra/test/rules/RULE-17-11/test.c +++ b/c/misra/test/rules/RULE-17-11/test.c @@ -88,4 +88,17 @@ __attribute__((noreturn)) void test_noreturn_f13(int i) { // COMPLIANT // noreturn. int main(char **argv, int argc) { // COMPLIANT abort(); +} + +_Noreturn void test_noreturn_f14(int i) { // COMPLIANT + test_noreturn_f1(i); +} + +void test_noreturn_f15(int i) { // NON_COMPLIANT + test_noreturn_f1(i); +} + +void test_noreturn_f16(int i) { // NON_COMPLIANT + // Infinite tail recursion + test_noreturn_f16(i); } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.expected b/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.expected deleted file mode 100644 index 9775f797de..0000000000 --- a/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.expected +++ /dev/null @@ -1,3 +0,0 @@ -| test.c:7:16:7:31 | test_noreturn_f2 | The function test_noreturn_f2 declared with attribute _Noreturn returns a value. | -| test.c:32:16:32:31 | test_noreturn_f5 | The function test_noreturn_f5 declared with attribute _Noreturn returns a value. | -| test.c:47:32:47:47 | test_noreturn_f7 | The function test_noreturn_f7 declared with attribute _Noreturn returns a value. | diff --git a/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.testref b/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.testref new file mode 100644 index 0000000000..09a6d90538 --- /dev/null +++ b/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.testref @@ -0,0 +1 @@ +c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.ql \ No newline at end of file diff --git a/c/common/src/codingstandards/c/Noreturn.qll b/cpp/common/src/codingstandards/cpp/Noreturn.qll similarity index 100% rename from c/common/src/codingstandards/c/Noreturn.qll rename to cpp/common/src/codingstandards/cpp/Noreturn.qll diff --git a/cpp/common/src/codingstandards/cpp/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.qll b/cpp/common/src/codingstandards/cpp/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.qll index 2b910612cb..e2c210282b 100644 --- a/cpp/common/src/codingstandards/cpp/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.qll +++ b/cpp/common/src/codingstandards/cpp/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.qll @@ -5,20 +5,29 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions +import codingstandards.cpp.Noreturn abstract class FunctionNoReturnAttributeConditionSharedQuery extends Query { } Query getQuery() { result instanceof FunctionNoReturnAttributeConditionSharedQuery } +/** + * `noreturn` functions are declared differently in c/c++. Attempt to match + * the description to the file; low risk if it chooses incorrectly. + */ +string describeNoreturn(Function f) { + if f.getFile().getExtension() = ["c", "C", "h", "H"] + then result = "_Noreturn" + else result = "[[noreturn]]" +} + /** * This checks that the return statement is reachable from the function entry point */ -query predicate problems(Function f, string message) { +query predicate problems(NoreturnFunction f, string message) { not isExcluded(f, getQuery()) and - f.getAnAttribute().getName() = "noreturn" and - exists(ReturnStmt s | - f = s.getEnclosingFunction() and - s.getBasicBlock().isReachable() - ) and - message = "The function " + f.getName() + " declared with attribute [[noreturn]] returns a value." + mayReturn(f) and + not f.isCompilerGenerated() and + message = + "The function " + f.getName() + " declared with attribute " + describeNoreturn(f) + " returns a value." } diff --git a/rule_packages/c/NoReturn.json b/rule_packages/c/NoReturn.json index 1cb4d02ab4..d06068f376 100644 --- a/rule_packages/c/NoReturn.json +++ b/rule_packages/c/NoReturn.json @@ -12,7 +12,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "NonVoidReturnTypeOfNoreturnFunction", - "tags": [] + "tags": ["correctness"] } ], "title": "A function declared with _noreturn shall have a return type of void" @@ -29,7 +29,7 @@ "precision": "high", "severity": "recommendation", "short_name": "FunctionWithNoReturningBranchShouldBeNoreturn", - "tags": [] + "tags": ["correctness"] } ], "title": "A function without a branch that returns shall be declared with _Noreturn" @@ -46,7 +46,8 @@ "precision": "very-high", "severity": "error", "short_name": "ReturnStatementInNoreturnFunction", - "tags": [] + "tags": ["correctness"], + "shared_implementation_short_name": "FunctionNoReturnAttributeCondition" } ], "title": "Verify that a function declared with _Noreturn does not return" From 8991e5f98183d015d02e64b8d47f1748d70b7250 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 27 Sep 2024 13:35:39 -0700 Subject: [PATCH 04/10] Fix format --- .../functionnoreturnattributecondition/test.c | 35 +++++++++++-------- .../FunctionNoReturnAttributeCondition.qll | 3 +- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/c/common/test/rules/functionnoreturnattributecondition/test.c b/c/common/test/rules/functionnoreturnattributecondition/test.c index 8299c0cc89..1b0ba759e1 100644 --- a/c/common/test/rules/functionnoreturnattributecondition/test.c +++ b/c/common/test/rules/functionnoreturnattributecondition/test.c @@ -1,6 +1,6 @@ +#include "setjmp.h" #include "stdlib.h" #include "threads.h" -#include "setjmp.h" _Noreturn void test_noreturn_f1(int i) { // COMPLIANT abort(); @@ -61,20 +61,25 @@ _Noreturn void test_noreturn_f9(int i) { // COMPLIANT } _Noreturn void test_noreturn_f10(int i) { // COMPLIANT - switch(i) { - case 0: - abort(); break; - case 1: - exit(0); break; - case 2: - _Exit(0); break; - case 3: - quick_exit(0); break; - case 4: - thrd_exit(0); break; - default: - jmp_buf jb; - longjmp(jb, 0); + switch (i) { + case 0: + abort(); + break; + case 1: + exit(0); + break; + case 2: + _Exit(0); + break; + case 3: + quick_exit(0); + break; + case 4: + thrd_exit(0); + break; + default: + jmp_buf jb; + longjmp(jb, 0); } } diff --git a/cpp/common/src/codingstandards/cpp/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.qll b/cpp/common/src/codingstandards/cpp/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.qll index e2c210282b..bb54a31df6 100644 --- a/cpp/common/src/codingstandards/cpp/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.qll +++ b/cpp/common/src/codingstandards/cpp/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.qll @@ -29,5 +29,6 @@ query predicate problems(NoreturnFunction f, string message) { mayReturn(f) and not f.isCompilerGenerated() and message = - "The function " + f.getName() + " declared with attribute " + describeNoreturn(f) + " returns a value." + "The function " + f.getName() + " declared with attribute " + describeNoreturn(f) + + " returns a value." } From b297513482e44fc24126b2c87250ace8fdc49338 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 27 Sep 2024 14:31:29 -0700 Subject: [PATCH 05/10] Fix tests --- .../test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.qlref | 1 - 1 file changed, 1 deletion(-) delete mode 100644 c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.qlref diff --git a/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.qlref b/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.qlref deleted file mode 100644 index eaa647d8a4..0000000000 --- a/c/misra/test/rules/RULE-17-9/ReturnStatementInNoreturnFunction.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql \ No newline at end of file From 6f860fcd49ccb88756ecc39c9c81d62093458aeb Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 30 Sep 2024 07:51:17 -0700 Subject: [PATCH 06/10] Add changelog; tweaks based on MRVA results. --- .../FunctionWithNoReturningBranchShouldBeNoreturn.ql | 7 +++++-- change_notes/2024-09-28-improved-noreturn-rules.md | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 change_notes/2024-09-28-improved-noreturn-rules.md diff --git a/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql b/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql index 5563822f9c..7383746d05 100644 --- a/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql +++ b/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql @@ -16,11 +16,14 @@ import codingstandards.cpp.Noreturn from Function f where - not isExcluded(f, NoReturnPackage::returnStatementInNoreturnFunctionQuery()) and + not isExcluded(f, NoReturnPackage::functionWithNoReturningBranchShouldBeNoreturnQuery()) and not f instanceof NoreturnFunction and not mayReturn(f) and f.hasDefinition() and not f.getName() = "main" and // Allowed exception; _Noreturn main() is undefined behavior. + // Harden against c++ cases. + not f.isFromUninstantiatedTemplate(_) and + not f.isDeleted() and not f.isCompilerGenerated() select f, - "The function " + f.getName() + " cannot return and should be declared attribute _Noreturn." + "The function " + f.getName() + " cannot return and should be declared as _Noreturn." diff --git a/change_notes/2024-09-28-improved-noreturn-rules.md b/change_notes/2024-09-28-improved-noreturn-rules.md new file mode 100644 index 0000000000..99fb4a0f46 --- /dev/null +++ b/change_notes/2024-09-28-improved-noreturn-rules.md @@ -0,0 +1,3 @@ + - `A7-6-1`, `MSC53-CPP`, `RULE-9-6-4` - `FunctionNoReturnAttbrituteCondition.qll` + - Analysis expanded from functions with "noreturn" attribute, now includes the "noreturn" specifier as well to handle new c rules. No difference in C++ results expected. + - Exclude compiler generated functions from being reported. \ No newline at end of file From 3356b5e0163cd51f1bf71cf8a235170c8d1563bf Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 30 Sep 2024 07:56:50 -0700 Subject: [PATCH 07/10] Fix format --- .../FunctionWithNoReturningBranchShouldBeNoreturn.ql | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql b/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql index 7383746d05..9769acdb7f 100644 --- a/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql +++ b/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql @@ -25,5 +25,4 @@ where not f.isFromUninstantiatedTemplate(_) and not f.isDeleted() and not f.isCompilerGenerated() -select f, - "The function " + f.getName() + " cannot return and should be declared as _Noreturn." +select f, "The function " + f.getName() + " cannot return and should be declared as _Noreturn." From 8ffbb1e41add56e47394e45abbaaefb65140aeea Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 30 Sep 2024 08:44:22 -0700 Subject: [PATCH 08/10] Update test expected message --- ...ionWithNoReturningBranchShouldBeNoreturn.expected | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected b/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected index fe275e9497..ecb77a477c 100644 --- a/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected +++ b/c/misra/test/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.expected @@ -1,6 +1,6 @@ -| test.c:7:6:7:21 | test_noreturn_f2 | The function test_noreturn_f2 cannot return and should be declared attribute _Noreturn. | -| test.c:18:6:18:21 | test_noreturn_f4 | The function test_noreturn_f4 cannot return and should be declared attribute _Noreturn. | -| test.c:47:6:47:21 | test_noreturn_f8 | The function test_noreturn_f8 cannot return and should be declared attribute _Noreturn. | -| test.c:63:6:63:22 | test_noreturn_f10 | The function test_noreturn_f10 cannot return and should be declared attribute _Noreturn. | -| test.c:97:6:97:22 | test_noreturn_f15 | The function test_noreturn_f15 cannot return and should be declared attribute _Noreturn. | -| test.c:101:6:101:22 | test_noreturn_f16 | The function test_noreturn_f16 cannot return and should be declared attribute _Noreturn. | +| test.c:7:6:7:21 | test_noreturn_f2 | The function test_noreturn_f2 cannot return and should be declared as _Noreturn. | +| test.c:18:6:18:21 | test_noreturn_f4 | The function test_noreturn_f4 cannot return and should be declared as _Noreturn. | +| test.c:47:6:47:21 | test_noreturn_f8 | The function test_noreturn_f8 cannot return and should be declared as _Noreturn. | +| test.c:63:6:63:22 | test_noreturn_f10 | The function test_noreturn_f10 cannot return and should be declared as _Noreturn. | +| test.c:97:6:97:22 | test_noreturn_f15 | The function test_noreturn_f15 cannot return and should be declared as _Noreturn. | +| test.c:101:6:101:22 | test_noreturn_f16 | The function test_noreturn_f16 cannot return and should be declared as _Noreturn. | From 81fb797339d5a9ea216fe41731956e07d7847df4 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 2 Oct 2024 13:46:24 -0700 Subject: [PATCH 09/10] Set FunctionWithNoReturningBranch... to very-high precision --- .../RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql b/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql index 9769acdb7f..90cb1af7c2 100644 --- a/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql +++ b/c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql @@ -3,7 +3,7 @@ * @name RULE-17-11: A function without a branch that returns shall be declared with _Noreturn * @description Functions which cannot return should be declared with _Noreturn. * @kind problem - * @precision high + * @precision very-high * @problem.severity recommendation * @tags external/misra/id/rule-17-11 * correctness From 71b4c250ffd667c447e0cb2247c932229e867d56 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 2 Oct 2024 13:54:25 -0700 Subject: [PATCH 10/10] Fix NoReturn.json package description precision 17-11 --- rule_packages/c/NoReturn.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule_packages/c/NoReturn.json b/rule_packages/c/NoReturn.json index d06068f376..49cdb4c255 100644 --- a/rule_packages/c/NoReturn.json +++ b/rule_packages/c/NoReturn.json @@ -26,7 +26,7 @@ "description": "Functions which cannot return should be declared with _Noreturn.", "kind": "problem", "name": "A function without a branch that returns shall be declared with _Noreturn", - "precision": "high", + "precision": "very-high", "severity": "recommendation", "short_name": "FunctionWithNoReturningBranchShouldBeNoreturn", "tags": ["correctness"]