Skip to content

Commit

Permalink
Merge pull request #713 from github/michaelrfairhurst/implement-misra…
Browse files Browse the repository at this point in the history
…-c-noreturn-rule-package

Implement Misra-c Noreturn rule package.
  • Loading branch information
lcartey authored Oct 4, 2024
2 parents 021fabb + 71b4c25 commit a5c743c
Show file tree
Hide file tree
Showing 19 changed files with 475 additions and 7 deletions.
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

0 comments on commit a5c743c

Please sign in to comment.