Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 5053722

Browse filesBrowse files
authored
Package Contracts3 (#88)
Add RULE-22-8 RULE-22-9 RULE-22-10 from package Contracts3
1 parent f793d14 commit 5053722
Copy full SHA for 5053722

17 files changed

+501
-3
lines changed
+100Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/** Provides a library for errno-setting functions. */
2+
3+
import cpp
4+
5+
/*
6+
* An errno-setting function
7+
*/
8+
9+
abstract class ErrnoSettingFunction extends Function { }
10+
11+
/*
12+
* An errno-setting function that return out-of-band errors indicators
13+
*/
14+
15+
class OutOfBandErrnoSettingFunction extends ErrnoSettingFunction {
16+
OutOfBandErrnoSettingFunction() {
17+
this.hasGlobalName(["ftell", "fgetpos", "fsetpos", "mbrtowc", "wcrtomb", "wcsrtombs"])
18+
}
19+
}
20+
21+
/*
22+
* An errno-setting function that return in-band errors indicators
23+
*/
24+
25+
class InBandErrnoSettingFunction extends ErrnoSettingFunction {
26+
InBandErrnoSettingFunction() {
27+
this.hasGlobalName([
28+
"fgetwc", "fputwc", "strtol", "wcstol", "strtoll", "wcstoll", "strtoul", "wcstoul",
29+
"strtoull", "wcstoull", "strtoumax", "wcstoumax", "strtod", "wcstod", "strtof", "wcstof",
30+
"strtold", "wcstold", "strtoimax", "wcstoimax"
31+
])
32+
}
33+
}
34+
35+
/*
36+
* A assignment expression setting `errno` to 0
37+
*/
38+
39+
class ErrnoZeroed extends AssignExpr {
40+
ErrnoZeroed() {
41+
this.getLValue() = any(MacroInvocation ma | ma.getMacroName() = "errno").getExpr() and
42+
this.getRValue().getValue() = "0"
43+
}
44+
}
45+
46+
/*
47+
* A guard controlled by a errno comparison
48+
*/
49+
50+
abstract class ErrnoGuard extends StmtParent {
51+
abstract ControlFlowNode getZeroedSuccessor();
52+
53+
abstract ControlFlowNode getNonZeroedSuccessor();
54+
}
55+
56+
class ErrnoIfGuard extends EqualityOperation, ErrnoGuard {
57+
ControlStructure i;
58+
59+
ErrnoIfGuard() {
60+
this.getAnOperand() = any(MacroInvocation ma | ma.getMacroName() = "errno").getExpr() and
61+
this.getAnOperand().getValue() = "0" and
62+
i.getControllingExpr() = this
63+
}
64+
65+
Stmt getThenSuccessor() {
66+
i.getControllingExpr() = this and
67+
(result = i.(IfStmt).getThen() or result = i.(Loop).getStmt())
68+
}
69+
70+
Stmt getElseSuccessor() {
71+
i.getControllingExpr() = this and
72+
(
73+
i.(IfStmt).hasElse() and result = i.(IfStmt).getElse()
74+
or
75+
result = i.getFollowingStmt()
76+
)
77+
}
78+
79+
override ControlFlowNode getZeroedSuccessor() {
80+
if this instanceof EQExpr then result = this.getThenSuccessor() else result = getElseSuccessor()
81+
}
82+
83+
override ControlFlowNode getNonZeroedSuccessor() {
84+
if this instanceof NEExpr then result = this.getThenSuccessor() else result = getElseSuccessor()
85+
}
86+
}
87+
88+
class ErrnoSwitchGuard extends SwitchCase, ErrnoGuard {
89+
ErrnoSwitchGuard() {
90+
this.getSwitchStmt().getExpr() = any(MacroInvocation ma | ma.getMacroName() = "errno").getExpr()
91+
}
92+
93+
override ControlFlowNode getZeroedSuccessor() {
94+
result = this.getAStmt() and this.getExpr().getValue() = "0"
95+
}
96+
97+
override ControlFlowNode getNonZeroedSuccessor() {
98+
result = this.getAStmt() and this.getExpr().getValue() != "0"
99+
}
100+
}
+64Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* @id c/misra/only-test-errno-right-after-errno-setting-function
3+
* @name RULE-22-10: The value of errno shall only be tested when the last called function is errno-setting
4+
* @description The value of errno shall only be tested when the last function to be called was an
5+
* errno-setting-function. Testing the value in these conditions does not guarantee the
6+
* absence of an errors.
7+
* @kind problem
8+
* @precision high
9+
* @problem.severity warning
10+
* @tags external/misra/id/rule-22-10
11+
* correctness
12+
* external/misra/obligation/required
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.misra
17+
import codingstandards.c.Errno
18+
19+
/*
20+
* A call to an `ErrnoSettingFunction`
21+
*/
22+
23+
class ErrnoSettingFunctionCall extends FunctionCall {
24+
ErrnoSettingFunctionCall() { this.getTarget() instanceof ErrnoSettingFunction }
25+
}
26+
27+
/*
28+
* A function call that is not part of the `errno` macro expansion
29+
*/
30+
31+
class MaySetErrnoCall extends FunctionCall {
32+
MaySetErrnoCall() {
33+
not inmacroexpansion(this, any(MacroInvocation ma | ma.getMacroName() = "errno"))
34+
}
35+
}
36+
37+
/*
38+
* CFG nodes preceding a `errno` test where `errno` is not set
39+
*/
40+
41+
ControlFlowNode notSetPriorToErrnoTest(EqualityOperation eg) {
42+
result = eg
43+
or
44+
exists(ControlFlowNode mid |
45+
result = mid.getAPredecessor() and
46+
mid = notSetPriorToErrnoTest(eg) and
47+
// stop recursion on an errno-setting function call
48+
not result = any(ErrnoSettingFunctionCall c)
49+
)
50+
}
51+
52+
from EqualityOperation eq, ControlFlowNode cause
53+
where
54+
not isExcluded(eq, Contracts3Package::onlyTestErrnoRightAfterErrnoSettingFunctionQuery()) and
55+
cause = notSetPriorToErrnoTest(eq) and
56+
eq.getAnOperand() = any(MacroInvocation ma | ma.getMacroName() = "errno").getExpr() and
57+
(
58+
// `errno` is not set anywhere in the function
59+
cause = eq.getEnclosingFunction().getBlock()
60+
or
61+
// `errno` is not set after a non-errno-setting function call
62+
cause = any(MaySetErrnoCall c)
63+
)
64+
select eq, "Value of `errno` is tested but not after an errno-setting function call."
+60Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/**
2+
* @id c/misra/errno-set-to-zero-prior-to-call
3+
* @name RULE-22-8: The value of errno shall be set to zero prior to a call to an errno-setting-function
4+
* @description The value of errno shall be set to zero prior to a call to an
5+
* errno-setting-function. Not setting the value leads to incorrectly identifying
6+
* errors.
7+
* @kind problem
8+
* @precision very-high
9+
* @problem.severity error
10+
* @tags external/misra/id/rule-22-8
11+
* correctness
12+
* external/misra/obligation/required
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.misra
17+
import codingstandards.c.Errno
18+
19+
/*
20+
* A call to an `ErrnoSettingFunction`
21+
*/
22+
23+
class ErrnoSettingFunctionCall extends FunctionCall {
24+
ErrnoSettingFunctionCall() { this.getTarget() instanceof ErrnoSettingFunction }
25+
}
26+
27+
/*
28+
* CFG nodes preceding a `ErrnoSettingFunctionCall`
29+
*/
30+
31+
ControlFlowNode notZeroedPriorToErrnoSet(ErrnoSettingFunctionCall fc) {
32+
result = fc
33+
or
34+
exists(ControlFlowNode mid |
35+
result = mid.getAPredecessor() and
36+
mid = notZeroedPriorToErrnoSet(fc) and
37+
// stop recursion when `errno` is set to zero
38+
not result instanceof ErrnoZeroed and
39+
not result = any(ErrnoGuard g).getZeroedSuccessor()
40+
)
41+
}
42+
43+
from ErrnoSettingFunctionCall fc, ControlFlowNode cause
44+
where
45+
not isExcluded(fc, Contracts3Package::errnoSetToZeroAfterCallQuery()) and
46+
cause = notZeroedPriorToErrnoSet(fc) and
47+
(
48+
// `errno` is not reset anywhere in the function
49+
cause = fc.getEnclosingFunction().getBlock()
50+
or
51+
// `errno` is not reset after a call to an errno-setting function
52+
cause = any(ErrnoSettingFunctionCall ec | ec != fc)
53+
or
54+
// `errno` is not reset after a call to a function
55+
cause = any(FunctionCall fc2 | fc2 != fc)
56+
or
57+
// `errno` value is known to be != 0
58+
cause = any(ErrnoGuard g).getNonZeroedSuccessor()
59+
)
60+
select fc, "The value of `errno` may be different than `0` when this function is called."
+52Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* @id c/misra/errno-set-to-zero-after-call
3+
* @name RULE-22-9: The value of errno shall be tested against zero after calling an errno-setting-function
4+
* @description The value of errno shall be tested against zero after calling an
5+
* errno-setting-function. Not testing the value leads to unidentified errors.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-22-9
10+
* correctness
11+
* external/misra/obligation/required
12+
*/
13+
14+
import cpp
15+
import codingstandards.c.misra
16+
import codingstandards.c.Errno
17+
18+
/*
19+
* A call to an `ErrnoSettingFunction`
20+
*/
21+
22+
class InBandErrnoSettingFunctionCall extends FunctionCall {
23+
InBandErrnoSettingFunctionCall() { this.getTarget() instanceof InBandErrnoSettingFunction }
24+
}
25+
26+
/*
27+
* CFG nodes following a `ErrnoSettingFunctionCall`
28+
*/
29+
30+
ControlFlowNode notTestedAfterErrnoSet(InBandErrnoSettingFunctionCall fc) {
31+
result = fc
32+
or
33+
exists(ControlFlowNode mid |
34+
result = mid.getASuccessor() and
35+
mid = notTestedAfterErrnoSet(fc) and
36+
// stop recursion when `errno` is checked
37+
not result = any(ControlStructure i | i.getControllingExpr() instanceof ErrnoGuard)
38+
)
39+
}
40+
41+
from InBandErrnoSettingFunctionCall fc, ControlFlowNode cause
42+
where
43+
not isExcluded(fc, Contracts3Package::errnoSetToZeroAfterCallQuery()) and
44+
cause = notTestedAfterErrnoSet(fc) and
45+
(
46+
// `errno` is not checked anywhere in the function
47+
cause = fc.getEnclosingFunction()
48+
or
49+
// `errno` is not checked before a call to a function
50+
cause = any(FunctionCall fc2 | fc2 != fc)
51+
)
52+
select fc, "The value of `errno` is not tested against `0` after the call."
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| test.c:7:7:7:16 | ... == ... | Value of `errno` is tested but not after an errno-setting function call. |
2+
| test.c:16:7:16:21 | ... == ... | Value of `errno` is tested but not after an errno-setting function call. |
3+
| test.c:17:10:17:23 | ... == ... | Value of `errno` is tested but not after an errno-setting function call. |
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-22-10/OnlyTestErrnoRightAfterErrnoSettingFunction.ql

‎c/misra/test/rules/RULE-22-10/test.c

Copy file name to clipboard
+26Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#include <errno.h>
2+
#include <stdlib.h>
3+
4+
void f1(void) {
5+
errno = 0;
6+
int i = atoi("0"); // non errno-setting function
7+
if (0 == errno) { // NON_COMPLIANT
8+
}
9+
errno = 0;
10+
strtod("0", NULL); // errno-setting function
11+
if (0 == errno) { // COMPLIANT
12+
}
13+
}
14+
15+
void f2(void) {
16+
if (EAGAIN == errno // NON_COMPLIANT
17+
|| errno == EINTR) { // NON_COMPLIANT
18+
}
19+
}
20+
21+
void f3(void) {
22+
errno = 0;
23+
strtod("0", NULL);
24+
if (errno == EAGAIN || errno == EINTR) { // COMPLIANT
25+
}
26+
}
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| test.c:5:3:5:8 | call to strtod | The value of `errno` may be different than `0` when this function is called. |
2+
| test.c:20:5:20:10 | call to strtod | The value of `errno` may be different than `0` when this function is called. |
3+
| test.c:24:5:24:10 | call to strtof | The value of `errno` may be different than `0` when this function is called. |
4+
| test.c:32:3:32:8 | call to strtod | The value of `errno` may be different than `0` when this function is called. |
5+
| test.c:41:5:41:10 | call to strtod | The value of `errno` may be different than `0` when this function is called. |
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-22-8/ErrnoSetToZeroPriorToCall.ql

‎c/misra/test/rules/RULE-22-8/test.c

Copy file name to clipboard
+43Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#include <errno.h>
2+
#include <stdlib.h>
3+
4+
void f1(void) {
5+
strtod("0", NULL); // NON_COMPLIANT
6+
if (0 == errno) {
7+
strtod("0", NULL); // COMPLIANT
8+
if (0 == errno) {
9+
}
10+
} else {
11+
errno = 0;
12+
strtod("0", NULL); // COMPLIANT
13+
if (0 == errno) {
14+
}
15+
}
16+
}
17+
18+
void f2(void) {
19+
if (0 != errno) {
20+
strtod("0", NULL); // NON_COMPLIANT
21+
} else {
22+
errno = 0;
23+
strtod("0", NULL); // COMPLIANT
24+
strtof("0", NULL); // NON_COMPLIANT
25+
}
26+
}
27+
28+
void f3_helper() {}
29+
void f3(void) {
30+
errno = 0;
31+
f3_helper();
32+
strtod("0", NULL); // NON_COMPLIANT
33+
}
34+
35+
void f4(void) {
36+
errno = 0;
37+
switch (errno) {
38+
case 0:
39+
strtod("0", NULL); // COMPLIANT
40+
case 1:
41+
strtod("0", NULL); // NON_COMPLIANT
42+
}
43+
}
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| test.c:9:3:9:8 | call to strtod | The value of `errno` is not tested against `0` after the call. |
2+
| test.c:19:3:19:8 | call to strtod | The value of `errno` is not tested against `0` after the call. |
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-22-9/ErrnoSetToZeroAfterCall.ql

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.