-
Notifications
You must be signed in to change notification settings - Fork 70
Implement Rule 22-4-1, only assign literal 0 to errno. #987
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| //** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ | ||
| import cpp | ||
| import RuleMetadata | ||
| import codingstandards.cpp.exclusions.RuleMetadata | ||
|
|
||
| newtype Preconditions4Query = TInvalidAssignmentToErrnoQuery() | ||
|
|
||
| predicate isPreconditions4QueryMetadata(Query query, string queryId, string ruleId, string category) { | ||
| query = | ||
| // `Query` instance for the `invalidAssignmentToErrno` query | ||
| Preconditions4Package::invalidAssignmentToErrnoQuery() and | ||
| queryId = | ||
| // `@id` for the `invalidAssignmentToErrno` query | ||
| "cpp/misra/invalid-assignment-to-errno" and | ||
| ruleId = "RULE-22-4-1" and | ||
| category = "required" | ||
| } | ||
|
|
||
| module Preconditions4Package { | ||
| Query invalidAssignmentToErrnoQuery() { | ||
| //autogenerate `Query` type | ||
| result = | ||
| // `Query` type for `invalidAssignmentToErrno` query | ||
| TQueryCPP(TPreconditions4PackageQuery(TInvalidAssignmentToErrnoQuery())) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| import cpp | ||
|
|
||
| predicate isErrno(VariableAccess va) { | ||
| va.getTarget().hasName("errno") or | ||
| va.getTarget().hasName("__errno") | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,35 @@ | ||||||
| /** | ||||||
| * @id cpp/misra/invalid-assignment-to-errno | ||||||
| * @name RULE-22-4-1: The literal value zero shall be the only value assigned to errno | ||||||
| * @description C++ provides better options for error handling than the use of errno. Errno should | ||||||
| * not be used for reporting errors within project code. | ||||||
| * @kind problem | ||||||
| * @precision very-high | ||||||
| * @problem.severity error | ||||||
| * @tags external/misra/id/rule-22-4-1 | ||||||
| * scope/single-translation-unit | ||||||
| * maintainability | ||||||
| * external/misra/enforcement/decidable | ||||||
| * external/misra/obligation/required | ||||||
| */ | ||||||
|
|
||||||
| import cpp | ||||||
| import codingstandards.cpp.misra | ||||||
| import codingstandards.cpp.standardlibrary.Errno | ||||||
| import codingstandards.cpp.Literals | ||||||
|
|
||||||
| from Assignment assign, VariableAccess errno, Expr rvalue, string message | ||||||
| where | ||||||
| not isExcluded(assign, Preconditions4Package::invalidAssignmentToErrnoQuery()) and | ||||||
| assign.getLValue() = errno and | ||||||
| isErrno(errno) and | ||||||
| assign.getRValue().getExplicitlyConverted() = rvalue and | ||||||
| ( | ||||||
| not rvalue instanceof LiteralZero and | ||||||
| message = "Assignment to 'errno' with non-zero literal value '" + rvalue.toString() + "'." | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with copilot that the message can be improved, see for example the results for line 86 and 128 in the test...
Suggested change
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ack, will do. Thanks Mauro! :) |
||||||
| or | ||||||
| assign instanceof AssignOperation and | ||||||
| message = | ||||||
| "Compound assignment to 'errno' with operator '" + assign.getOperator() + "' is not allowed." | ||||||
| ) | ||||||
| select assign, message | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| | test.cpp:26:3:26:13 | ... = ... | Assignment to 'errno' with non-zero literal value '0.0'. | | ||
| | test.cpp:27:3:27:14 | ... = ... | Assignment to 'errno' with non-zero literal value '0.0'. | | ||
| | test.cpp:31:3:31:11 | ... = ... | Assignment to 'errno' with non-zero literal value '1'. | | ||
| | test.cpp:32:3:32:12 | ... = ... | Assignment to 'errno' with non-zero literal value '42'. | | ||
| | test.cpp:33:3:33:12 | ... = ... | Assignment to 'errno' with non-zero literal value '- ...'. | | ||
| | test.cpp:39:3:39:22 | ... = ... | Assignment to 'errno' with non-zero literal value '42'. | | ||
| | test.cpp:49:3:49:12 | ... = ... | Assignment to 'errno' with non-zero literal value 'l1'. | | ||
| | test.cpp:50:3:50:12 | ... = ... | Assignment to 'errno' with non-zero literal value 'l2'. | | ||
| | test.cpp:51:3:51:12 | ... = ... | Assignment to 'errno' with non-zero literal value 'l3'. | | ||
| | test.cpp:52:3:52:12 | ... = ... | Assignment to 'errno' with non-zero literal value 'l4'. | | ||
| | test.cpp:53:3:53:12 | ... = ... | Assignment to 'errno' with non-zero literal value 'l5'. | | ||
| | test.cpp:57:3:57:16 | ... = ... | Assignment to 'errno' with non-zero literal value '22'. | | ||
| | test.cpp:58:3:58:16 | ... = ... | Assignment to 'errno' with non-zero literal value '34'. | | ||
| | test.cpp:59:3:59:14 | ... = ... | Assignment to 'errno' with non-zero literal value '33'. | | ||
| | test.cpp:63:3:63:15 | ... = ... | Assignment to 'errno' with non-zero literal value '... + ...'. | | ||
| | test.cpp:64:3:64:15 | ... = ... | Assignment to 'errno' with non-zero literal value '... - ...'. | | ||
| | test.cpp:65:3:65:15 | ... = ... | Assignment to 'errno' with non-zero literal value '... * ...'. | | ||
| | test.cpp:66:3:66:35 | ... = ... | Assignment to 'errno' with non-zero literal value '... - ...'. | | ||
| | test.cpp:70:3:70:11 | ... = ... | Assignment to 'errno' with non-zero literal value '5'. | | ||
| | test.cpp:71:3:71:12 | ... += ... | Compound assignment to 'errno' with operator '+=' is not allowed. | | ||
| | test.cpp:72:3:72:12 | ... -= ... | Assignment to 'errno' with non-zero literal value '5'. | | ||
| | test.cpp:72:3:72:12 | ... -= ... | Compound assignment to 'errno' with operator '-=' is not allowed. | | ||
| | test.cpp:73:3:73:12 | ... *= ... | Compound assignment to 'errno' with operator '*=' is not allowed. | | ||
| | test.cpp:74:3:74:12 | ... /= ... | Assignment to 'errno' with non-zero literal value '1'. | | ||
| | test.cpp:74:3:74:12 | ... /= ... | Compound assignment to 'errno' with operator '/=' is not allowed. | | ||
| | test.cpp:81:3:81:14 | ... = ... | Assignment to 'errno' with non-zero literal value 'call to operator()'. | | ||
| | test.cpp:82:3:82:14 | ... = ... | Assignment to 'errno' with non-zero literal value 'call to operator()'. | | ||
| | test.cpp:86:3:86:29 | ... = ... | Assignment to 'errno' with non-zero literal value 'static_cast<int>...'. | | ||
| | test.cpp:87:3:87:31 | ... = ... | Assignment to 'errno' with non-zero literal value 'static_cast<int>...'. | | ||
| | test.cpp:88:3:88:16 | ... = ... | Assignment to 'errno' with non-zero literal value '(int)...'. | | ||
| | test.cpp:89:3:89:16 | ... = ... | Assignment to 'errno' with non-zero literal value '(int)...'. | | ||
| | test.cpp:108:3:108:40 | ... = ... | Assignment to 'errno' with non-zero literal value 'reinterpret_cast<int>...'. | | ||
| | test.cpp:110:3:110:35 | ... = ... | Assignment to 'errno' with non-zero literal value 'reinterpret_cast<int>...'. | | ||
| | test.cpp:111:3:111:35 | ... = ... | Assignment to 'errno' with non-zero literal value 'reinterpret_cast<int>...'. | | ||
| | test.cpp:113:3:113:40 | ... = ... | Assignment to 'errno' with non-zero literal value 'reinterpret_cast<int>...'. | | ||
| | test.cpp:122:3:122:13 | ... = ... | Assignment to 'errno' with non-zero literal value '48'. | | ||
| | test.cpp:128:3:128:14 | ... = ... | Assignment to 'errno' with non-zero literal value '1'. | |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| rules/RULE-22-4-1/InvalidAssignmentToErrno.ql |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| #include <cerrno> | ||
| #include <cstdint> | ||
| #include <optional> | ||
| #include <string> | ||
|
|
||
| void errnoSettingFunction(); | ||
| void handleError(); | ||
| void f(); | ||
|
|
||
| #define OK 0 | ||
| #define CUSTOM_ERROR 42 | ||
| #define ZERO_MACRO 0 | ||
|
|
||
| void test_literal_zero_assignment() { | ||
| errno = 0; // COMPLIANT | ||
| } | ||
|
|
||
| void test_different_zero_literal_formats() { | ||
| errno = 0; // COMPLIANT - decimal zero literal | ||
| errno = 0x0; // COMPLIANT - hexadecimal zero literal | ||
| errno = 00; // COMPLIANT - octal zero literal | ||
| errno = 0b0; // COMPLIANT - binary zero literal | ||
| } | ||
|
|
||
| void test_floating_point_zero_literals() { | ||
| errno = 0.0; // NON_COMPLIANT - floating point literal, not integer literal | ||
| errno = 0.0f; // NON_COMPLIANT - floating point literal, not integer literal | ||
| } | ||
|
|
||
| void test_non_zero_literal_assignment() { | ||
| errno = 1; // NON_COMPLIANT | ||
| errno = 42; // NON_COMPLIANT | ||
| errno = -1; // NON_COMPLIANT | ||
| } | ||
|
|
||
| void test_macro_assignments() { | ||
| errno = OK; // COMPLIANT - expands to literal 0 | ||
| errno = ZERO_MACRO; // COMPLIANT - expands to literal 0 | ||
| errno = CUSTOM_ERROR; // NON_COMPLIANT - expands to non-zero literal | ||
| } | ||
|
|
||
| void test_variable_assignments() { | ||
| std::uint32_t l1 = 0; | ||
| const std::uint32_t l2 = 0; | ||
| constexpr std::uint32_t l3 = 0; | ||
| std::uint32_t l4 = 42; | ||
| const std::uint32_t l5 = 42; | ||
|
|
||
| errno = l1; // NON_COMPLIANT - variable, not literal | ||
| errno = l2; // NON_COMPLIANT - constant variable, not literal | ||
| errno = l3; // NON_COMPLIANT - constexpr variable, not literal | ||
| errno = l4; // NON_COMPLIANT - variable with non-zero value | ||
| errno = l5; // NON_COMPLIANT - constant variable with non-zero value | ||
| } | ||
|
|
||
| void test_standard_error_macros() { | ||
| errno = EINVAL; // NON_COMPLIANT - standard error macro | ||
| errno = ERANGE; // NON_COMPLIANT - standard error macro | ||
| errno = EDOM; // NON_COMPLIANT - standard error macro | ||
| } | ||
|
|
||
| void test_expressions() { | ||
| errno = 0 + 0; // NON_COMPLIANT - expression, not literal | ||
| errno = 1 - 1; // NON_COMPLIANT - expression, not literal | ||
| errno = 0 * 5; // NON_COMPLIANT - expression, not literal | ||
| errno = sizeof(int) - sizeof(int); // NON_COMPLIANT - expression, not literal | ||
| } | ||
|
|
||
| void test_compound_assignments() { | ||
| errno = 5; // NON_COMPLIANT - initial assignment to non-zero value | ||
| errno += 0; // NON_COMPLIANT - compound assignment, not simple assignment | ||
| errno -= 5; // NON_COMPLIANT - compound assignment, not simple assignment | ||
| errno *= 0; // NON_COMPLIANT - compound assignment, not simple assignment | ||
| errno /= 1; // NON_COMPLIANT - compound assignment, not simple assignment | ||
| } | ||
|
|
||
| void test_function_return_values() { | ||
| auto l1 = []() { return 0; }; | ||
| auto l2 = []() { return 42; }; | ||
|
|
||
| errno = l1(); // NON_COMPLIANT - function return value, not literal | ||
| errno = l2(); // NON_COMPLIANT - function return value, not literal | ||
| } | ||
|
|
||
| void test_cast_expressions() { | ||
| errno = static_cast<int>(0); // NON_COMPLIANT - cast expression | ||
| errno = static_cast<int>(0.0); // NON_COMPLIANT - cast expression | ||
| errno = (int)0; // NON_COMPLIANT - C-style cast | ||
| errno = int(0); // NON_COMPLIANT - functional cast | ||
| } | ||
|
|
||
| void test_reading_errno_is_allowed() { | ||
| std::uint32_t l1 = errno; // COMPLIANT - reading errno is allowed | ||
| if (errno != 0) { // COMPLIANT - reading errno is allowed | ||
| handleError(); | ||
| } | ||
|
|
||
| errnoSettingFunction(); | ||
| std::uint32_t l2 = 0; | ||
| if (errno != l2) { // COMPLIANT - reading errno is allowed | ||
| handleError(); | ||
| } | ||
| } | ||
|
|
||
| void test_pointer_and_null_assignments() { | ||
| label: | ||
| static const int x = 0; | ||
| errno = reinterpret_cast<int>(nullptr); // NON_COMPLIANT - nullptr is | ||
| // not an integer literal | ||
| errno = reinterpret_cast<int>(&x); // NON_COMPLIANT - pointer cast to integer | ||
| errno = reinterpret_cast<int>(&f); // NON_COMPLIANT - pointer cast to | ||
| // integer | ||
| errno = reinterpret_cast<int>(&&label); // NON_COMPLIANT - pointer | ||
| // cast to integer | ||
| errno = NULL; // NON_COMPLIANT[FALSE_NEGATIVE] - NULL may expand to 0 but not | ||
| // literal | ||
| } | ||
|
|
||
| void test_character_literals() { | ||
| errno = '\0'; // NON_COMPLIANT[FALSE_NEGATIVE] - character literal, not | ||
| // integer literal | ||
| errno = '0'; // NON_COMPLIANT - character '0' has value 48 | ||
| } | ||
|
|
||
| void test_boolean_literals() { | ||
| errno = false; // NON_COMPLIANT[FALSE_NEGATIVE] - boolean literal, not integer | ||
| // literal | ||
| errno = true; // NON_COMPLIANT - boolean literal with non-zero value | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| { | ||
| "MISRA-C++-2023": { | ||
| "RULE-22-4-1": { | ||
| "properties": { | ||
| "enforcement": "decidable", | ||
| "obligation": "required" | ||
| }, | ||
| "queries": [ | ||
| { | ||
| "description": "C++ provides better options for error handling than the use of errno. Errno should not be used for reporting errors within project code.", | ||
| "kind": "problem", | ||
| "name": "The literal value zero shall be the only value assigned to errno", | ||
| "precision": "very-high", | ||
| "severity": "error", | ||
| "short_name": "InvalidAssignmentToErrno", | ||
| "tags": [ | ||
| "scope/single-translation-unit", | ||
| "maintainability" | ||
| ] | ||
| } | ||
| ], | ||
| "title": "The literal value zero shall be the only value assigned to errno" | ||
| } | ||
| } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.