Skip to content

Commit 778db73

Browse files
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.
1 parent 104bdc7 commit 778db73

File tree

10 files changed

+74
-28
lines changed

10 files changed

+74
-28
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import cpp
2+
3+
/**
4+
* A function marked with _Noreturn or __attribute((noreturn))
5+
*/
6+
class NoreturnFunction extends Function {
7+
NoreturnFunction() {
8+
this.getASpecifier().getName() = "noreturn" or
9+
this.getAnAttribute().getName() = "noreturn"
10+
}
11+
}
12+
13+
/**
14+
* A function that may complete normally, and/or contains an explicit reachable
15+
* return statement.
16+
*/
17+
predicate mayReturn(Function function) {
18+
exists(ReturnStmt s |
19+
function = s.getEnclosingFunction() and
20+
s.getBasicBlock().isReachable()
21+
)
22+
}

c/misra/src/rules/RULE-17-10/NonVoidReturnTypeOfNoreturnFunction.ql

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@
1212

1313
import cpp
1414
import codingstandards.c.misra
15+
import codingstandards.c.Noreturn
1516

16-
from Function f, Type returnType
17+
from NoreturnFunction f, Type returnType
1718
where
1819
not isExcluded(f, NoReturnPackage::nonVoidReturnTypeOfNoreturnFunctionQuery()) and
19-
f.getASpecifier().getName() = "noreturn" and
2020
returnType = f.getType() and
2121
not returnType instanceof VoidType
22-
select
23-
f, "The function " + f.getName() + " is declared _noreturn but has a return type of " + returnType.toString() + "."
22+
select f,
23+
"The function " + f.getName() + " is declared _noreturn but has a return type of " +
24+
returnType.toString() + "."

c/misra/src/rules/RULE-17-11/FunctionWithNoReturningBranchShouldBeNoreturn.ql

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111

1212
import cpp
1313
import codingstandards.c.misra
14+
import codingstandards.c.Noreturn
1415

1516
from Function f
1617
where
1718
not isExcluded(f, NoReturnPackage::returnStatementInNoreturnFunctionQuery()) and
18-
not f.getASpecifier().getName() = "noreturn" and
19-
not exists(ReturnStmt s |
20-
f = s.getEnclosingFunction() and
21-
s.getBasicBlock().isReachable()
22-
)
23-
select
24-
f, "The function " + f.getName() + " cannot return and should be declared attribute _Noreturn."
19+
not f instanceof NoreturnFunction and
20+
not mayReturn(f) and
21+
f.hasDefinition() and
22+
f.getName() != "main" // Allowed exception; _Noreturn main() is undefined behavior.
23+
select f,
24+
"The function " + f.getName() + " cannot return and should be declared attribute _Noreturn."

c/misra/src/rules/RULE-17-9/ReturnStatementInNoreturnFunction.ql

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,10 @@
1111

1212
import cpp
1313
import codingstandards.c.misra
14+
import codingstandards.c.Noreturn
1415

15-
from Function f
16+
from NoreturnFunction f
1617
where
1718
not isExcluded(f, NoReturnPackage::returnStatementInNoreturnFunctionQuery()) and
18-
f.getASpecifier().getName() = "noreturn" and
19-
exists(ReturnStmt s |
20-
f = s.getEnclosingFunction() and
21-
s.getBasicBlock().isReachable()
22-
)
23-
select
24-
f, "The function " + f.getName() + " declared with attribute _Noreturn returns a value."
19+
mayReturn(f)
20+
select f, "The function " + f.getName() + " declared with attribute _Noreturn returns a value."
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
No expected results have yet been specified
1+
| test.c:6:15:6:16 | f4 | The function f4 is declared _noreturn but has a return type of int. |
2+
| test.c:19:15:19:16 | f8 | The function f8 is declared _noreturn but has a return type of int. |
3+
| test.c:24:17:24:18 | f9 | The function f9 is declared _noreturn but has a return type of void *. |
4+
| test.c:26:31:26:33 | f10 | The function f10 is declared _noreturn but has a return type of int. |

