Skip to content

Implement Misra-c Noreturn rule package. #713

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions c/common/src/codingstandards/c/Noreturn.qll
Original file line number Diff line number Diff line change
@@ -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()
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* @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
import codingstandards.c.Noreturn

from NoreturnFunction f, Type returnType
where
not isExcluded(f, NoReturnPackage::nonVoidReturnTypeOfNoreturnFunctionQuery()) 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() + "."
Original file line number Diff line number Diff line change
@@ -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
import codingstandards.c.Noreturn

from Function f
where
not isExcluded(f, NoReturnPackage::returnStatementInNoreturnFunctionQuery()) and
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."
20 changes: 20 additions & 0 deletions c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* @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
import codingstandards.c.Noreturn

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."
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
| 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. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql
26 changes: 26 additions & 0 deletions c/misra/test/rules/RULE-17-10/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#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

__attribute__((noreturn)) int f10(); // NON-COMPLIANT
Original file line number Diff line number Diff line change
@@ -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: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. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql
91 changes: 91 additions & 0 deletions c/misra/test/rules/RULE-17-11/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#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;
}
}

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();
}
Original file line number Diff line number Diff line change
@@ -0,0 +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. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql
55 changes: 55 additions & 0 deletions c/misra/test/rules/RULE-17-9/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#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;
}
}

__attribute__((noreturn)) void test_noreturn_f7(int i) { // NON_COMPLIANT
if (i > 0) {
abort();
}
}

__attribute__((noreturn)) void test_noreturn_f8(int i) { // COMPLIANT
abort();
}
61 changes: 61 additions & 0 deletions cpp/common/src/codingstandards/cpp/exclusions/c/NoReturn.qll
Original file line number Diff line number Diff line change
@@ -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()))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import Memory1
import Memory2
import Memory3
import Misc
import NoReturn
import OutOfBounds
import Pointers1
import Pointers2
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
Loading
Loading