Skip to content

Commit 1e07871

Browse files
Implement Rule 22-4-1, only assign literal 0 to errno.
1 parent 33bc0b1 commit 1e07871

File tree

11 files changed

+268
-1
lines changed

11 files changed

+268
-1
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/
2+
import cpp
3+
import RuleMetadata
4+
import codingstandards.cpp.exclusions.RuleMetadata
5+
6+
newtype Preconditions4Query = TInvalidAssignmentToErrnoQuery()
7+
8+
predicate isPreconditions4QueryMetadata(Query query, string queryId, string ruleId, string category) {
9+
query =
10+
// `Query` instance for the `invalidAssignmentToErrno` query
11+
Preconditions4Package::invalidAssignmentToErrnoQuery() and
12+
queryId =
13+
// `@id` for the `invalidAssignmentToErrno` query
14+
"cpp/misra/invalid-assignment-to-errno" and
15+
ruleId = "RULE-22-4-1" and
16+
category = "required"
17+
}
18+
19+
module Preconditions4Package {
20+
Query invalidAssignmentToErrnoQuery() {
21+
//autogenerate `Query` type
22+
result =
23+
// `Query` type for `invalidAssignmentToErrno` query
24+
TQueryCPP(TPreconditions4PackageQuery(TInvalidAssignmentToErrnoQuery()))
25+
}
26+
}

cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import Operators
4444
import OrderOfEvaluation
4545
import OutOfBounds
4646
import Pointers
47+
import Preconditions4
4748
import Representation
4849
import Scope
4950
import SideEffects1
@@ -103,6 +104,7 @@ newtype TCPPQuery =
103104
TOrderOfEvaluationPackageQuery(OrderOfEvaluationQuery q) or
104105
TOutOfBoundsPackageQuery(OutOfBoundsQuery q) or
105106
TPointersPackageQuery(PointersQuery q) or
107+
TPreconditions4PackageQuery(Preconditions4Query q) or
106108
TRepresentationPackageQuery(RepresentationQuery q) or
107109
TScopePackageQuery(ScopeQuery q) or
108110
TSideEffects1PackageQuery(SideEffects1Query q) or
@@ -162,6 +164,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat
162164
isOrderOfEvaluationQueryMetadata(query, queryId, ruleId, category) or
163165
isOutOfBoundsQueryMetadata(query, queryId, ruleId, category) or
164166
isPointersQueryMetadata(query, queryId, ruleId, category) or
167+
isPreconditions4QueryMetadata(query, queryId, ruleId, category) or
165168
isRepresentationQueryMetadata(query, queryId, ruleId, category) or
166169
isScopeQueryMetadata(query, queryId, ruleId, category) or
167170
isSideEffects1QueryMetadata(query, queryId, ruleId, category) or
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import cpp
2+
3+
predicate isErrno(VariableAccess va) {
4+
va.getTarget().hasName("errno") or
5+
va.getTarget().hasName("__errno")
6+
}

cpp/common/test/includes/standard-library/errno.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22
#define _GHLIBCPP_ERRNO
33
int __errno;
44
#define errno __errno
5+
#define EINVAL 22
6+
#define ERANGE 34
7+
#define EDOM 33
58
#endif // _GHLIBCPP_ERRNO

cpp/common/test/includes/standard-library/string

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ public:
248248
int compare(size_type pos1, size_type n1, const charT *s) const;
249249
int compare(size_type pos1, size_type n1, const charT *s, size_type n2) const;
250250

