-
Notifications
You must be signed in to change notification settings - Fork 69
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
Merged
MichaelRFairhurst
merged 3 commits into
main
from
michaelrfairhurst/preconditions-rule-22-4-1-literal-value-0-errno
Dec 4, 2025
Merged
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
1e07871
Implement Rule 22-4-1, only assign literal 0 to errno.
MichaelRFairhurst 81062d7
Improves error message to clarify that value must be int, literal, AN…
MichaelRFairhurst 0d3a06e
Merge remote-tracking branch 'origin/main' into michaelrfairhurst/pre…
MichaelRFairhurst File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
26 changes: 26 additions & 0 deletions
26
cpp/common/src/codingstandards/cpp/exclusions/cpp/Preconditions4.qll
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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())) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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") | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
cpp/misra/src/rules/RULE-22-4-1/InvalidAssignmentToErrno.ql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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() + "'." | ||
MichaelRFairhurst marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| or | ||
| assign instanceof AssignOperation and | ||
| message = | ||
| "Compound assignment to 'errno' with operator '" + assign.getOperator() + "' is not allowed." | ||
| ) | ||
| select assign, message | ||
37 changes: 37 additions & 0 deletions
37
cpp/misra/test/rules/RULE-22-4-1/InvalidAssignmentToErrno.expected
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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'. | |
1 change: 1 addition & 0 deletions
1
cpp/misra/test/rules/RULE-22-4-1/InvalidAssignmentToErrno.qlref
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| rules/RULE-22-4-1/InvalidAssignmentToErrno.ql |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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" | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.