c/misra/test/rules/RULE-17-10/test.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
#include "stdlib.h"
22

3-
void f1(); // COMPLIANT
4-
int f2(); // COMPLIANT
3+
void f1(); // COMPLIANT
4+
int f2(); // COMPLIANT
55
_Noreturn void f3(); // COMPLIANT
6-
_Noreturn int f4(); // NON-COMPLIANT
6+
_Noreturn int f4(); // NON-COMPLIANT
77

88
void f5() { // COMPLIANT
99
}
@@ -21,4 +21,6 @@ _Noreturn int f8() { // NON-COMPLIANT
2121
return 0;
2222
}
2323

24-
_Noreturn void* f9(); // NON-COMPLIANT
24+
_Noreturn void *f9(); // NON-COMPLIANT
25+
26+
__attribute__((noreturn)) int f10(); // NON-COMPLIANT
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
| test.c:7:6:7:21 | test_noreturn_f2 | The function test_noreturn_f2 cannot return and should be declared attribute _Noreturn. |
2-
| test.c:19:6:19:21 | test_noreturn_f4 | The function test_noreturn_f4 cannot return and should be declared attribute _Noreturn. |
3-
| test.c:48:6:48:21 | test_noreturn_f8 | The function test_noreturn_f8 cannot return and should be declared attribute _Noreturn. |
4-
| test.c:64:6:64:22 | test_noreturn_f10 | The function test_noreturn_f10 cannot return and should be declared attribute _Noreturn. |
2+
| test.c:18:6:18:21 | test_noreturn_f4 | The function test_noreturn_f4 cannot return and should be declared attribute _Noreturn. |
3+
| test.c:47:6:47:21 | test_noreturn_f8 | The function test_noreturn_f8 cannot return and should be declared attribute _Noreturn. |
4+
| test.c:63:6:63:22 | test_noreturn_f10 | The function test_noreturn_f10 cannot return and should be declared attribute _Noreturn. |

c/misra/test/rules/RULE-17-11/test.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ void test_noreturn_f2(int i) { // NON_COMPLIANT
88
abort();
99
}
1010

11-
1211
_Noreturn void test_noreturn_f3(int i) { // COMPLIANT
1312
if (i > 0) {
1413
abort();
@@ -78,3 +77,15 @@ _Noreturn void test_noreturn_f11(int i) { // COMPLIANT
7877
i = 5;
7978
}
8079
}
80+
81+
void test_noreturn_f12(); // COMPLIANT
82+
83+
__attribute__((noreturn)) void test_noreturn_f13(int i) { // COMPLIANT
84+
abort();
85+
}
86+
87+
// Allowed by exception. It is undefined behavior for main() to be declared with
88+
// noreturn.
89+
int main(char **argv, int argc) { // COMPLIANT
90+
abort();
91+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
| test.c:7:16:7:31 | test_noreturn_f2 | The function test_noreturn_f2 declared with attribute _Noreturn returns a value. |
22
| test.c:32:16:32:31 | test_noreturn_f5 | The function test_noreturn_f5 declared with attribute _Noreturn returns a value. |
3+
| test.c:47:32:47:47 | test_noreturn_f7 | The function test_noreturn_f7 declared with attribute _Noreturn returns a value. |

c/misra/test/rules/RULE-17-9/test.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,13 @@ _Noreturn void test_noreturn_f6(int i) { // COMPLIANT
4343
i = 5;
4444
}
4545
}
46+
47+
__attribute__((noreturn)) void test_noreturn_f7(int i) { // NON_COMPLIANT
48+
if (i > 0) {
49+
abort();
50+
}
51+
}
52+
53+
__attribute__((noreturn)) void test_noreturn_f8(int i) { // COMPLIANT
54+
abort();
55+
}

0 commit comments

Comments
 (0)