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 all 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
Original file line number Diff line number Diff line change
@@ -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. |
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// GENERATED FILE - DO NOT MODIFY
import codingstandards.cpp.rules.functionnoreturnattributecondition.FunctionNoReturnAttributeCondition

class TestFileQuery extends FunctionNoReturnAttributeConditionSharedQuery, TestQuery { }
88 changes: 88 additions & 0 deletions c/common/test/rules/functionnoreturnattributecondition/test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#include "setjmp.h"
#include "stdlib.h"
#include "threads.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();
}

_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);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* @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
* correctness
* external/misra/obligation/required
*/

import cpp
import codingstandards.c.misra
import codingstandards.cpp.Noreturn

from NoreturnFunction f, Type returnType
where
not isExcluded(f, NoReturnPackage::nonVoidReturnTypeOfNoreturnFunctionQuery()) and
returnType = f.getType() and
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() + "."
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* @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 very-high
* @problem.severity recommendation
* @tags external/misra/id/rule-17-11
* correctness
* external/misra/obligation/advisory
*/

import cpp
import codingstandards.c.misra
import codingstandards.cpp.Noreturn

from Function f
where
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 as _Noreturn."
21 changes: 21 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,21 @@
/**
* @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
* correctness
* external/misra/obligation/mandatory
*/

import cpp
import codingstandards.c.misra
import codingstandards.cpp.rules.functionnoreturnattributecondition.FunctionNoReturnAttributeCondition

class ReturnStatementInNoreturnFunctionQuery extends FunctionNoReturnAttributeConditionSharedQuery {
ReturnStatementInNoreturnFunctionQuery() {
this = NoReturnPackage::returnStatementInNoreturnFunctionQuery()
}
}
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,6 @@
| 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. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql
104 changes: 104 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,104 @@
#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();
}

_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);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
c/common/test/rules/functionnoreturnattributecondition/FunctionNoReturnAttributeCondition.ql
3 changes: 3 additions & 0 deletions change_notes/2024-09-28-improved-noreturn-rules.md
Original file line number Diff line number Diff line change
@@ -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.
22 changes: 22 additions & 0 deletions cpp/common/src/codingstandards/cpp/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()
)
}
Loading
Loading