251+
bool empty() const noexcept;
252+
251253
void reserve(size_type new_cap = 0);
252254
};
253255

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* @id cpp/misra/invalid-assignment-to-errno
3+
* @name RULE-22-4-1: The literal value zero shall be the only value assigned to errno
4+
* @description C++ provides better options for error handling than the use of errno. Errno should
5+
* not be used for reporting errors within project code.
6+
* @kind problem
7+
* @precision very-high
8+
* @problem.severity error
9+
* @tags external/misra/id/rule-22-4-1
10+
* scope/single-translation-unit
11+
* maintainability
12+
* external/misra/enforcement/decidable
13+
* external/misra/obligation/required
14+
*/
15+
16+
import cpp
17+
import codingstandards.cpp.misra
18+
import codingstandards.cpp.standardlibrary.Errno
19+
import codingstandards.cpp.Literals
20+
21+
from Assignment assign, VariableAccess errno, Expr rvalue, string message
22+
where
23+
not isExcluded(assign, Preconditions4Package::invalidAssignmentToErrnoQuery()) and
24+
assign.getLValue() = errno and
25+
isErrno(errno) and
26+
assign.getRValue().getExplicitlyConverted() = rvalue and
27+
(
28+
not rvalue instanceof LiteralZero and
29+
message = "Assignment to 'errno' with non-zero literal value '" + rvalue.toString() + "'."
30+
or
31+
assign instanceof AssignOperation and
32+
message =
33+
"Compound assignment to 'errno' with operator '" + assign.getOperator() + "' is not allowed."
34+
)
35+
select assign, message
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
| test.cpp:26:3:26:13 | ... = ... | Assignment to 'errno' with non-zero literal value '0.0'. |
2+
| test.cpp:27:3:27:14 | ... = ... | Assignment to 'errno' with non-zero literal value '0.0'. |
3+
| test.cpp:31:3:31:11 | ... = ... | Assignment to 'errno' with non-zero literal value '1'. |
4+
| test.cpp:32:3:32:12 | ... = ... | Assignment to 'errno' with non-zero literal value '42'. |
5+
| test.cpp:33:3:33:12 | ... = ... | Assignment to 'errno' with non-zero literal value '- ...'. |
6+
| test.cpp:39:3:39:22 | ... = ... | Assignment to 'errno' with non-zero literal value '42'. |
7+
| test.cpp:49:3:49:12 | ... = ... | Assignment to 'errno' with non-zero literal value 'l1'. |
8+
| test.cpp:50:3:50:12 | ... = ... | Assignment to 'errno' with non-zero literal value 'l2'. |
9+
| test.cpp:51:3:51:12 | ... = ... | Assignment to 'errno' with non-zero literal value 'l3'. |
10+
| test.cpp:52:3:52:12 | ... = ... | Assignment to 'errno' with non-zero literal value 'l4'. |
11+
| test.cpp:53:3:53:12 | ... = ... | Assignment to 'errno' with non-zero literal value 'l5'. |
12+
| test.cpp:57:3:57:16 | ... = ... | Assignment to 'errno' with non-zero literal value '22'. |
13+
| test.cpp:58:3:58:16 | ... = ... | Assignment to 'errno' with non-zero literal value '34'. |
14+
| test.cpp:59:3:59:14 | ... = ... | Assignment to 'errno' with non-zero literal value '33'. |
15+
| test.cpp:63:3:63:15 | ... = ... | Assignment to 'errno' with non-zero literal value '... + ...'. |
16+
| test.cpp:64:3:64:15 | ... = ... | Assignment to 'errno' with non-zero literal value '... - ...'. |
17+
| test.cpp:65:3:65:15 | ... = ... | Assignment to 'errno' with non-zero literal value '... * ...'. |
18+
| test.cpp:66:3:66:35 | ... = ... | Assignment to 'errno' with non-zero literal value '... - ...'. |
19+
| test.cpp:70:3:70:11 | ... = ... | Assignment to 'errno' with non-zero literal value '5'. |
20+
| test.cpp:71:3:71:12 | ... += ... | Compound assignment to 'errno' with operator '+=' is not allowed. |
21+
| test.cpp:72:3:72:12 | ... -= ... | Assignment to 'errno' with non-zero literal value '5'. |
22+
| test.cpp:72:3:72:12 | ... -= ... | Compound assignment to 'errno' with operator '-=' is not allowed. |
23+
| test.cpp:73:3:73:12 | ... *= ... | Compound assignment to 'errno' with operator '*=' is not allowed. |
24+
| test.cpp:74:3:74:12 | ... /= ... | Assignment to 'errno' with non-zero literal value '1'. |
25+
| test.cpp:74:3:74:12 | ... /= ... | Compound assignment to 'errno' with operator '/=' is not allowed. |
26+
| test.cpp:81:3:81:14 | ... = ... | Assignment to 'errno' with non-zero literal value 'call to operator()'. |
27+
| test.cpp:82:3:82:14 | ... = ... | Assignment to 'errno' with non-zero literal value 'call to operator()'. |
28+
| test.cpp:86:3:86:29 | ... = ... | Assignment to 'errno' with non-zero literal value 'static_cast<int>...'. |
29+
| test.cpp:87:3:87:31 | ... = ... | Assignment to 'errno' with non-zero literal value 'static_cast<int>...'. |
30+
| test.cpp:88:3:88:16 | ... = ... | Assignment to 'errno' with non-zero literal value '(int)...'. |
31+
| test.cpp:89:3:89:16 | ... = ... | Assignment to 'errno' with non-zero literal value '(int)...'. |
32+
| test.cpp:108:3:108:40 | ... = ... | Assignment to 'errno' with non-zero literal value 'reinterpret_cast<int>...'. |
33+
| test.cpp:110:3:110:35 | ... = ... | Assignment to 'errno' with non-zero literal value 'reinterpret_cast<int>...'. |
34+
| test.cpp:111:3:111:35 | ... = ... | Assignment to 'errno' with non-zero literal value 'reinterpret_cast<int>...'. |
35+
| test.cpp:113:3:113:40 | ... = ... | Assignment to 'errno' with non-zero literal value 'reinterpret_cast<int>...'. |
36+
| test.cpp:122:3:122:13 | ... = ... | Assignment to 'errno' with non-zero literal value '48'. |
37+
| test.cpp:128:3:128:14 | ... = ... | Assignment to 'errno' with non-zero literal value '1'. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/RULE-22-4-1/InvalidAssignmentToErrno.ql
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#include <cerrno>
2+
#include <cstdint>
3+
#include <optional>
4+
#include <string>
5+
6+
void errnoSettingFunction();
7+
void handleError();
8+
void f();
9+
10+
#define OK 0
11+
#define CUSTOM_ERROR 42
12+
#define ZERO_MACRO 0
13+
14+
void test_literal_zero_assignment() {
15+
errno = 0; // COMPLIANT
16+
}
17+
18+
void test_different_zero_literal_formats() {
19+
errno = 0; // COMPLIANT - decimal zero literal
20+
errno = 0x0; // COMPLIANT - hexadecimal zero literal
21+
errno = 00; // COMPLIANT - octal zero literal
22+
errno = 0b0; // COMPLIANT - binary zero literal
23+
}
24+
25+
void test_floating_point_zero_literals() {
26+
errno = 0.0; // NON_COMPLIANT - floating point literal, not integer literal
27+
errno = 0.0f; // NON_COMPLIANT - floating point literal, not integer literal
28+
}
29+
30+
void test_non_zero_literal_assignment() {
31+
errno = 1; // NON_COMPLIANT
32+
errno = 42; // NON_COMPLIANT
33+
errno = -1; // NON_COMPLIANT
34+
}
35+
36+
void test_macro_assignments() {
37+
errno = OK; // COMPLIANT - expands to literal 0
38+
errno = ZERO_MACRO; // COMPLIANT - expands to literal 0
39+
errno = CUSTOM_ERROR; // NON_COMPLIANT - expands to non-zero literal
40+
}
41+
42+
void test_variable_assignments() {
43+
std::uint32_t l1 = 0;
44+
const std::uint32_t l2 = 0;
45+
constexpr std::uint32_t l3 = 0;
46+
std::uint32_t l4 = 42;
47+
const std::uint32_t l5 = 42;
48+
49+
errno = l1; // NON_COMPLIANT - variable, not literal
50+
errno = l2; // NON_COMPLIANT - constant variable, not literal
51+
errno = l3; // NON_COMPLIANT - constexpr variable, not literal
52+
errno = l4; // NON_COMPLIANT - variable with non-zero value
53+
errno = l5; // NON_COMPLIANT - constant variable with non-zero value
54+
}
55+
56+
void test_standard_error_macros() {
57+
errno = EINVAL; // NON_COMPLIANT - standard error macro
58+
errno = ERANGE; // NON_COMPLIANT - standard error macro
59+
errno = EDOM; // NON_COMPLIANT - standard error macro
60+
}
61+
62+
void test_expressions() {
63+
errno = 0 + 0; // NON_COMPLIANT - expression, not literal
64+
errno = 1 - 1; // NON_COMPLIANT - expression, not literal
65+
errno = 0 * 5; // NON_COMPLIANT - expression, not literal
66+
errno = sizeof(int) - sizeof(int); // NON_COMPLIANT - expression, not literal
67+
}
68+
69+
void test_compound_assignments() {
70+
errno = 5; // NON_COMPLIANT - initial assignment to non-zero value
71+
errno += 0; // NON_COMPLIANT - compound assignment, not simple assignment
72+
errno -= 5; // NON_COMPLIANT - compound assignment, not simple assignment
73+
errno *= 0; // NON_COMPLIANT - compound assignment, not simple assignment
74+
errno /= 1; // NON_COMPLIANT - compound assignment, not simple assignment
75+
}
76+
77+
void test_function_return_values() {
78+
auto l1 = []() { return 0; };
79+
auto l2 = []() { return 42; };
80+
81+
errno = l1(); // NON_COMPLIANT - function return value, not literal
82+
errno = l2(); // NON_COMPLIANT - function return value, not literal
83+
}
84+
85+
void test_cast_expressions() {
86+
errno = static_cast<int>(0); // NON_COMPLIANT - cast expression
87+
errno = static_cast<int>(0.0); // NON_COMPLIANT - cast expression
88+
errno = (int)0; // NON_COMPLIANT - C-style cast
89+
errno = int(0); // NON_COMPLIANT - functional cast
90+
}
91+
92+
void test_reading_errno_is_allowed() {
93+
std::uint32_t l1 = errno; // COMPLIANT - reading errno is allowed
94+
if (errno != 0) { // COMPLIANT - reading errno is allowed
95+
handleError();
96+
}
97+
98+
errnoSettingFunction();
99+
std::uint32_t l2 = 0;
100+
if (errno != l2) { // COMPLIANT - reading errno is allowed
101+
handleError();
102+
}
103+
}
104+
105+
void test_pointer_and_null_assignments() {
106+
label:
107+
static const int x = 0;
108+
errno = reinterpret_cast<int>(nullptr); // NON_COMPLIANT - nullptr is
109+
// not an integer literal
110+
errno = reinterpret_cast<int>(&x); // NON_COMPLIANT - pointer cast to integer
111+
errno = reinterpret_cast<int>(&f); // NON_COMPLIANT - pointer cast to
112+
// integer
113+
errno = reinterpret_cast<int>(&&label); // NON_COMPLIANT - pointer
114+
// cast to integer
115+
errno = NULL; // NON_COMPLIANT[FALSE_NEGATIVE] - NULL may expand to 0 but not
116+
// literal
117+
}
118+
119+
void test_character_literals() {
120+
errno = '\0'; // NON_COMPLIANT[FALSE_NEGATIVE] - character literal, not
121+
// integer literal
122+
errno = '0'; // NON_COMPLIANT - character '0' has value 48
123+
}
124+
125+
void test_boolean_literals() {
126+
errno = false; // NON_COMPLIANT[FALSE_NEGATIVE] - boolean literal, not integer
127+
// literal
128+
errno = true; // NON_COMPLIANT - boolean literal with non-zero value
129+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"MISRA-C++-2023": {
3+
"RULE-22-4-1": {
4+
"properties": {
5+
"enforcement": "decidable",
6+
"obligation": "required"
7+
},
8+
"queries": [
9+
{
10+
"description": "C++ provides better options for error handling than the use of errno. Errno should not be used for reporting errors within project code.",
11+
"kind": "problem",
12+
"name": "The literal value zero shall be the only value assigned to errno",
13+
"precision": "very-high",
14+
"severity": "error",
15+
"short_name": "InvalidAssignmentToErrno",
16+
"tags": [
17+
"scope/single-translation-unit",
18+
"maintainability"
19+
]
20+
}
21+
],
22+
"title": "The literal value zero shall be the only value assigned to errno"
23+
}
24+
}
25+
}

0 commit comments

Comments
 (0)