From 41fdf0776492aa7dcde36ddd7fc402b9540adca4 Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Fri, 12 Jan 2024 14:44:47 -0800 Subject: [PATCH 001/628] Include test case FP/FN report --- .../MissingSpecialMemberFunction.expected | 6 ++ cpp/autosar/test/rules/A12-0-1/test.cpp | 61 +++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/cpp/autosar/test/rules/A12-0-1/MissingSpecialMemberFunction.expected b/cpp/autosar/test/rules/A12-0-1/MissingSpecialMemberFunction.expected index 9e1cd591c6..ced97cced2 100644 --- a/cpp/autosar/test/rules/A12-0-1/MissingSpecialMemberFunction.expected +++ b/cpp/autosar/test/rules/A12-0-1/MissingSpecialMemberFunction.expected @@ -1,2 +1,8 @@ | test.cpp:12:7:12:8 | C3 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:12:7:12:8 | C3 | C3 | | test.cpp:28:7:28:8 | C5 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:28:7:28:8 | C5 | C5 | +| test.cpp:51:7:51:9 | C10 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:51:7:51:9 | C10 | C10 | +| test.cpp:55:7:55:9 | C11 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:55:7:55:9 | C11 | C11 | +| test.cpp:59:7:59:9 | C12 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:59:7:59:9 | C12 | C12 | +| test.cpp:63:7:63:9 | C13 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:63:7:63:9 | C13 | C13 | +| test.cpp:67:7:67:9 | C14 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:67:7:67:9 | C14 | C14 | +| test.cpp:71:7:71:9 | C15 | Class $@ has provided at least one user-defined special member function but is missing definitions for all five special member functions. | test.cpp:71:7:71:9 | C15 | C15 | diff --git a/cpp/autosar/test/rules/A12-0-1/test.cpp b/cpp/autosar/test/rules/A12-0-1/test.cpp index 71652633b4..4711420ce0 100644 --- a/cpp/autosar/test/rules/A12-0-1/test.cpp +++ b/cpp/autosar/test/rules/A12-0-1/test.cpp @@ -46,4 +46,65 @@ struct C7::C8 { // COMPLIANT struct C9 { // COMPLIANT C9() {} C9(int x) {} +}; + +class C10 { + ~C10() = default; // NON_COMPLIANT +}; + +class C11 { + ~C11() = delete; // NON_COMPLIANT +}; + +class C12 { + C12(C12 const &); // NON_COMPLIANT +}; + +class C13 { + C13(C13 const &) = default; // NON_COMPLIANT +}; + +class C14 { + C14(C14 const &) = delete; // NON_COMPLIANT +}; + +class C15 { + C15& operator=(C15 const &); // NON_COMPLIANT +}; + +template +class C16 { // COMPLIANT + C16() = default;}; + +template +class C17 { // COMPLIANT + C17() = default; + C17(C17 const &) = default; + C17(C17 &&) = default; + virtual ~C17() = default; + C17 &operator=(C17 const &) = default; + C17 &operator=(C17 &&) = default; +}; + +template +class C18 { // COMPLIANT + C18() = default; + C18(C18 const &) = delete; + C18(C18 &&) = delete; + virtual ~C18() = default; + C18 &operator=(C18 const &) = delete; + C18 &operator=(C18 &&) = delete; +}; + +template +class C19 { // COMPLIANT + public: + explicit C19(T i) : i(i) {} + C19(C19 const &) = delete; + C19(C19 &&) = delete; + virtual ~C19() = default; + C19 &operator=(C19 const &) = delete; + C19 &operator=(C19 &&) = delete; + private: + T i; }; \ No newline at end of file From 01d32f0cbf4c2bfe16d5e4a40fdaa7bbcb68638a Mon Sep 17 00:00:00 2001 From: Remco Vermeulen Date: Thu, 18 Jan 2024 18:29:19 -0800 Subject: [PATCH 002/628] Fix test file formatting --- cpp/autosar/test/rules/A12-0-1/test.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/cpp/autosar/test/rules/A12-0-1/test.cpp b/cpp/autosar/test/rules/A12-0-1/test.cpp index 4711420ce0..9a38204641 100644 --- a/cpp/autosar/test/rules/A12-0-1/test.cpp +++ b/cpp/autosar/test/rules/A12-0-1/test.cpp @@ -69,15 +69,14 @@ class C14 { }; class C15 { - C15& operator=(C15 const &); // NON_COMPLIANT + C15 &operator=(C15 const &); // NON_COMPLIANT }; -template -class C16 { // COMPLIANT - C16() = default;}; +template class C16 { // COMPLIANT + C16() = default; +}; -template -class C17 { // COMPLIANT +template class C17 { // COMPLIANT C17() = default; C17(C17 const &) = default; C17(C17 &&) = default; @@ -86,8 +85,7 @@ class C17 { // COMPLIANT C17 &operator=(C17 &&) = default; }; -template -class C18 { // COMPLIANT +template class C18 { // COMPLIANT C18() = default; C18(C18 const &) = delete; C18(C18 &&) = delete; @@ -96,15 +94,15 @@ class C18 { // COMPLIANT C18 &operator=(C18 &&) = delete; }; -template -class C19 { // COMPLIANT - public: +template class C19 { // COMPLIANT +public: explicit C19(T i) : i(i) {} C19(C19 const &) = delete; C19(C19 &&) = delete; virtual ~C19() = default; C19 &operator=(C19 const &) = delete; C19 &operator=(C19 &&) = delete; - private: - T i; + +private: + T i; }; \ No newline at end of file From 84f007e427f3112442deeb7772f7cdcf2d694ce6 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 30 Jan 2024 09:23:41 +0000 Subject: [PATCH 003/628] Contracts: add metadata. --- .../cpp/exclusions/c/Contracts.qll | 61 +++++++++++++++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + rule_packages/c/Contracts.json | 65 +++++++++++++++++++ rule_packages/cpp/Expressions.json | 1 + 4 files changed, 130 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Contracts.qll create mode 100644 rule_packages/c/Contracts.json diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts.qll new file mode 100644 index 0000000000..32a44a4355 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts.qll @@ -0,0 +1,61 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype ContractsQuery = + TDoNotViolateInLineLinkageConstraintsQuery() or + TCheckMathLibraryFunctionParametersQuery() or + TFunctionErrorInformationUntestedQuery() + +predicate isContractsQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `doNotViolateInLineLinkageConstraints` query + ContractsPackage::doNotViolateInLineLinkageConstraintsQuery() and + queryId = + // `@id` for the `doNotViolateInLineLinkageConstraints` query + "c/cert/do-not-violate-in-line-linkage-constraints" and + ruleId = "MSC40-C" and + category = "rule" + or + query = + // `Query` instance for the `checkMathLibraryFunctionParameters` query + ContractsPackage::checkMathLibraryFunctionParametersQuery() and + queryId = + // `@id` for the `checkMathLibraryFunctionParameters` query + "c/misra/check-math-library-function-parameters" and + ruleId = "DIR-4-11" and + category = "required" + or + query = + // `Query` instance for the `functionErrorInformationUntested` query + ContractsPackage::functionErrorInformationUntestedQuery() and + queryId = + // `@id` for the `functionErrorInformationUntested` query + "c/misra/function-error-information-untested" and + ruleId = "DIR-4-7" and + category = "required" +} + +module ContractsPackage { + Query doNotViolateInLineLinkageConstraintsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotViolateInLineLinkageConstraints` query + TQueryC(TContractsPackageQuery(TDoNotViolateInLineLinkageConstraintsQuery())) + } + + Query checkMathLibraryFunctionParametersQuery() { + //autogenerate `Query` type + result = + // `Query` type for `checkMathLibraryFunctionParameters` query + TQueryC(TContractsPackageQuery(TCheckMathLibraryFunctionParametersQuery())) + } + + Query functionErrorInformationUntestedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `functionErrorInformationUntested` query + TQueryC(TContractsPackageQuery(TFunctionErrorInformationUntestedQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index c2771f4171..6425f27e28 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -9,6 +9,7 @@ import Concurrency2 import Concurrency3 import Concurrency4 import Concurrency5 +import Contracts import Contracts1 import Contracts2 import Contracts3 @@ -80,6 +81,7 @@ newtype TCQuery = TConcurrency3PackageQuery(Concurrency3Query q) or TConcurrency4PackageQuery(Concurrency4Query q) or TConcurrency5PackageQuery(Concurrency5Query q) or + TContractsPackageQuery(ContractsQuery q) or TContracts1PackageQuery(Contracts1Query q) or TContracts2PackageQuery(Contracts2Query q) or TContracts3PackageQuery(Contracts3Query q) or @@ -151,6 +153,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isConcurrency3QueryMetadata(query, queryId, ruleId, category) or isConcurrency4QueryMetadata(query, queryId, ruleId, category) or isConcurrency5QueryMetadata(query, queryId, ruleId, category) or + isContractsQueryMetadata(query, queryId, ruleId, category) or isContracts1QueryMetadata(query, queryId, ruleId, category) or isContracts2QueryMetadata(query, queryId, ruleId, category) or isContracts3QueryMetadata(query, queryId, ruleId, category) or diff --git a/rule_packages/c/Contracts.json b/rule_packages/c/Contracts.json new file mode 100644 index 0000000000..e2239908f0 --- /dev/null +++ b/rule_packages/c/Contracts.json @@ -0,0 +1,65 @@ +{ + "CERT-C": { + "MSC40-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Inlined external functions are prohibited by the language standard from defining modifiable static or thread storage objects, or referencing identifiers with internal linkage.", + "kind": "problem", + "name": "Do not violate inline linkage constraints", + "precision": "very-high", + "severity": "error", + "short_name": "DoNotViolateInLineLinkageConstraints", + "tags": [ + "correctness" + ] + } + ], + "title": "Do not violate constraints" + } + }, + "MISRA-C-2012": { + "DIR-4-11": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Range, domain or pole errors in math functions may return unexpected values, trigger floating-point exceptions or set unexpected error modes.", + "kind": "problem", + "name": "The validity of values passed to `math.h` library functions shall be checked", + "precision": "high", + "severity": "error", + "short_name": "CheckMathLibraryFunctionParameters", + "shared_implementation_short_name": "UncheckedRangeDomainPoleErrors", + "tags": [ + "correctness" + ] + } + ], + "title": "The validity of values passed to library functions shall be checked" + }, + "DIR-4-7": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "A function (whether it is part of the standard library, a third party library or a user defined function) may provide some means of indicating the occurrence of an error. This may be via a global error flag, a parametric error flag, a special return value or some other means. Whenever such a mechanism is provided by a function the calling program shall check for the indication of an error as soon as the function returns.", + "kind": "problem", + "name": "If a function generates error information, then that error information shall be tested", + "precision": "very-high", + "severity": "recommendation", + "short_name": "FunctionErrorInformationUntested", + "shared_implementation_short_name": "FunctionErroneousReturnValueNotTested", + "tags": [ + "maintainability" + ] + } + ], + "title": "If a function returns error information, then that error information shall be tested" + } + } +} \ No newline at end of file diff --git a/rule_packages/cpp/Expressions.json b/rule_packages/cpp/Expressions.json index c0a7b6bb0b..5668c78a0a 100644 --- a/rule_packages/cpp/Expressions.json +++ b/rule_packages/cpp/Expressions.json @@ -86,6 +86,7 @@ "precision": "very-high", "severity": "recommendation", "short_name": "FunctionErroneousReturnValueNotTested", + "shared_implementation_short_name": "FunctionErroneousReturnValueNotTested", "tags": [ "maintainability" ] From 52bdbd7f536c723267489f8822d8c81a99db96e2 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 30 Jan 2024 09:33:15 +0000 Subject: [PATCH 004/628] MSC40-C: Add query for finding inline linkage constraints. Adds a query that finds cases where extern inlined functions reference internal linkage objects, or declare objects which are static or thread local. --- .../DoNotViolateInLineLinkageConstraints.md | 210 ++++++++++++++++++ .../DoNotViolateInLineLinkageConstraints.ql | 59 +++++ ...otViolateInLineLinkageConstraints.expected | 6 + ...DoNotViolateInLineLinkageConstraints.qlref | 1 + c/cert/test/rules/MSC40-C/test.c | 31 +++ 5 files changed, 307 insertions(+) create mode 100644 c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.md create mode 100644 c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.ql create mode 100644 c/cert/test/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.expected create mode 100644 c/cert/test/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.qlref create mode 100644 c/cert/test/rules/MSC40-C/test.c diff --git a/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.md b/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.md new file mode 100644 index 0000000000..26545fb812 --- /dev/null +++ b/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.md @@ -0,0 +1,210 @@ +# MSC40-C: Do not violate inline linkage constraints + +This query implements the CERT-C rule MSC40-C: + +> Do not violate constraints + + +## Description + +According to the C Standard, 3.8 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO%2FIEC9899-2011)\], a constraint is a "restriction, either syntactic or semantic, by which the exposition of language elements is to be interpreted." Despite the similarity of the terms, a runtime constraint is not a kind of constraint. + +Violating any *shall* statement within a constraint clause in the C Standard requires an [implementation](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation) to issue a diagnostic message, the C Standard, 5.1.1.3 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO%2FIEC9899-2011)\] states + +> A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined. Diagnostic messages need not be produced in other circumstances. + + +The C Standard further explains in a footnote + +> The intent is that an implementation should identify the nature of, and where possible localize, each violation. Of course, an implementation is free to produce any number of diagnostics as long as a valid program is still correctly translated. It may also successfully translate an invalid program. + + +Any constraint violation is a violation of this rule because it can result in an invalid program. + +## Noncompliant Code Example (Inline, Internal Linkage) + +The C Standard, 6.7.4, paragraph 3 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO%2FIEC9899-2011)\], states + +> An inline definition of a function with external linkage shall not contain a definition of a modifiable object with static or thread storage duration, and shall not contain a reference to an identifier with internal linkage. + + +The motivation behind this constraint lies in the semantics of inline definitions. Paragraph 7 of subclause 6.7.4 reads, in part: + +> An inline definition provides an alternative to an external definition, which a translator may use to implement any call to the function in the same translation unit. It is unspecified whether a call to the function uses the inline definition or the external definition. + + +That is, if a function has an external and inline definition, implementations are free to choose which definition to invoke (two distinct invocations of the function may call different definitions, one the external definition, the other the inline definition). Therefore, issues can arise when these definitions reference internally linked objects or mutable objects with static or thread storage duration. + +This noncompliant code example refers to a static variable with file scope and internal linkage from within an external inline function: + +```cpp +static int I = 12; +extern inline void func(int a) { + int b = a * I; + /* ... */ +} + +``` + +## Compliant Solution (Inline, Internal Linkage) + +This compliant solution omits the `static` qualifier; consequently, the variable `I` has external linkage by default: + +```cpp +int I = 12; +extern inline void func(int a) { + int b = a * I; + /* ... */ +} + +``` + +## Noncompliant Code Example (inline, Modifiable Static) + +This noncompliant code example defines a modifiable `static` variable within an `extern inline` function. + +```cpp +extern inline void func(void) { + static int I = 12; + /* Perform calculations which may modify I */ +} + +``` + +## Compliant Solution (Inline, Modifiable Static) + +This compliant solution removes the `static` keyword from the local variable definition. If the modifications to `I` must be retained between invocations of `func()`, it must be declared at file scope so that it will be defined with external linkage. + +```cpp +extern inline void func(void) { + int I = 12; + /* Perform calculations which may modify I */ +} +``` + +## Noncompliant Code Example (Inline, Modifiable static) + +This noncompliant code example includes two translation units: `file1.c` and `file2.c`. The first file, `file1.c`, defines a pseudorandom number generation function: + +```cpp +/* file1.c */ + +/* Externally linked definition of the function get_random() */ +extern unsigned int get_random(void) { + /* Initialize the seeds */ + static unsigned int m_z = 0xdeadbeef; + static unsigned int m_w = 0xbaddecaf; + + /* Compute the next pseudorandom value and update the seeds */ + m_z = 36969 * (m_z & 65535) + (m_z >> 16); + m_w = 18000 * (m_w & 65535) + (m_w >> 16); + return (m_z << 16) + m_w; +} + +``` +The left-shift operation in the last line may wrap, but this is permitted by exception INT30-C-EX3 to rule [INT30-C. Ensure that unsigned integer operations do not wrap](https://wiki.sei.cmu.edu/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap). + +The second file, `file2.c`, defines an `inline` version of this function that references mutable `static` objects—namely, objects that maintain the state of the pseudorandom number generator. Separate invocations of the `get_random()` function can call different definitions, each operating on separate static objects, resulting in a faulty pseudorandom number generator. + +```cpp +/* file2.c */ + +/* Inline definition of get_random function */ +inline unsigned int get_random(void) { + /* + * Initialize the seeds + * Constraint violation: static duration storage referenced + * in non-static inline definition + */ + static unsigned int m_z = 0xdeadbeef; + static unsigned int m_w = 0xbaddecaf; + + /* Compute the next pseudorandom value and update the seeds */ + m_z = 36969 * (m_z & 65535) + (m_z >> 16); + m_w = 18000 * (m_w & 65535) + (m_w >> 16); + return (m_z << 16) + m_w; +} + +int main(void) { + unsigned int rand_no; + for (int ii = 0; ii < 100; ii++) { + /* + * Get a pseudorandom number. Implementation defined whether the + * inline definition in this file or the external definition + * in file2.c is called. + */ + rand_no = get_random(); + /* Use rand_no... */ + } + + /* ... */ + + /* + * Get another pseudorandom number. Behavior is + * implementation defined. + */ + rand_no = get_random(); + /* Use rand_no... */ + return 0; +} + +``` + +## Compliant Solution (Inline, Modifiable static) + +This compliant solution adds the `static` modifier to the `inline` function definition in `file2.c`, giving it internal linkage. All references to `get_random()` in `file.2.c` will now reference the internally linked definition. The first file, which was not changed, is not shown here. + +```cpp +/* file2.c */ + +/* Static inline definition of get_random function */ +static inline unsigned int get_random(void) { + /* + * Initialize the seeds. + * No more constraint violation; the inline function is now + * internally linked. + */ + static unsigned int m_z = 0xdeadbeef; + static unsigned int m_w = 0xbaddecaf; + + /* Compute the next pseudorandom value and update the seeds */ + m_z = 36969 * (m_z & 65535) + (m_z >> 16); + m_w = 18000 * (m_w & 65535) + (m_w >> 16); + return (m_z << 16) + m_w; +} + +int main(void) { + /* Generate pseudorandom numbers using get_random()... */ + return 0; +} + +``` + +## Risk Assessment + +Constraint violations are a broad category of error that can result in unexpected control flow and corrupted data. + +
Rule Severity Likelihood Remediation Cost Priority Level
MSC40-C Low Unlikely Medium P2 L3
+ + +## Automated Detection + +
Tool Version Checker Description
Astrée 23.04 alignas-extended assignment-to-non-modifiable-lvalue cast-pointer-void-arithmetic-implicit element-type-incomplete function-pointer-integer-cast-implicit function-return-type inappropriate-pointer-cast-implicit incompatible-function-pointer-conversion incompatible-object-pointer-conversion initializer-excess invalid-array-size non-constant-static-assert parameter-match-type pointer-integral-cast-implicit pointer-qualifier-cast-const-implicit pointer-qualifier-cast-volatile-implicit redeclaration return-empty return-non-empty static-assert type-compatibility type-compatibility-link type-specifier undeclared-parameter unnamed-parameter Partially checked
Helix QAC 2023.4 C0232, C0233, C0244, C0268, C0321, C0322, C0338, C0422, C0423, C0426, C0427, C0429, C0430, C0431, C0432, C0435, C0436, C0437, C0446, C0447, C0448, C0449, C0451, C0452, C0453, C0454, C0456, C0457, C0458, C0460, C0461, C0462, C0463, C0466, C0467, C0468, C0469, C0476, C0477, C0478, C0481, C0482, C0483, C0484, C0485, C0486, C0487, C0493, C0494, C0495, C0496, C0497, C0513, C0514, C0515, C0536, C0537, C0540, C0541, C0542, C0546, C0547, C0550, C0554, C0555, C0556, C0557, C0558, C0559, C0560, C0561, C0562, C0563, C0564, C0565, C0580, C0588, C0589, C0590, C0591, C0605, C0616, C0619, C0620, C0621, C0622, C0627, C0628, C0629, C0631, C0638, C0640, C0641, C0642, C0643, C0644, C0645, C0646, C0649, C0650, C0651, C0653, C0655, C0656, C0657, C0659, C0664, C0665, C0669, C0671, C0673, C0674, C0675, C0677, C0682, C0683, C0684, C0685, C0690, C0698, C0699, C0708, C0709, C0736, C0737, C0738, C0746, C0747, C0755, C0756, C0757, C0758, C0766, C0767, C0768, C0774, C0775, C0801, C0802, C0803, C0804, C0811, C0821, C0834, C0835, C0844, C0845, C0851, C0852, C0866, C0873, C0877, C0940, C0941, C0943, C0944, C1023, C1024, C1025, C1033, C1047, C1048, C1050, C1061, C1062, C3236, C3237, C3238, C3244 C++4122
Klocwork 2023.4 MISRA.FUNC.STATIC.REDECL
LDRA tool suite 9.7.1 21 S, 145 S, 323 S, 345 S, 387 S, 404 S, 481 S, 580 S, 612 S, 615 S, 646 S
Parasoft C/C++test 2023.1 CERT_C-MSC40-a An inline definition of a function with external linkage shall not contain definitions and uses of static objects
Polyspace Bug Finder CERT C: Rule MSC40-C Checks for inline constraint not respected (rule partially covered)
RuleChecker 23.04 alignas-extended assignment-to-non-modifiable-lvalue cast-pointer-void-arithmetic-implicit element-type-incomplete function-pointer-integer-cast-implicit function-return-type inappropriate-pointer-cast-implicit incompatible-function-pointer-conversion incompatible-object-pointer-conversion initializer-excess invalid-array-size non-constant-static-assert parameter-match-type pointer-integral-cast-implicit pointer-qualifier-cast-const-implicit pointer-qualifier-cast-volatile-implicit redeclaration return-empty return-non-empty static-assert type-compatibility type-compatibility-link type-specifier undeclared-parameter unnamed-parameter Partially checked
+ + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+MSC40-C). + +## Bibliography + +
\[ ISO/IEC 9899:2011 \] 4, "Conformance" 5.1.1.3, "Diagnostics" 6.7.4, "Function Specifiers"
+ + +## Implementation notes + +None + +## References + +* CERT-C: [MSC40-C: Do not violate constraints](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.ql b/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.ql new file mode 100644 index 0000000000..63dec179c6 --- /dev/null +++ b/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.ql @@ -0,0 +1,59 @@ +/** + * @id c/cert/do-not-violate-in-line-linkage-constraints + * @name MSC40-C: Do not violate inline linkage constraints + * @description Inlined external functions are prohibited by the language standard from defining + * modifiable static or thread storage objects, or referencing identifiers with + * internal linkage. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/msc40-c + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.Linkage + +/* + * This is C specific, because in C++ all extern function definitions must be identical. + * Only in C is it permitted for an extern function to be defined in multiple translation + * units with different implementations, when using the inline keyword. + */ + +from Element accessOrDecl, Variable v, Function f, string message +where + not isExcluded(f, ContractsPackage::doNotViolateInLineLinkageConstraintsQuery()) and + f.isInline() and + hasExternalLinkage(f) and + // Pre-emptively exclude compiler generated functions + not f.isCompilerGenerated() and + // This rule does not apply to C++, but exclude C++ specific cases anyway + not f instanceof MemberFunction and + not f.isFromUninstantiatedTemplate(_) and + ( + // There exists a modifiable local variable which is static or thread local + exists(LocalVariable lsv, string storageModifier | + lsv.isStatic() and storageModifier = "Static" + or + lsv.isThreadLocal() and storageModifier = "Thread-local" + | + lsv.getFunction() = f and + not lsv.isConst() and + accessOrDecl = lsv and + message = storageModifier + " local variable $@ declared" and + v = lsv + ) + or + // References an identifier with internal linkage + exists(GlobalOrNamespaceVariable gv | + accessOrDecl = v.getAnAccess() and + accessOrDecl.(VariableAccess).getEnclosingFunction() = f and + hasInternalLinkage(v) and + message = "Identifier $@ with internal linkage referenced" and + v = gv + ) + ) +select accessOrDecl, message + " in the extern inlined function $@.", v, v.getName(), f, + f.getQualifiedName() diff --git a/c/cert/test/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.expected b/c/cert/test/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.expected new file mode 100644 index 0000000000..f258d4adef --- /dev/null +++ b/c/cert/test/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.expected @@ -0,0 +1,6 @@ +| test.c:6:14:6:14 | i | Static local variable $@ declared in the extern inlined function $@. | test.c:6:14:6:14 | i | i | test.c:5:20:5:24 | test1 | test1 | +| test.c:7:3:7:4 | g1 | Identifier $@ with internal linkage referenced in the extern inlined function $@. | test.c:1:12:1:13 | g1 | g1 | test.c:5:20:5:24 | test1 | test1 | +| test.c:9:3:9:4 | g3 | Identifier $@ with internal linkage referenced in the extern inlined function $@. | test.c:3:11:3:12 | g3 | g3 | test.c:5:20:5:24 | test1 | test1 | +| test.c:27:14:27:14 | i | Static local variable $@ declared in the extern inlined function $@. | test.c:27:14:27:14 | i | i | test.c:26:13:26:17 | test4 | test4 | +| test.c:28:3:28:4 | g1 | Identifier $@ with internal linkage referenced in the extern inlined function $@. | test.c:1:12:1:13 | g1 | g1 | test.c:26:13:26:17 | test4 | test4 | +| test.c:30:3:30:4 | g3 | Identifier $@ with internal linkage referenced in the extern inlined function $@. | test.c:3:11:3:12 | g3 | g3 | test.c:26:13:26:17 | test4 | test4 | diff --git a/c/cert/test/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.qlref b/c/cert/test/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.qlref new file mode 100644 index 0000000000..f14d4270cc --- /dev/null +++ b/c/cert/test/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.qlref @@ -0,0 +1 @@ +rules/MSC40-C/DoNotViolateInLineLinkageConstraints.ql \ No newline at end of file diff --git a/c/cert/test/rules/MSC40-C/test.c b/c/cert/test/rules/MSC40-C/test.c new file mode 100644 index 0000000000..3ca4afff4a --- /dev/null +++ b/c/cert/test/rules/MSC40-C/test.c @@ -0,0 +1,31 @@ +static int g1 = 0; +extern int g2 = 1; +const int g3 = 1; // defaults to internal linkage + +extern inline void test1() { + static int i = 0; // NON_COMPLIANT + g1++; // NON_COMPLIANT + g2++; // COMPLIANT + g3; // NON_COMPLIANT +} + +extern void test2() { + static int i = 0; // COMPLIANT + g1++; // COMPLIANT + g2++; // COMPLIANT + g3; // COMPLIANT +} + +void test3() { + static int i = 0; // COMPLIANT + g1++; // COMPLIANT + g2++; // COMPLIANT + g3; // COMPLIANT +} + +inline void test4() { + static int i = 0; // NON_COMPLIANT + g1++; // NON_COMPLIANT + g2++; // COMPLIANT + g3; // NON_COMPLIANT +} \ No newline at end of file From dcb32c1a017b50a1602a8d3e2e8afbf35ef0e534 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 30 Jan 2024 09:44:43 +0000 Subject: [PATCH 005/628] DIR-4-11: Add query for checking math.h functions Add query which detects domain and pole errors for math.h functions. --- .../CheckMathLibraryFunctionParameters.ql | 22 +++++++++++++++++++ ...CheckMathLibraryFunctionParameters.testref | 1 + 2 files changed, 23 insertions(+) create mode 100644 c/misra/src/rules/DIR-4-11/CheckMathLibraryFunctionParameters.ql create mode 100644 c/misra/test/rules/DIR-4-11/CheckMathLibraryFunctionParameters.testref diff --git a/c/misra/src/rules/DIR-4-11/CheckMathLibraryFunctionParameters.ql b/c/misra/src/rules/DIR-4-11/CheckMathLibraryFunctionParameters.ql new file mode 100644 index 0000000000..6810784a0e --- /dev/null +++ b/c/misra/src/rules/DIR-4-11/CheckMathLibraryFunctionParameters.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/check-math-library-function-parameters + * @name DIR-4-11: The validity of values passed to `math.h` library functions shall be checked + * @description Range, domain or pole errors in math functions may return unexpected values, trigger + * floating-point exceptions or set unexpected error modes. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/dir-4-11 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.uncheckedrangedomainpoleerrors.UncheckedRangeDomainPoleErrors + +class CheckMathLibraryFunctionParametersQuery extends UncheckedRangeDomainPoleErrorsSharedQuery { + CheckMathLibraryFunctionParametersQuery() { + this = ContractsPackage::checkMathLibraryFunctionParametersQuery() + } +} diff --git a/c/misra/test/rules/DIR-4-11/CheckMathLibraryFunctionParameters.testref b/c/misra/test/rules/DIR-4-11/CheckMathLibraryFunctionParameters.testref new file mode 100644 index 0000000000..50cf3fcb51 --- /dev/null +++ b/c/misra/test/rules/DIR-4-11/CheckMathLibraryFunctionParameters.testref @@ -0,0 +1 @@ +c/common/test/rules/uncheckedrangedomainpoleerrors/UncheckedRangeDomainPoleErrors.ql \ No newline at end of file From 377124004116573572197eabd39ceb905e8b5e30 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 30 Jan 2024 09:47:55 +0000 Subject: [PATCH 006/628] DIR-4-7: Create shared query for unchecked return values Create a new shared query from the implementation of M0-3-2, which detects cases where error checking has not occurred after a call to a standard C library function. --- ...tionErroneousReturnValueNotTested.expected | 1 + .../FunctionErroneousReturnValueNotTested.ql | 4 ++ .../test.c | 0 .../FunctionErrorInformationUntested.ql | 26 ++++++++ .../FunctionErrorInformationUntested.testref | 1 + .../FunctionErroneousReturnValueNotTested.ql | 57 +++-------------- ...unctionErroneousReturnValueNotTested.qlref | 1 - .../FunctionErroneousReturnValueNotTested.qll | 62 +++++++++++++++++++ ...tionErroneousReturnValueNotTested.expected | 0 .../FunctionErroneousReturnValueNotTested.ql | 4 ++ .../test.cpp | 17 +++++ 11 files changed, 122 insertions(+), 51 deletions(-) create mode 100644 c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected create mode 100644 c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql rename cpp/autosar/test/rules/M0-3-2/test.cpp => c/common/test/rules/functionerroneousreturnvaluenottested/test.c (100%) create mode 100644 c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql create mode 100644 c/misra/test/rules/DIR-4-7/FunctionErrorInformationUntested.testref delete mode 100644 cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.qlref create mode 100644 cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll rename cpp/{autosar/test/rules/M0-3-2 => common/test/rules/functionerroneousreturnvaluenottested}/FunctionErroneousReturnValueNotTested.expected (100%) create mode 100644 cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql create mode 100644 cpp/common/test/rules/functionerroneousreturnvaluenottested/test.cpp diff --git a/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected b/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected new file mode 100644 index 0000000000..015f52348c --- /dev/null +++ b/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected @@ -0,0 +1 @@ +| test.c:16:3:16:8 | call to remove | Return value is not tested for errors. | diff --git a/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql b/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql new file mode 100644 index 0000000000..12c2196efd --- /dev/null +++ b/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.functionerroneousreturnvaluenottested.FunctionErroneousReturnValueNotTested + +class TestFileQuery extends FunctionErroneousReturnValueNotTestedSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M0-3-2/test.cpp b/c/common/test/rules/functionerroneousreturnvaluenottested/test.c similarity index 100% rename from cpp/autosar/test/rules/M0-3-2/test.cpp rename to c/common/test/rules/functionerroneousreturnvaluenottested/test.c diff --git a/c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql b/c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql new file mode 100644 index 0000000000..b827e101e3 --- /dev/null +++ b/c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql @@ -0,0 +1,26 @@ +/** + * @id c/misra/function-error-information-untested + * @name DIR-4-7: If a function generates error information, then that error information shall be tested + * @description A function (whether it is part of the standard library, a third party library or a + * user defined function) may provide some means of indicating the occurrence of an + * error. This may be via a global error flag, a parametric error flag, a special + * return value or some other means. Whenever such a mechanism is provided by a + * function the calling program shall check for the indication of an error as soon as + * the function returns. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/dir-4-7 + * maintainability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.functionerroneousreturnvaluenottested.FunctionErroneousReturnValueNotTested + +class FunctionErrorInformationUntestedQuery extends FunctionErroneousReturnValueNotTestedSharedQuery { + FunctionErrorInformationUntestedQuery() { + this = ContractsPackage::functionErrorInformationUntestedQuery() + } +} diff --git a/c/misra/test/rules/DIR-4-7/FunctionErrorInformationUntested.testref b/c/misra/test/rules/DIR-4-7/FunctionErrorInformationUntested.testref new file mode 100644 index 0000000000..51bd5fbefb --- /dev/null +++ b/c/misra/test/rules/DIR-4-7/FunctionErrorInformationUntested.testref @@ -0,0 +1 @@ +c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql \ No newline at end of file diff --git a/cpp/autosar/src/rules/M0-3-2/FunctionErroneousReturnValueNotTested.ql b/cpp/autosar/src/rules/M0-3-2/FunctionErroneousReturnValueNotTested.ql index aee4e40838..77e6278960 100644 --- a/cpp/autosar/src/rules/M0-3-2/FunctionErroneousReturnValueNotTested.ql +++ b/cpp/autosar/src/rules/M0-3-2/FunctionErroneousReturnValueNotTested.ql @@ -19,54 +19,11 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow -import semmle.code.cpp.controlflow.Guards +import codingstandards.cpp.rules.functionerroneousreturnvaluenottested.FunctionErroneousReturnValueNotTested -from FunctionCall fc -where - not isExcluded(fc, ExpressionsPackage::functionErroneousReturnValueNotTestedQuery()) and - fc.getTarget() - .hasGlobalOrStdName([ - // fcntl.h - "open", "openat", "fcntl", "creat", - // locale.h - "setlocale", - // stdlib.h - "system", "getenv", "getenv_s", - // signal.h - "signal", "raise", - // setjmp.h - "setjmp", - // stdio.h - "fopen", "fopen_s", "freopen", "freopen_s", "fclose", "fcloseall", "fflush", "setvbuf", - "fgetc", "getc", "fgets", "fputc", "getchar", "gets", "gets_s", "putchar", "puts", - "ungetc", "scanf", "fscanf", "sscanf", "scanf_s", "fscanf_s", "sscanf_s", "vscanf", - "vfscanf", "vsscanf", "vscanf_s", "vfscanf_s", "vsscanf_s", "printf", "fprintf", - "sprintf", "snprintf", "printf_s", "fprintf_s", "sprintf_s", "snprintf_s", "vprintf", - "vfprintf", "vsprintf", "vsnprintf", "vprintf_s", "vfprintf_s", "vsprintf_s", - "vsnprintf_s", "ftell", "fgetpos", "fseek", "fsetpos", "remove", "rename", "tmpfile", - "tmpfile_s", "tmpnam", "tmpnam_s", - // string.h - "strcpy_s", "strncpy_s", "strcat_s", "strncat_s", "memset_s", "memcpy_s", "memmove_s", - "strerror_s", - // threads.h - "thrd_create", "thrd_sleep", "thrd_detach", "thrd_join", "mtx_init", "mtx_lock", - "mtx_timedlock", "mtx_trylock", "mtx_unlock", "cnd_init", "cnd_signal", "cnd_broadcast", - "cnd_wait", "cnd_timedwait", "tss_create", "tss_get", "tss_set", - // time.h - "time", "clock", "timespec_get", "asctime_s", "ctime_s", "gmtime", "gmtime_s", - "localtime", "localtime_s", - // unistd.h - "write", "read", "close", "unlink", - // wchar.h - "fgetwc", "getwc", "fgetws", "fputwc", "putwc", "fputws", "getwchar", "putwchar", - "ungetwc", "wscanf", "fwscanf", "swscanf", "wscanf_s", "fwscanf_s", "swscanf_s", - "vwscanf", "vfwscanf", "vswscanf", "vwscanf_s", "vfwscanf_s", "vswscanf_s", "wprintf", - "fwprintf", "swprintf", "wprintf_s", "fwprintf_s", "swprintf_s", "snwprintf_s", - "vwprintf", "vfwprintf", "vswprintf", "vwprintf_s", "vfwprintf_s", "vswprintf_s", - "vsnwprintf_s" - ]) and - forall(GuardCondition gc | - not DataFlow::localFlow(DataFlow::exprNode(fc), DataFlow::exprNode(gc.getAChild*())) - ) -select fc, "Return value is not tested for errors." +class FunctionErrorInformationUntestedQuery extends FunctionErroneousReturnValueNotTestedSharedQuery +{ + FunctionErrorInformationUntestedQuery() { + this = ExpressionsPackage::functionErroneousReturnValueNotTestedQuery() + } +} diff --git a/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.qlref b/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.qlref deleted file mode 100644 index 3cfea1dc31..0000000000 --- a/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M0-3-2/FunctionErroneousReturnValueNotTested.ql \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll b/cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll new file mode 100644 index 0000000000..fe4f788847 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll @@ -0,0 +1,62 @@ +/** + * Provides a library which includes a `problems` predicate for reporting unchecked error values. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.controlflow.Guards +import codingstandards.cpp.Exclusions + +abstract class FunctionErroneousReturnValueNotTestedSharedQuery extends Query { } + +Query getQuery() { result instanceof FunctionErroneousReturnValueNotTestedSharedQuery } + +query predicate problems(FunctionCall fc, string message) { + not isExcluded(fc, getQuery()) and + fc.getTarget() + .hasGlobalOrStdName([ + // fcntl.h + "open", "openat", "fcntl", "creat", + // locale.h + "setlocale", + // stdlib.h + "system", "getenv", "getenv_s", + // signal.h + "signal", "raise", + // setjmp.h + "setjmp", + // stdio.h + "fopen", "fopen_s", "freopen", "freopen_s", "fclose", "fcloseall", "fflush", "setvbuf", + "fgetc", "getc", "fgets", "fputc", "getchar", "gets", "gets_s", "putchar", "puts", + "ungetc", "scanf", "fscanf", "sscanf", "scanf_s", "fscanf_s", "sscanf_s", "vscanf", + "vfscanf", "vsscanf", "vscanf_s", "vfscanf_s", "vsscanf_s", "printf", "fprintf", + "sprintf", "snprintf", "printf_s", "fprintf_s", "sprintf_s", "snprintf_s", "vprintf", + "vfprintf", "vsprintf", "vsnprintf", "vprintf_s", "vfprintf_s", "vsprintf_s", + "vsnprintf_s", "ftell", "fgetpos", "fseek", "fsetpos", "remove", "rename", "tmpfile", + "tmpfile_s", "tmpnam", "tmpnam_s", + // string.h + "strcpy_s", "strncpy_s", "strcat_s", "strncat_s", "memset_s", "memcpy_s", "memmove_s", + "strerror_s", + // threads.h + "thrd_create", "thrd_sleep", "thrd_detach", "thrd_join", "mtx_init", "mtx_lock", + "mtx_timedlock", "mtx_trylock", "mtx_unlock", "cnd_init", "cnd_signal", "cnd_broadcast", + "cnd_wait", "cnd_timedwait", "tss_create", "tss_get", "tss_set", + // time.h + "time", "clock", "timespec_get", "asctime_s", "ctime_s", "gmtime", "gmtime_s", + "localtime", "localtime_s", + // unistd.h + "write", "read", "close", "unlink", + // wchar.h + "fgetwc", "getwc", "fgetws", "fputwc", "putwc", "fputws", "getwchar", "putwchar", + "ungetwc", "wscanf", "fwscanf", "swscanf", "wscanf_s", "fwscanf_s", "swscanf_s", + "vwscanf", "vfwscanf", "vswscanf", "vwscanf_s", "vfwscanf_s", "vswscanf_s", "wprintf", + "fwprintf", "swprintf", "wprintf_s", "fwprintf_s", "swprintf_s", "snwprintf_s", + "vwprintf", "vfwprintf", "vswprintf", "vwprintf_s", "vfwprintf_s", "vswprintf_s", + "vsnwprintf_s" + ]) and + forall(GuardCondition gc | + not DataFlow::localFlow(DataFlow::exprNode(fc), DataFlow::exprNode(gc.getAChild*())) + ) and + message = "Return value is not tested for errors." +} diff --git a/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.expected b/cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected similarity index 100% rename from cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.expected rename to cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected diff --git a/cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql b/cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql new file mode 100644 index 0000000000..12c2196efd --- /dev/null +++ b/cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.functionerroneousreturnvaluenottested.FunctionErroneousReturnValueNotTested + +class TestFileQuery extends FunctionErroneousReturnValueNotTestedSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/functionerroneousreturnvaluenottested/test.cpp b/cpp/common/test/rules/functionerroneousreturnvaluenottested/test.cpp new file mode 100644 index 0000000000..08e2f23dec --- /dev/null +++ b/cpp/common/test/rules/functionerroneousreturnvaluenottested/test.cpp @@ -0,0 +1,17 @@ +#include + +void test_compliant() { + // Return value is passed to an lvalue and then tested. + FILE *fh = fopen("/etc/foo", "r"); + if (!fh) { // COMPLIANT + return; + } + + // Return value is tested immediately as an rvalue. + if (fclose(fh)) // COMPLIANT + return; +} + +void test_noncompliant() { + remove("/bin/bash"); // NON_COMPLIANT +} \ No newline at end of file From 81200896b07034ad5120918e91df6295f2d9feb0 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 30 Jan 2024 09:53:23 +0000 Subject: [PATCH 007/628] FunctionErroneousReturnValueNotTested rewritten for clarity --- .../FunctionErroneousReturnValueNotTested.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll b/cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll index fe4f788847..5cd98c05d6 100644 --- a/cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll +++ b/cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll @@ -55,8 +55,8 @@ query predicate problems(FunctionCall fc, string message) { "vwprintf", "vfwprintf", "vswprintf", "vwprintf_s", "vfwprintf_s", "vswprintf_s", "vsnwprintf_s" ]) and - forall(GuardCondition gc | - not DataFlow::localFlow(DataFlow::exprNode(fc), DataFlow::exprNode(gc.getAChild*())) + not exists(GuardCondition gc | + DataFlow::localFlow(DataFlow::exprNode(fc), DataFlow::exprNode(gc.getAChild*())) ) and message = "Return value is not tested for errors." } From 7e5ef5f8306fee09522415cfda8cf708d8a32ea0 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 30 Jan 2024 09:55:42 +0000 Subject: [PATCH 008/628] Add name of function to message. --- .../FunctionErroneousReturnValueNotTested.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll b/cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll index 5cd98c05d6..dd2f7d75e0 100644 --- a/cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll +++ b/cpp/common/src/codingstandards/cpp/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.qll @@ -58,5 +58,5 @@ query predicate problems(FunctionCall fc, string message) { not exists(GuardCondition gc | DataFlow::localFlow(DataFlow::exprNode(fc), DataFlow::exprNode(gc.getAChild*())) ) and - message = "Return value is not tested for errors." + message = "Return value from " + fc.getTarget().getName() + " is not tested for errors." } From a19855bd20ace838d2f7748f45de341e5e7b97ef Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 30 Jan 2024 10:02:11 +0000 Subject: [PATCH 009/628] Add implementation scope properties Specify the scope of each of the newly supported rules. --- rule_packages/c/Contracts.json | 15 ++++++++++++--- rule_packages/c/FloatingTypes.json | 5 ++++- rule_packages/cpp/Expressions.json | 5 ++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/rule_packages/c/Contracts.json b/rule_packages/c/Contracts.json index e2239908f0..735e84d9da 100644 --- a/rule_packages/c/Contracts.json +++ b/rule_packages/c/Contracts.json @@ -14,7 +14,10 @@ "short_name": "DoNotViolateInLineLinkageConstraints", "tags": [ "correctness" - ] + ], + "implementation_scope": { + "description": "This query only considers the constraints related to inline extern functions." + } } ], "title": "Do not violate constraints" @@ -36,7 +39,10 @@ "shared_implementation_short_name": "UncheckedRangeDomainPoleErrors", "tags": [ "correctness" - ] + ], + "implementation_scope": { + "description": "This query identifies possible domain, pole and range errors on a selection of C standard library fuctions from math.h." + } } ], "title": "The validity of values passed to library functions shall be checked" @@ -56,7 +62,10 @@ "shared_implementation_short_name": "FunctionErroneousReturnValueNotTested", "tags": [ "maintainability" - ] + ], + "implementation_scope": { + "description": "This query enforces checking on some C standard library functions that may return error codes." + } } ], "title": "If a function returns error information, then that error information shall be tested" diff --git a/rule_packages/c/FloatingTypes.json b/rule_packages/c/FloatingTypes.json index 1dfd663597..7df2298ad1 100644 --- a/rule_packages/c/FloatingTypes.json +++ b/rule_packages/c/FloatingTypes.json @@ -15,7 +15,10 @@ "shared_implementation_short_name": "UncheckedRangeDomainPoleErrors", "tags": [ "correctness" - ] + ], + "implementation_scope": { + "description": "This query identifies possible domain, pole and range errors on a selection of C standard library fuctions from math.h." + } } ], "title": "Prevent or detect domain and range errors in math functions" diff --git a/rule_packages/cpp/Expressions.json b/rule_packages/cpp/Expressions.json index 5668c78a0a..935c3fa6f1 100644 --- a/rule_packages/cpp/Expressions.json +++ b/rule_packages/cpp/Expressions.json @@ -89,7 +89,10 @@ "shared_implementation_short_name": "FunctionErroneousReturnValueNotTested", "tags": [ "maintainability" - ] + ], + "implementation_scope": { + "description": "The query enforces checking on some C standard library functions that may return error codes." + } } ], "title": "If a function generates error information, then that error information shall be tested." From 9b7102e149ad57a8b45f6b09b5df452d731f1f2c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 30 Jan 2024 10:03:21 +0000 Subject: [PATCH 010/628] Add change note. --- change_notes/2024-01-30-m0-3-2.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 change_notes/2024-01-30-m0-3-2.md diff --git a/change_notes/2024-01-30-m0-3-2.md b/change_notes/2024-01-30-m0-3-2.md new file mode 100644 index 0000000000..b074f6b2b1 --- /dev/null +++ b/change_notes/2024-01-30-m0-3-2.md @@ -0,0 +1 @@ + * `M0-3-2` - the alert messages now include the name of the called function. \ No newline at end of file From 78d5e793b66136c9ea7eec6c3da011d0af335011 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 30 Jan 2024 11:33:02 +0000 Subject: [PATCH 011/628] Add missing file. --- .../rules/M0-3-2/FunctionErroneousReturnValueNotTested.testref | 1 + 1 file changed, 1 insertion(+) create mode 100644 cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.testref diff --git a/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.testref b/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.testref new file mode 100644 index 0000000000..50847523ce --- /dev/null +++ b/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.testref @@ -0,0 +1 @@ +cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.ql \ No newline at end of file From 9776de1211801f333c827630352daf9bef931455 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 30 Jan 2024 12:58:50 +0000 Subject: [PATCH 012/628] Update expected result files. --- .../FunctionErroneousReturnValueNotTested.expected | 2 +- .../FunctionErroneousReturnValueNotTested.expected | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected b/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected index 015f52348c..dc72201a8a 100644 --- a/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected +++ b/c/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected @@ -1 +1 @@ -| test.c:16:3:16:8 | call to remove | Return value is not tested for errors. | +| test.c:16:3:16:8 | call to remove | Return value from remove is not tested for errors. | diff --git a/cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected b/cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected index 76cbcebed0..2f681c9210 100644 --- a/cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected +++ b/cpp/common/test/rules/functionerroneousreturnvaluenottested/FunctionErroneousReturnValueNotTested.expected @@ -1 +1 @@ -| test.cpp:16:3:16:8 | call to remove | Return value is not tested for errors. | +| test.cpp:16:3:16:8 | call to remove | Return value from remove is not tested for errors. | From af9226208ee43cb49f0940a36972be3061ca7c01 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 30 Jan 2024 13:00:51 +0000 Subject: [PATCH 013/628] Update rules.csv to exclude unimplemented contracts rules. --- rules.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rules.csv b/rules.csv index 20af9fbc01..9f4afac4fa 100644 --- a/rules.csv +++ b/rules.csv @@ -614,8 +614,8 @@ c,MISRA-C-2012,DIR-4-9,Yes,Advisory,,,A function should be used in preference to c,MISRA-C-2012,DIR-4-10,Yes,Required,,,Precautions shall be taken in order to prevent the contents of a header file being included more than once,M16-2-3,Preprocessor2,Medium, c,MISRA-C-2012,DIR-4-11,Yes,Required,,,The validity of values passed to library functions shall be checked,,Contracts,Hard, c,MISRA-C-2012,DIR-4-12,Yes,Required,,,Dynamic memory allocation shall not be used,,Banned,Medium, -c,MISRA-C-2012,DIR-4-13,Yes,Advisory,,,Functions which are designed to provide operations on a resource should be called in an appropriate sequence,,Contracts,Hard, -c,MISRA-C-2012,DIR-4-14,Yes,Required,,,The validity of values received from external sources shall be checked,,Contracts,Hard, +c,MISRA-C-2012,DIR-4-13,No,Advisory,,,Functions which are designed to provide operations on a resource should be called in an appropriate sequence,,,,Rule 22.1, 22.2 and 22.6 cover aspects of this rule. In other cases this is a design issue and needs to be checked manually. +c,MISRA-C-2012,DIR-4-14,Yes,Required,,,The validity of values received from external sources shall be checked,,Contracts9,Hard,This is supported by CodeQLs default C security queries. c,MISRA-C-2012,RULE-1-1,No,Required,,,"The program shall contain no violations of the standard C syntax and constraints, and shall not exceed the implementation's translation limits",,,Easy,"This should be checked via the compiler output, rather than CodeQL, which adds unnecessary steps." c,MISRA-C-2012,RULE-1-2,Yes,Advisory,,,Language extensions should not be used,,Language3,Hard, c,MISRA-C-2012,RULE-1-3,Yes,Required,,,There shall be no occurrence of undefined or critical unspecified behaviour,,Language3,Hard, From 3d2cd94fd92681127dbb38fa0833150a2536eb00 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 30 Jan 2024 13:13:14 +0000 Subject: [PATCH 014/628] Update documentation. --- c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.md | 2 +- .../src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.md b/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.md index d6427b9081..ca24a02498 100644 --- a/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.md +++ b/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.md @@ -345,7 +345,7 @@ Independent( INT34-C, FLP32-C, INT33-C) CWE-682 = Union( FLP32-C, list) where li ## Implementation notes -None +This query identifies possible domain, pole and range errors on a selection of C standard library fuctions from math.h. ## References diff --git a/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.md b/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.md index 26545fb812..f767c91baf 100644 --- a/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.md +++ b/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.md @@ -203,7 +203,7 @@ Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+D ## Implementation notes -None +This query only considers the constraints related to inline extern functions. ## References From bccdb93c2b7b0e2dcbe82feb134c0c0423ae9d81 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 30 Jan 2024 13:13:59 +0000 Subject: [PATCH 015/628] Fix formatting --- c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql b/c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql index b827e101e3..63236d422d 100644 --- a/c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql +++ b/c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql @@ -19,7 +19,8 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.rules.functionerroneousreturnvaluenottested.FunctionErroneousReturnValueNotTested -class FunctionErrorInformationUntestedQuery extends FunctionErroneousReturnValueNotTestedSharedQuery { +class FunctionErrorInformationUntestedQuery extends FunctionErroneousReturnValueNotTestedSharedQuery +{ FunctionErrorInformationUntestedQuery() { this = ContractsPackage::functionErrorInformationUntestedQuery() } From 337604e56719a36e6098e8b8b41114168e3ab39a Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 30 Jan 2024 13:14:37 +0000 Subject: [PATCH 016/628] Fix test formatting --- c/cert/test/rules/MSC40-C/test.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/c/cert/test/rules/MSC40-C/test.c b/c/cert/test/rules/MSC40-C/test.c index 3ca4afff4a..d892935d41 100644 --- a/c/cert/test/rules/MSC40-C/test.c +++ b/c/cert/test/rules/MSC40-C/test.c @@ -4,28 +4,28 @@ const int g3 = 1; // defaults to internal linkage extern inline void test1() { static int i = 0; // NON_COMPLIANT - g1++; // NON_COMPLIANT - g2++; // COMPLIANT - g3; // NON_COMPLIANT + g1++; // NON_COMPLIANT + g2++; // COMPLIANT + g3; // NON_COMPLIANT } extern void test2() { static int i = 0; // COMPLIANT - g1++; // COMPLIANT - g2++; // COMPLIANT - g3; // COMPLIANT + g1++; // COMPLIANT + g2++; // COMPLIANT + g3; // COMPLIANT } void test3() { static int i = 0; // COMPLIANT - g1++; // COMPLIANT - g2++; // COMPLIANT - g3; // COMPLIANT + g1++; // COMPLIANT + g2++; // COMPLIANT + g3; // COMPLIANT } inline void test4() { static int i = 0; // NON_COMPLIANT - g1++; // NON_COMPLIANT - g2++; // COMPLIANT - g3; // NON_COMPLIANT + g1++; // NON_COMPLIANT + g2++; // COMPLIANT + g3; // NON_COMPLIANT } \ No newline at end of file From 1f9bc6b4445ae3203a7c11e3ff6ecdfe5f16ed4f Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 13 Mar 2024 15:12:34 +0000 Subject: [PATCH 017/628] Remove the copy of DataFlow that was added in 6aee03ef5ac577d77fbf034a46a6637f31aefbee now that the 'absolute path' problem has been fixed. --- ...interArithmeticOnNonArrayObjectPointers.ql | 2 +- ...otAddOrSubtractAScaledIntegerToAPointer.ql | 2 +- .../CON30-C/CleanUpThreadSpecificStorage.ql | 4 +- ...AppropriateThreadObjectStorageDurations.ql | 4 +- ...eadObjectStorageDurationsNotInitialized.ql | 4 +- ...propriateStorageDurationsFunctionReturn.ql | 2 +- .../ERR30-C/FunctionCallBeforeErrnoCheck.ql | 2 +- ...nOrderOfFunctionArgumentsForSideEffects.ql | 4 +- ...PointerToMoreStrictlyAlignedPointerType.ql | 2 +- ...CallFunctionPointerWithIncompatibleType.ql | 2 +- ...essVariableViaPointerOfIncompatibleType.ql | 2 +- .../EXP40-C/DoNotModifyConstantObjects.ql | 2 +- ...sAliasedPointerToRestrictQualifiedParam.ql | 2 +- ...trictPointerReferencesOverlappingObject.ql | 2 +- ...sfulFgetsOrFgetwsMayReturnAnEmptyString.ql | 2 +- ...uesForFsetposThatAreReturnedFromFgetpos.ql | 2 +- ...ToctouRaceConditionsWhileAccessingFiles.ql | 2 +- .../InsufficientMemoryAllocatedForObject.ql | 2 +- ...DoNotModifyAlignmentOfMemoryWithRealloc.ql | 2 +- ...oNotPassInvalidDataToTheAsctimeFunction.ql | 2 +- ...ArgOnAVaListThatHasAnIndeterminateValue.ql | 2 +- ...yAsyncSafeFunctionsWithinSignalHandlers.ql | 2 +- ...eturnFromAComputationalExceptionHandler.ql | 2 +- .../DoNotAttemptToModifyStringLiterals.ql | 2 +- ...sHasSufficientSpaceForTheNullTerminator.ql | 2 +- ...lTerminatedToFunctionThatExpectsAString.ql | 2 +- c/common/src/codingstandards/c/Errno.qll | 2 +- .../src/codingstandards/c/OutOfBounds.qll | 2 +- c/common/src/codingstandards/c/Signal.qll | 2 +- .../ArrayFunctionArgumentNumberOfElements.ql | 2 +- .../ValueReturnedByAFunctionNotUsed.ql | 2 +- .../ObjectCopiedToAnOverlappingObject.ql | 2 +- ...emcmpUsedToCompareNullTerminatedStrings.ql | 2 +- ...leOpenForReadAndWriteOnDifferentStreams.ql | 2 +- .../AttemptToWriteToAReadOnlyStream.ql | 2 +- ...OnlyPerformConversionOfPassedParameters.ql | 2 +- .../A13-2-1/AssignmentOperatorReturnThis.ql | 2 +- .../A15-1-3/ThrownExceptionsShouldBeUnique.ql | 2 +- ...structorErrorLeavesObjectInInvalidState.ql | 2 +- ...AnElementOfAnArrayPassedToASmartPointer.ql | 2 +- .../rules/A18-5-2/DoNotUseNonPlacementNew.ql | 2 +- .../A18-5-8/UnnecessaryUseOfDynamicStorage.ql | 2 +- .../ArgumentToForwardSubsequentlyUsed.ql | 2 +- ...SharedPointerUsedWithNoOwnershipSharing.ql | 2 +- .../src/rules/A27-0-4/CStyleStringsUsed.ql | 2 +- ...hmeticUsedWithPointersToNonFinalClasses.ql | 2 +- .../rules/A5-1-7/LambdaPassedToDecltype.ql | 2 +- .../src/rules/A5-1-7/LambdaPassedToTypeid.ql | 2 +- .../rules/A7-5-1/InvalidFunctionReturnType.ql | 2 +- ...nterAsParameterWithoutLifetimeSemantics.ql | 2 +- ...trPassedToFunctionWithImproperSemantics.ql | 2 +- .../FunctionReturnMultipleValueCondition.ql | 2 +- ...ersOrReferencesToPrivateOrProtectedData.ql | 2 +- .../FunctionErroneousReturnValueNotTested.ql | 2 +- ...epresentationsOfFloatingPointValuesUsed.ql | 2 +- .../PointerSubtractionOnDifferentArrays.ql | 2 +- ...ointerToAVirtualBaseClassCastToAPointer.ql | 2 +- ...nstMemberFunctionReturnsNonConstPointer.ql | 2 +- ...GenericCppLibraryFunctionsDoNotOverflow.ql | 2 +- ...sePointerArithmeticOnPolymorphicObjects.ql | 2 +- ...fectsInFunctionCallsAsFunctionArguments.ql | 4 +- ...nArrayThroughAPointerOfTheIncorrectType.ql | 2 +- .../DetectAndHandleMemoryAllocationErrors.ql | 2 +- .../MEM53-CPP/ManuallyManagedLifetime.qll | 2 +- ...ConstructorCallForManuallyManagedObject.ql | 2 +- ...gDestructorCallForManuallyManagedObject.ql | 2 +- .../BadlySeededRandomNumberGenerator.ql | 2 +- .../src/codingstandards/cpp/AccessPath.qll | 2 +- .../src/codingstandards/cpp/Allocations.qll | 2 +- .../src/codingstandards/cpp/Concurrency.qll | 2 +- .../src/codingstandards/cpp/ConstHelpers.qll | 2 +- .../cpp/FgetsErrorManagement.qll | 2 +- .../src/codingstandards/cpp/Iterators.qll | 4 +- .../src/codingstandards/cpp/Nullness.qll | 2 +- .../src/codingstandards/cpp/Overflow.qll | 2 +- .../codingstandards/cpp/ReadErrorsAndEOF.qll | 2 +- .../src/codingstandards/cpp/SideEffect.qll | 2 +- .../src/codingstandards/cpp/SmartPointers.qll | 2 +- .../cpp/allocations/PlacementNew.qll | 2 +- .../codingstandards/cpp/dataflow/DataFlow.qll | 36 ------------------ .../cpp/dataflow/DataFlow2.qll | 25 ------------- .../cpp/dataflow/TaintTracking.qll | 37 ------------------- .../tainttracking1/TaintTrackingParameter.qll | 6 --- .../lifetimeprofile/LifetimeProfile.qll | 2 +- .../cpp/resources/ResourceManagement.qll | 2 +- ...onExistingMemberThroughPointerToMember.qll | 2 +- ...essOfUndefinedMemberThroughNullPointer.qll | 2 +- ...emberThroughUninitializedStaticPointer.qll | 2 +- .../BasicStringMayNotBeNullTerminated.qll | 4 +- .../ConstLikeReturnValue.qll | 2 +- .../ContainerAccessWithoutRangeCheck.qll | 2 +- .../DanglingCaptureWhenMovingLambdaObject.qll | 2 +- ...nglingCaptureWhenReturningLambdaObject.qll | 2 +- .../DoNotAccessAClosedFile.qll | 2 +- ...otAllowAMutexToGoOutOfScopeWhileLocked.qll | 2 +- .../DoNotDestroyAMutexWhileItIsLocked.qll | 2 +- ...tractPointersAddressingDifferentArrays.qll | 2 +- ...nterArithmeticToAddressDifferentArrays.qll | 2 +- ...RelationalOperatorsWithDifferingArrays.qll | 2 +- .../InvalidatedEnvStringPointers.qll | 2 +- .../InvalidatedEnvStringPointersWarn.qll | 2 +- .../IOFstreamMissingPositioning.qll | 2 +- .../MovedFromObjectsUnspecifiedState.qll | 2 +- .../nonconstantformat/NonConstantFormat.qll | 2 +- ...lyFreeMemoryAllocatedDynamicallyShared.qll | 2 +- ...nterValueStoredInUnrelatedSmartPointer.qll | 2 +- .../PlacementNewInsufficientStorage.qll | 2 +- .../PlacementNewNotProperlyAligned.qll | 2 +- ...tringNumberConversionMissingErrorCheck.qll | 2 +- .../ThrowingOperatorNewReturnsNull.qll | 2 +- ...eOnlyArrayIndexingForPointerArithmetic.qll | 2 +- .../cpp/standardlibrary/FileStreams.qll | 4 +- .../cpp/trustboundary/UninitializedField.qll | 2 +- .../UnusedReturnValue.ql | 2 +- .../UnusedReturnValue.ql | 2 +- .../UnusedReturnValue.ql | 2 +- 116 files changed, 120 insertions(+), 224 deletions(-) delete mode 100644 cpp/common/src/codingstandards/cpp/dataflow/DataFlow.qll delete mode 100644 cpp/common/src/codingstandards/cpp/dataflow/DataFlow2.qll delete mode 100644 cpp/common/src/codingstandards/cpp/dataflow/TaintTracking.qll delete mode 100644 cpp/common/src/codingstandards/cpp/dataflow/internal/tainttracking1/TaintTrackingParameter.qll diff --git a/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql b/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql index 2f8ecec25d..0ddf56150c 100644 --- a/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql +++ b/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import NonArrayPointerToArrayIndexingExprFlow::PathGraph /** diff --git a/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql b/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql index c641c17124..d832eb6014 100644 --- a/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql +++ b/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.cert import codingstandards.c.Pointers -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import ScaledIntegerPointerArithmeticFlow::PathGraph /** diff --git a/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql b/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql index 59fab6e455..d55f1326bf 100644 --- a/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql +++ b/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql @@ -15,8 +15,8 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Concurrency -import codingstandards.cpp.dataflow.TaintTracking -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.DataFlow module TssCreateToTssDeleteConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node node) { diff --git a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql index e0617c266d..71138f4ff8 100644 --- a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql +++ b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql @@ -15,8 +15,8 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Concurrency -import codingstandards.cpp.dataflow.TaintTracking -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.commons.Alloc from C11ThreadCreateCall tcc, StackVariable sv, Expr arg, Expr acc diff --git a/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql b/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql index 0fd94911ec..ddcddb8dc5 100644 --- a/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql +++ b/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql @@ -16,8 +16,8 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Concurrency -import codingstandards.cpp.dataflow.TaintTracking -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.DataFlow from TSSGetFunctionCall tsg, ThreadedFunction tf where diff --git a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql index 9097f14297..b5d7e5e378 100644 --- a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql +++ b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow class Source extends StackVariable { Source() { not this instanceof Parameter } diff --git a/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql b/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql index 8d63bb5d06..dd2e2175f7 100644 --- a/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql +++ b/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.cert import codingstandards.c.Errno -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * A call to an `OutOfBandErrnoSettingFunction` diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql index bf8f99fd27..fb14515c61 100644 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql @@ -14,8 +14,8 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.SideEffect -import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.valuenumbering.GlobalValueNumbering /** Holds if the function's return value is derived from the `AliasParamter` p. */ diff --git a/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql b/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql index e5735a5fda..f3b3aa364d 100644 --- a/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql +++ b/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Alignment -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis import ExprWithAlignmentToCStyleCastFlow::PathGraph diff --git a/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql b/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql index e28dbddaaf..9bbe27aa31 100644 --- a/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql +++ b/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import SuspectFunctionPointerToCallFlow::PathGraph /** diff --git a/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql b/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql index 825f85b0bd..fde564665c 100644 --- a/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql +++ b/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.controlflow.Dominance import IndirectCastFlow::PathGraph diff --git a/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql b/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql index d79224435f..20c9f1bcc8 100644 --- a/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql +++ b/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql @@ -12,7 +12,7 @@ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import CastFlow::PathGraph import codingstandards.cpp.SideEffect diff --git a/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql b/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql index a4cc4e8944..1b792d16d5 100644 --- a/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql +++ b/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.cert import codingstandards.c.Pointers import codingstandards.c.Variable -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.pointsto.PointsTo import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis diff --git a/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql b/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql index bbe41259b8..f220401c82 100644 --- a/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql +++ b/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql @@ -11,7 +11,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.controlflow.Dominance import codingstandards.c.cert import codingstandards.c.Variable diff --git a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql index 2dce0d465c..54f555d7cb 100644 --- a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql +++ b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.FgetsErrorManagement import codingstandards.cpp.Dereferenced -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking /* * CFG nodes that follows a successful call to `fgets` diff --git a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql index 33a906136f..7ed5887e42 100644 --- a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql +++ b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql @@ -12,7 +12,7 @@ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow class FgetposCall extends FunctionCall { FgetposCall() { this.getTarget().hasGlobalOrStdName("fgetpos") } diff --git a/c/cert/src/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql b/c/cert/src/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql index 2ddfa6cf4c..b02ce2f58d 100644 --- a/c/cert/src/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql +++ b/c/cert/src/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.standardlibrary.FileAccess -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.valuenumbering.GlobalValueNumbering /** diff --git a/c/cert/src/rules/MEM35-C/InsufficientMemoryAllocatedForObject.ql b/c/cert/src/rules/MEM35-C/InsufficientMemoryAllocatedForObject.ql index 7683140327..5ff1725269 100644 --- a/c/cert/src/rules/MEM35-C/InsufficientMemoryAllocatedForObject.ql +++ b/c/cert/src/rules/MEM35-C/InsufficientMemoryAllocatedForObject.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Overflow import semmle.code.cpp.controlflow.Guards -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.models.Models /** diff --git a/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql b/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql index 512b783030..df0eb3b1e3 100644 --- a/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql +++ b/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Alignment -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import AlignedAllocToReallocFlow::PathGraph int getStatedValue(Expr e) { diff --git a/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql b/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql index 52dd0b1046..fa4a29cb3d 100644 --- a/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql +++ b/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * The argument of a call to `asctime` diff --git a/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql b/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql index 821b79c8e4..338dc83308 100644 --- a/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql +++ b/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Macro -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow abstract class VaAccess extends Expr { } diff --git a/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql b/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql index 19730b4677..0da48daa70 100644 --- a/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql +++ b/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.cert import codingstandards.c.Signal -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * Does not access an external variable except diff --git a/c/cert/src/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.ql b/c/cert/src/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.ql index 5a064c0904..fa3cc3bf14 100644 --- a/c/cert/src/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.ql +++ b/c/cert/src/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.cert import codingstandards.c.Signal -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * CFG nodes preceeding a `ReturnStmt` diff --git a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql index 40f19ed4a0..244fe6d8e5 100644 --- a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql +++ b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.cert import semmle.code.cpp.security.BufferWrite -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * Class that includes into `BufferWrite` functions that will modify their diff --git a/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql index 4e2e48708a..3742207720 100644 --- a/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql +++ b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.c.cert -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.PossiblyUnsafeStringOperation /** diff --git a/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql index d661edade5..365136f99d 100644 --- a/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql +++ b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Naming -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.PossiblyUnsafeStringOperation /** diff --git a/c/common/src/codingstandards/c/Errno.qll b/c/common/src/codingstandards/c/Errno.qll index 86ecabe8f1..d606593a1e 100644 --- a/c/common/src/codingstandards/c/Errno.qll +++ b/c/common/src/codingstandards/c/Errno.qll @@ -1,7 +1,7 @@ /** Provides a library for errno-setting functions. */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * An errno-setting function diff --git a/c/common/src/codingstandards/c/OutOfBounds.qll b/c/common/src/codingstandards/c/OutOfBounds.qll index 87c7c17870..92d519699c 100644 --- a/c/common/src/codingstandards/c/OutOfBounds.qll +++ b/c/common/src/codingstandards/c/OutOfBounds.qll @@ -11,7 +11,7 @@ import codingstandards.cpp.Allocations import codingstandards.cpp.Overflow import codingstandards.cpp.PossiblyUnsafeStringOperation import codingstandards.cpp.SimpleRangeAnalysisCustomizations -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.valuenumbering.GlobalValueNumbering module OOB { diff --git a/c/common/src/codingstandards/c/Signal.qll b/c/common/src/codingstandards/c/Signal.qll index 35286be4d9..95b27e2898 100644 --- a/c/common/src/codingstandards/c/Signal.qll +++ b/c/common/src/codingstandards/c/Signal.qll @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * A signal corresponding to a computational exception diff --git a/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql b/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql index 208e8153d6..a6f5f2c1a2 100644 --- a/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql +++ b/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * Models a function parameter of type array with specified size diff --git a/c/misra/src/rules/RULE-17-7/ValueReturnedByAFunctionNotUsed.ql b/c/misra/src/rules/RULE-17-7/ValueReturnedByAFunctionNotUsed.ql index 02d0a54ec1..3b224544f2 100644 --- a/c/misra/src/rules/RULE-17-7/ValueReturnedByAFunctionNotUsed.ql +++ b/c/misra/src/rules/RULE-17-7/ValueReturnedByAFunctionNotUsed.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow from Call c where diff --git a/c/misra/src/rules/RULE-19-1/ObjectCopiedToAnOverlappingObject.ql b/c/misra/src/rules/RULE-19-1/ObjectCopiedToAnOverlappingObject.ql index bee9b41e2c..fe1226dcea 100644 --- a/c/misra/src/rules/RULE-19-1/ObjectCopiedToAnOverlappingObject.ql +++ b/c/misra/src/rules/RULE-19-1/ObjectCopiedToAnOverlappingObject.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.c.misra import semmle.code.cpp.valuenumbering.GlobalValueNumbering -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * Offset in bytes of a field access diff --git a/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql b/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql index 44e21d14db..ec1470a8ec 100644 --- a/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql +++ b/c/misra/src/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.c.misra import codingstandards.c.misra.EssentialTypes -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import NullTerminatedStringToMemcmpFlow::PathGraph // Data flow from a StringLiteral or from an array of characters, to a memcmp call diff --git a/c/misra/src/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.ql b/c/misra/src/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.ql index c01afea39f..877fbea9aa 100644 --- a/c/misra/src/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.ql +++ b/c/misra/src/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.standardlibrary.FileAccess -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.valuenumbering.GlobalValueNumbering import semmle.code.cpp.controlflow.SubBasicBlocks diff --git a/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql b/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql index 6dc3b3ee71..8c27b936b8 100644 --- a/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql +++ b/c/misra/src/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.standardlibrary.FileAccess -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow module FileDFConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { diff --git a/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql b/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql index 840d7423fb..4593065e01 100644 --- a/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql +++ b/cpp/autosar/src/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql @@ -14,7 +14,7 @@ */ import cpp -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.autosar import codingstandards.cpp.UserDefinedLiteral as udl import codingstandards.cpp.SideEffect diff --git a/cpp/autosar/src/rules/A13-2-1/AssignmentOperatorReturnThis.ql b/cpp/autosar/src/rules/A13-2-1/AssignmentOperatorReturnThis.ql index ae0acc3bb5..4e6b7d6f0c 100644 --- a/cpp/autosar/src/rules/A13-2-1/AssignmentOperatorReturnThis.ql +++ b/cpp/autosar/src/rules/A13-2-1/AssignmentOperatorReturnThis.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.Operator -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow predicate returnsThisPointer(UserAssignmentOperator o) { exists(PointerDereferenceExpr p, ThisExpr t, ReturnStmt r | diff --git a/cpp/autosar/src/rules/A15-1-3/ThrownExceptionsShouldBeUnique.ql b/cpp/autosar/src/rules/A15-1-3/ThrownExceptionsShouldBeUnique.ql index 1459b79b43..97e9133a7a 100644 --- a/cpp/autosar/src/rules/A15-1-3/ThrownExceptionsShouldBeUnique.ql +++ b/cpp/autosar/src/rules/A15-1-3/ThrownExceptionsShouldBeUnique.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.exceptions.ExceptionFlow -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.valuenumbering.HashCons /** Find a value which defines the exception thrown by the `DirectThrowExpr`, if any. */ diff --git a/cpp/autosar/src/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.ql b/cpp/autosar/src/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.ql index 9fcd8fa609..1b3a3cfed2 100644 --- a/cpp/autosar/src/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.ql +++ b/cpp/autosar/src/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.ql @@ -15,7 +15,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.autosar import codingstandards.cpp.exceptions.ExceptionFlow import codingstandards.cpp.exceptions.ExceptionSpecifications diff --git a/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql b/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql index 842dc14390..353c985137 100644 --- a/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql +++ b/cpp/autosar/src/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SmartPointers -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import SingleObjectSmartPointerArrayConstructionFlow::PathGraph class AutosarSmartPointerArraySpecialisation extends AutosarSmartPointer { diff --git a/cpp/autosar/src/rules/A18-5-2/DoNotUseNonPlacementNew.ql b/cpp/autosar/src/rules/A18-5-2/DoNotUseNonPlacementNew.ql index 082827f5bb..1320d6e486 100644 --- a/cpp/autosar/src/rules/A18-5-2/DoNotUseNonPlacementNew.ql +++ b/cpp/autosar/src/rules/A18-5-2/DoNotUseNonPlacementNew.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow from NewOrNewArrayExpr na where diff --git a/cpp/autosar/src/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.ql b/cpp/autosar/src/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.ql index 979dc0824e..cdf35374f9 100644 --- a/cpp/autosar/src/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.ql +++ b/cpp/autosar/src/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.standardlibrary.Utility /* diff --git a/cpp/autosar/src/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.ql b/cpp/autosar/src/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.ql index d87366c624..a3acf916ec 100644 --- a/cpp/autosar/src/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.ql +++ b/cpp/autosar/src/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.standardlibrary.Utility -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow from StdForwardCall f, Access a where diff --git a/cpp/autosar/src/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.ql b/cpp/autosar/src/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.ql index c7ff6f6bf2..0294bfe2e6 100644 --- a/cpp/autosar/src/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.ql +++ b/cpp/autosar/src/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SmartPointers -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /* * Finds `std::shared_ptr` local variables which are not copy or move initialized, and are not used in diff --git a/cpp/autosar/src/rules/A27-0-4/CStyleStringsUsed.ql b/cpp/autosar/src/rules/A27-0-4/CStyleStringsUsed.ql index b698ecf351..b24a4a96cf 100644 --- a/cpp/autosar/src/rules/A27-0-4/CStyleStringsUsed.ql +++ b/cpp/autosar/src/rules/A27-0-4/CStyleStringsUsed.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow class InstanceOfCStyleString extends Expr { InstanceOfCStyleString() { diff --git a/cpp/autosar/src/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.ql b/cpp/autosar/src/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.ql index 34b6660778..ac2375f6aa 100644 --- a/cpp/autosar/src/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.ql +++ b/cpp/autosar/src/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.ql @@ -17,7 +17,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.Type -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import NonFinalClassToPointerArithmeticExprFlow::PathGraph class ArrayAccessOrPointerArith extends Expr { diff --git a/cpp/autosar/src/rules/A5-1-7/LambdaPassedToDecltype.ql b/cpp/autosar/src/rules/A5-1-7/LambdaPassedToDecltype.ql index afbd809664..971d3b9259 100644 --- a/cpp/autosar/src/rules/A5-1-7/LambdaPassedToDecltype.ql +++ b/cpp/autosar/src/rules/A5-1-7/LambdaPassedToDecltype.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow module LambdaExpressionToInitializerConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { source.asExpr() instanceof LambdaExpression } diff --git a/cpp/autosar/src/rules/A5-1-7/LambdaPassedToTypeid.ql b/cpp/autosar/src/rules/A5-1-7/LambdaPassedToTypeid.ql index 08dbecc755..56952dace9 100644 --- a/cpp/autosar/src/rules/A5-1-7/LambdaPassedToTypeid.ql +++ b/cpp/autosar/src/rules/A5-1-7/LambdaPassedToTypeid.ql @@ -14,7 +14,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.autosar import LambdaExpressionToTypeidFlow::PathGraph diff --git a/cpp/autosar/src/rules/A7-5-1/InvalidFunctionReturnType.ql b/cpp/autosar/src/rules/A7-5-1/InvalidFunctionReturnType.ql index 6994ab028f..c36bda6cdd 100644 --- a/cpp/autosar/src/rules/A7-5-1/InvalidFunctionReturnType.ql +++ b/cpp/autosar/src/rules/A7-5-1/InvalidFunctionReturnType.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow from Parameter p, ReturnStmt ret where diff --git a/cpp/autosar/src/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.ql b/cpp/autosar/src/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.ql index 811d98eccb..0bf42ce4ca 100644 --- a/cpp/autosar/src/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.ql +++ b/cpp/autosar/src/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SmartPointers -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.standardlibrary.Utility Expr lifetimeAffectingSmartPointerExpr(Function f) { diff --git a/cpp/autosar/src/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.ql b/cpp/autosar/src/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.ql index 5dec96ed81..3cd310b59b 100644 --- a/cpp/autosar/src/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.ql +++ b/cpp/autosar/src/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.ql @@ -18,7 +18,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.SmartPointers import codingstandards.cpp.standardlibrary.Utility -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow Expr underlyingObjectAffectingUniquePointerExpr(Function f) { result = diff --git a/cpp/autosar/src/rules/A8-4-4/FunctionReturnMultipleValueCondition.ql b/cpp/autosar/src/rules/A8-4-4/FunctionReturnMultipleValueCondition.ql index fa38b1d3f6..ff0040f26f 100644 --- a/cpp/autosar/src/rules/A8-4-4/FunctionReturnMultipleValueCondition.ql +++ b/cpp/autosar/src/rules/A8-4-4/FunctionReturnMultipleValueCondition.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow abstract class OutputValue extends Element { abstract string getOutputName(); diff --git a/cpp/autosar/src/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql b/cpp/autosar/src/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql index f40faad3dd..478f8dcdf0 100644 --- a/cpp/autosar/src/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql +++ b/cpp/autosar/src/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.CommonTypes as CommonTypes -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow class AccessAwareMemberFunction extends MemberFunction { Class c; diff --git a/cpp/autosar/src/rules/M0-3-2/FunctionErroneousReturnValueNotTested.ql b/cpp/autosar/src/rules/M0-3-2/FunctionErroneousReturnValueNotTested.ql index aee4e40838..cd94d63ffc 100644 --- a/cpp/autosar/src/rules/M0-3-2/FunctionErroneousReturnValueNotTested.ql +++ b/cpp/autosar/src/rules/M0-3-2/FunctionErroneousReturnValueNotTested.ql @@ -19,7 +19,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.controlflow.Guards from FunctionCall fc diff --git a/cpp/autosar/src/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql b/cpp/autosar/src/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql index f7e6664269..279ad08f3c 100644 --- a/cpp/autosar/src/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql +++ b/cpp/autosar/src/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow predicate pointeeIsModified(PointerDereferenceExpr e, Expr m) { exists(Assignment a | a.getLValue() = e and m = a) diff --git a/cpp/autosar/src/rules/M5-0-17/PointerSubtractionOnDifferentArrays.ql b/cpp/autosar/src/rules/M5-0-17/PointerSubtractionOnDifferentArrays.ql index ec432cea42..d6d4f6130a 100644 --- a/cpp/autosar/src/rules/M5-0-17/PointerSubtractionOnDifferentArrays.ql +++ b/cpp/autosar/src/rules/M5-0-17/PointerSubtractionOnDifferentArrays.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import ArrayToPointerDiffOperandFlow::PathGraph module ArrayToPointerDiffOperandConfig implements DataFlow::ConfigSig { diff --git a/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql b/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql index 8f20bf808e..d24c4d35df 100644 --- a/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql +++ b/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow from Cast cast, VirtualBaseClass castFrom, Class castTo where diff --git a/cpp/autosar/src/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.ql b/cpp/autosar/src/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.ql index 98207a62a3..559b41527c 100644 --- a/cpp/autosar/src/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.ql +++ b/cpp/autosar/src/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.ql @@ -18,7 +18,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow class ReferenceTypeWithNonConstBaseType extends ReferenceType { ReferenceTypeWithNonConstBaseType() { not this.getBaseType().isConst() } diff --git a/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql b/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql index 720880dbe4..d60227d2c8 100644 --- a/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql +++ b/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql @@ -16,7 +16,7 @@ import codingstandards.cpp.cert import codingstandards.cpp.Iterators import codingstandards.cpp.rules.containeraccesswithoutrangecheck.ContainerAccessWithoutRangeCheck as ContainerAccessWithoutRangeCheck import semmle.code.cpp.controlflow.Guards -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.valuenumbering.GlobalValueNumbering /** diff --git a/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql b/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql index a7756b6a6a..0f5c50164c 100644 --- a/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql +++ b/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.cpp.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import NonFinalClassToPointerArithmeticExprFlow::PathGraph class ArrayAccessOrPointerArith extends Expr { diff --git a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql index a385ee1ffc..7bfb298d3d 100644 --- a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql +++ b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql @@ -14,8 +14,8 @@ import cpp import codingstandards.cpp.cert import codingstandards.cpp.SideEffect -import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.valuenumbering.GlobalValueNumbering /** Holds if the function's return value is derived from the `AliasParamter` p. */ diff --git a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql index bdf6a7973e..e900d1b259 100644 --- a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql +++ b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.cpp.cert -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import AllocationToDeleteFlow::PathGraph module AllocationToDeleteConfig implements DataFlow::ConfigSig { diff --git a/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql b/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql index c25e1aa0ad..083aad1e3c 100644 --- a/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql +++ b/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.cpp.cert import semmle.code.cpp.controlflow.Guards -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.exceptions.ExceptionSpecifications /** diff --git a/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll b/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll index 358a3583fc..413a4b0d3c 100644 --- a/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll +++ b/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll @@ -3,7 +3,7 @@ import codingstandards.cpp.Conversion import codingstandards.cpp.TrivialType import ManuallyManagedLifetime import semmle.code.cpp.controlflow.Dominance -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking /** * A taint-tracking configuration from allocation expressions to casts to a specific pointer type. diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql index 30c5280482..6e3121e46d 100644 --- a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql +++ b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.cpp.cert import codingstandards.cpp.TrivialType import ManuallyManagedLifetime -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import AllocToStaticCastFlow::PathGraph /* diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql b/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql index b498729d69..22e2ac336f 100644 --- a/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql +++ b/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.cpp.cert import ManuallyManagedLifetime -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import FreeWithoutDestructorFlow::PathGraph from FreeWithoutDestructorFlow::PathNode source, FreeWithoutDestructorFlow::PathNode sink diff --git a/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.ql b/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.ql index 52b14d9629..76f8500362 100644 --- a/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.ql +++ b/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.cpp.cert import codingstandards.cpp.standardlibrary.Random -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking from RandomNumberEngineCreation createRandomNumberEngine, string seedSource where diff --git a/cpp/common/src/codingstandards/cpp/AccessPath.qll b/cpp/common/src/codingstandards/cpp/AccessPath.qll index 2393d25db4..ff7601ed4b 100644 --- a/cpp/common/src/codingstandards/cpp/AccessPath.qll +++ b/cpp/common/src/codingstandards/cpp/AccessPath.qll @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow newtype TFieldQualifier = ExplicitQualifier(VariableAccess v) or diff --git a/cpp/common/src/codingstandards/cpp/Allocations.qll b/cpp/common/src/codingstandards/cpp/Allocations.qll index 5bc87221e2..db47b0b028 100644 --- a/cpp/common/src/codingstandards/cpp/Allocations.qll +++ b/cpp/common/src/codingstandards/cpp/Allocations.qll @@ -7,7 +7,7 @@ import cpp import semmle.code.cpp.controlflow.SSA -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * Holds if `alloc` is a use of `malloc` or `new`. `kind` is diff --git a/cpp/common/src/codingstandards/cpp/Concurrency.qll b/cpp/common/src/codingstandards/cpp/Concurrency.qll index d856fa4515..5e7d154d59 100644 --- a/cpp/common/src/codingstandards/cpp/Concurrency.qll +++ b/cpp/common/src/codingstandards/cpp/Concurrency.qll @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking /** * Models CFG nodes which should be added to a thread context. diff --git a/cpp/common/src/codingstandards/cpp/ConstHelpers.qll b/cpp/common/src/codingstandards/cpp/ConstHelpers.qll index 8cba3efde4..a7457dc845 100644 --- a/cpp/common/src/codingstandards/cpp/ConstHelpers.qll +++ b/cpp/common/src/codingstandards/cpp/ConstHelpers.qll @@ -4,7 +4,7 @@ import cpp import codingstandards.cpp.SideEffect -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.FunctionParameter /** A variable that can be modified (both the pointer and object pointed to if pointer type) */ diff --git a/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll b/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll index 7686714635..4f99b02e2e 100644 --- a/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll +++ b/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll @@ -4,7 +4,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.controlflow.Guards /* diff --git a/cpp/common/src/codingstandards/cpp/Iterators.qll b/cpp/common/src/codingstandards/cpp/Iterators.qll index 593da544ea..72a9909c20 100644 --- a/cpp/common/src/codingstandards/cpp/Iterators.qll +++ b/cpp/common/src/codingstandards/cpp/Iterators.qll @@ -3,8 +3,8 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.StdNamespace abstract class ContainerAccess extends VariableAccess { diff --git a/cpp/common/src/codingstandards/cpp/Nullness.qll b/cpp/common/src/codingstandards/cpp/Nullness.qll index d76db4afad..8751c54d9b 100644 --- a/cpp/common/src/codingstandards/cpp/Nullness.qll +++ b/cpp/common/src/codingstandards/cpp/Nullness.qll @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow private class PointerToMember extends Variable { PointerToMember() { this.getType() instanceof PointerToMemberType } diff --git a/cpp/common/src/codingstandards/cpp/Overflow.qll b/cpp/common/src/codingstandards/cpp/Overflow.qll index dca1386513..28a5c0d9db 100644 --- a/cpp/common/src/codingstandards/cpp/Overflow.qll +++ b/cpp/common/src/codingstandards/cpp/Overflow.qll @@ -6,7 +6,7 @@ import cpp import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis import SimpleRangeAnalysisCustomizations import semmle.code.cpp.controlflow.Guards -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.valuenumbering.GlobalValueNumbering import codingstandards.cpp.Expr import codingstandards.cpp.UndefinedBehavior diff --git a/cpp/common/src/codingstandards/cpp/ReadErrorsAndEOF.qll b/cpp/common/src/codingstandards/cpp/ReadErrorsAndEOF.qll index 7adb911c9f..c3c433d20d 100644 --- a/cpp/common/src/codingstandards/cpp/ReadErrorsAndEOF.qll +++ b/cpp/common/src/codingstandards/cpp/ReadErrorsAndEOF.qll @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.standardlibrary.FileAccess /** diff --git a/cpp/common/src/codingstandards/cpp/SideEffect.qll b/cpp/common/src/codingstandards/cpp/SideEffect.qll index 08cd9394d3..4b78b5c818 100644 --- a/cpp/common/src/codingstandards/cpp/SideEffect.qll +++ b/cpp/common/src/codingstandards/cpp/SideEffect.qll @@ -1,7 +1,7 @@ /** A module to reason about side effects. */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow private import exceptions.ExceptionFlow private import codingstandards.cpp.Expr private import codingstandards.cpp.Variable diff --git a/cpp/common/src/codingstandards/cpp/SmartPointers.qll b/cpp/common/src/codingstandards/cpp/SmartPointers.qll index dda645a399..0f01d886be 100644 --- a/cpp/common/src/codingstandards/cpp/SmartPointers.qll +++ b/cpp/common/src/codingstandards/cpp/SmartPointers.qll @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow // Local cached version of localExprFlow to avoid bad magic cached diff --git a/cpp/common/src/codingstandards/cpp/allocations/PlacementNew.qll b/cpp/common/src/codingstandards/cpp/allocations/PlacementNew.qll index 5547f2e151..2c9139d0ae 100644 --- a/cpp/common/src/codingstandards/cpp/allocations/PlacementNew.qll +++ b/cpp/common/src/codingstandards/cpp/allocations/PlacementNew.qll @@ -22,7 +22,7 @@ import cpp import codingstandards.cpp.Conversion -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /* * TODO You can also have alignas on types diff --git a/cpp/common/src/codingstandards/cpp/dataflow/DataFlow.qll b/cpp/common/src/codingstandards/cpp/dataflow/DataFlow.qll deleted file mode 100644 index c11bf80fc6..0000000000 --- a/cpp/common/src/codingstandards/cpp/dataflow/DataFlow.qll +++ /dev/null @@ -1,36 +0,0 @@ -/** - * Provides a library for local (intra-procedural) and global (inter-procedural) - * data flow analysis: deciding whether data can flow from a _source_ to a - * _sink_. - * - * Unless configured otherwise, _flow_ means that the exact value of - * the source may reach the sink. We do not track flow across pointer - * dereferences or array indexing. To track these types of flow, where the - * exact value may not be preserved, import - * `semmle.code.cpp.dataflow.TaintTracking`. - * - * To use global (interprocedural) data flow, extend the class - * `DataFlow::Configuration` as documented on that class. To use local - * (intraprocedural) data flow between expressions, call - * `DataFlow::localExprFlow`. For more general cases of local data flow, call - * `DataFlow::localFlow` or `DataFlow::localFlowStep` with arguments of type - * `DataFlow::Node`. - * - * NOTE: This is copied from `codeql/cpp-all` to avoid deprecation warnings - * that cannot be avoided in tests. - */ - -import cpp - -/** - * DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow` instead. - * - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ -module DataFlow { - private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific - private import codeql.dataflow.DataFlow - import DataFlowMake - import semmle.code.cpp.dataflow.internal.DataFlowImpl1 -} diff --git a/cpp/common/src/codingstandards/cpp/dataflow/DataFlow2.qll b/cpp/common/src/codingstandards/cpp/dataflow/DataFlow2.qll deleted file mode 100644 index 83859535d8..0000000000 --- a/cpp/common/src/codingstandards/cpp/dataflow/DataFlow2.qll +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Provides a `DataFlow2` module, which is a copy of the `DataFlow` module. Use - * this class when data-flow configurations must depend on each other. Two - * classes extending `DataFlow::Configuration` should never depend on each - * other, but one of them should instead depend on a - * `DataFlow2::Configuration`, a `DataFlow3::Configuration`, or a - * `DataFlow4::Configuration`. - * - * See `semmle.code.cpp.dataflow.DataFlow` for the full documentation. - * - * NOTE: This is copied from `codeql/cpp-all` to avoid deprecation warnings - * that cannot be avoided in tests. - */ - -import cpp - -/** - * DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow2` instead. - * - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) data flow analyses. - */ -module DataFlow2 { - import semmle.code.cpp.dataflow.internal.DataFlowImpl2 -} diff --git a/cpp/common/src/codingstandards/cpp/dataflow/TaintTracking.qll b/cpp/common/src/codingstandards/cpp/dataflow/TaintTracking.qll deleted file mode 100644 index 2b43a53ccb..0000000000 --- a/cpp/common/src/codingstandards/cpp/dataflow/TaintTracking.qll +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - * - * We define _taint propagation_ informally to mean that a substantial part of - * the information from the source is preserved at the sink. For example, taint - * propagates from `x` to `x + 100`, but it does not propagate from `x` to `x > - * 100` since we consider a single bit of information to be too little. - * - * To use global (interprocedural) taint tracking, extend the class - * `TaintTracking::Configuration` as documented on that class. To use local - * (intraprocedural) taint tracking between expressions, call - * `TaintTracking::localExprTaint`. For more general cases of local taint - * tracking, call `TaintTracking::localTaint` or - * `TaintTracking::localTaintStep` with arguments of type `DataFlow::Node`. - * - * NOTE: This is copied from `codeql/cpp-all` to avoid deprecation warnings - * that cannot be avoided in tests. - */ - -import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.DataFlow2 - -/** - * DEPRECATED: Use `semmle.code.cpp.dataflow.new.TaintTracking` instead. - * - * Provides classes for performing local (intra-procedural) and - * global (inter-procedural) taint-tracking analyses. - */ -module TaintTracking { - import codingstandards.cpp.dataflow.internal.tainttracking1.TaintTrackingParameter::Public - private import semmle.code.cpp.dataflow.internal.DataFlowImplSpecific - private import semmle.code.cpp.dataflow.internal.TaintTrackingImplSpecific - private import codeql.dataflow.TaintTracking - import TaintFlowMake - import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl -} diff --git a/cpp/common/src/codingstandards/cpp/dataflow/internal/tainttracking1/TaintTrackingParameter.qll b/cpp/common/src/codingstandards/cpp/dataflow/internal/tainttracking1/TaintTrackingParameter.qll deleted file mode 100644 index 63e9c85e22..0000000000 --- a/cpp/common/src/codingstandards/cpp/dataflow/internal/tainttracking1/TaintTrackingParameter.qll +++ /dev/null @@ -1,6 +0,0 @@ -import semmle.code.cpp.dataflow.internal.TaintTrackingUtil as Public - -module Private { - import codingstandards.cpp.dataflow.DataFlow::DataFlow as DataFlow - import semmle.code.cpp.dataflow.internal.DataFlowImpl as DataFlowInternal -} diff --git a/cpp/common/src/codingstandards/cpp/lifetimes/lifetimeprofile/LifetimeProfile.qll b/cpp/common/src/codingstandards/cpp/lifetimes/lifetimeprofile/LifetimeProfile.qll index 7990f50216..354dccdc56 100644 --- a/cpp/common/src/codingstandards/cpp/lifetimes/lifetimeprofile/LifetimeProfile.qll +++ b/cpp/common/src/codingstandards/cpp/lifetimes/lifetimeprofile/LifetimeProfile.qll @@ -1,5 +1,5 @@ import cpp -private import codingstandards.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow private import semmle.code.cpp.controlflow.Nullness private import codingstandards.cpp.Dereferenced private import codingstandards.cpp.Expr diff --git a/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll b/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll index 0798575495..db65dd4920 100644 --- a/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll +++ b/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow /** * The `ResourceAcquisitionExpr` abstract class models resource diff --git a/cpp/common/src/codingstandards/cpp/rules/accessofnonexistingmemberthroughpointertomember/AccessOfNonExistingMemberThroughPointerToMember.qll b/cpp/common/src/codingstandards/cpp/rules/accessofnonexistingmemberthroughpointertomember/AccessOfNonExistingMemberThroughPointerToMember.qll index 138c0a89b5..ac135386f3 100644 --- a/cpp/common/src/codingstandards/cpp/rules/accessofnonexistingmemberthroughpointertomember/AccessOfNonExistingMemberThroughPointerToMember.qll +++ b/cpp/common/src/codingstandards/cpp/rules/accessofnonexistingmemberthroughpointertomember/AccessOfNonExistingMemberThroughPointerToMember.qll @@ -7,7 +7,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Expr -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow abstract class AccessOfNonExistingMemberThroughPointerToMemberSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll b/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll index ab8659efd8..e0fb382008 100644 --- a/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll +++ b/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll @@ -7,7 +7,7 @@ import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Nullness import codingstandards.cpp.Expr -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import NullPointerToPointerMemberExpressionFlow::PathGraph abstract class AccessOfUndefinedMemberThroughNullPointerSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughuninitializedstaticpointer/AccessOfUndefinedMemberThroughUninitializedStaticPointer.qll b/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughuninitializedstaticpointer/AccessOfUndefinedMemberThroughUninitializedStaticPointer.qll index ca1e2a4282..0271d7c6e7 100644 --- a/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughuninitializedstaticpointer/AccessOfUndefinedMemberThroughUninitializedStaticPointer.qll +++ b/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughuninitializedstaticpointer/AccessOfUndefinedMemberThroughUninitializedStaticPointer.qll @@ -12,7 +12,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.EncapsulatingFunctions diff --git a/cpp/common/src/codingstandards/cpp/rules/basicstringmaynotbenullterminated/BasicStringMayNotBeNullTerminated.qll b/cpp/common/src/codingstandards/cpp/rules/basicstringmaynotbenullterminated/BasicStringMayNotBeNullTerminated.qll index cea798ae11..e27f09fd98 100644 --- a/cpp/common/src/codingstandards/cpp/rules/basicstringmaynotbenullterminated/BasicStringMayNotBeNullTerminated.qll +++ b/cpp/common/src/codingstandards/cpp/rules/basicstringmaynotbenullterminated/BasicStringMayNotBeNullTerminated.qll @@ -8,8 +8,8 @@ import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import semmle.code.cpp.security.BufferWrite import semmle.code.cpp.commons.Buffer -import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.PossiblyUnsafeStringOperation abstract class BasicStringMayNotBeNullTerminatedSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/constlikereturnvalue/ConstLikeReturnValue.qll b/cpp/common/src/codingstandards/cpp/rules/constlikereturnvalue/ConstLikeReturnValue.qll index f4636b6b13..e5fa82df19 100644 --- a/cpp/common/src/codingstandards/cpp/rules/constlikereturnvalue/ConstLikeReturnValue.qll +++ b/cpp/common/src/codingstandards/cpp/rules/constlikereturnvalue/ConstLikeReturnValue.qll @@ -5,7 +5,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import DFFlow::PathGraph abstract class ConstLikeReturnValueSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/containeraccesswithoutrangecheck/ContainerAccessWithoutRangeCheck.qll b/cpp/common/src/codingstandards/cpp/rules/containeraccesswithoutrangecheck/ContainerAccessWithoutRangeCheck.qll index a3dabedd5a..840cd5330a 100644 --- a/cpp/common/src/codingstandards/cpp/rules/containeraccesswithoutrangecheck/ContainerAccessWithoutRangeCheck.qll +++ b/cpp/common/src/codingstandards/cpp/rules/containeraccesswithoutrangecheck/ContainerAccessWithoutRangeCheck.qll @@ -12,7 +12,7 @@ import codingstandards.cpp.Operator import semmle.code.cpp.controlflow.Guards private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.valuenumbering.GlobalValueNumbering abstract class ContainerAccessWithoutRangeCheckSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenmovinglambdaobject/DanglingCaptureWhenMovingLambdaObject.qll b/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenmovinglambdaobject/DanglingCaptureWhenMovingLambdaObject.qll index ab2b067279..902d0ecf1f 100644 --- a/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenmovinglambdaobject/DanglingCaptureWhenMovingLambdaObject.qll +++ b/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenmovinglambdaobject/DanglingCaptureWhenMovingLambdaObject.qll @@ -5,7 +5,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Expr diff --git a/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenreturninglambdaobject/DanglingCaptureWhenReturningLambdaObject.qll b/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenreturninglambdaobject/DanglingCaptureWhenReturningLambdaObject.qll index c35b723ff3..4ab01520f6 100644 --- a/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenreturninglambdaobject/DanglingCaptureWhenReturningLambdaObject.qll +++ b/cpp/common/src/codingstandards/cpp/rules/danglingcapturewhenreturninglambdaobject/DanglingCaptureWhenReturningLambdaObject.qll @@ -5,7 +5,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions diff --git a/cpp/common/src/codingstandards/cpp/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.qll b/cpp/common/src/codingstandards/cpp/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.qll index 3d84366d9a..83266ed524 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotaccessaclosedfile/DoNotAccessAClosedFile.qll @@ -6,7 +6,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.standardlibrary.FileAccess import semmle.code.cpp.controlflow.SubBasicBlocks diff --git a/cpp/common/src/codingstandards/cpp/rules/donotallowamutextogooutofscopewhilelocked/DoNotAllowAMutexToGoOutOfScopeWhileLocked.qll b/cpp/common/src/codingstandards/cpp/rules/donotallowamutextogooutofscopewhilelocked/DoNotAllowAMutexToGoOutOfScopeWhileLocked.qll index 8a8155f971..759d235eb4 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotallowamutextogooutofscopewhilelocked/DoNotAllowAMutexToGoOutOfScopeWhileLocked.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotallowamutextogooutofscopewhilelocked/DoNotAllowAMutexToGoOutOfScopeWhileLocked.qll @@ -17,7 +17,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Concurrency -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking abstract class DoNotAllowAMutexToGoOutOfScopeWhileLockedSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/donotdestroyamutexwhileitislocked/DoNotDestroyAMutexWhileItIsLocked.qll b/cpp/common/src/codingstandards/cpp/rules/donotdestroyamutexwhileitislocked/DoNotDestroyAMutexWhileItIsLocked.qll index 46335c3d94..d77ae8cf39 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotdestroyamutexwhileitislocked/DoNotDestroyAMutexWhileItIsLocked.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotdestroyamutexwhileitislocked/DoNotDestroyAMutexWhileItIsLocked.qll @@ -15,7 +15,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Concurrency -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking abstract class DoNotDestroyAMutexWhileItIsLockedSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll index 0aa8d64feb..adb9785814 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.qll @@ -6,7 +6,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import ArrayToPointerDiffOperandFlow::PathGraph module ArrayToPointerDiffOperandConfig implements DataFlow::ConfigSig { diff --git a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll index dd10b840c5..57b4eb0bfb 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll @@ -7,7 +7,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis abstract class DoNotUsePointerArithmeticToAddressDifferentArraysSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll index 155ed1a7f4..aa8fa29bfd 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.qll @@ -7,7 +7,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import ArrayToRelationalOperationOperandFlow::PathGraph abstract class DoNotUseRelationalOperatorsWithDifferingArraysSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll b/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll index 81a3251355..3949ff50a8 100644 --- a/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll +++ b/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll @@ -6,7 +6,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow abstract class InvalidatedEnvStringPointersSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.qll b/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.qll index fd8a969d00..8bc1b0c920 100644 --- a/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.qll +++ b/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.qll @@ -6,7 +6,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.rules.invalidatedenvstringpointers.InvalidatedEnvStringPointers as EnvString abstract class InvalidatedEnvStringPointersWarnSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll b/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll index 3a7e225369..89f847c5aa 100644 --- a/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll +++ b/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll @@ -5,7 +5,7 @@ */ import cpp -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.Exclusions import codingstandards.cpp.standardlibrary.FileStreams import codingstandards.cpp.standardlibrary.FileAccess diff --git a/cpp/common/src/codingstandards/cpp/rules/movedfromobjectsunspecifiedstate/MovedFromObjectsUnspecifiedState.qll b/cpp/common/src/codingstandards/cpp/rules/movedfromobjectsunspecifiedstate/MovedFromObjectsUnspecifiedState.qll index a0006eb643..f17da7e457 100644 --- a/cpp/common/src/codingstandards/cpp/rules/movedfromobjectsunspecifiedstate/MovedFromObjectsUnspecifiedState.qll +++ b/cpp/common/src/codingstandards/cpp/rules/movedfromobjectsunspecifiedstate/MovedFromObjectsUnspecifiedState.qll @@ -4,7 +4,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.Exclusions import codingstandards.cpp.standardlibrary.Utility diff --git a/cpp/common/src/codingstandards/cpp/rules/nonconstantformat/NonConstantFormat.qll b/cpp/common/src/codingstandards/cpp/rules/nonconstantformat/NonConstantFormat.qll index 91b2b05a3f..248cde106f 100644 --- a/cpp/common/src/codingstandards/cpp/rules/nonconstantformat/NonConstantFormat.qll +++ b/cpp/common/src/codingstandards/cpp/rules/nonconstantformat/NonConstantFormat.qll @@ -1,7 +1,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.commons.Printf abstract class NonConstantFormatSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.qll b/cpp/common/src/codingstandards/cpp/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.qll index bede451e24..89c732ff5a 100644 --- a/cpp/common/src/codingstandards/cpp/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.qll +++ b/cpp/common/src/codingstandards/cpp/rules/onlyfreememoryallocateddynamicallyshared/OnlyFreeMemoryAllocatedDynamicallyShared.qll @@ -7,7 +7,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Allocations -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import NonDynamicPointerToFreeFlow::PathGraph /** diff --git a/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll b/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll index e24fb91539..2ee92b1611 100644 --- a/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll +++ b/cpp/common/src/codingstandards/cpp/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.qll @@ -8,7 +8,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.SmartPointers -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import PointerToSmartPointerConstructorFlowFlow::PathGraph abstract class OwnedPointerValueStoredInUnrelatedSmartPointerSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.qll b/cpp/common/src/codingstandards/cpp/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.qll index dc26d13b87..6b2c6c87c9 100644 --- a/cpp/common/src/codingstandards/cpp/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.qll +++ b/cpp/common/src/codingstandards/cpp/rules/placementnewinsufficientstorage/PlacementNewInsufficientStorage.qll @@ -7,7 +7,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.allocations.PlacementNew -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import PlacementNewOriginFlow::PathGraph abstract class PlacementNewInsufficientStorageSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/placementnewnotproperlyaligned/PlacementNewNotProperlyAligned.qll b/cpp/common/src/codingstandards/cpp/rules/placementnewnotproperlyaligned/PlacementNewNotProperlyAligned.qll index 72286f2d79..d250061a23 100644 --- a/cpp/common/src/codingstandards/cpp/rules/placementnewnotproperlyaligned/PlacementNewNotProperlyAligned.qll +++ b/cpp/common/src/codingstandards/cpp/rules/placementnewnotproperlyaligned/PlacementNewNotProperlyAligned.qll @@ -7,7 +7,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.allocations.PlacementNew -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import PlacementNewOriginFlow::PathGraph abstract class PlacementNewNotProperlyAlignedSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/stringnumberconversionmissingerrorcheck/StringNumberConversionMissingErrorCheck.qll b/cpp/common/src/codingstandards/cpp/rules/stringnumberconversionmissingerrorcheck/StringNumberConversionMissingErrorCheck.qll index 98fd51a58f..fd56f5d899 100644 --- a/cpp/common/src/codingstandards/cpp/rules/stringnumberconversionmissingerrorcheck/StringNumberConversionMissingErrorCheck.qll +++ b/cpp/common/src/codingstandards/cpp/rules/stringnumberconversionmissingerrorcheck/StringNumberConversionMissingErrorCheck.qll @@ -7,7 +7,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import semmle.code.cpp.valuenumbering.GlobalValueNumbering -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.standardlibrary.CharStreams abstract class StringNumberConversionMissingErrorCheckSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.qll b/cpp/common/src/codingstandards/cpp/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.qll index 9dbefeaa75..e28ef7ab07 100644 --- a/cpp/common/src/codingstandards/cpp/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.qll +++ b/cpp/common/src/codingstandards/cpp/rules/throwingoperatornewreturnsnull/ThrowingOperatorNewReturnsNull.qll @@ -4,7 +4,7 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.allocations.CustomOperatorNewDelete import codingstandards.cpp.exceptions.ExceptionSpecifications import codingstandards.cpp.Customizations diff --git a/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll b/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll index c421ae3cc9..3b0abbad0d 100644 --- a/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll +++ b/cpp/common/src/codingstandards/cpp/rules/useonlyarrayindexingforpointerarithmetic/UseOnlyArrayIndexingForPointerArithmetic.qll @@ -6,7 +6,7 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow abstract class UseOnlyArrayIndexingForPointerArithmeticSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll b/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll index c4724d36c2..709e80dc1a 100644 --- a/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll +++ b/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll @@ -10,8 +10,8 @@ */ import cpp -import codingstandards.cpp.dataflow.DataFlow -import codingstandards.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.TaintTracking private import codingstandards.cpp.Operator /** diff --git a/cpp/common/src/codingstandards/cpp/trustboundary/UninitializedField.qll b/cpp/common/src/codingstandards/cpp/trustboundary/UninitializedField.qll index e6a2bbe706..f58f1352a7 100644 --- a/cpp/common/src/codingstandards/cpp/trustboundary/UninitializedField.qll +++ b/cpp/common/src/codingstandards/cpp/trustboundary/UninitializedField.qll @@ -5,7 +5,7 @@ */ import cpp -private import codingstandards.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow private import semmle.code.cpp.controlflow.SubBasicBlocks private import semmle.code.cpp.padding.Padding as Padding private import semmle.code.cpp.dataflow.internal.FlowVar diff --git a/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql b/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql index 2517965fc1..38b75bda3c 100644 --- a/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql +++ b/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.CodingStandards -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.exclusions.cpp.RuleMetadata /* This is a copy of an AUTOSAR rule, which we are using for testing purposes. */ diff --git a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql index 2517965fc1..38b75bda3c 100644 --- a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql +++ b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.CodingStandards -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.exclusions.cpp.RuleMetadata /* This is a copy of an AUTOSAR rule, which we are using for testing purposes. */ diff --git a/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql b/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql index 2517965fc1..38b75bda3c 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql +++ b/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.CodingStandards -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.exclusions.cpp.RuleMetadata /* This is a copy of an AUTOSAR rule, which we are using for testing purposes. */ From 4b4373615affbe350aef308db34d8e26b2d4fd75 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 13 Mar 2024 21:53:02 +0000 Subject: [PATCH 018/628] Accept test changes. --- ...bleLengthArraySizeNotInValidRange.expected | 2 ++ ...rithmeticOnNonArrayObjectPointers.expected | 5 ++++ ...rSubtractAScaledIntegerToAPointer.expected | 4 ++++ .../CleanUpThreadSpecificStorage.expected | 6 +++++ ...riateThreadObjectStorageDurations.expected | 8 +++++++ ...ectStorageDurationsNotInitialized.expected | 5 ++++ ...ateStorageDurationsFunctionReturn.expected | 5 ++++ .../ERR30-C/ErrnoReadBeforeReturn.expected | 1 + .../ERR30-C/SetlocaleMightSetErrno.expected | 1 + ...tRelyOnIndeterminateValuesOfErrno.expected | 4 ++++ ...ectAndHandleStandardLibraryErrors.expected | 1 + ...OfFunctionArgumentsForSideEffects.expected | 24 +++++++++++++++++++ ...rToMoreStrictlyAlignedPointerType.expected | 10 ++++++++ ...nctionPointerWithIncompatibleType.expected | 4 ++++ ...iableViaPointerOfIncompatibleType.expected | 7 ++++++ .../DoNotModifyConstantObjects.expected | 4 ++++ ...edPointerToRestrictQualifiedParam.expected | 12 ++++++++++ ...ointerReferencesOverlappingObject.expected | 7 ++++++ ...esetStringsOnFgetsOrFgetwsFailure.expected | 3 +++ ...FsetposThatAreReturnedFromFgetpos.expected | 5 ++++ ...RaceConditionsWhileAccessingFiles.expected | 1 + ...ufficientMemoryAllocatedForObject.expected | 2 ++ ...odifyAlignmentOfMemoryWithRealloc.expected | 5 ++++ ...ssInvalidDataToTheAsctimeFunction.expected | 4 ++++ ...VaListThatHasAnIndeterminateValue.expected | 7 ++++++ ...SafeFunctionsWithinSignalHandlers.expected | 3 +++ ...romAComputationalExceptionHandler.expected | 1 + ...oNotAttemptToModifyStringLiterals.expected | 15 ++++++++++++ ...fficientSpaceForTheNullTerminator.expected | 6 +++++ ...natedToFunctionThatExpectsAString.expected | 9 +++++++ ...yFunctionArgumentNumberOfElements.expected | 6 +++++ ...sedToCompareNullTerminatedStrings.expected | 4 ++++ ...ForReadAndWriteOnDifferentStreams.expected | 1 + .../AttemptToWriteToAReadOnlyStream.expected | 6 +++++ ...omparedWithUnmodifiedReturnValues.expected | 8 +++++++ ...rformConversionOfPassedParameters.expected | 3 +++ .../AssignmentOperatorReturnThis.expected | 1 + .../ThrownExceptionsShouldBeUnique.expected | 1 + ...orErrorLeavesObjectInInvalidState.expected | 9 +++++++ ...entOfAnArrayPassedToASmartPointer.expected | 7 ++++++ .../UnnecessaryUseOfDynamicStorage.expected | 4 ++++ ...ArgumentToForwardSubsequentlyUsed.expected | 3 +++ ...PointerUsedWithNoOwnershipSharing.expected | 1 + .../rules/A27-0-4/CStyleStringsUsed.expected | 3 +++ ...UsedWithPointersToNonFinalClasses.expected | 4 ++++ .../A5-1-7/LambdaPassedToDecltype.expected | 6 +++++ .../A5-1-7/LambdaPassedToTypeid.expected | 4 ++++ .../A7-1-2/VariableMissingConstexpr.expected | 6 +++++ .../A7-5-1/InvalidFunctionReturnType.expected | 3 +++ ...ParameterWithoutLifetimeSemantics.expected | 2 ++ ...edToFunctionWithImproperSemantics.expected | 2 ++ ...tParametersDeclaredAsTNotModified.expected | 2 ++ ...eferencesToPrivateOrProtectedData.expected | 3 +++ ...tionErroneousReturnValueNotTested.expected | 3 +++ ...ntationsOfFloatingPointValuesUsed.expected | 3 +++ ...berFunctionReturnsNonConstPointer.expected | 2 ++ ...cCppLibraryFunctionsDoNotOverflow.expected | 9 +++++++ .../CTR53-CPP/UseValidIteratorRanges.expected | 6 +++++ ...terArithmeticOnPolymorphicObjects.expected | 4 ++++ ...nFunctionCallsAsFunctionArguments.expected | 24 +++++++++++++++++++ ...ThroughAPointerOfTheIncorrectType.expected | 4 ++++ ...ctAndHandleMemoryAllocationErrors.expected | 7 ++++++ .../BadlySeededRandomNumberGenerator.expected | 1 + 63 files changed, 323 insertions(+) diff --git a/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected b/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected index 25153f195b..bcb1c8eddd 100644 --- a/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected +++ b/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected @@ -1,3 +1,5 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:104,11-19) +WARNING: Module TaintTracking has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:87,5-18) | test.c:14:8:14:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | | test.c:15:8:15:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | | test.c:16:8:16:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | diff --git a/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected b/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected index e5e0252e3a..d75db521af 100644 --- a/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected +++ b/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected @@ -1,3 +1,8 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:23,60-68) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:24,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:36,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:44,26-34) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:65,3-11) edges | test.c:14:38:14:39 | p1 | test.c:18:10:18:11 | v1 | provenance | | | test.c:14:38:14:39 | p1 | test.c:19:10:19:11 | v2 | provenance | | diff --git a/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected b/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected index bfd6b23128..7782984e5b 100644 --- a/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected +++ b/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected @@ -1,3 +1,7 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:72,56-64) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:73,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:75,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:84,45-53) edges | test.c:7:13:7:14 | p1 | test.c:9:9:9:10 | p1 | provenance | | | test.c:16:19:16:41 | ... - ... | test.c:18:26:18:31 | offset | provenance | | diff --git a/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected b/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected index e03b665a1c..9b1288d578 100644 --- a/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected +++ b/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected @@ -1,3 +1,9 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:21,46-54) +WARNING: Module DataFlow has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:22,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:31,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:41,35-43) +WARNING: Module DataFlow has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:49,36-44) +WARNING: Module DataFlow has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:51,36-44) | test.c:27:3:27:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | | test.c:49:3:49:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | | test.c:71:3:71:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | diff --git a/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected b/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected index c3cdc8bd7b..a513b55b73 100644 --- a/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected +++ b/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected @@ -1,3 +1,11 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,29-37) +WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,54-62) +WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:35,62-70) +WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:40,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:40,30-38) +WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:41,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:41,30-38) +WARNING: Module TaintTracking has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,3-16) | test.c:23:3:23:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:23:24:23:29 | & ... | Shared object | | test.c:74:3:74:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:74:24:74:24 | p | Shared object | | test.c:85:3:85:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:85:24:85:24 | p | Shared object | diff --git a/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected b/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected index 95d0a20041..337df4c14c 100644 --- a/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected +++ b/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected @@ -1 +1,6 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:28,38-46) +WARNING: Module DataFlow has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:31,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:31,30-38) +WARNING: Module DataFlow has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:32,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:32,30-38) | test.c:14:7:14:13 | call to tss_get | Call to a thread specific storage function from within a threaded context on an object that may not be owned by this thread. | diff --git a/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected b/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected index ff842ddcad..18d28b61bc 100644 --- a/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected +++ b/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected @@ -1,2 +1,7 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:22,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:26,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:39,6-14) +WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:39,26-34) +WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:45,3-11) | test.c:3:10:3:10 | a | $@ with automatic storage may be accessible outside of its lifetime. | test.c:3:10:3:10 | a | a | | test.c:15:4:15:8 | param [inner post update] | $@ with automatic storage may be accessible outside of its lifetime. | test.c:15:12:15:13 | a2 | a2 | diff --git a/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected b/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected index b6d7caa513..b3e5c4b7fc 100644 --- a/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected +++ b/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected @@ -1,3 +1,4 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (ErrnoReadBeforeReturn.ql:40,7-15) | test.c:69:7:69:11 | * ... | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | | test.c:69:7:69:11 | call to __errno_location | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | | test.c:70:5:70:10 | call to perror | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | diff --git a/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected b/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected index 9ab88a3395..0ffaf56bd1 100644 --- a/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected +++ b/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected @@ -1,2 +1,3 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (SetlocaleMightSetErrno.ql:64,7-15) | test.c:98:3:98:11 | call to setlocale | Do not read `errno` before checking the return value of a call to `setlocale`. | | test.c:104:7:104:15 | call to setlocale | The value of `errno` may be different than `0` when `setlocale` is called. The following `errno` check might be invalid. | diff --git a/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected b/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected index da9122cfd4..77fa7b7ba7 100644 --- a/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected +++ b/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected @@ -1,3 +1,7 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:50,7-15) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:50,27-35) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:51,9-17) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:54,9-17) | test.c:12:5:12:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:10:21:10:26 | call to signal | call to signal | | test.c:30:5:30:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:26:21:26:26 | call to signal | call to signal | | test.c:49:5:49:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:45:21:45:26 | call to signal | call to signal | diff --git a/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected b/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected index fbcc44b856..a32a03a3b9 100644 --- a/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected +++ b/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected @@ -1,3 +1,4 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleStandardLibraryErrors.ql:453,5-13) | test.c:18:3:18:11 | call to setlocale | Missing error detection for the call to function `setlocale`. | | test.c:24:23:24:31 | call to setlocale | Missing error detection for the call to function `setlocale`. | | test.c:29:22:29:27 | call to calloc | Missing error detection for the call to function `calloc`. | diff --git a/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected index 3ea1a05fd7..6ea3499517 100644 --- a/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected +++ b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected @@ -1 +1,25 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:24,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:24,59-67) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:27,33-41) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:27,57-65) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,33-41) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,59-67) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:40,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:40,25-33) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:40,53-61) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:43,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:43,57-65) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:52,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:52,55-63) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:59,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:59,57-65) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:71,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:71,55-63) +WARNING: Module TaintTracking has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:24,5-18) +WARNING: Module TaintTracking has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:27,7-20) +WARNING: Module TaintTracking has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,7-20) +WARNING: Module TaintTracking has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:43,5-18) +WARNING: Module TaintTracking has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:52,5-18) +WARNING: Module TaintTracking has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:59,5-18) +WARNING: Module TaintTracking has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:71,5-18) | test.c:20:3:20:4 | call to f1 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.c:20:6:20:7 | call to f2 | call to f2 | test.c:20:12:20:13 | call to f3 | call to f3 | diff --git a/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected b/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected index c4bc63cc94..b6f96f6ea5 100644 --- a/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected +++ b/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected @@ -1,3 +1,13 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:98,86-94) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:120,3-11) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:122,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:127,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:133,3-11) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:139,55-63) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:140,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:142,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:149,26-34) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:164,44-52) edges | test.c:75:14:75:16 | & ... | test.c:76:11:76:12 | v1 | provenance | | | test.c:75:14:75:16 | & ... | test.c:77:12:77:13 | v1 | provenance | | diff --git a/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected b/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected index 546c753ebb..1b6505f472 100644 --- a/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected +++ b/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected @@ -1,3 +1,7 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:40,54-62) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:41,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:45,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:50,43-51) edges | test.c:48:68:48:70 | fns [f1] | test.c:49:3:49:5 | fns [f1] | provenance | | | test.c:49:3:49:5 | fns [f1] | test.c:49:8:49:9 | f1 | provenance | | diff --git a/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected b/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected index 137017d53a..3316256acb 100644 --- a/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected +++ b/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected @@ -1,3 +1,10 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:61,38-46) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:64,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:69,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:102,23-31) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:111,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:111,45-53) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:133,27-35) edges | test.c:49:8:49:9 | s3 | test.c:50:8:50:9 | s1 | provenance | | | test.c:60:16:60:18 | E1A | test.c:61:16:61:17 | e1 | provenance | | diff --git a/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected b/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected index bef45f3841..e7af404ec1 100644 --- a/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected +++ b/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected @@ -1,3 +1,7 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:35,30-38) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:36,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:42,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:47,19-27) edges | test.c:5:8:5:9 | & ... | test.c:6:4:6:5 | aa | provenance | | | test.c:26:15:26:15 | a | test.c:27:4:27:4 | a | provenance | | diff --git a/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.expected b/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.expected index 4d4c20a39c..a77a92ee81 100644 --- a/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.expected +++ b/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.expected @@ -1,3 +1,15 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:103,36-44) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:118,51-59) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:119,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:121,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:127,25-33) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:132,40-48) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:146,41-49) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:147,7-15) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:150,43-51) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:151,9-17) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:158,43-51) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:159,9-17) | test.c:59:3:59:6 | call to copy | Call to 'copy' passes an $@ to a $@ (pointer value derived from a pair of address-of expressions ($@, $@). | test.c:59:13:59:15 | & ... | aliased pointer | test.c:59:8:59:10 | & ... | restrict-qualified parameter | test.c:59:8:59:10 | & ... | addressof1 | test.c:59:13:59:15 | & ... | addressof2 | | test.c:65:3:65:6 | call to copy | Call to 'copy' passes an $@ to a $@ (pointer value derived from a pair of address-of expressions ($@, $@). | test.c:65:15:65:19 | & ... | aliased pointer | test.c:65:8:65:12 | & ... | restrict-qualified parameter | test.c:65:8:65:12 | & ... | addressof1 | test.c:65:15:65:19 | & ... | addressof2 | | test.c:67:3:67:6 | call to copy | Call to 'copy' passes an $@ to a $@ (pointer value derived from a pair of address-of expressions ($@, $@). | test.c:67:15:67:16 | px | aliased pointer | test.c:67:8:67:12 | & ... | restrict-qualified parameter | test.c:67:8:67:12 | & ... | addressof1 | test.c:63:13:63:17 | & ... | addressof2 | diff --git a/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected b/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected index 3746991c09..591e17661a 100644 --- a/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected +++ b/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected @@ -1,3 +1,10 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:42,57-65) +WARNING: Module DataFlow has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:43,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:47,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:53,3-11) +WARNING: Module DataFlow has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:56,58-66) +WARNING: Module DataFlow has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:72,64-72) +WARNING: Module DataFlow has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:73,64-72) | test.c:18:22:18:23 | i2 | Assignment to restrict-qualified pointer $@ results in pointers aliasing $@. | test.c:18:17:18:18 | i3 | i3 | test.c:18:22:18:23 | i2 | the object pointed to by i2 | | test.c:19:8:19:9 | g2 | Assignment to restrict-qualified pointer $@ results in pointers aliasing $@. | test.c:5:15:5:16 | g1 | g1 | test.c:19:8:19:9 | g2 | the object pointed to by g2 | | test.c:20:8:20:9 | i2 | Assignment to restrict-qualified pointer $@ results in pointers aliasing $@. | test.c:16:17:16:18 | i1 | i1 | test.c:20:8:20:9 | i2 | the object pointed to by i2 | diff --git a/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected b/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected index 20c108cfa0..6a73ee98a7 100644 --- a/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected +++ b/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected @@ -1,3 +1,6 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:42,11-19) +WARNING: Module DataFlow has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:42,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:43,13-21) | test.c:20:10:20:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:15:7:15:11 | call to fgets | call to fgets | | test.c:57:10:57:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:52:7:52:11 | call to fgets | call to fgets | | test.c:66:18:66:20 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:61:7:61:11 | call to fgets | call to fgets | diff --git a/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected b/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected index 8074710738..637918f241 100644 --- a/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected +++ b/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected @@ -1,2 +1,7 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:25,32-40) +WARNING: Module DataFlow has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:26,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:28,14-22) +WARNING: Module DataFlow has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:31,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:37,21-29) | test.c:7:24:7:30 | & ... | The position argument of a call to `fsetpos()` should be obtained from a call to `fgetpos()`. | | test.c:33:24:33:30 | & ... | The position argument of a call to `fsetpos()` should be obtained from a call to `fgetpos()`. | diff --git a/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected b/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected index 1b2923b780..f294ce05b7 100644 --- a/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected +++ b/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected @@ -1,2 +1,3 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (ToctouRaceConditionsWhileAccessingFiles.ql:27,35-43) | test.c:4:13:4:17 | call to fopen | This call is trying to prevent an existing file from being overwritten by $@. An attacker might be able to exploit the race window between the two calls. | test.c:11:9:11:13 | call to fopen | another call | | test.c:88:13:88:17 | call to fopen | This call is trying to prevent an existing file from being overwritten by $@. An attacker might be able to exploit the race window between the two calls. | test.c:95:9:95:13 | call to fopen | another call | diff --git a/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected b/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected index 30dece9299..73dd6ba1e0 100644 --- a/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected +++ b/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected @@ -1,3 +1,5 @@ +WARNING: Module TaintTracking has been deprecated and may be removed in future (InsufficientMemoryAllocatedForObject.ql:85,5-18) +WARNING: Module TaintTracking has been deprecated and may be removed in future (InsufficientMemoryAllocatedForObject.ql:143,5-18) | test.c:12:19:12:24 | call to malloc | Allocation size (32 bytes) is not a multiple of the size of 'S1' (36 bytes). | test.c:12:26:12:32 | 32 | | | test.c:15:19:15:24 | call to malloc | Allocation size calculated from the size of a different type ($@). | test.c:15:26:15:35 | sizeof() | sizeof(S1 *) | | test.c:20:19:20:24 | call to malloc | Allocation size (128 bytes) is not a multiple of the size of 'S1' (36 bytes). | test.c:20:26:20:36 | ... * ... | | diff --git a/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected b/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected index 0ae87f2ee8..61c2cfb1f0 100644 --- a/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected +++ b/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected @@ -1,3 +1,8 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:26,36-44) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:40,47-55) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:41,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:45,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:50,36-44) edges | test.c:5:10:5:22 | call to aligned_alloc | test.c:15:8:15:28 | call to aligned_alloc_wrapper | provenance | | | test.c:8:29:8:31 | ptr | test.c:8:64:8:66 | ptr | provenance | | diff --git a/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected b/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected index 70d60c528a..713646db10 100644 --- a/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected +++ b/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected @@ -1 +1,5 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:33,38-46) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:34,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:41,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:44,27-35) | test.c:6:24:6:30 | time_tm | The function `asctime` and `asctime_r` should be discouraged. Unsanitized input can overflow the output buffer. | diff --git a/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected b/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected index 2b7bb2bdbc..4d4a713487 100644 --- a/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected +++ b/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected @@ -1,3 +1,10 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:38,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:39,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:44,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:47,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:68,10-18) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:69,29-37) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:70,29-37) | test.c:23:32:23:33 | ap | The value of ap is indeterminate after the $@. | test.c:17:7:17:19 | call to contains_zero | call to contains_zero | | test.c:26:10:26:11 | ap | The value of ap is indeterminate after the $@. | test.c:17:7:17:19 | call to contains_zero | call to contains_zero | | test.c:39:12:39:13 | ap | The value of ap is indeterminate after the $@. | test.c:35:7:35:19 | call to contains_zero | call to contains_zero | diff --git a/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected b/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected index a601fe63f4..a5f4af8c3c 100644 --- a/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected +++ b/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected @@ -1,3 +1,6 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:105,11-19) +WARNING: Module DataFlow has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:105,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:106,9-17) | test.c:10:3:10:18 | call to log_local_unsafe | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:16:7:16:12 | call to signal | signal handler | | test.c:11:3:11:6 | call to free | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:16:7:16:12 | call to signal | signal handler | | test.c:46:3:46:9 | call to longjmp | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:50:7:50:12 | call to signal | signal handler | diff --git a/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected b/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected index 31412c466a..d4796c6ede 100644 --- a/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected +++ b/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected @@ -1 +1,2 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotReturnFromAComputationalExceptionHandler.ql:39,5-13) | test.c:10:1:10:1 | return ... | Do not return from a $@ signal handler. | test.c:13:10:13:15 | SIGFPE | computational exception | diff --git a/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected b/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected index 27ef66bc7a..7215fd8603 100644 --- a/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected +++ b/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected @@ -1,3 +1,18 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:42,65-73) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:43,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:64,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:77,3-11) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:101,11-19) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:101,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:101,55-63) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,11-19) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,57-65) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:139,11-19) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:139,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:139,55-63) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:150,53-61) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:151,5-13) | test.c:7:3:7:3 | a | This operation may write to a string that may be a string literal that was $@. | test.c:6:13:6:20 | codeql | created here | | test.c:30:3:30:3 | a | This operation may write to a string that may be a string literal that was $@. | test.c:29:13:29:18 | call to strchr | created here | | test.c:36:3:36:3 | b | This operation may write to a string that may be a string literal that was $@. | test.c:35:13:35:18 | call to strchr | created here | diff --git a/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected b/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected index 71e713d120..4c411382f0 100644 --- a/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected +++ b/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected @@ -1,3 +1,9 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:57,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:57,55-63) +WARNING: Module DataFlow has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:63,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:63,54-62) +WARNING: Module TaintTracking has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:57,5-18) +WARNING: Module TaintTracking has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:63,5-18) | test.c:10:20:10:24 | Cod | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | | test.c:16:3:16:9 | call to strncpy | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | | test.c:26:3:26:10 | call to snprintf | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | diff --git a/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected b/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected index 4099e3fb1a..341440d589 100644 --- a/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected +++ b/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected @@ -1,3 +1,12 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:55,33-41) +WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:55,73-81) +WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:61,33-41) +WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:61,57-65) +WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:69,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:69,69-77) +WARNING: Module TaintTracking has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:55,7-20) +WARNING: Module TaintTracking has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:61,7-20) +WARNING: Module TaintTracking has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:69,5-18) | test.c:19:3:19:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:7:20:7:24 | Cod | this expression | | test.c:20:3:20:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:7:20:7:24 | Cod | this expression | | test.c:22:3:22:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:13:3:13:9 | call to strncpy | this expression | diff --git a/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected b/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected index 913f6f1c34..d9cd037d42 100644 --- a/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected +++ b/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected @@ -1,3 +1,9 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:47,36-44) +WARNING: Module DataFlow has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:48,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:50,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:55,25-33) +WARNING: Module DataFlow has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:71,28-36) +WARNING: Module DataFlow has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:71,51-59) | test.c:18:6:18:6 | 0 | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | | test.c:19:6:19:7 | ar | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | | test.c:21:6:21:9 | ar2p | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | diff --git a/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected b/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected index cded1a0a89..ef6703a285 100644 --- a/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected +++ b/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected @@ -1,3 +1,7 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:22,54-62) +WARNING: Module DataFlow has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:23,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:49,20-28) +WARNING: Module TaintTracking has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:57,43-56) edges | test.c:12:13:12:15 | a | test.c:14:10:14:10 | a | provenance | | | test.c:12:13:12:15 | a | test.c:23:13:23:13 | a | provenance | | diff --git a/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected b/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected index 6111072ba8..3382b66847 100644 --- a/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected +++ b/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected @@ -1,3 +1,4 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (FileOpenForReadAndWriteOnDifferentStreams.ql:38,9-17) | test.c:6:14:6:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:5:14:5:18 | call to fopen | here | | test.c:17:14:17:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:16:14:16:18 | call to fopen | here | | test.c:33:14:33:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:32:14:32:18 | call to fopen | here | diff --git a/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected b/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected index 0bfce133c5..08363e7dda 100644 --- a/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected +++ b/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected @@ -1,2 +1,8 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:18,32-40) +WARNING: Module DataFlow has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:19,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:24,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:30,21-29) +WARNING: Module DataFlow has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:32,6-14) +WARNING: Module DataFlow has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:35,28-36) | test.c:10:3:10:9 | call to fprintf | Attempt to write to a $@ opened as read-only. | test.c:9:14:9:18 | call to fopen | stream | | test.c:15:3:15:9 | call to fprintf | Attempt to write to a $@ opened as read-only. | test.c:18:14:18:18 | call to fopen | stream | diff --git a/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected index 709d8b002c..9e975d34e4 100644 --- a/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected +++ b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected @@ -1,2 +1,10 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:22,28-36) +WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:23,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:27,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:36,23-31) +WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:41,17-25) +WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:50,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:58,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:58,46-54) | test.c:6:7:6:20 | ... != ... | The check is not reliable as the type of the return value of $@ is converted. | test.c:5:14:5:20 | call to getchar | call to getchar | | test.c:13:7:13:15 | ... != ... | The check is not reliable as the type of the return value of $@ is converted. | test.c:12:14:12:20 | call to getchar | call to getchar | diff --git a/cpp/autosar/test/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.expected b/cpp/autosar/test/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.expected index 53dc884023..11b622f271 100644 --- a/cpp/autosar/test/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.expected +++ b/cpp/autosar/test/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.expected @@ -1 +1,4 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql:27,33-41) +WARNING: Module DataFlow has been deprecated and may be removed in future (UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql:28,5-13) +WARNING: Module TaintTracking has been deprecated and may be removed in future (UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql:27,7-20) | test.cpp:47:8:47:23 | operator ""_uds5 | User defined literal operator returns $@, which is not converted from a passed parameter | test.cpp:48:10:48:12 | 0.0 | expression | diff --git a/cpp/autosar/test/rules/A13-2-1/AssignmentOperatorReturnThis.expected b/cpp/autosar/test/rules/A13-2-1/AssignmentOperatorReturnThis.expected index e9929173b0..4a4697facc 100644 --- a/cpp/autosar/test/rules/A13-2-1/AssignmentOperatorReturnThis.expected +++ b/cpp/autosar/test/rules/A13-2-1/AssignmentOperatorReturnThis.expected @@ -1,3 +1,4 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (AssignmentOperatorReturnThis.ql:25,5-13) | test.cpp:10:12:10:20 | operator= | User-defined assignment operator $@ does not return *this | test.cpp:10:12:10:20 | operator= | user defined assignment operator | | test.cpp:17:11:17:19 | operator= | User-defined assignment operator $@ does not return *this | test.cpp:17:11:17:19 | operator= | user defined assignment operator | | test.cpp:24:12:24:20 | operator= | User-defined assignment operator $@ does not return *this | test.cpp:24:12:24:20 | operator= | user defined assignment operator | diff --git a/cpp/autosar/test/rules/A15-1-3/ThrownExceptionsShouldBeUnique.expected b/cpp/autosar/test/rules/A15-1-3/ThrownExceptionsShouldBeUnique.expected index b085736659..92504006b9 100644 --- a/cpp/autosar/test/rules/A15-1-3/ThrownExceptionsShouldBeUnique.expected +++ b/cpp/autosar/test/rules/A15-1-3/ThrownExceptionsShouldBeUnique.expected @@ -1,3 +1,4 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (ThrownExceptionsShouldBeUnique.ql:24,3-11) | test.cpp:6:5:6:26 | throw ... | The $@ thrown here is a possible duplicate of the $@ thrown $@. | test.cpp:6:5:6:26 | call to exception | std::exception exception | test.cpp:14:5:14:26 | call to exception | exception | test.cpp:14:5:14:26 | throw ... | here | | test.cpp:8:5:8:53 | throw ... | The $@ thrown here is a possible duplicate of the $@ thrown $@. | test.cpp:8:5:8:53 | call to runtime_error | std::runtime_error exception | test.cpp:16:5:16:53 | call to runtime_error | exception | test.cpp:16:5:16:53 | throw ... | here | | test.cpp:14:5:14:26 | throw ... | The $@ thrown here is a possible duplicate of the $@ thrown $@. | test.cpp:14:5:14:26 | call to exception | std::exception exception | test.cpp:6:5:6:26 | call to exception | exception | test.cpp:6:5:6:26 | throw ... | here | diff --git a/cpp/autosar/test/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.expected b/cpp/autosar/test/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.expected index 941771dada..2fd57c3b20 100644 --- a/cpp/autosar/test/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.expected +++ b/cpp/autosar/test/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.expected @@ -1,3 +1,12 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:47,12-20) +WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:48,30-38) +WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:48,57-65) +WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:74,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:74,25-33) +WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:75,7-15) +WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:130,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:130,25-33) +WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:130,54-62) edges | test.cpp:12:16:12:27 | new [bad_alloc] | test.cpp:14:33:16:5 | { ... } [bad_alloc] | | test.cpp:13:7:13:28 | throw ... [exception] | test.cpp:14:33:16:5 | { ... } [exception] | diff --git a/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected b/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected index 5f752403dc..6babf2c883 100644 --- a/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected +++ b/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected @@ -1,3 +1,10 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:26,67-75) +WARNING: Module DataFlow has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:27,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:39,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:50,34-42) +WARNING: Module DataFlow has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:50,57-65) +WARNING: Module DataFlow has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:58,25-33) +WARNING: Module TaintTracking has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:70,3-16) edges | test.cpp:3:36:3:45 | new[] | test.cpp:19:27:19:44 | call to allocate_int_array | provenance | | | test.cpp:3:36:3:45 | new[] | test.cpp:23:12:23:29 | call to allocate_int_array | provenance | | diff --git a/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected b/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected index d9dd02c054..cf611ded5b 100644 --- a/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected +++ b/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected @@ -1,3 +1,7 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:55,34-42) +WARNING: Module DataFlow has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:57,26-34) +WARNING: Module TaintTracking has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:71,5-18) +WARNING: Module TaintTracking has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:76,41-54) | test.cpp:17:17:17:29 | new | StructA object of size 8 bytes does not appear to outlive the function, but is created on the heap instead of the stack. | | test.cpp:21:17:21:32 | new[] | StructA[] object of size 800 bytes does not appear to outlive the function, but is created on the heap instead of the stack. | | test.cpp:35:20:35:44 | call to make_shared | StructA object of size 8 bytes does not appear to outlive the function, but is created on the heap instead of the stack. | diff --git a/cpp/autosar/test/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.expected b/cpp/autosar/test/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.expected index 1c72dd7bf3..2875a68f28 100644 --- a/cpp/autosar/test/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.expected +++ b/cpp/autosar/test/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.expected @@ -1 +1,4 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (ArgumentToForwardSubsequentlyUsed.ql:22,10-18) +WARNING: Module DataFlow has been deprecated and may be removed in future (ArgumentToForwardSubsequentlyUsed.ql:24,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (ArgumentToForwardSubsequentlyUsed.ql:24,30-38) | test.cpp:8:5:8:6 | t2 | The argument $@ of `std::forward` may be indeterminate when accessed at this location. | test.cpp:7:45:7:46 | t2 | t2 | diff --git a/cpp/autosar/test/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.expected b/cpp/autosar/test/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.expected index f15f142b3b..03406ac254 100644 --- a/cpp/autosar/test/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.expected +++ b/cpp/autosar/test/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.expected @@ -1,3 +1,4 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (SharedPointerUsedWithNoOwnershipSharing.ql:47,7-15) | test.cpp:14:24:14:26 | sp3 | The ownership of shared_ptr $@ is not shared within or passed out of the local scope of function $@. | test.cpp:14:24:14:26 | sp3 | sp3 | test.cpp:11:22:11:23 | f1 | f1 | | test.cpp:16:24:16:26 | sp5 | The ownership of shared_ptr $@ is not shared within or passed out of the local scope of function $@. | test.cpp:16:24:16:26 | sp5 | sp5 | test.cpp:11:22:11:23 | f1 | f1 | | test.cpp:17:24:17:26 | sp6 | The ownership of shared_ptr $@ is not shared within or passed out of the local scope of function $@. | test.cpp:17:24:17:26 | sp6 | sp6 | test.cpp:11:22:11:23 | f1 | f1 | diff --git a/cpp/autosar/test/rules/A27-0-4/CStyleStringsUsed.expected b/cpp/autosar/test/rules/A27-0-4/CStyleStringsUsed.expected index 6184aad74e..eaaaaac98d 100644 --- a/cpp/autosar/test/rules/A27-0-4/CStyleStringsUsed.expected +++ b/cpp/autosar/test/rules/A27-0-4/CStyleStringsUsed.expected @@ -1,3 +1,6 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (CStyleStringsUsed.ql:39,3-11) +WARNING: Module DataFlow has been deprecated and may be removed in future (CStyleStringsUsed.ql:39,23-31) +WARNING: Module DataFlow has been deprecated and may be removed in future (CStyleStringsUsed.ql:39,47-55) | test.cpp:7:20:7:27 | CodeQL | Usage of C-style string in $@. | test.cpp:7:20:7:27 | CodeQL | expression | | test.cpp:7:20:7:27 | CodeQL | Usage of C-style string in $@. | test.cpp:16:16:16:17 | a1 | expression | | test.cpp:8:22:8:26 | call to c_str | Usage of C-style string in $@. | test.cpp:8:22:8:26 | call to c_str | expression | diff --git a/cpp/autosar/test/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.expected b/cpp/autosar/test/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.expected index b47755725c..9f97a58467 100644 --- a/cpp/autosar/test/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.expected +++ b/cpp/autosar/test/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.expected @@ -1,3 +1,7 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:45,62-70) +WARNING: Module DataFlow has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:46,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:55,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:61,3-11) edges | test.cpp:10:18:10:20 | foo | test.cpp:11:23:11:25 | foo | provenance | | | test.cpp:10:18:10:20 | foo | test.cpp:11:50:11:52 | foo | provenance | | diff --git a/cpp/autosar/test/rules/A5-1-7/LambdaPassedToDecltype.expected b/cpp/autosar/test/rules/A5-1-7/LambdaPassedToDecltype.expected index 8f6447a96b..03eaab82aa 100644 --- a/cpp/autosar/test/rules/A5-1-7/LambdaPassedToDecltype.expected +++ b/cpp/autosar/test/rules/A5-1-7/LambdaPassedToDecltype.expected @@ -1 +1,7 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:20,55-63) +WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:21,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:23,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:28,44-52) +WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:39,47-55) +WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:40,9-17) | test.cpp:14:23:14:24 | decltype(...) | Lambda $@ passed as operand to decltype. | test.cpp:5:13:5:30 | [...](...){...} | expression | diff --git a/cpp/autosar/test/rules/A5-1-7/LambdaPassedToTypeid.expected b/cpp/autosar/test/rules/A5-1-7/LambdaPassedToTypeid.expected index 6d65a7b5d5..916b9db113 100644 --- a/cpp/autosar/test/rules/A5-1-7/LambdaPassedToTypeid.expected +++ b/cpp/autosar/test/rules/A5-1-7/LambdaPassedToTypeid.expected @@ -1,3 +1,7 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:21,50-58) +WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:22,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:24,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:27,39-47) edges | test.cpp:5:13:5:30 | [...](...){...} | test.cpp:8:38:8:39 | l1 | provenance | | | test.cpp:6:13:6:30 | [...](...){...} | test.cpp:9:38:9:39 | l2 | provenance | | diff --git a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected index dbf223e0cf..dd499ceb57 100644 --- a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected +++ b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected @@ -1,3 +1,9 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (VariableMissingConstexpr.ql:64,7-15) +WARNING: Module DataFlow has been deprecated and may be removed in future (VariableMissingConstexpr.ql:79,10-18) +WARNING: Module DataFlow has been deprecated and may be removed in future (VariableMissingConstexpr.ql:79,44-52) +WARNING: Module DataFlow has been deprecated and may be removed in future (VariableMissingConstexpr.ql:80,17-25) +WARNING: Module DataFlow has been deprecated and may be removed in future (VariableMissingConstexpr.ql:81,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (VariableMissingConstexpr.ql:82,9-17) | test.cpp:4:5:4:6 | g1 | Variable g1 could be marked 'constexpr'. | | test.cpp:6:5:6:6 | g2 | Variable g2 could be marked 'constexpr'. | | test.cpp:13:14:13:15 | lc | Variable lc could be marked 'constexpr'. | diff --git a/cpp/autosar/test/rules/A7-5-1/InvalidFunctionReturnType.expected b/cpp/autosar/test/rules/A7-5-1/InvalidFunctionReturnType.expected index b6d9490803..0ab837454a 100644 --- a/cpp/autosar/test/rules/A7-5-1/InvalidFunctionReturnType.expected +++ b/cpp/autosar/test/rules/A7-5-1/InvalidFunctionReturnType.expected @@ -1,2 +1,5 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (InvalidFunctionReturnType.ql:27,3-11) +WARNING: Module DataFlow has been deprecated and may be removed in future (InvalidFunctionReturnType.ql:27,23-31) +WARNING: Module DataFlow has been deprecated and may be removed in future (InvalidFunctionReturnType.ql:27,51-59) | test.cpp:5:3:5:11 | return ... | Function test_refconst_return returns a reference or a pointer to $@ that is passed by reference to const. | test.cpp:4:44:4:44 | x | parameter | | test.cpp:8:3:8:14 | return ... | Function test_ptrconst_return returns a reference or a pointer to $@ that is passed by reference to const. | test.cpp:7:44:7:44 | x | parameter | diff --git a/cpp/autosar/test/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.expected b/cpp/autosar/test/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.expected index b751d81835..be4a4107fd 100644 --- a/cpp/autosar/test/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.expected +++ b/cpp/autosar/test/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.expected @@ -1,3 +1,5 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (SmartPointerAsParameterWithoutLifetimeSemantics.ql:47,3-11) +WARNING: Module DataFlow has been deprecated and may be removed in future (SmartPointerAsParameterWithoutLifetimeSemantics.ql:56,5-13) | test.cpp:7:41:7:43 | up1 | Function $@ takes smart pointer parameter 'up1' but does not implement any lifetime-affecting operations. | test.cpp:7:6:7:18 | smart_ptr_get | smart_ptr_get | | test.cpp:16:53:16:55 | sp1 | Function $@ takes smart pointer parameter 'sp1' but does not implement any lifetime-affecting operations. | test.cpp:16:6:16:29 | smart_ptr_ref_assign_ref | smart_ptr_ref_assign_ref | | test.cpp:28:55:28:57 | sp1 | Function $@ takes smart pointer parameter 'sp1' but does not implement any lifetime-affecting operations. | test.cpp:28:6:28:31 | smart_ptr_ref_noncompliant | smart_ptr_ref_noncompliant | diff --git a/cpp/autosar/test/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.expected b/cpp/autosar/test/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.expected index a01b93335d..b2273e66f3 100644 --- a/cpp/autosar/test/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.expected +++ b/cpp/autosar/test/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.expected @@ -1,3 +1,5 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (UniquePtrPassedToFunctionWithImproperSemantics.ql:41,3-11) +WARNING: Module DataFlow has been deprecated and may be removed in future (UniquePtrPassedToFunctionWithImproperSemantics.ql:51,5-13) | test.cpp:13:55:13:56 | v1 | Parameter of type std::unique_ptr passed as lvalue reference but not used to modify underlying object. | | test.cpp:17:47:17:48 | v1 | Parameter of type std::unique_ptr passed as lvalue reference but not used to modify underlying object. | | test.cpp:22:27:22:28 | v1 | Parameter of type std::unique_ptr passed as lvalue reference but not used to modify underlying object. | diff --git a/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected b/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected index e3cfa71bb7..15e513c639 100644 --- a/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected +++ b/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected @@ -1,3 +1,5 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (InOutParametersDeclaredAsTNotModified.ql:49,7-15) +WARNING: Module DataFlow has been deprecated and may be removed in future (InOutParametersDeclaredAsTNotModified.ql:63,7-15) | test.cpp:4:13:4:13 | i | In-out parameter i that is not written to. | | test.cpp:7:22:7:24 | str | In-out parameter str that is not read from. | | test.cpp:18:14:18:14 | i | In-out parameter i that is not read from. | diff --git a/cpp/autosar/test/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.expected b/cpp/autosar/test/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.expected index 04c1f35a45..84d7f2d7f0 100644 --- a/cpp/autosar/test/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.expected +++ b/cpp/autosar/test/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.expected @@ -1,3 +1,6 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql:73,3-11) +WARNING: Module DataFlow has been deprecated and may be removed in future (ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql:73,23-31) +WARNING: Module DataFlow has been deprecated and may be removed in future (ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql:73,46-54) | test.cpp:20:8:20:12 | getB2 | Member function A::getB2 $@ a non-const raw pointer or reference to a private or protected $@. | test.cpp:20:25:20:25 | b | returns | test.cpp:54:7:54:7 | b | field | | test.cpp:22:8:22:12 | getB3 | Member function A::getB3 $@ a non-const raw pointer or reference to a private or protected $@. | test.cpp:22:25:22:26 | & ... | returns | test.cpp:54:7:54:7 | b | field | | test.cpp:24:8:24:13 | getB33 | Member function A::getB33 $@ a non-const raw pointer or reference to a private or protected $@. | test.cpp:26:12:26:13 | bb | returns | test.cpp:54:7:54:7 | b | field | diff --git a/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.expected b/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.expected index 76cbcebed0..15f4e9a793 100644 --- a/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.expected +++ b/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.expected @@ -1 +1,4 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (FunctionErroneousReturnValueNotTested.ql:70,9-17) +WARNING: Module DataFlow has been deprecated and may be removed in future (FunctionErroneousReturnValueNotTested.ql:70,29-37) +WARNING: Module DataFlow has been deprecated and may be removed in future (FunctionErroneousReturnValueNotTested.ql:70,53-61) | test.cpp:16:3:16:8 | call to remove | Return value is not tested for errors. | diff --git a/cpp/autosar/test/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.expected b/cpp/autosar/test/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.expected index 9aec2314da..2545360a7b 100644 --- a/cpp/autosar/test/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.expected +++ b/cpp/autosar/test/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.expected @@ -1,2 +1,5 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql:27,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql:36,10-18) +WARNING: Module DataFlow has been deprecated and may be removed in future (UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql:37,5-13) | test.cpp:5:3:5:20 | ... &= ... | Modification of bit-representation of float originated at $@ | test.cpp:4:24:4:60 | reinterpret_cast... | cast | | test.cpp:12:3:12:14 | ... &= ... | Modification of bit-representation of float originated at $@ | test.cpp:11:18:11:30 | (uint8_t *)... | cast | diff --git a/cpp/autosar/test/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.expected b/cpp/autosar/test/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.expected index ee9652f505..eee85d22c0 100644 --- a/cpp/autosar/test/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.expected +++ b/cpp/autosar/test/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.expected @@ -1,3 +1,5 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (ConstMemberFunctionReturnsNonConstPointer.ql:53,7-15) +WARNING: Module DataFlow has been deprecated and may be removed in future (ConstMemberFunctionReturnsNonConstPointer.ql:55,7-15) | test.cpp:8:8:8:11 | getA | Const member function returns a pointer to class data $@. | test.cpp:3:8:3:8 | a | a | | test.cpp:9:8:9:11 | getB | Const member function returns a pointer to class data $@. | test.cpp:4:8:4:8 | b | b | | test.cpp:11:6:11:12 | getThis | Const member function returns a pointer to class data $@. | test.cpp:11:36:11:39 | this | this | diff --git a/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected b/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected index 4e87d1436c..06abadc4fe 100644 --- a/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected +++ b/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected @@ -1,3 +1,12 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:97,7-15) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:97,27-35) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:98,9-17) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:102,9-17) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:102,29-37) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:103,11-19) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:113,35-43) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:114,11-19) +WARNING: Module TaintTracking has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:113,9-22) | test.cpp:8:42:8:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:8:3:8:11 | call to copy | call to copy | | test.cpp:17:42:17:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:17:3:17:11 | call to copy | call to copy | | test.cpp:55:42:55:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:55:3:55:11 | call to copy | call to copy | diff --git a/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected b/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected index 61260a0579..5730a54b2c 100644 --- a/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected +++ b/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected @@ -1,3 +1,9 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (UseValidIteratorRanges.ql:23,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (UseValidIteratorRanges.ql:23,25-33) +WARNING: Module DataFlow has been deprecated and may be removed in future (UseValidIteratorRanges.ql:24,7-15) +WARNING: Module DataFlow has been deprecated and may be removed in future (UseValidIteratorRanges.ql:30,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (UseValidIteratorRanges.ql:30,25-33) +WARNING: Module DataFlow has been deprecated and may be removed in future (UseValidIteratorRanges.ql:31,7-15) | test.cpp:7:3:7:15 | call to for_each | The $@ of iterator range function does not point to the end of an iterator. | test.cpp:7:28:7:32 | call to begin | argument | | test.cpp:7:3:7:15 | call to for_each | The $@ of iterator range function does not point to the start of an iterator. | test.cpp:7:19:7:21 | call to end | argument | | test.cpp:8:3:8:15 | call to for_each | The $@ of iterator range function does not point to the end of an iterator. | test.cpp:8:30:8:34 | call to begin | argument | diff --git a/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected b/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected index eabb6d7515..1f97f2ca40 100644 --- a/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected +++ b/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected @@ -1,3 +1,7 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:41,62-70) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:42,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:51,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:57,3-11) edges | test.cpp:15:19:15:21 | foo | test.cpp:16:24:16:26 | foo | provenance | | | test.cpp:15:19:15:21 | foo | test.cpp:16:51:16:53 | foo | provenance | | diff --git a/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected b/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected index b432856e8b..243602e104 100644 --- a/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected +++ b/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected @@ -1,3 +1,27 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:24,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:24,59-67) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:27,33-41) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:27,57-65) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:31,33-41) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:31,59-67) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:40,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:40,25-33) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:40,53-61) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:43,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:43,57-65) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:52,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:52,55-63) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:59,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:59,57-65) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:71,31-39) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:71,55-63) +WARNING: Module TaintTracking has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:24,5-18) +WARNING: Module TaintTracking has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:27,7-20) +WARNING: Module TaintTracking has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:31,7-20) +WARNING: Module TaintTracking has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:43,5-18) +WARNING: Module TaintTracking has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:52,5-18) +WARNING: Module TaintTracking has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:59,5-18) +WARNING: Module TaintTracking has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:71,5-18) | test.cpp:82:3:82:4 | call to f2 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.cpp:82:6:82:7 | call to f5 | call to f5 | test.cpp:82:12:82:13 | call to f6 | call to f6 | | test.cpp:84:3:84:4 | call to f2 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.cpp:84:6:84:7 | call to f5 | call to f5 | test.cpp:84:12:84:13 | call to f7 | call to f7 | | test.cpp:87:3:87:4 | call to f2 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.cpp:87:9:87:10 | call to m1 | call to m1 | test.cpp:87:18:87:19 | call to m1 | call to m1 | diff --git a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected index 9c6e6dd071..a3c0c08011 100644 --- a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected +++ b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected @@ -1,3 +1,7 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:19,44-52) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:20,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:22,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:27,33-41) edges | test.cpp:6:19:6:37 | new[] | test.cpp:9:12:9:13 | l1 | provenance | | | test.cpp:7:22:7:40 | new[] | test.cpp:10:12:10:13 | l2 | provenance | | diff --git a/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected b/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected index b7452ec199..b30e94a38e 100644 --- a/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected +++ b/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected @@ -1,2 +1,9 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:59,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:61,36-44) +WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:77,46-54) +WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:78,22-30) +WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:82,20-28) +WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:85,35-43) +WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:90,38-46) | test.cpp:24:7:24:34 | new | nothrow new allocation of $@ returns here without a subsequent check to see whether the pointer is valid. | test.cpp:24:7:24:34 | new | StructA * | | test.cpp:40:17:40:38 | call to allocate_without_check | nothrow new allocation of $@ returns here without a subsequent check to see whether the pointer is valid. | test.cpp:35:17:35:44 | new | StructA * | diff --git a/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected b/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected index 0128221ffc..adabb21674 100644 --- a/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected +++ b/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected @@ -1,3 +1,4 @@ +WARNING: Module TaintTracking has been deprecated and may be removed in future (BadlySeededRandomNumberGenerator.ql:37,7-20) | test.cpp:9:33:9:33 | call to linear_congruential_engine | Random number generator linear_congruential_engine is default-initialized and is therefore not properly seeded. | | test.cpp:10:30:10:31 | call to linear_congruential_engine | Random number generator linear_congruential_engine is default-initialized and is therefore not properly seeded. | | test.cpp:11:21:11:22 | call to linear_congruential_engine | Random number generator linear_congruential_engine is default-initialized and is therefore not properly seeded. | From e5cdb71cf7b21c1d03fa209be40fc6fb16a59087 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 23 May 2024 17:42:29 +0200 Subject: [PATCH 019/628] C++: Update expected test results after dataflow library changes and merge from main --- ...riableViaPointerOfIncompatibleType.expected | 2 +- ...tPointersAddressingDifferentArrays.expected | 4 ++-- ...tionalOperatorsWithDifferingArrays.expected | 6 +++--- ...mentOfAnArrayPassedToASmartPointer.expected | 1 + .../A7-1-2/VariableMissingConstexpr.expected | 6 ------ ...icCppLibraryFunctionsDoNotOverflow.expected | 18 +++++++++--------- ...tUseAnAdditiveOperatorOnAnIterator.expected | 9 +++++++++ ...tPointersAddressingDifferentArrays.expected | 4 ++-- ...tionalOperatorsWithDifferingArrays.expected | 6 +++--- ...ValueStoredInUnrelatedSmartPointer.expected | 5 +++-- 10 files changed, 33 insertions(+), 28 deletions(-) diff --git a/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected b/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected index 3316256acb..6cf822fa15 100644 --- a/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected +++ b/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected @@ -16,7 +16,7 @@ edges | test.c:97:32:97:37 | call to malloc | test.c:98:40:98:41 | s2 | provenance | | | test.c:98:32:98:38 | call to realloc | test.c:99:3:99:4 | s3 | provenance | | | test.c:98:32:98:38 | call to realloc | test.c:100:10:100:11 | s3 | provenance | | -| test.c:98:40:98:41 | s2 | test.c:98:32:98:38 | call to realloc | provenance | | +| test.c:98:40:98:41 | s2 | test.c:98:32:98:38 | call to realloc | provenance | Config | nodes | test.c:6:19:6:20 | & ... | semmle.label | & ... | | test.c:11:10:11:11 | & ... | semmle.label | & ... | diff --git a/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected b/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected index c595e7e5f7..75866b8503 100644 --- a/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected +++ b/c/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected @@ -4,10 +4,10 @@ problems | test.c:13:10:13:11 | p4 | test.c:5:14:5:15 | l2 | test.c:13:10:13:11 | p4 | Subtraction between left operand pointing to array $@ and other operand pointing to array $@. | test.c:3:7:3:8 | l2 | l2 | test.c:2:7:2:8 | l1 | l1 | | test.c:13:15:13:16 | l1 | test.c:13:15:13:16 | l1 | test.c:13:15:13:16 | l1 | Subtraction between right operand pointing to array $@ and other operand pointing to array $@. | test.c:2:7:2:8 | l1 | l1 | test.c:3:7:3:8 | l2 | l2 | edges -| test.c:4:14:4:15 | l1 | test.c:4:14:4:18 | access to array | provenance | | +| test.c:4:14:4:15 | l1 | test.c:4:14:4:18 | access to array | provenance | Config | | test.c:4:14:4:18 | access to array | test.c:10:10:10:11 | p1 | provenance | | | test.c:4:14:4:18 | access to array | test.c:12:10:12:11 | p1 | provenance | | -| test.c:5:14:5:15 | l2 | test.c:5:14:5:19 | access to array | provenance | | +| test.c:5:14:5:15 | l2 | test.c:5:14:5:19 | access to array | provenance | Config | | test.c:5:14:5:19 | access to array | test.c:11:10:11:11 | p2 | provenance | | | test.c:5:14:5:19 | access to array | test.c:12:15:12:16 | p2 | provenance | | | test.c:5:14:5:19 | access to array | test.c:13:10:13:11 | p4 | provenance | | diff --git a/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected b/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected index 05c0ed4ca0..bda6c7ad05 100644 --- a/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected +++ b/c/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected @@ -11,17 +11,17 @@ problems | test.c:25:7:25:14 | ... >= ... | test.c:25:13:25:14 | l3 | test.c:25:13:25:14 | l3 | Compare operation >= comparing right operand pointing to array $@ and other operand pointing to array $@. | test.c:4:7:4:8 | l3 | l3 | test.c:2:7:2:8 | l1 | l1 | edges | test.c:6:13:6:14 | l1 | test.c:13:12:13:13 | p0 | provenance | | -| test.c:7:14:7:15 | l1 | test.c:7:14:7:18 | access to array | provenance | | +| test.c:7:14:7:15 | l1 | test.c:7:14:7:18 | access to array | provenance | Config | | test.c:7:14:7:18 | access to array | test.c:11:7:11:8 | p1 | provenance | | | test.c:7:14:7:18 | access to array | test.c:13:7:13:8 | p1 | provenance | | | test.c:7:14:7:18 | access to array | test.c:15:13:15:14 | p1 | provenance | | | test.c:7:14:7:18 | access to array | test.c:17:7:17:8 | p1 | provenance | | | test.c:7:14:7:18 | access to array | test.c:23:13:23:14 | p1 | provenance | | | test.c:7:14:7:18 | access to array | test.c:25:7:25:8 | p1 | provenance | | -| test.c:8:14:8:15 | l1 | test.c:8:14:8:18 | access to array | provenance | | +| test.c:8:14:8:15 | l1 | test.c:8:14:8:18 | access to array | provenance | Config | | test.c:8:14:8:18 | access to array | test.c:11:12:11:13 | p2 | provenance | | | test.c:8:14:8:18 | access to array | test.c:21:7:21:8 | p2 | provenance | | -| test.c:9:14:9:15 | l2 | test.c:9:14:9:18 | access to array | provenance | | +| test.c:9:14:9:15 | l2 | test.c:9:14:9:18 | access to array | provenance | Config | | test.c:9:14:9:18 | access to array | test.c:21:12:21:13 | p3 | provenance | | nodes | test.c:6:13:6:14 | l1 | semmle.label | l1 | diff --git a/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected b/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected index 6babf2c883..e71e667685 100644 --- a/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected +++ b/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected @@ -11,6 +11,7 @@ edges | test.cpp:3:36:3:45 | new[] | test.cpp:27:20:27:37 | call to allocate_int_array | provenance | | | test.cpp:11:29:11:41 | call to unique_ptr | test.cpp:12:27:12:28 | v2 | provenance | | | test.cpp:12:27:12:28 | v2 | test.cpp:12:30:12:36 | call to release | provenance | | +| test.cpp:12:27:12:28 | v2 | test.cpp:12:30:12:36 | call to release | provenance | Config | | test.cpp:27:20:27:37 | call to allocate_int_array | test.cpp:32:12:32:20 | int_array | provenance | | nodes | test.cpp:3:36:3:45 | new[] | semmle.label | new[] | diff --git a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected index dd499ceb57..dbf223e0cf 100644 --- a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected +++ b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected @@ -1,9 +1,3 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (VariableMissingConstexpr.ql:64,7-15) -WARNING: Module DataFlow has been deprecated and may be removed in future (VariableMissingConstexpr.ql:79,10-18) -WARNING: Module DataFlow has been deprecated and may be removed in future (VariableMissingConstexpr.ql:79,44-52) -WARNING: Module DataFlow has been deprecated and may be removed in future (VariableMissingConstexpr.ql:80,17-25) -WARNING: Module DataFlow has been deprecated and may be removed in future (VariableMissingConstexpr.ql:81,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (VariableMissingConstexpr.ql:82,9-17) | test.cpp:4:5:4:6 | g1 | Variable g1 could be marked 'constexpr'. | | test.cpp:6:5:6:6 | g2 | Variable g2 could be marked 'constexpr'. | | test.cpp:13:14:13:15 | lc | Variable lc could be marked 'constexpr'. | diff --git a/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected b/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected index 06abadc4fe..9259112890 100644 --- a/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected +++ b/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected @@ -1,12 +1,12 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:97,7-15) -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:97,27-35) -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:98,9-17) -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:102,9-17) -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:102,29-37) -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:103,11-19) -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:113,35-43) -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:114,11-19) -WARNING: Module TaintTracking has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:113,9-22) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:88,7-15) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:88,27-35) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:89,9-17) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:93,9-17) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:93,29-37) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:94,11-19) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:104,35-43) +WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:105,11-19) +WARNING: Module TaintTracking has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:104,9-22) | test.cpp:8:42:8:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:8:3:8:11 | call to copy | call to copy | | test.cpp:17:42:17:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:17:3:17:11 | call to copy | call to copy | | test.cpp:55:42:55:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:55:3:55:11 | call to copy | call to copy | diff --git a/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected b/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected index 0a06677b54..be69b2024d 100644 --- a/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected +++ b/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected @@ -1,3 +1,12 @@ +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:38,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:38,25-33) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:38,51-59) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:39,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:39,25-33) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:39,52-60) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:74,5-13) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:74,25-33) +WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:75,7-15) | test.cpp:8:7:8:7 | i | Increment of iterator may overflow since its bounds are not checked. | | test.cpp:9:9:9:9 | i | Increment of iterator may overflow since its bounds are not checked. | | test.cpp:10:9:10:9 | i | Increment of iterator may overflow since its bounds are not checked. | diff --git a/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected b/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected index dcbc6d05bc..2d293e6928 100644 --- a/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected +++ b/cpp/common/test/rules/donotsubtractpointersaddressingdifferentarrays/DoNotSubtractPointersAddressingDifferentArrays.expected @@ -4,10 +4,10 @@ problems | test.cpp:13:10:13:11 | p4 | test.cpp:5:14:5:15 | l2 | test.cpp:13:10:13:11 | p4 | Subtraction between left operand pointing to array $@ and other operand pointing to array $@. | test.cpp:3:7:3:8 | l2 | l2 | test.cpp:2:7:2:8 | l1 | l1 | | test.cpp:13:15:13:16 | l1 | test.cpp:13:15:13:16 | l1 | test.cpp:13:15:13:16 | l1 | Subtraction between right operand pointing to array $@ and other operand pointing to array $@. | test.cpp:2:7:2:8 | l1 | l1 | test.cpp:3:7:3:8 | l2 | l2 | edges -| test.cpp:4:14:4:15 | l1 | test.cpp:4:14:4:18 | access to array | provenance | | +| test.cpp:4:14:4:15 | l1 | test.cpp:4:14:4:18 | access to array | provenance | Config | | test.cpp:4:14:4:18 | access to array | test.cpp:10:10:10:11 | p1 | provenance | | | test.cpp:4:14:4:18 | access to array | test.cpp:12:10:12:11 | p1 | provenance | | -| test.cpp:5:14:5:15 | l2 | test.cpp:5:14:5:19 | access to array | provenance | | +| test.cpp:5:14:5:15 | l2 | test.cpp:5:14:5:19 | access to array | provenance | Config | | test.cpp:5:14:5:19 | access to array | test.cpp:11:10:11:11 | p2 | provenance | | | test.cpp:5:14:5:19 | access to array | test.cpp:12:15:12:16 | p2 | provenance | | | test.cpp:5:14:5:19 | access to array | test.cpp:13:10:13:11 | p4 | provenance | | diff --git a/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected b/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected index f02c9a5712..cab80e0fe0 100644 --- a/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected +++ b/cpp/common/test/rules/donotuserelationaloperatorswithdifferingarrays/DoNotUseRelationalOperatorsWithDifferingArrays.expected @@ -11,17 +11,17 @@ problems | test.cpp:25:7:25:14 | ... >= ... | test.cpp:25:13:25:14 | l3 | test.cpp:25:13:25:14 | l3 | Compare operation >= comparing right operand pointing to array $@ and other operand pointing to array $@. | test.cpp:4:7:4:8 | l3 | l3 | test.cpp:2:7:2:8 | l1 | l1 | edges | test.cpp:6:13:6:14 | l1 | test.cpp:13:12:13:13 | p0 | provenance | | -| test.cpp:7:14:7:15 | l1 | test.cpp:7:14:7:18 | access to array | provenance | | +| test.cpp:7:14:7:15 | l1 | test.cpp:7:14:7:18 | access to array | provenance | Config | | test.cpp:7:14:7:18 | access to array | test.cpp:11:7:11:8 | p1 | provenance | | | test.cpp:7:14:7:18 | access to array | test.cpp:13:7:13:8 | p1 | provenance | | | test.cpp:7:14:7:18 | access to array | test.cpp:15:13:15:14 | p1 | provenance | | | test.cpp:7:14:7:18 | access to array | test.cpp:17:7:17:8 | p1 | provenance | | | test.cpp:7:14:7:18 | access to array | test.cpp:23:13:23:14 | p1 | provenance | | | test.cpp:7:14:7:18 | access to array | test.cpp:25:7:25:8 | p1 | provenance | | -| test.cpp:8:14:8:15 | l1 | test.cpp:8:14:8:18 | access to array | provenance | | +| test.cpp:8:14:8:15 | l1 | test.cpp:8:14:8:18 | access to array | provenance | Config | | test.cpp:8:14:8:18 | access to array | test.cpp:11:12:11:13 | p2 | provenance | | | test.cpp:8:14:8:18 | access to array | test.cpp:21:7:21:8 | p2 | provenance | | -| test.cpp:9:14:9:15 | l2 | test.cpp:9:14:9:18 | access to array | provenance | | +| test.cpp:9:14:9:15 | l2 | test.cpp:9:14:9:18 | access to array | provenance | Config | | test.cpp:9:14:9:18 | access to array | test.cpp:21:12:21:13 | p3 | provenance | | nodes | test.cpp:6:13:6:14 | l1 | semmle.label | l1 | diff --git a/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected b/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected index 0b23493cfa..7790582443 100644 --- a/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected +++ b/cpp/common/test/rules/ownedpointervaluestoredinunrelatedsmartpointer/OwnedPointerValueStoredInUnrelatedSmartPointer.expected @@ -11,10 +11,11 @@ edges | test.cpp:3:14:3:15 | v1 | test.cpp:7:28:7:29 | v2 | provenance | | | test.cpp:4:13:4:14 | v1 | test.cpp:7:28:7:29 | v2 | provenance | | | test.cpp:5:27:5:28 | v1 | test.cpp:5:27:5:29 | call to shared_ptr | provenance | | +| test.cpp:5:27:5:28 | v1 | test.cpp:5:27:5:29 | call to shared_ptr | provenance | Config | | test.cpp:5:27:5:29 | call to shared_ptr | test.cpp:6:28:6:29 | p1 | provenance | | | test.cpp:5:27:5:29 | call to shared_ptr | test.cpp:6:28:6:29 | p1 | provenance | | -| test.cpp:6:28:6:29 | p1 | test.cpp:6:31:6:33 | call to get | provenance | | -| test.cpp:6:28:6:29 | p1 | test.cpp:6:31:6:33 | call to get | provenance | | +| test.cpp:6:28:6:29 | p1 | test.cpp:6:31:6:33 | call to get | provenance | Config | +| test.cpp:6:28:6:29 | p1 | test.cpp:6:31:6:33 | call to get | provenance | Config | | test.cpp:8:8:8:14 | 0 | test.cpp:9:28:9:29 | v2 | provenance | | | test.cpp:10:8:10:17 | new | test.cpp:11:28:11:29 | v2 | provenance | | | test.cpp:10:8:10:17 | new | test.cpp:12:28:12:29 | v2 | provenance | | From 9ca0d42a6e32a395dccff48fb1eb16476ccac1ce Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 3 Jun 2024 16:51:30 +0100 Subject: [PATCH 020/628] A3-1-5: Remove invalid interpretation of rule As per: https://forum.misra.org.uk/archive/index.php?thread-1588.html --- ...teFunctionDefinedOutsideClassDefinition.ql | 51 ------------------- ...tionDefinedOutsideClassDefinition.expected | 7 --- ...unctionDefinedOutsideClassDefinition.qlref | 1 - 3 files changed, 59 deletions(-) delete mode 100644 cpp/autosar/src/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.ql delete mode 100644 cpp/autosar/test/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.expected delete mode 100644 cpp/autosar/test/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.qlref diff --git a/cpp/autosar/src/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.ql b/cpp/autosar/src/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.ql deleted file mode 100644 index 920875ca3b..0000000000 --- a/cpp/autosar/src/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.ql +++ /dev/null @@ -1,51 +0,0 @@ -/** - * @id cpp/autosar/trivial-or-template-function-defined-outside-class-definition - * @name A3-1-5: A function shall be defined with a class body if and only if it is intended to be inlined - * @description A function that is either trivial, a template function, or a member of a template - * class may not be defined outside of a class body. - * @kind problem - * @precision very-high - * @problem.severity recommendation - * @tags external/autosar/id/a3-1-5 - * external/autosar/allocated-target/design - * external/autosar/enforcement/partially-automated - * external/autosar/obligation/required - */ - -import cpp -import codingstandards.cpp.autosar -import codingstandards.cpp.Class - -/* - * Find instances of `MemberFunction` where the `MemberFunction` is trivial - * and it is not inlined within the class. - */ - -from MemberFunction mf, string kind -where - not isExcluded(mf, ClassesPackage::trivialOrTemplateFunctionDefinedOutsideClassDefinitionQuery()) and - // The member function `mf` is not defined in the class body. - exists(FunctionDeclarationEntry fde | - fde = mf.getClassBodyDeclarationEntry() and not fde.isDefinition() - ) and - //ignore destructors - not mf instanceof Destructor and - // Report functions that are NOT defined in the class body if they are either trivial or - // either a template member or part of a template class (i.e., they should - // be defined in the class body) - ( - if - mf instanceof TemplateOrTemplateClassMemberFunction and - mf instanceof TrivialMemberFunction - then kind = "template" - else - if mf instanceof TrivialMemberFunction - then kind = "trivial" - else - if mf instanceof TemplateOrTemplateClassMemberFunction - then kind = "template" - else none() - ) -select mf, - "The " + kind + " member function " + mf.getName() + " is not defined in the class body of $@.", - mf.getDeclaringType(), mf.getDeclaringType().getName() diff --git a/cpp/autosar/test/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.expected b/cpp/autosar/test/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.expected deleted file mode 100644 index af8a1d4588..0000000000 --- a/cpp/autosar/test/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.expected +++ /dev/null @@ -1,7 +0,0 @@ -| test.cpp:58:5:58:11 | getB | The trivial member function getB is not defined in the class body of $@. | test.cpp:2:7:2:7 | A | A | -| test.cpp:60:25:60:28 | d | The template member function d is not defined in the class body of $@. | test.cpp:2:7:2:7 | A | A | -| test.cpp:62:5:62:8 | b | The trivial member function b is not defined in the class body of $@. | test.cpp:2:7:2:7 | A | A | -| test.cpp:81:34:81:57 | complexCalculation | The template member function complexCalculation is not defined in the class body of $@. | test.cpp:64:29:64:29 | B | B | -| test.cpp:97:47:97:53 | d | The template member function d is not defined in the class body of $@. | test.cpp:64:29:64:29 | B | B | -| test.cpp:101:27:101:33 | b | The template member function b is not defined in the class body of $@. | test.cpp:64:29:64:29 | B | B | -| test.cpp:106:27:106:36 | getB | The template member function getB is not defined in the class body of $@. | test.cpp:64:29:64:29 | B | B | diff --git a/cpp/autosar/test/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.qlref b/cpp/autosar/test/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.qlref deleted file mode 100644 index c644147bb4..0000000000 --- a/cpp/autosar/test/rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A3-1-5/TrivialOrTemplateFunctionDefinedOutsideClassDefinition.ql \ No newline at end of file From f1024ae1ca5109f925e9ab7d78e0dd6b8e4c540a Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 3 Jun 2024 17:10:34 +0100 Subject: [PATCH 021/628] A3-1-5: Exclude member functions in template instantiations --- cpp/autosar/test/rules/A3-1-5/test.cpp | 59 +++++++++++++++++--- cpp/common/src/codingstandards/cpp/Class.qll | 5 +- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/cpp/autosar/test/rules/A3-1-5/test.cpp b/cpp/autosar/test/rules/A3-1-5/test.cpp index eb5bc9edb7..62edb8f582 100644 --- a/cpp/autosar/test/rules/A3-1-5/test.cpp +++ b/cpp/autosar/test/rules/A3-1-5/test.cpp @@ -23,7 +23,7 @@ class A { int complexCalculation(); - int gcd(int a, int b) { + int gcd(int a, int b) { // NON_COMPLIANT if (b == 0) return a; int result = gcd(b, (a % b)); @@ -55,11 +55,11 @@ inline int A::complexCalculation() { // COMPLIANT return 1; } -int A::getB() { return 1; } // NON_COMPLIANT +int A::getB() { return 1; } // COMPLIANT -template T A::d(T t) { return t; } // NON_COMPLIANT +template T A::d(T t) { return t; } // COMPLIANT -int A::b() { return 3; } // NON_COMPLIANT +int A::b() { return 3; } // COMPLIANT template class B { public: @@ -76,9 +76,30 @@ template class B { template T d(T t); int complexCalculation(); + + int complexCalculation2() { // COMPLIANT - template + ; + ; + ; + ; + ; + ; + ; + ; + ; + ; + ; + ; + return 1; + } }; -template inline int B::complexCalculation() { // NON_COMPLIANT +void test_B() { + B b; + b.complexCalculation2(); +} + +template inline int B::complexCalculation() { // COMPLIANT ; ; ; @@ -94,16 +115,16 @@ template inline int B::complexCalculation() { // NON_COMPLIANT return 1; } -template template T B::d(T t) { // NON_COMPLIANT +template template T B::d(T t) { // COMPLIANT return t; } -template int B::b() { // NON_COMPLIANT +template int B::b() { // COMPLIANT C c; return 3; } -template int B::getB() { return 3; } // NON_COMPLIANT +template int B::getB() { return 3; } // COMPLIANT template class Foo { public: @@ -121,8 +142,30 @@ class FooBar { public: ~FooBar(); int f1(int a, int b); + + template int complexCalculation() { // COMPLIANT - template + ; + ; + ; + ; + ; + ; + ; + ; + ; + ; + ; + ; + return 1; + } }; +void test_FooBar() { + FooBar foobar; + foobar.complexCalculation(); +} + + FooBar::~FooBar() {} // COMPLIANT want to ignore pImpl uses of destructors int FooBar::f1(int a, int b) { // COMPLIANT not a trivial function diff --git a/cpp/common/src/codingstandards/cpp/Class.qll b/cpp/common/src/codingstandards/cpp/Class.qll index 19bec9fa5f..09d39ce6f8 100644 --- a/cpp/common/src/codingstandards/cpp/Class.qll +++ b/cpp/common/src/codingstandards/cpp/Class.qll @@ -192,7 +192,10 @@ class TrivialMemberFunction extends IntrospectedMemberFunction { * class. */ class TemplateOrTemplateClassMemberFunction extends MemberFunction { - TemplateOrTemplateClassMemberFunction() { isFromUninstantiatedTemplate(_) } + TemplateOrTemplateClassMemberFunction() { + isFromUninstantiatedTemplate(_) or + isFromTemplateInstantiation(_) + } } /** From 8078f8167744651ef4db0d2e795126a7ede83093 Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Wed, 19 Jun 2024 09:42:28 +0200 Subject: [PATCH 022/628] Accept new warning format in ql tests --- ...bleLengthArraySizeNotInValidRange.expected | 4 +- ...rithmeticOnNonArrayObjectPointers.expected | 10 ++-- ...rSubtractAScaledIntegerToAPointer.expected | 8 ++-- .../CleanUpThreadSpecificStorage.expected | 12 ++--- ...riateThreadObjectStorageDurations.expected | 16 +++---- ...ectStorageDurationsNotInitialized.expected | 10 ++-- ...ateStorageDurationsFunctionReturn.expected | 10 ++-- .../ERR30-C/ErrnoReadBeforeReturn.expected | 2 +- .../ERR30-C/SetlocaleMightSetErrno.expected | 2 +- ...tRelyOnIndeterminateValuesOfErrno.expected | 8 ++-- ...ectAndHandleStandardLibraryErrors.expected | 2 +- ...OfFunctionArgumentsForSideEffects.expected | 48 +++++++++---------- ...rToMoreStrictlyAlignedPointerType.expected | 20 ++++---- ...nctionPointerWithIncompatibleType.expected | 8 ++-- ...iableViaPointerOfIncompatibleType.expected | 14 +++--- .../DoNotModifyConstantObjects.expected | 8 ++-- ...edPointerToRestrictQualifiedParam.expected | 24 +++++----- ...ointerReferencesOverlappingObject.expected | 14 +++--- ...esetStringsOnFgetsOrFgetwsFailure.expected | 6 +-- ...FsetposThatAreReturnedFromFgetpos.expected | 10 ++-- ...RaceConditionsWhileAccessingFiles.expected | 2 +- ...ufficientMemoryAllocatedForObject.expected | 4 +- ...odifyAlignmentOfMemoryWithRealloc.expected | 10 ++-- ...ssInvalidDataToTheAsctimeFunction.expected | 8 ++-- ...VaListThatHasAnIndeterminateValue.expected | 14 +++--- ...SafeFunctionsWithinSignalHandlers.expected | 6 +-- ...romAComputationalExceptionHandler.expected | 2 +- ...oNotAttemptToModifyStringLiterals.expected | 30 ++++++------ ...fficientSpaceForTheNullTerminator.expected | 12 ++--- ...natedToFunctionThatExpectsAString.expected | 20 ++++---- ...yFunctionArgumentNumberOfElements.expected | 12 ++--- ...sedToCompareNullTerminatedStrings.expected | 8 ++-- ...ForReadAndWriteOnDifferentStreams.expected | 2 +- .../AttemptToWriteToAReadOnlyStream.expected | 12 ++--- ...omparedWithUnmodifiedReturnValues.expected | 16 +++---- ...rformConversionOfPassedParameters.expected | 6 +-- .../AssignmentOperatorReturnThis.expected | 2 +- .../ThrownExceptionsShouldBeUnique.expected | 2 +- ...orErrorLeavesObjectInInvalidState.expected | 18 +++---- ...entOfAnArrayPassedToASmartPointer.expected | 14 +++--- .../UnnecessaryUseOfDynamicStorage.expected | 8 ++-- ...ArgumentToForwardSubsequentlyUsed.expected | 6 +-- ...PointerUsedWithNoOwnershipSharing.expected | 2 +- .../rules/A27-0-4/CStyleStringsUsed.expected | 6 +-- ...UsedWithPointersToNonFinalClasses.expected | 8 ++-- .../A5-1-7/LambdaPassedToDecltype.expected | 12 ++--- .../A5-1-7/LambdaPassedToTypeid.expected | 8 ++-- .../A7-5-1/InvalidFunctionReturnType.expected | 6 +-- ...ParameterWithoutLifetimeSemantics.expected | 4 +- ...edToFunctionWithImproperSemantics.expected | 4 +- ...tParametersDeclaredAsTNotModified.expected | 4 +- ...eferencesToPrivateOrProtectedData.expected | 6 +-- ...tionErroneousReturnValueNotTested.expected | 6 +-- ...ntationsOfFloatingPointValuesUsed.expected | 6 +-- ...berFunctionReturnsNonConstPointer.expected | 4 +- ...cCppLibraryFunctionsDoNotOverflow.expected | 18 +++---- .../CTR53-CPP/UseValidIteratorRanges.expected | 12 ++--- ...UseAnAdditiveOperatorOnAnIterator.expected | 18 +++---- ...terArithmeticOnPolymorphicObjects.expected | 8 ++-- ...nFunctionCallsAsFunctionArguments.expected | 48 +++++++++---------- ...ThroughAPointerOfTheIncorrectType.expected | 8 ++-- ...ctAndHandleMemoryAllocationErrors.expected | 14 +++--- .../BadlySeededRandomNumberGenerator.expected | 2 +- 63 files changed, 327 insertions(+), 327 deletions(-) diff --git a/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected b/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected index bcb1c8eddd..083e7dfb87 100644 --- a/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected +++ b/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected @@ -1,5 +1,5 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:104,11-19) -WARNING: Module TaintTracking has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:87,5-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:104,11-19) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:87,5-18) | test.c:14:8:14:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | | test.c:15:8:15:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | | test.c:16:8:16:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | diff --git a/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected b/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected index d75db521af..ca4ef2a7a0 100644 --- a/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected +++ b/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected @@ -1,8 +1,8 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:23,60-68) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:24,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:36,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:44,26-34) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:65,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:23,60-68) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:24,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:36,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:44,26-34) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:65,3-11) edges | test.c:14:38:14:39 | p1 | test.c:18:10:18:11 | v1 | provenance | | | test.c:14:38:14:39 | p1 | test.c:19:10:19:11 | v2 | provenance | | diff --git a/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected b/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected index 7782984e5b..d343811aaf 100644 --- a/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected +++ b/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected @@ -1,7 +1,7 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:72,56-64) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:73,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:75,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:84,45-53) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:72,56-64) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:73,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:75,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:84,45-53) edges | test.c:7:13:7:14 | p1 | test.c:9:9:9:10 | p1 | provenance | | | test.c:16:19:16:41 | ... - ... | test.c:18:26:18:31 | offset | provenance | | diff --git a/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected b/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected index 9b1288d578..2706474f29 100644 --- a/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected +++ b/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected @@ -1,9 +1,9 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:21,46-54) -WARNING: Module DataFlow has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:22,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:31,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:41,35-43) -WARNING: Module DataFlow has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:49,36-44) -WARNING: Module DataFlow has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:51,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:21,46-54) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:22,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:31,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:41,35-43) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:49,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:51,36-44) | test.c:27:3:27:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | | test.c:49:3:49:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | | test.c:71:3:71:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | diff --git a/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected b/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected index a513b55b73..25cb74d7fa 100644 --- a/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected +++ b/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected @@ -1,11 +1,11 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,29-37) -WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,54-62) -WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:35,62-70) -WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:40,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:40,30-38) -WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:41,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:41,30-38) -WARNING: Module TaintTracking has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,3-16) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,29-37) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,54-62) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:35,62-70) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:40,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:40,30-38) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:41,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:41,30-38) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,3-16) | test.c:23:3:23:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:23:24:23:29 | & ... | Shared object | | test.c:74:3:74:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:74:24:74:24 | p | Shared object | | test.c:85:3:85:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:85:24:85:24 | p | Shared object | diff --git a/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected b/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected index 337df4c14c..d6b6548581 100644 --- a/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected +++ b/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected @@ -1,6 +1,6 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:28,38-46) -WARNING: Module DataFlow has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:31,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:31,30-38) -WARNING: Module DataFlow has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:32,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:32,30-38) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:28,38-46) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:31,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:31,30-38) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:32,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:32,30-38) | test.c:14:7:14:13 | call to tss_get | Call to a thread specific storage function from within a threaded context on an object that may not be owned by this thread. | diff --git a/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected b/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected index 18d28b61bc..905c9cc22b 100644 --- a/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected +++ b/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected @@ -1,7 +1,7 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:22,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:26,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:39,6-14) -WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:39,26-34) -WARNING: Module DataFlow has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:45,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:22,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:26,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:39,6-14) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:39,26-34) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:45,3-11) | test.c:3:10:3:10 | a | $@ with automatic storage may be accessible outside of its lifetime. | test.c:3:10:3:10 | a | a | | test.c:15:4:15:8 | param [inner post update] | $@ with automatic storage may be accessible outside of its lifetime. | test.c:15:12:15:13 | a2 | a2 | diff --git a/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected b/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected index b3e5c4b7fc..659a731d7c 100644 --- a/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected +++ b/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected @@ -1,4 +1,4 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (ErrnoReadBeforeReturn.ql:40,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ErrnoReadBeforeReturn.ql:40,7-15) | test.c:69:7:69:11 | * ... | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | | test.c:69:7:69:11 | call to __errno_location | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | | test.c:70:5:70:10 | call to perror | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | diff --git a/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected b/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected index 0ffaf56bd1..d20f4a4e34 100644 --- a/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected +++ b/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected @@ -1,3 +1,3 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (SetlocaleMightSetErrno.ql:64,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (SetlocaleMightSetErrno.ql:64,7-15) | test.c:98:3:98:11 | call to setlocale | Do not read `errno` before checking the return value of a call to `setlocale`. | | test.c:104:7:104:15 | call to setlocale | The value of `errno` may be different than `0` when `setlocale` is called. The following `errno` check might be invalid. | diff --git a/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected b/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected index 77fa7b7ba7..a90dd6b7f5 100644 --- a/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected +++ b/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected @@ -1,7 +1,7 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:50,7-15) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:50,27-35) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:51,9-17) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:54,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:50,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:50,27-35) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:51,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:54,9-17) | test.c:12:5:12:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:10:21:10:26 | call to signal | call to signal | | test.c:30:5:30:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:26:21:26:26 | call to signal | call to signal | | test.c:49:5:49:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:45:21:45:26 | call to signal | call to signal | diff --git a/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected b/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected index a32a03a3b9..030596976e 100644 --- a/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected +++ b/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected @@ -1,4 +1,4 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleStandardLibraryErrors.ql:453,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleStandardLibraryErrors.ql:453,5-13) | test.c:18:3:18:11 | call to setlocale | Missing error detection for the call to function `setlocale`. | | test.c:24:23:24:31 | call to setlocale | Missing error detection for the call to function `setlocale`. | | test.c:29:22:29:27 | call to calloc | Missing error detection for the call to function `calloc`. | diff --git a/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected index 6ea3499517..6567ef6fd1 100644 --- a/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected +++ b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected @@ -1,25 +1,25 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:24,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:24,59-67) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:27,33-41) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:27,57-65) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,33-41) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,59-67) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:40,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:40,25-33) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:40,53-61) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:43,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:43,57-65) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:52,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:52,55-63) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:59,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:59,57-65) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:71,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:71,55-63) -WARNING: Module TaintTracking has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:24,5-18) -WARNING: Module TaintTracking has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:27,7-20) -WARNING: Module TaintTracking has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,7-20) -WARNING: Module TaintTracking has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:43,5-18) -WARNING: Module TaintTracking has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:52,5-18) -WARNING: Module TaintTracking has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:59,5-18) -WARNING: Module TaintTracking has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:71,5-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:24,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:24,59-67) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:27,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:27,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,59-67) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:40,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:40,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:40,53-61) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:43,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:43,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:52,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:52,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:59,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:59,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:71,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:71,55-63) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:24,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:27,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:43,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:52,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:59,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:71,5-18) | test.c:20:3:20:4 | call to f1 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.c:20:6:20:7 | call to f2 | call to f2 | test.c:20:12:20:13 | call to f3 | call to f3 | diff --git a/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected b/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected index b6f96f6ea5..eed9fb4585 100644 --- a/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected +++ b/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected @@ -1,13 +1,13 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:98,86-94) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:120,3-11) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:122,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:127,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:133,3-11) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:139,55-63) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:140,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:142,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:149,26-34) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:164,44-52) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:98,86-94) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:120,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:122,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:127,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:133,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:139,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:140,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:142,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:149,26-34) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:164,44-52) edges | test.c:75:14:75:16 | & ... | test.c:76:11:76:12 | v1 | provenance | | | test.c:75:14:75:16 | & ... | test.c:77:12:77:13 | v1 | provenance | | diff --git a/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected b/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected index 1b6505f472..229bd74165 100644 --- a/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected +++ b/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected @@ -1,7 +1,7 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:40,54-62) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:41,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:45,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:50,43-51) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:40,54-62) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:41,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:45,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:50,43-51) edges | test.c:48:68:48:70 | fns [f1] | test.c:49:3:49:5 | fns [f1] | provenance | | | test.c:49:3:49:5 | fns [f1] | test.c:49:8:49:9 | f1 | provenance | | diff --git a/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected b/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected index 6cf822fa15..9f0880455f 100644 --- a/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected +++ b/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected @@ -1,10 +1,10 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:61,38-46) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:64,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:69,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:102,23-31) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:111,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:111,45-53) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:133,27-35) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:61,38-46) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:64,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:69,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:102,23-31) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:111,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:111,45-53) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:133,27-35) edges | test.c:49:8:49:9 | s3 | test.c:50:8:50:9 | s1 | provenance | | | test.c:60:16:60:18 | E1A | test.c:61:16:61:17 | e1 | provenance | | diff --git a/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected b/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected index e7af404ec1..6dd4ec261a 100644 --- a/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected +++ b/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected @@ -1,7 +1,7 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:35,30-38) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:36,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:42,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:47,19-27) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:35,30-38) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:36,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:42,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:47,19-27) edges | test.c:5:8:5:9 | & ... | test.c:6:4:6:5 | aa | provenance | | | test.c:26:15:26:15 | a | test.c:27:4:27:4 | a | provenance | | diff --git a/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.expected b/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.expected index a77a92ee81..1c8a649094 100644 --- a/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.expected +++ b/c/cert/test/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.expected @@ -1,15 +1,15 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:103,36-44) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:118,51-59) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:119,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:121,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:127,25-33) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:132,40-48) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:146,41-49) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:147,7-15) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:150,43-51) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:151,9-17) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:158,43-51) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:159,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:103,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:118,51-59) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:119,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:121,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:127,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:132,40-48) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:146,41-49) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:147,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:150,43-51) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:151,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:158,43-51) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:159,9-17) | test.c:59:3:59:6 | call to copy | Call to 'copy' passes an $@ to a $@ (pointer value derived from a pair of address-of expressions ($@, $@). | test.c:59:13:59:15 | & ... | aliased pointer | test.c:59:8:59:10 | & ... | restrict-qualified parameter | test.c:59:8:59:10 | & ... | addressof1 | test.c:59:13:59:15 | & ... | addressof2 | | test.c:65:3:65:6 | call to copy | Call to 'copy' passes an $@ to a $@ (pointer value derived from a pair of address-of expressions ($@, $@). | test.c:65:15:65:19 | & ... | aliased pointer | test.c:65:8:65:12 | & ... | restrict-qualified parameter | test.c:65:8:65:12 | & ... | addressof1 | test.c:65:15:65:19 | & ... | addressof2 | | test.c:67:3:67:6 | call to copy | Call to 'copy' passes an $@ to a $@ (pointer value derived from a pair of address-of expressions ($@, $@). | test.c:67:15:67:16 | px | aliased pointer | test.c:67:8:67:12 | & ... | restrict-qualified parameter | test.c:67:8:67:12 | & ... | addressof1 | test.c:63:13:63:17 | & ... | addressof2 | diff --git a/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected b/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected index 591e17661a..b9765e77fb 100644 --- a/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected +++ b/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected @@ -1,10 +1,10 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:42,57-65) -WARNING: Module DataFlow has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:43,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:47,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:53,3-11) -WARNING: Module DataFlow has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:56,58-66) -WARNING: Module DataFlow has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:72,64-72) -WARNING: Module DataFlow has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:73,64-72) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:42,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:43,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:47,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:53,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:56,58-66) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:72,64-72) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:73,64-72) | test.c:18:22:18:23 | i2 | Assignment to restrict-qualified pointer $@ results in pointers aliasing $@. | test.c:18:17:18:18 | i3 | i3 | test.c:18:22:18:23 | i2 | the object pointed to by i2 | | test.c:19:8:19:9 | g2 | Assignment to restrict-qualified pointer $@ results in pointers aliasing $@. | test.c:5:15:5:16 | g1 | g1 | test.c:19:8:19:9 | g2 | the object pointed to by g2 | | test.c:20:8:20:9 | i2 | Assignment to restrict-qualified pointer $@ results in pointers aliasing $@. | test.c:16:17:16:18 | i1 | i1 | test.c:20:8:20:9 | i2 | the object pointed to by i2 | diff --git a/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected b/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected index 6a73ee98a7..669dd829c8 100644 --- a/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected +++ b/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected @@ -1,6 +1,6 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:42,11-19) -WARNING: Module DataFlow has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:42,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:43,13-21) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:42,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:42,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:43,13-21) | test.c:20:10:20:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:15:7:15:11 | call to fgets | call to fgets | | test.c:57:10:57:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:52:7:52:11 | call to fgets | call to fgets | | test.c:66:18:66:20 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:61:7:61:11 | call to fgets | call to fgets | diff --git a/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected b/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected index 637918f241..5bff6016e4 100644 --- a/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected +++ b/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected @@ -1,7 +1,7 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:25,32-40) -WARNING: Module DataFlow has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:26,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:28,14-22) -WARNING: Module DataFlow has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:31,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:37,21-29) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:25,32-40) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:26,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:28,14-22) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:31,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:37,21-29) | test.c:7:24:7:30 | & ... | The position argument of a call to `fsetpos()` should be obtained from a call to `fgetpos()`. | | test.c:33:24:33:30 | & ... | The position argument of a call to `fsetpos()` should be obtained from a call to `fgetpos()`. | diff --git a/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected b/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected index f294ce05b7..71df14e907 100644 --- a/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected +++ b/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected @@ -1,3 +1,3 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (ToctouRaceConditionsWhileAccessingFiles.ql:27,35-43) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ToctouRaceConditionsWhileAccessingFiles.ql:27,35-43) | test.c:4:13:4:17 | call to fopen | This call is trying to prevent an existing file from being overwritten by $@. An attacker might be able to exploit the race window between the two calls. | test.c:11:9:11:13 | call to fopen | another call | | test.c:88:13:88:17 | call to fopen | This call is trying to prevent an existing file from being overwritten by $@. An attacker might be able to exploit the race window between the two calls. | test.c:95:9:95:13 | call to fopen | another call | diff --git a/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected b/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected index 73dd6ba1e0..6bfbbefc14 100644 --- a/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected +++ b/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected @@ -1,5 +1,5 @@ -WARNING: Module TaintTracking has been deprecated and may be removed in future (InsufficientMemoryAllocatedForObject.ql:85,5-18) -WARNING: Module TaintTracking has been deprecated and may be removed in future (InsufficientMemoryAllocatedForObject.ql:143,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (InsufficientMemoryAllocatedForObject.ql:85,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (InsufficientMemoryAllocatedForObject.ql:143,5-18) | test.c:12:19:12:24 | call to malloc | Allocation size (32 bytes) is not a multiple of the size of 'S1' (36 bytes). | test.c:12:26:12:32 | 32 | | | test.c:15:19:15:24 | call to malloc | Allocation size calculated from the size of a different type ($@). | test.c:15:26:15:35 | sizeof() | sizeof(S1 *) | | test.c:20:19:20:24 | call to malloc | Allocation size (128 bytes) is not a multiple of the size of 'S1' (36 bytes). | test.c:20:26:20:36 | ... * ... | | diff --git a/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected b/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected index 61c2cfb1f0..2f5889c4c6 100644 --- a/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected +++ b/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected @@ -1,8 +1,8 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:26,36-44) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:40,47-55) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:41,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:45,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:50,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:26,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:40,47-55) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:41,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:45,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:50,36-44) edges | test.c:5:10:5:22 | call to aligned_alloc | test.c:15:8:15:28 | call to aligned_alloc_wrapper | provenance | | | test.c:8:29:8:31 | ptr | test.c:8:64:8:66 | ptr | provenance | | diff --git a/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected b/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected index 713646db10..853d999d4e 100644 --- a/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected +++ b/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected @@ -1,5 +1,5 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:33,38-46) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:34,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:41,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:44,27-35) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:33,38-46) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:34,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:41,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:44,27-35) | test.c:6:24:6:30 | time_tm | The function `asctime` and `asctime_r` should be discouraged. Unsanitized input can overflow the output buffer. | diff --git a/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected b/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected index 4d4a713487..4eaa05b179 100644 --- a/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected +++ b/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected @@ -1,10 +1,10 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:38,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:39,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:44,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:47,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:68,10-18) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:69,29-37) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:70,29-37) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:38,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:39,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:44,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:47,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:68,10-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:69,29-37) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:70,29-37) | test.c:23:32:23:33 | ap | The value of ap is indeterminate after the $@. | test.c:17:7:17:19 | call to contains_zero | call to contains_zero | | test.c:26:10:26:11 | ap | The value of ap is indeterminate after the $@. | test.c:17:7:17:19 | call to contains_zero | call to contains_zero | | test.c:39:12:39:13 | ap | The value of ap is indeterminate after the $@. | test.c:35:7:35:19 | call to contains_zero | call to contains_zero | diff --git a/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected b/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected index a5f4af8c3c..6190259408 100644 --- a/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected +++ b/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected @@ -1,6 +1,6 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:105,11-19) -WARNING: Module DataFlow has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:105,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:106,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:105,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:105,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:106,9-17) | test.c:10:3:10:18 | call to log_local_unsafe | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:16:7:16:12 | call to signal | signal handler | | test.c:11:3:11:6 | call to free | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:16:7:16:12 | call to signal | signal handler | | test.c:46:3:46:9 | call to longjmp | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:50:7:50:12 | call to signal | signal handler | diff --git a/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected b/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected index d4796c6ede..e861e90e9e 100644 --- a/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected +++ b/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected @@ -1,2 +1,2 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotReturnFromAComputationalExceptionHandler.ql:39,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotReturnFromAComputationalExceptionHandler.ql:39,5-13) | test.c:10:1:10:1 | return ... | Do not return from a $@ signal handler. | test.c:13:10:13:15 | SIGFPE | computational exception | diff --git a/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected b/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected index 7215fd8603..2a45193a17 100644 --- a/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected +++ b/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected @@ -1,18 +1,18 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:42,65-73) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:43,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:64,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:77,3-11) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:101,11-19) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:101,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:101,55-63) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,11-19) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,57-65) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:139,11-19) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:139,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:139,55-63) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:150,53-61) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:151,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:42,65-73) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:43,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:64,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:77,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:101,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:101,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:101,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:139,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:139,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:139,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:150,53-61) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:151,5-13) | test.c:7:3:7:3 | a | This operation may write to a string that may be a string literal that was $@. | test.c:6:13:6:20 | codeql | created here | | test.c:30:3:30:3 | a | This operation may write to a string that may be a string literal that was $@. | test.c:29:13:29:18 | call to strchr | created here | | test.c:36:3:36:3 | b | This operation may write to a string that may be a string literal that was $@. | test.c:35:13:35:18 | call to strchr | created here | diff --git a/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected b/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected index 4c411382f0..9012a2d78a 100644 --- a/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected +++ b/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected @@ -1,9 +1,9 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:57,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:57,55-63) -WARNING: Module DataFlow has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:63,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:63,54-62) -WARNING: Module TaintTracking has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:57,5-18) -WARNING: Module TaintTracking has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:63,5-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:57,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:57,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:63,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:63,54-62) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:57,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:63,5-18) | test.c:10:20:10:24 | Cod | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | | test.c:16:3:16:9 | call to strncpy | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | | test.c:26:3:26:10 | call to snprintf | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | diff --git a/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected b/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected index e20b708dab..da86e69b88 100644 --- a/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected +++ b/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected @@ -1,13 +1,13 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:64,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:66,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:74,39-47) -WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:75,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:81,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:83,34-42) -WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:83,57-65) -WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:123,3-11) -WARNING: Module DataFlow has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:123,26-34) -WARNING: Module TaintTracking has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:120,17-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:64,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:66,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:74,39-47) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:75,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:81,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:83,34-42) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:83,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:123,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:123,26-34) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:120,17-30) | test.c:20:3:20:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:8:20:8:24 | Cod | this expression | | test.c:21:3:21:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:8:20:8:24 | Cod | this expression | | test.c:23:3:23:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:14:3:14:9 | call to strncpy | this expression | diff --git a/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected b/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected index d9cd037d42..cb4422f5f1 100644 --- a/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected +++ b/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected @@ -1,9 +1,9 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:47,36-44) -WARNING: Module DataFlow has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:48,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:50,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:55,25-33) -WARNING: Module DataFlow has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:71,28-36) -WARNING: Module DataFlow has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:71,51-59) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:47,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:48,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:50,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:55,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:71,28-36) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:71,51-59) | test.c:18:6:18:6 | 0 | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | | test.c:19:6:19:7 | ar | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | | test.c:21:6:21:9 | ar2p | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | diff --git a/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected b/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected index ef6703a285..cf45b21eb4 100644 --- a/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected +++ b/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected @@ -1,7 +1,7 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:22,54-62) -WARNING: Module DataFlow has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:23,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:49,20-28) -WARNING: Module TaintTracking has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:57,43-56) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:22,54-62) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:23,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:49,20-28) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:57,43-56) edges | test.c:12:13:12:15 | a | test.c:14:10:14:10 | a | provenance | | | test.c:12:13:12:15 | a | test.c:23:13:23:13 | a | provenance | | diff --git a/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected b/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected index 3382b66847..6360b21973 100644 --- a/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected +++ b/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected @@ -1,4 +1,4 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (FileOpenForReadAndWriteOnDifferentStreams.ql:38,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (FileOpenForReadAndWriteOnDifferentStreams.ql:38,9-17) | test.c:6:14:6:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:5:14:5:18 | call to fopen | here | | test.c:17:14:17:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:16:14:16:18 | call to fopen | here | | test.c:33:14:33:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:32:14:32:18 | call to fopen | here | diff --git a/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected b/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected index 08363e7dda..88dca316a2 100644 --- a/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected +++ b/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected @@ -1,8 +1,8 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:18,32-40) -WARNING: Module DataFlow has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:19,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:24,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:30,21-29) -WARNING: Module DataFlow has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:32,6-14) -WARNING: Module DataFlow has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:35,28-36) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:18,32-40) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:19,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:24,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:30,21-29) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:32,6-14) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:35,28-36) | test.c:10:3:10:9 | call to fprintf | Attempt to write to a $@ opened as read-only. | test.c:9:14:9:18 | call to fopen | stream | | test.c:15:3:15:9 | call to fprintf | Attempt to write to a $@ opened as read-only. | test.c:18:14:18:18 | call to fopen | stream | diff --git a/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected index 9e975d34e4..a7ee20c0b0 100644 --- a/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected +++ b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected @@ -1,10 +1,10 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:22,28-36) -WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:23,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:27,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:36,23-31) -WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:41,17-25) -WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:50,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:58,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:58,46-54) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:22,28-36) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:23,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:27,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:36,23-31) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:41,17-25) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:50,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:58,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:58,46-54) | test.c:6:7:6:20 | ... != ... | The check is not reliable as the type of the return value of $@ is converted. | test.c:5:14:5:20 | call to getchar | call to getchar | | test.c:13:7:13:15 | ... != ... | The check is not reliable as the type of the return value of $@ is converted. | test.c:12:14:12:20 | call to getchar | call to getchar | diff --git a/cpp/autosar/test/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.expected b/cpp/autosar/test/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.expected index 11b622f271..5d1d6022b5 100644 --- a/cpp/autosar/test/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.expected +++ b/cpp/autosar/test/rules/A13-1-3/UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.expected @@ -1,4 +1,4 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql:27,33-41) -WARNING: Module DataFlow has been deprecated and may be removed in future (UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql:28,5-13) -WARNING: Module TaintTracking has been deprecated and may be removed in future (UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql:27,7-20) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql:27,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql:28,5-13) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UserDefinedLiteralsOperatorsShallOnlyPerformConversionOfPassedParameters.ql:27,7-20) | test.cpp:47:8:47:23 | operator ""_uds5 | User defined literal operator returns $@, which is not converted from a passed parameter | test.cpp:48:10:48:12 | 0.0 | expression | diff --git a/cpp/autosar/test/rules/A13-2-1/AssignmentOperatorReturnThis.expected b/cpp/autosar/test/rules/A13-2-1/AssignmentOperatorReturnThis.expected index 4a4697facc..9c0d50ca86 100644 --- a/cpp/autosar/test/rules/A13-2-1/AssignmentOperatorReturnThis.expected +++ b/cpp/autosar/test/rules/A13-2-1/AssignmentOperatorReturnThis.expected @@ -1,4 +1,4 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (AssignmentOperatorReturnThis.ql:25,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AssignmentOperatorReturnThis.ql:25,5-13) | test.cpp:10:12:10:20 | operator= | User-defined assignment operator $@ does not return *this | test.cpp:10:12:10:20 | operator= | user defined assignment operator | | test.cpp:17:11:17:19 | operator= | User-defined assignment operator $@ does not return *this | test.cpp:17:11:17:19 | operator= | user defined assignment operator | | test.cpp:24:12:24:20 | operator= | User-defined assignment operator $@ does not return *this | test.cpp:24:12:24:20 | operator= | user defined assignment operator | diff --git a/cpp/autosar/test/rules/A15-1-3/ThrownExceptionsShouldBeUnique.expected b/cpp/autosar/test/rules/A15-1-3/ThrownExceptionsShouldBeUnique.expected index 92504006b9..5db0f83985 100644 --- a/cpp/autosar/test/rules/A15-1-3/ThrownExceptionsShouldBeUnique.expected +++ b/cpp/autosar/test/rules/A15-1-3/ThrownExceptionsShouldBeUnique.expected @@ -1,4 +1,4 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (ThrownExceptionsShouldBeUnique.ql:24,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThrownExceptionsShouldBeUnique.ql:24,3-11) | test.cpp:6:5:6:26 | throw ... | The $@ thrown here is a possible duplicate of the $@ thrown $@. | test.cpp:6:5:6:26 | call to exception | std::exception exception | test.cpp:14:5:14:26 | call to exception | exception | test.cpp:14:5:14:26 | throw ... | here | | test.cpp:8:5:8:53 | throw ... | The $@ thrown here is a possible duplicate of the $@ thrown $@. | test.cpp:8:5:8:53 | call to runtime_error | std::runtime_error exception | test.cpp:16:5:16:53 | call to runtime_error | exception | test.cpp:16:5:16:53 | throw ... | here | | test.cpp:14:5:14:26 | throw ... | The $@ thrown here is a possible duplicate of the $@ thrown $@. | test.cpp:14:5:14:26 | call to exception | std::exception exception | test.cpp:6:5:6:26 | call to exception | exception | test.cpp:6:5:6:26 | throw ... | here | diff --git a/cpp/autosar/test/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.expected b/cpp/autosar/test/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.expected index 2fd57c3b20..529a7ccf99 100644 --- a/cpp/autosar/test/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.expected +++ b/cpp/autosar/test/rules/A15-2-2/ConstructorErrorLeavesObjectInInvalidState.expected @@ -1,12 +1,12 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:47,12-20) -WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:48,30-38) -WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:48,57-65) -WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:74,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:74,25-33) -WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:75,7-15) -WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:130,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:130,25-33) -WARNING: Module DataFlow has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:130,54-62) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:47,12-20) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:48,30-38) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:48,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:74,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:74,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:75,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:130,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:130,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstructorErrorLeavesObjectInInvalidState.ql:130,54-62) edges | test.cpp:12:16:12:27 | new [bad_alloc] | test.cpp:14:33:16:5 | { ... } [bad_alloc] | | test.cpp:13:7:13:28 | throw ... [exception] | test.cpp:14:33:16:5 | { ... } [exception] | diff --git a/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected b/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected index e71e667685..bd46224da6 100644 --- a/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected +++ b/cpp/autosar/test/rules/A18-1-4/PointerToAnElementOfAnArrayPassedToASmartPointer.expected @@ -1,10 +1,10 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:26,67-75) -WARNING: Module DataFlow has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:27,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:39,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:50,34-42) -WARNING: Module DataFlow has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:50,57-65) -WARNING: Module DataFlow has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:58,25-33) -WARNING: Module TaintTracking has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:70,3-16) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:26,67-75) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:27,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:39,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:50,34-42) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:50,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:58,25-33) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (PointerToAnElementOfAnArrayPassedToASmartPointer.ql:70,3-16) edges | test.cpp:3:36:3:45 | new[] | test.cpp:19:27:19:44 | call to allocate_int_array | provenance | | | test.cpp:3:36:3:45 | new[] | test.cpp:23:12:23:29 | call to allocate_int_array | provenance | | diff --git a/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected b/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected index cf611ded5b..6ab75d989e 100644 --- a/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected +++ b/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected @@ -1,7 +1,7 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:55,34-42) -WARNING: Module DataFlow has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:57,26-34) -WARNING: Module TaintTracking has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:71,5-18) -WARNING: Module TaintTracking has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:76,41-54) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:55,34-42) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:57,26-34) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:71,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:76,41-54) | test.cpp:17:17:17:29 | new | StructA object of size 8 bytes does not appear to outlive the function, but is created on the heap instead of the stack. | | test.cpp:21:17:21:32 | new[] | StructA[] object of size 800 bytes does not appear to outlive the function, but is created on the heap instead of the stack. | | test.cpp:35:20:35:44 | call to make_shared | StructA object of size 8 bytes does not appear to outlive the function, but is created on the heap instead of the stack. | diff --git a/cpp/autosar/test/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.expected b/cpp/autosar/test/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.expected index 2875a68f28..9e1cf41d3d 100644 --- a/cpp/autosar/test/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.expected +++ b/cpp/autosar/test/rules/A18-9-4/ArgumentToForwardSubsequentlyUsed.expected @@ -1,4 +1,4 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (ArgumentToForwardSubsequentlyUsed.ql:22,10-18) -WARNING: Module DataFlow has been deprecated and may be removed in future (ArgumentToForwardSubsequentlyUsed.ql:24,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (ArgumentToForwardSubsequentlyUsed.ql:24,30-38) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArgumentToForwardSubsequentlyUsed.ql:22,10-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArgumentToForwardSubsequentlyUsed.ql:24,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArgumentToForwardSubsequentlyUsed.ql:24,30-38) | test.cpp:8:5:8:6 | t2 | The argument $@ of `std::forward` may be indeterminate when accessed at this location. | test.cpp:7:45:7:46 | t2 | t2 | diff --git a/cpp/autosar/test/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.expected b/cpp/autosar/test/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.expected index 03406ac254..5b770a1925 100644 --- a/cpp/autosar/test/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.expected +++ b/cpp/autosar/test/rules/A20-8-4/SharedPointerUsedWithNoOwnershipSharing.expected @@ -1,4 +1,4 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (SharedPointerUsedWithNoOwnershipSharing.ql:47,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (SharedPointerUsedWithNoOwnershipSharing.ql:47,7-15) | test.cpp:14:24:14:26 | sp3 | The ownership of shared_ptr $@ is not shared within or passed out of the local scope of function $@. | test.cpp:14:24:14:26 | sp3 | sp3 | test.cpp:11:22:11:23 | f1 | f1 | | test.cpp:16:24:16:26 | sp5 | The ownership of shared_ptr $@ is not shared within or passed out of the local scope of function $@. | test.cpp:16:24:16:26 | sp5 | sp5 | test.cpp:11:22:11:23 | f1 | f1 | | test.cpp:17:24:17:26 | sp6 | The ownership of shared_ptr $@ is not shared within or passed out of the local scope of function $@. | test.cpp:17:24:17:26 | sp6 | sp6 | test.cpp:11:22:11:23 | f1 | f1 | diff --git a/cpp/autosar/test/rules/A27-0-4/CStyleStringsUsed.expected b/cpp/autosar/test/rules/A27-0-4/CStyleStringsUsed.expected index eaaaaac98d..555cb412b8 100644 --- a/cpp/autosar/test/rules/A27-0-4/CStyleStringsUsed.expected +++ b/cpp/autosar/test/rules/A27-0-4/CStyleStringsUsed.expected @@ -1,6 +1,6 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (CStyleStringsUsed.ql:39,3-11) -WARNING: Module DataFlow has been deprecated and may be removed in future (CStyleStringsUsed.ql:39,23-31) -WARNING: Module DataFlow has been deprecated and may be removed in future (CStyleStringsUsed.ql:39,47-55) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CStyleStringsUsed.ql:39,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CStyleStringsUsed.ql:39,23-31) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CStyleStringsUsed.ql:39,47-55) | test.cpp:7:20:7:27 | CodeQL | Usage of C-style string in $@. | test.cpp:7:20:7:27 | CodeQL | expression | | test.cpp:7:20:7:27 | CodeQL | Usage of C-style string in $@. | test.cpp:16:16:16:17 | a1 | expression | | test.cpp:8:22:8:26 | call to c_str | Usage of C-style string in $@. | test.cpp:8:22:8:26 | call to c_str | expression | diff --git a/cpp/autosar/test/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.expected b/cpp/autosar/test/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.expected index 9f97a58467..e2b51e5fb9 100644 --- a/cpp/autosar/test/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.expected +++ b/cpp/autosar/test/rules/A5-0-4/PointerArithmeticUsedWithPointersToNonFinalClasses.expected @@ -1,7 +1,7 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:45,62-70) -WARNING: Module DataFlow has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:46,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:55,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:61,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:45,62-70) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:46,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:55,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (PointerArithmeticUsedWithPointersToNonFinalClasses.ql:61,3-11) edges | test.cpp:10:18:10:20 | foo | test.cpp:11:23:11:25 | foo | provenance | | | test.cpp:10:18:10:20 | foo | test.cpp:11:50:11:52 | foo | provenance | | diff --git a/cpp/autosar/test/rules/A5-1-7/LambdaPassedToDecltype.expected b/cpp/autosar/test/rules/A5-1-7/LambdaPassedToDecltype.expected index 03eaab82aa..56896d69fd 100644 --- a/cpp/autosar/test/rules/A5-1-7/LambdaPassedToDecltype.expected +++ b/cpp/autosar/test/rules/A5-1-7/LambdaPassedToDecltype.expected @@ -1,7 +1,7 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:20,55-63) -WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:21,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:23,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:28,44-52) -WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:39,47-55) -WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:40,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:20,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:21,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:23,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:28,44-52) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:39,47-55) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToDecltype.ql:40,9-17) | test.cpp:14:23:14:24 | decltype(...) | Lambda $@ passed as operand to decltype. | test.cpp:5:13:5:30 | [...](...){...} | expression | diff --git a/cpp/autosar/test/rules/A5-1-7/LambdaPassedToTypeid.expected b/cpp/autosar/test/rules/A5-1-7/LambdaPassedToTypeid.expected index 916b9db113..8f86a87616 100644 --- a/cpp/autosar/test/rules/A5-1-7/LambdaPassedToTypeid.expected +++ b/cpp/autosar/test/rules/A5-1-7/LambdaPassedToTypeid.expected @@ -1,7 +1,7 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:21,50-58) -WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:22,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:24,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:27,39-47) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:21,50-58) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:22,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:24,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (LambdaPassedToTypeid.ql:27,39-47) edges | test.cpp:5:13:5:30 | [...](...){...} | test.cpp:8:38:8:39 | l1 | provenance | | | test.cpp:6:13:6:30 | [...](...){...} | test.cpp:9:38:9:39 | l2 | provenance | | diff --git a/cpp/autosar/test/rules/A7-5-1/InvalidFunctionReturnType.expected b/cpp/autosar/test/rules/A7-5-1/InvalidFunctionReturnType.expected index 0ab837454a..3287ba88d1 100644 --- a/cpp/autosar/test/rules/A7-5-1/InvalidFunctionReturnType.expected +++ b/cpp/autosar/test/rules/A7-5-1/InvalidFunctionReturnType.expected @@ -1,5 +1,5 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (InvalidFunctionReturnType.ql:27,3-11) -WARNING: Module DataFlow has been deprecated and may be removed in future (InvalidFunctionReturnType.ql:27,23-31) -WARNING: Module DataFlow has been deprecated and may be removed in future (InvalidFunctionReturnType.ql:27,51-59) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (InvalidFunctionReturnType.ql:27,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (InvalidFunctionReturnType.ql:27,23-31) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (InvalidFunctionReturnType.ql:27,51-59) | test.cpp:5:3:5:11 | return ... | Function test_refconst_return returns a reference or a pointer to $@ that is passed by reference to const. | test.cpp:4:44:4:44 | x | parameter | | test.cpp:8:3:8:14 | return ... | Function test_ptrconst_return returns a reference or a pointer to $@ that is passed by reference to const. | test.cpp:7:44:7:44 | x | parameter | diff --git a/cpp/autosar/test/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.expected b/cpp/autosar/test/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.expected index be4a4107fd..2ce56fdce9 100644 --- a/cpp/autosar/test/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.expected +++ b/cpp/autosar/test/rules/A8-4-11/SmartPointerAsParameterWithoutLifetimeSemantics.expected @@ -1,5 +1,5 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (SmartPointerAsParameterWithoutLifetimeSemantics.ql:47,3-11) -WARNING: Module DataFlow has been deprecated and may be removed in future (SmartPointerAsParameterWithoutLifetimeSemantics.ql:56,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (SmartPointerAsParameterWithoutLifetimeSemantics.ql:47,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (SmartPointerAsParameterWithoutLifetimeSemantics.ql:56,5-13) | test.cpp:7:41:7:43 | up1 | Function $@ takes smart pointer parameter 'up1' but does not implement any lifetime-affecting operations. | test.cpp:7:6:7:18 | smart_ptr_get | smart_ptr_get | | test.cpp:16:53:16:55 | sp1 | Function $@ takes smart pointer parameter 'sp1' but does not implement any lifetime-affecting operations. | test.cpp:16:6:16:29 | smart_ptr_ref_assign_ref | smart_ptr_ref_assign_ref | | test.cpp:28:55:28:57 | sp1 | Function $@ takes smart pointer parameter 'sp1' but does not implement any lifetime-affecting operations. | test.cpp:28:6:28:31 | smart_ptr_ref_noncompliant | smart_ptr_ref_noncompliant | diff --git a/cpp/autosar/test/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.expected b/cpp/autosar/test/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.expected index b2273e66f3..0a8ead4af8 100644 --- a/cpp/autosar/test/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.expected +++ b/cpp/autosar/test/rules/A8-4-12/UniquePtrPassedToFunctionWithImproperSemantics.expected @@ -1,5 +1,5 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (UniquePtrPassedToFunctionWithImproperSemantics.ql:41,3-11) -WARNING: Module DataFlow has been deprecated and may be removed in future (UniquePtrPassedToFunctionWithImproperSemantics.ql:51,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UniquePtrPassedToFunctionWithImproperSemantics.ql:41,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UniquePtrPassedToFunctionWithImproperSemantics.ql:51,5-13) | test.cpp:13:55:13:56 | v1 | Parameter of type std::unique_ptr passed as lvalue reference but not used to modify underlying object. | | test.cpp:17:47:17:48 | v1 | Parameter of type std::unique_ptr passed as lvalue reference but not used to modify underlying object. | | test.cpp:22:27:22:28 | v1 | Parameter of type std::unique_ptr passed as lvalue reference but not used to modify underlying object. | diff --git a/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected b/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected index 15e513c639..bafa98112f 100644 --- a/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected +++ b/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected @@ -1,5 +1,5 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (InOutParametersDeclaredAsTNotModified.ql:49,7-15) -WARNING: Module DataFlow has been deprecated and may be removed in future (InOutParametersDeclaredAsTNotModified.ql:63,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (InOutParametersDeclaredAsTNotModified.ql:49,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (InOutParametersDeclaredAsTNotModified.ql:63,7-15) | test.cpp:4:13:4:13 | i | In-out parameter i that is not written to. | | test.cpp:7:22:7:24 | str | In-out parameter str that is not read from. | | test.cpp:18:14:18:14 | i | In-out parameter i that is not read from. | diff --git a/cpp/autosar/test/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.expected b/cpp/autosar/test/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.expected index 84d7f2d7f0..70892c12c8 100644 --- a/cpp/autosar/test/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.expected +++ b/cpp/autosar/test/rules/A9-3-1/ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.expected @@ -1,6 +1,6 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql:73,3-11) -WARNING: Module DataFlow has been deprecated and may be removed in future (ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql:73,23-31) -WARNING: Module DataFlow has been deprecated and may be removed in future (ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql:73,46-54) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql:73,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql:73,23-31) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ReturnsNonConstRawPointersOrReferencesToPrivateOrProtectedData.ql:73,46-54) | test.cpp:20:8:20:12 | getB2 | Member function A::getB2 $@ a non-const raw pointer or reference to a private or protected $@. | test.cpp:20:25:20:25 | b | returns | test.cpp:54:7:54:7 | b | field | | test.cpp:22:8:22:12 | getB3 | Member function A::getB3 $@ a non-const raw pointer or reference to a private or protected $@. | test.cpp:22:25:22:26 | & ... | returns | test.cpp:54:7:54:7 | b | field | | test.cpp:24:8:24:13 | getB33 | Member function A::getB33 $@ a non-const raw pointer or reference to a private or protected $@. | test.cpp:26:12:26:13 | bb | returns | test.cpp:54:7:54:7 | b | field | diff --git a/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.expected b/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.expected index 15f4e9a793..1b2aef1b24 100644 --- a/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.expected +++ b/cpp/autosar/test/rules/M0-3-2/FunctionErroneousReturnValueNotTested.expected @@ -1,4 +1,4 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (FunctionErroneousReturnValueNotTested.ql:70,9-17) -WARNING: Module DataFlow has been deprecated and may be removed in future (FunctionErroneousReturnValueNotTested.ql:70,29-37) -WARNING: Module DataFlow has been deprecated and may be removed in future (FunctionErroneousReturnValueNotTested.ql:70,53-61) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (FunctionErroneousReturnValueNotTested.ql:70,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (FunctionErroneousReturnValueNotTested.ql:70,29-37) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (FunctionErroneousReturnValueNotTested.ql:70,53-61) | test.cpp:16:3:16:8 | call to remove | Return value is not tested for errors. | diff --git a/cpp/autosar/test/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.expected b/cpp/autosar/test/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.expected index 2545360a7b..d0fe6416ca 100644 --- a/cpp/autosar/test/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.expected +++ b/cpp/autosar/test/rules/M3-9-3/UnderlyingBitRepresentationsOfFloatingPointValuesUsed.expected @@ -1,5 +1,5 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql:27,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql:36,10-18) -WARNING: Module DataFlow has been deprecated and may be removed in future (UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql:37,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql:27,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql:36,10-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnderlyingBitRepresentationsOfFloatingPointValuesUsed.ql:37,5-13) | test.cpp:5:3:5:20 | ... &= ... | Modification of bit-representation of float originated at $@ | test.cpp:4:24:4:60 | reinterpret_cast... | cast | | test.cpp:12:3:12:14 | ... &= ... | Modification of bit-representation of float originated at $@ | test.cpp:11:18:11:30 | (uint8_t *)... | cast | diff --git a/cpp/autosar/test/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.expected b/cpp/autosar/test/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.expected index eee85d22c0..af7e9efc36 100644 --- a/cpp/autosar/test/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.expected +++ b/cpp/autosar/test/rules/M9-3-1/ConstMemberFunctionReturnsNonConstPointer.expected @@ -1,5 +1,5 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (ConstMemberFunctionReturnsNonConstPointer.ql:53,7-15) -WARNING: Module DataFlow has been deprecated and may be removed in future (ConstMemberFunctionReturnsNonConstPointer.ql:55,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstMemberFunctionReturnsNonConstPointer.ql:53,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ConstMemberFunctionReturnsNonConstPointer.ql:55,7-15) | test.cpp:8:8:8:11 | getA | Const member function returns a pointer to class data $@. | test.cpp:3:8:3:8 | a | a | | test.cpp:9:8:9:11 | getB | Const member function returns a pointer to class data $@. | test.cpp:4:8:4:8 | b | b | | test.cpp:11:6:11:12 | getThis | Const member function returns a pointer to class data $@. | test.cpp:11:36:11:39 | this | this | diff --git a/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected b/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected index 9259112890..209d81ba8b 100644 --- a/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected +++ b/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected @@ -1,12 +1,12 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:88,7-15) -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:88,27-35) -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:89,9-17) -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:93,9-17) -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:93,29-37) -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:94,11-19) -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:104,35-43) -WARNING: Module DataFlow has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:105,11-19) -WARNING: Module TaintTracking has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:104,9-22) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:88,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:88,27-35) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:89,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:93,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:93,29-37) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:94,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:104,35-43) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:105,11-19) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:104,9-22) | test.cpp:8:42:8:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:8:3:8:11 | call to copy | call to copy | | test.cpp:17:42:17:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:17:3:17:11 | call to copy | call to copy | | test.cpp:55:42:55:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:55:3:55:11 | call to copy | call to copy | diff --git a/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected b/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected index 5730a54b2c..b5c36727f5 100644 --- a/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected +++ b/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected @@ -1,9 +1,9 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (UseValidIteratorRanges.ql:23,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (UseValidIteratorRanges.ql:23,25-33) -WARNING: Module DataFlow has been deprecated and may be removed in future (UseValidIteratorRanges.ql:24,7-15) -WARNING: Module DataFlow has been deprecated and may be removed in future (UseValidIteratorRanges.ql:30,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (UseValidIteratorRanges.ql:30,25-33) -WARNING: Module DataFlow has been deprecated and may be removed in future (UseValidIteratorRanges.ql:31,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:23,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:23,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:24,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:30,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:30,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:31,7-15) | test.cpp:7:3:7:15 | call to for_each | The $@ of iterator range function does not point to the end of an iterator. | test.cpp:7:28:7:32 | call to begin | argument | | test.cpp:7:3:7:15 | call to for_each | The $@ of iterator range function does not point to the start of an iterator. | test.cpp:7:19:7:21 | call to end | argument | | test.cpp:8:3:8:15 | call to for_each | The $@ of iterator range function does not point to the end of an iterator. | test.cpp:8:30:8:34 | call to begin | argument | diff --git a/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected b/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected index be69b2024d..0ba2fad433 100644 --- a/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected +++ b/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected @@ -1,12 +1,12 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:38,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:38,25-33) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:38,51-59) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:39,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:39,25-33) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:39,52-60) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:74,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:74,25-33) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:75,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:38,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:38,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:38,51-59) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:39,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:39,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:39,52-60) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:74,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:74,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:75,7-15) | test.cpp:8:7:8:7 | i | Increment of iterator may overflow since its bounds are not checked. | | test.cpp:9:9:9:9 | i | Increment of iterator may overflow since its bounds are not checked. | | test.cpp:10:9:10:9 | i | Increment of iterator may overflow since its bounds are not checked. | diff --git a/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected b/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected index 1f97f2ca40..59caaa22d8 100644 --- a/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected +++ b/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected @@ -1,7 +1,7 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:41,62-70) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:42,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:51,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:57,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:41,62-70) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:42,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:51,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:57,3-11) edges | test.cpp:15:19:15:21 | foo | test.cpp:16:24:16:26 | foo | provenance | | | test.cpp:15:19:15:21 | foo | test.cpp:16:51:16:53 | foo | provenance | | diff --git a/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected b/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected index 243602e104..00f1a6ba03 100644 --- a/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected +++ b/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected @@ -1,27 +1,27 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:24,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:24,59-67) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:27,33-41) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:27,57-65) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:31,33-41) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:31,59-67) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:40,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:40,25-33) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:40,53-61) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:43,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:43,57-65) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:52,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:52,55-63) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:59,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:59,57-65) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:71,31-39) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:71,55-63) -WARNING: Module TaintTracking has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:24,5-18) -WARNING: Module TaintTracking has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:27,7-20) -WARNING: Module TaintTracking has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:31,7-20) -WARNING: Module TaintTracking has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:43,5-18) -WARNING: Module TaintTracking has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:52,5-18) -WARNING: Module TaintTracking has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:59,5-18) -WARNING: Module TaintTracking has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:71,5-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:24,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:24,59-67) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:27,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:27,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:31,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:31,59-67) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:40,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:40,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:40,53-61) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:43,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:43,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:52,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:52,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:59,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:59,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:71,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:71,55-63) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:24,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:27,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:31,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:43,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:52,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:59,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:71,5-18) | test.cpp:82:3:82:4 | call to f2 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.cpp:82:6:82:7 | call to f5 | call to f5 | test.cpp:82:12:82:13 | call to f6 | call to f6 | | test.cpp:84:3:84:4 | call to f2 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.cpp:84:6:84:7 | call to f5 | call to f5 | test.cpp:84:12:84:13 | call to f7 | call to f7 | | test.cpp:87:3:87:4 | call to f2 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.cpp:87:9:87:10 | call to m1 | call to m1 | test.cpp:87:18:87:19 | call to m1 | call to m1 | diff --git a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected index a3c0c08011..c271269ab8 100644 --- a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected +++ b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected @@ -1,7 +1,7 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:19,44-52) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:20,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:22,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:27,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:19,44-52) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:20,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:22,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:27,33-41) edges | test.cpp:6:19:6:37 | new[] | test.cpp:9:12:9:13 | l1 | provenance | | | test.cpp:7:22:7:40 | new[] | test.cpp:10:12:10:13 | l2 | provenance | | diff --git a/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected b/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected index b30e94a38e..b7b4891776 100644 --- a/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected +++ b/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected @@ -1,9 +1,9 @@ -WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:59,5-13) -WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:61,36-44) -WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:77,46-54) -WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:78,22-30) -WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:82,20-28) -WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:85,35-43) -WARNING: Module DataFlow has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:90,38-46) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:59,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:61,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:77,46-54) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:78,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:82,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:85,35-43) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:90,38-46) | test.cpp:24:7:24:34 | new | nothrow new allocation of $@ returns here without a subsequent check to see whether the pointer is valid. | test.cpp:24:7:24:34 | new | StructA * | | test.cpp:40:17:40:38 | call to allocate_without_check | nothrow new allocation of $@ returns here without a subsequent check to see whether the pointer is valid. | test.cpp:35:17:35:44 | new | StructA * | diff --git a/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected b/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected index adabb21674..3743c3d414 100644 --- a/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected +++ b/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected @@ -1,4 +1,4 @@ -WARNING: Module TaintTracking has been deprecated and may be removed in future (BadlySeededRandomNumberGenerator.ql:37,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (BadlySeededRandomNumberGenerator.ql:37,7-20) | test.cpp:9:33:9:33 | call to linear_congruential_engine | Random number generator linear_congruential_engine is default-initialized and is therefore not properly seeded. | | test.cpp:10:30:10:31 | call to linear_congruential_engine | Random number generator linear_congruential_engine is default-initialized and is therefore not properly seeded. | | test.cpp:11:21:11:22 | call to linear_congruential_engine | Random number generator linear_congruential_engine is default-initialized and is therefore not properly seeded. | From 87fa7c1c3d9bc079d46d045a182591c2347d7aaa Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Fri, 5 Jul 2024 19:49:48 +0200 Subject: [PATCH 023/628] STR34-C: Do not consider integer type aliases in templates --- .../CastCharBeforeConvertingToLargerSizes.ql | 21 +++++---------- ...CharBeforeConvertingToLargerSizes.expected | 21 --------------- ...astCharBeforeConvertingToLargerSizes.qlref | 1 - ...tCharBeforeConvertingToLargerSizes.testref | 1 + ...oreConvertingToLargerSizes_shared.expected | 21 +++++++++++++++ ...ertingToLargerSizes_shared.expected.clang} | 14 +++++----- ...nvertingToLargerSizes_shared.expected.gcc} | 12 ++++----- ...nvertingToLargerSizes_shared.expected.qcc} | 14 +++++----- ...harBeforeConvertingToLargerSizes_shared.ql | 4 +++ .../test.c | 2 ++ ...arBeforeConvertingToLargerSizes_shared.qll | 26 +++++++++++++++++++ ...oreConvertingToLargerSizes_shared.expected | 2 ++ ...harBeforeConvertingToLargerSizes_shared.ql | 4 +++ .../test.cpp | 17 ++++++++++++ rule_packages/c/Strings3.json | 1 + 15 files changed, 105 insertions(+), 56 deletions(-) delete mode 100644 c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected delete mode 100644 c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qlref create mode 100644 c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.testref create mode 100644 c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected rename c/{cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.gcc => common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.clang} (75%) rename c/{cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.clang => common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.gcc} (78%) rename c/{cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.qcc => common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.qcc} (75%) create mode 100644 c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql rename c/{cert/test/rules/STR34-C => common/test/rules/castcharbeforeconvertingtolargersizes_shared}/test.c (95%) create mode 100644 cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.qll create mode 100644 cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected create mode 100644 cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql create mode 100644 cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/test.cpp diff --git a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql index b0d4088f9f..1f2af0b588 100644 --- a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql +++ b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql @@ -14,18 +14,11 @@ import cpp import codingstandards.c.cert -import semmle.code.cpp.commons.CommonType +import codingstandards.cpp.rules.castcharbeforeconvertingtolargersizes_shared.CastCharBeforeConvertingToLargerSizes_shared -from Cast c -where - not isExcluded(c, Strings3Package::castCharBeforeConvertingToLargerSizesQuery()) and - // find cases where there is a conversion happening wherein the - // base type is a char - c.getExpr().getType() instanceof CharType and - not c.getExpr().getType() instanceof UnsignedCharType and - // it's a bigger type - c.getType().getSize() > c.getExpr().getType().getSize() and - // and it's some kind of integer type - c.getType() instanceof IntegralType -select c.getExpr(), - "Expression not converted to `unsigned char` before converting to a larger integer type." +class CastCharBeforeConvertingToLargerSizesQuery extends CastCharBeforeConvertingToLargerSizes_sharedSharedQuery +{ + CastCharBeforeConvertingToLargerSizesQuery() { + this = Strings3Package::castCharBeforeConvertingToLargerSizesQuery() + } +} diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected b/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected deleted file mode 100644 index 1c6424dc0c..0000000000 --- a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected +++ /dev/null @@ -1,21 +0,0 @@ -| test.c:7:7:7:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:28:11:28:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:29:3:29:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:29:11:29:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:31:11:31:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:32:11:32:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:33:3:33:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:33:11:33:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:34:3:34:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:34:11:34:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:35:3:35:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:35:11:35:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:36:3:36:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:36:11:36:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:37:11:37:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:38:11:38:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:39:3:39:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:39:11:39:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:40:12:40:13 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:42:11:42:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:43:11:43:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qlref b/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qlref deleted file mode 100644 index 379d3b3f68..0000000000 --- a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql \ No newline at end of file diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.testref b/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.testref new file mode 100644 index 0000000000..fefb98580c --- /dev/null +++ b/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.testref @@ -0,0 +1 @@ +c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql \ No newline at end of file diff --git a/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected b/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected new file mode 100644 index 0000000000..c318f791e9 --- /dev/null +++ b/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected @@ -0,0 +1,21 @@ +| test.c:9:7:9:14 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:30:11:30:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:31:3:31:13 | (unsigned int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:31:11:31:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:33:11:33:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:34:11:34:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:35:3:35:13 | (unsigned int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:35:11:35:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:36:3:36:13 | (unsigned int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:36:11:36:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:37:3:37:13 | (unsigned int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:37:11:37:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:38:3:38:13 | (unsigned int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:38:11:38:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:39:11:39:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:40:11:40:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:41:3:41:13 | (unsigned int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:41:11:41:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:42:12:42:13 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:44:11:44:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:45:11:45:12 | (int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.gcc b/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.clang similarity index 75% rename from c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.gcc rename to c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.clang index 1cf143a196..0378c8a6b5 100644 --- a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.gcc +++ b/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.clang @@ -1,8 +1,6 @@ -| test.c:7:7:7:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:28:3:28:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:29:3:29:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:9:7:9:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:30:3:30:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:31:3:31:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:32:3:32:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:33:3:33:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:34:3:34:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:35:3:35:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | @@ -10,6 +8,8 @@ | test.c:37:3:37:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:38:3:38:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:39:3:39:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:40:3:40:14 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:42:11:42:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:43:11:43:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:40:3:40:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:41:3:41:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:42:3:42:14 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:44:11:44:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:45:11:45:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.clang b/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.gcc similarity index 78% rename from c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.clang rename to c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.gcc index 1cf143a196..f729c9e42d 100644 --- a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.clang +++ b/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.gcc @@ -1,8 +1,6 @@ -| test.c:7:7:7:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:28:3:28:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:29:3:29:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:9:7:9:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:30:3:30:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:31:3:31:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:32:3:32:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:33:3:33:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:34:3:34:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:35:3:35:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | @@ -10,6 +8,8 @@ | test.c:37:3:37:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:38:3:38:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:39:3:39:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:40:3:40:14 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:42:11:42:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:40:3:40:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:41:3:41:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:42:3:42:14 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:43:11:43:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:44:11:44:12 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.qcc b/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.qcc similarity index 75% rename from c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.qcc rename to c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.qcc index fec6522014..551423495c 100644 --- a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.expected.qcc +++ b/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.qcc @@ -1,8 +1,6 @@ -| test.c:7:7:7:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:28:3:28:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:29:3:29:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:9:7:9:14 | * ... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:30:3:30:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:31:3:31:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:32:3:32:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:33:3:33:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:34:3:34:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:35:3:35:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | @@ -10,6 +8,8 @@ | test.c:37:3:37:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:38:3:38:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | | test.c:39:3:39:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:40:3:40:14 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:42:3:42:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | -| test.c:43:3:43:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:40:3:40:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:41:3:41:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:42:3:42:14 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:44:3:44:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.c:45:3:45:13 | (...) | Expression not converted to `unsigned char` before converting to a larger integer type. | diff --git a/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql b/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql new file mode 100644 index 0000000000..2aceff89c0 --- /dev/null +++ b/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.castcharbeforeconvertingtolargersizes_shared.CastCharBeforeConvertingToLargerSizes_shared + +class TestFileQuery extends CastCharBeforeConvertingToLargerSizes_sharedSharedQuery, TestQuery { } diff --git a/c/cert/test/rules/STR34-C/test.c b/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/test.c similarity index 95% rename from c/cert/test/rules/STR34-C/test.c rename to c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/test.c index d4bd825c8e..8865e477fb 100644 --- a/c/cert/test/rules/STR34-C/test.c +++ b/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/test.c @@ -1,3 +1,5 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C++ TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. #include #include diff --git a/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.qll b/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.qll new file mode 100644 index 0000000000..3ef9033910 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.qll @@ -0,0 +1,26 @@ +/** + * Provides a library which includes a `problems` predicate for reporting.... + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class CastCharBeforeConvertingToLargerSizes_sharedSharedQuery extends Query { } + +Query getQuery() { result instanceof CastCharBeforeConvertingToLargerSizes_sharedSharedQuery } + +query predicate problems(Cast c, string message) { + not isExcluded(c, getQuery()) and + // find cases where there is a conversion happening wherein the + // base type is a char + c.getExpr().getType() instanceof CharType and + not c.getExpr().getType() instanceof UnsignedCharType and + // it's a bigger type + c.getType().getSize() > c.getExpr().getType().getSize() and + // and it's some kind of integer type + c.getType().getUnderlyingType() instanceof IntegralType and + not c.isFromTemplateInstantiation(_) and + message = + "Expression not converted to `unsigned char` before converting to a larger integer type." +} diff --git a/cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected new file mode 100644 index 0000000000..886d03ddac --- /dev/null +++ b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected @@ -0,0 +1,2 @@ +| test.cpp:11:9:11:9 | (int32_t)... | Expression not converted to `unsigned char` before converting to a larger integer type. | +| test.cpp:12:41:12:41 | (signed int)... | Expression not converted to `unsigned char` before converting to a larger integer type. | diff --git a/cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql new file mode 100644 index 0000000000..2aceff89c0 --- /dev/null +++ b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.castcharbeforeconvertingtolargersizes_shared.CastCharBeforeConvertingToLargerSizes_shared + +class TestFileQuery extends CastCharBeforeConvertingToLargerSizes_sharedSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/test.cpp b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/test.cpp new file mode 100644 index 0000000000..4e5d90e714 --- /dev/null +++ b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/test.cpp @@ -0,0 +1,17 @@ +// NOTICE: THE TEST CASES BELOW ARE ALSO INCLUDED IN THE C TEST CASE AND +// CHANGES SHOULD BE REFLECTED THERE AS WELL. +#include + +template S get(T t) { + S s = t; // COMPLIANT + return s; +} + +void test(std::int32_t i32, std::int8_t i8, char c) { + i32 = c; // NON_COMPLIANT + i32 = get(c); // NON_COMPLIANT + i32 = get(c); // COMPLIANT + i32 = i8; // COMPLIANT + i32 = get(i8); // COMPLIANT + i32 = get(i8); // COMPLIANT +} diff --git a/rule_packages/c/Strings3.json b/rule_packages/c/Strings3.json index 9456f4b422..b0131fb55b 100644 --- a/rule_packages/c/Strings3.json +++ b/rule_packages/c/Strings3.json @@ -12,6 +12,7 @@ "precision": "very-high", "severity": "error", "short_name": "CastCharBeforeConvertingToLargerSizes", + "shared_implementation_short_name": "CastCharBeforeConvertingToLargerSizes_shared", "tags": [ "correctness", "security" From dc6bed13a81d6956856ce1c58b9aee12f3d31ab3 Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Fri, 5 Jul 2024 20:00:09 +0200 Subject: [PATCH 024/628] Add change notes --- change_notes/2024-07-05-fix-fp-576-STR34-C.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change_notes/2024-07-05-fix-fp-576-STR34-C.md diff --git a/change_notes/2024-07-05-fix-fp-576-STR34-C.md b/change_notes/2024-07-05-fix-fp-576-STR34-C.md new file mode 100644 index 0000000000..340d8f4288 --- /dev/null +++ b/change_notes/2024-07-05-fix-fp-576-STR34-C.md @@ -0,0 +1,2 @@ +- `STR34-C` - `CastCharBeforeConvertingToLargerSizes.ql`: + - Fixes #576. Do not consider integer type aliases in templates. \ No newline at end of file From b67dc05ffa5cce5da451bd737e1ad041ef7c15b5 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 12 Jul 2024 11:11:18 +0100 Subject: [PATCH 025/628] C++: Accept test changes after #16969. --- .../ValidContainerElementAccess.expected | 2 ++ cpp/common/test/rules/validcontainerelementaccess/test.cpp | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cpp/common/test/rules/validcontainerelementaccess/ValidContainerElementAccess.expected b/cpp/common/test/rules/validcontainerelementaccess/ValidContainerElementAccess.expected index 988846beef..1738cbe330 100644 --- a/cpp/common/test/rules/validcontainerelementaccess/ValidContainerElementAccess.expected +++ b/cpp/common/test/rules/validcontainerelementaccess/ValidContainerElementAccess.expected @@ -7,4 +7,6 @@ | test.cpp:89:15:89:16 | it | Elements of $@ not accessed with valid reference, pointer, or iterator because of a prior $@. | test.cpp:86:20:86:20 | d | container | test.cpp:92:7:92:12 | call to insert | invalidation | | test.cpp:91:9:91:10 | it | Elements of $@ not accessed with valid reference, pointer, or iterator because of a prior $@. | test.cpp:86:20:86:20 | d | container | test.cpp:92:7:92:12 | call to insert | invalidation | | test.cpp:98:56:98:58 | loc | Elements of $@ not accessed with valid reference, pointer, or iterator because of a prior $@. | test.cpp:96:44:96:46 | str | container | test.cpp:99:9:99:14 | call to insert | invalidation | +| test.cpp:99:5:99:7 | str | Elements of $@ not accessed with valid reference, pointer, or iterator because of a prior $@. | test.cpp:96:44:96:46 | str | container | test.cpp:99:9:99:14 | call to insert | invalidation | | test.cpp:99:16:99:18 | loc | Elements of $@ not accessed with valid reference, pointer, or iterator because of a prior $@. | test.cpp:96:44:96:46 | str | container | test.cpp:99:9:99:14 | call to insert | invalidation | +| test.cpp:106:11:106:13 | str | Elements of $@ not accessed with valid reference, pointer, or iterator because of a prior $@. | test.cpp:103:45:103:47 | str | container | test.cpp:106:15:106:20 | call to insert | invalidation | diff --git a/cpp/common/test/rules/validcontainerelementaccess/test.cpp b/cpp/common/test/rules/validcontainerelementaccess/test.cpp index 55c94cf8f1..0f40687110 100644 --- a/cpp/common/test/rules/validcontainerelementaccess/test.cpp +++ b/cpp/common/test/rules/validcontainerelementaccess/test.cpp @@ -96,14 +96,14 @@ void f8(const int *ar) { void f9(const std::string &s, std::string &str) { std::string::iterator loc = str.begin(); for (auto i = s.begin(), e = s.end(); i != e; ++i, ++loc) { // NON_COMPLIANT - str.insert(loc, 'c'); // NON_COMPLIANT + str.insert(loc, 'c'); // NON_COMPLIANT[FALSE POSITIVE for str] } } void f10(const std::string &s, std::string &str) { std::string::iterator loc = str.begin(); for (auto i = s.begin(), e = s.end(); i != e; ++i, ++loc) { // COMPLIANT - loc = str.insert(loc, 'c'); // COMPLIANT + loc = str.insert(loc, 'c'); // COMPLIANT[FALSE POSITIVE] } } From e32a4e452aa8e74733a86d710b58bb5057586c51 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 12 Jul 2024 11:17:04 +0100 Subject: [PATCH 026/628] C++: Format test file expectations. --- cpp/common/test/rules/validcontainerelementaccess/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/common/test/rules/validcontainerelementaccess/test.cpp b/cpp/common/test/rules/validcontainerelementaccess/test.cpp index 0f40687110..d9e2c2d89a 100644 --- a/cpp/common/test/rules/validcontainerelementaccess/test.cpp +++ b/cpp/common/test/rules/validcontainerelementaccess/test.cpp @@ -96,14 +96,14 @@ void f8(const int *ar) { void f9(const std::string &s, std::string &str) { std::string::iterator loc = str.begin(); for (auto i = s.begin(), e = s.end(); i != e; ++i, ++loc) { // NON_COMPLIANT - str.insert(loc, 'c'); // NON_COMPLIANT[FALSE POSITIVE for str] + str.insert(loc, 'c'); // NON_COMPLIANT[FALSE POSITIVE for str] } } void f10(const std::string &s, std::string &str) { std::string::iterator loc = str.begin(); for (auto i = s.begin(), e = s.end(); i != e; ++i, ++loc) { // COMPLIANT - loc = str.insert(loc, 'c'); // COMPLIANT[FALSE POSITIVE] + loc = str.insert(loc, 'c'); // COMPLIANT[FALSE POSITIVE] } } From cfbdc212fcbd1b5f1e5274b19a06e3ff796b7ba9 Mon Sep 17 00:00:00 2001 From: Alexandre Boulgakov Date: Tue, 16 Jul 2024 14:09:34 +0100 Subject: [PATCH 027/628] A12-8-6: Update tests around unused template special members. --- .../rules/A12-8-6/CopyAndMoveNotDeclaredProtected.expected | 4 ---- 1 file changed, 4 deletions(-) diff --git a/cpp/autosar/test/rules/A12-8-6/CopyAndMoveNotDeclaredProtected.expected b/cpp/autosar/test/rules/A12-8-6/CopyAndMoveNotDeclaredProtected.expected index 9f85da12d6..74ed472a52 100644 --- a/cpp/autosar/test/rules/A12-8-6/CopyAndMoveNotDeclaredProtected.expected +++ b/cpp/autosar/test/rules/A12-8-6/CopyAndMoveNotDeclaredProtected.expected @@ -20,7 +20,3 @@ | test.cpp:109:3:109:12 | declaration of BaseClass8 | Move constructor for base class 'BaseClass8' is not declared protected. | | test.cpp:110:15:110:23 | declaration of operator= | Copy assignment operator for base class 'BaseClass8' is not declared protected. | | test.cpp:111:15:111:23 | declaration of operator= | Move assignment operator for base class 'BaseClass8' is not declared protected. | -| test.cpp:124:26:124:26 | declaration of BaseClass9 | Implicit copy constructor for base class 'BaseClass9' is not declared deleted. | -| test.cpp:124:26:124:26 | declaration of BaseClass9 | Implicit move constructor for base class 'BaseClass9' is not declared deleted. | -| test.cpp:124:26:124:26 | declaration of operator= | Implicit copy assignment operator for base class 'BaseClass9' is not declared deleted. | -| test.cpp:124:26:124:26 | declaration of operator= | Implicit move assignment operator for base class 'BaseClass9' is not declared deleted. | From 80ab9a6954315c6c70b37d257e4b269406b5e01c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 23 Jul 2024 21:57:11 +0100 Subject: [PATCH 028/628] Add change note --- change_notes/2024-06-03-a3-1-5-trivial-defs.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 change_notes/2024-06-03-a3-1-5-trivial-defs.md diff --git a/change_notes/2024-06-03-a3-1-5-trivial-defs.md b/change_notes/2024-06-03-a3-1-5-trivial-defs.md new file mode 100644 index 0000000000..29a7f48eb5 --- /dev/null +++ b/change_notes/2024-06-03-a3-1-5-trivial-defs.md @@ -0,0 +1,4 @@ + - `A3-1-5` - `TrivialOrTemplateFunctionDefinedOutsideClassDefinition.ql`: + - Query deleted - rule was never intended to cover this case (see https://forum.misra.org.uk/archive/index.php?thread-1588.html). + - `A3-1-5` - `NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql`: + - Removed false positives caused by flagging member functions in template instantiations From dfe7dca65eb02779b9004607f9e2832e2eaeec3c Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Tue, 23 Jul 2024 22:02:33 +0100 Subject: [PATCH 029/628] Update cpp/common/src/codingstandards/cpp/Class.qll Co-authored-by: Kristen Newbury --- cpp/common/src/codingstandards/cpp/Class.qll | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Class.qll b/cpp/common/src/codingstandards/cpp/Class.qll index 09d39ce6f8..73c0930f09 100644 --- a/cpp/common/src/codingstandards/cpp/Class.qll +++ b/cpp/common/src/codingstandards/cpp/Class.qll @@ -193,8 +193,11 @@ class TrivialMemberFunction extends IntrospectedMemberFunction { */ class TemplateOrTemplateClassMemberFunction extends MemberFunction { TemplateOrTemplateClassMemberFunction() { - isFromUninstantiatedTemplate(_) or - isFromTemplateInstantiation(_) +( + isFromUninstantiatedTemplate(_) or + isFromTemplateInstantiation(_) + ) and + not this.isCompilerGenerated() } } From 1de5223159e72821e9d5a8eb4215cf00b372d217 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 24 Jul 2024 22:26:49 +0100 Subject: [PATCH 030/628] Remove extra line --- cpp/autosar/test/rules/A3-1-5/test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/autosar/test/rules/A3-1-5/test.cpp b/cpp/autosar/test/rules/A3-1-5/test.cpp index 0bff554785..1b2898bf63 100644 --- a/cpp/autosar/test/rules/A3-1-5/test.cpp +++ b/cpp/autosar/test/rules/A3-1-5/test.cpp @@ -172,7 +172,6 @@ void test_FooBar() { foobar.complexCalculation(); } - FooBar::~FooBar() {} // COMPLIANT want to ignore pImpl uses of destructors int FooBar::f1(int a, int b) { // COMPLIANT not a trivial function From 52c7e45ccf8efcb8459cbeb7be779e591e4c3c87 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 24 Jul 2024 22:30:25 +0100 Subject: [PATCH 031/628] Remove A3-1-5 deleted query --- .../cpp/exclusions/cpp/Classes.qll | 17 ----------------- rule_packages/cpp/Classes.json | 9 --------- 2 files changed, 26 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Classes.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Classes.qll index 92c7a4280e..3daf48c696 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Classes.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Classes.qll @@ -13,7 +13,6 @@ newtype ClassesQuery = TClassDataMembersInitializationConditionQuery() or TRedundantMemberFunctionsShouldBeDefaultedOrLeftUndefinedQuery() or TNonTemplateMemberDefinedInTemplateQuery() or - TTrivialOrTemplateFunctionDefinedOutsideClassDefinitionQuery() or TNonTrivialNonTemplateFunctionDefinedInsideClassDefinitionQuery() or TInParametersForNotCheapToCopyTypesNotPassedByReferenceQuery() or TInParametersForCheapToCopyTypesNotPassedByValueQuery() or @@ -105,15 +104,6 @@ predicate isClassesQueryMetadata(Query query, string queryId, string ruleId, str ruleId = "A14-5-2" and category = "advisory" or - query = - // `Query` instance for the `trivialOrTemplateFunctionDefinedOutsideClassDefinition` query - ClassesPackage::trivialOrTemplateFunctionDefinedOutsideClassDefinitionQuery() and - queryId = - // `@id` for the `trivialOrTemplateFunctionDefinedOutsideClassDefinition` query - "cpp/autosar/trivial-or-template-function-defined-outside-class-definition" and - ruleId = "A3-1-5" and - category = "required" - or query = // `Query` instance for the `nonTrivialNonTemplateFunctionDefinedInsideClassDefinition` query ClassesPackage::nonTrivialNonTemplateFunctionDefinedInsideClassDefinitionQuery() and @@ -251,13 +241,6 @@ module ClassesPackage { TQueryCPP(TClassesPackageQuery(TNonTemplateMemberDefinedInTemplateQuery())) } - Query trivialOrTemplateFunctionDefinedOutsideClassDefinitionQuery() { - //autogenerate `Query` type - result = - // `Query` type for `trivialOrTemplateFunctionDefinedOutsideClassDefinition` query - TQueryCPP(TClassesPackageQuery(TTrivialOrTemplateFunctionDefinedOutsideClassDefinitionQuery())) - } - Query nonTrivialNonTemplateFunctionDefinedInsideClassDefinitionQuery() { //autogenerate `Query` type result = diff --git a/rule_packages/cpp/Classes.json b/rule_packages/cpp/Classes.json index 61eab45081..6dd130a55b 100644 --- a/rule_packages/cpp/Classes.json +++ b/rule_packages/cpp/Classes.json @@ -178,15 +178,6 @@ "obligation": "required" }, "queries": [ - { - "description": "A function that is either trivial, a template function, or a member of a template class may not be defined outside of a class body.", - "kind": "problem", - "name": "A function shall be defined with a class body if and only if it is intended to be inlined", - "precision": "very-high", - "severity": "recommendation", - "short_name": "TrivialOrTemplateFunctionDefinedOutsideClassDefinition", - "tags": [] - }, { "description": "A function that is not either trivial, a template function, or a member of a template class may not be defined within a class body.", "kind": "problem", From 099dbb85308413ee319f42df22c6d3f870dee221 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 24 Jul 2024 23:28:04 +0100 Subject: [PATCH 032/628] Fix Class.qll formatting. --- cpp/common/src/codingstandards/cpp/Class.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/Class.qll b/cpp/common/src/codingstandards/cpp/Class.qll index 3aa7719fb8..6f730736f9 100644 --- a/cpp/common/src/codingstandards/cpp/Class.qll +++ b/cpp/common/src/codingstandards/cpp/Class.qll @@ -192,7 +192,7 @@ class TrivialMemberFunction extends IntrospectedMemberFunction { */ class TemplateOrTemplateClassMemberFunction extends MemberFunction { TemplateOrTemplateClassMemberFunction() { -( + ( isFromUninstantiatedTemplate(_) or isFromTemplateInstantiation(_) ) and From e3a5b8cdd87726a0faa4862e24ee1db9b5257b08 Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Thu, 25 Jul 2024 20:13:49 +0200 Subject: [PATCH 033/628] renamed the shared query --- .../CastCharBeforeConvertingToLargerSizes.ql | 4 +-- ...tCharBeforeConvertingToLargerSizes.testref | 2 +- ...harBeforeConvertingToLargerSizes.expected} | 0 ...oreConvertingToLargerSizes.expected.clang} | 0 ...eforeConvertingToLargerSizes.expected.gcc} | 0 ...eforeConvertingToLargerSizes.expected.qcc} | 0 .../CastCharBeforeConvertingToLargerSizes.ql} | 4 +-- .../test.c | 0 .../CastCharBeforeConvertingToLargerSizes.qll | 27 +++++++++++++++++++ ...arBeforeConvertingToLargerSizes_shared.qll | 26 ------------------ ...harBeforeConvertingToLargerSizes.expected} | 0 .../CastCharBeforeConvertingToLargerSizes.ql} | 4 +-- .../test.cpp | 0 rule_packages/c/Strings3.json | 2 +- 14 files changed, 35 insertions(+), 34 deletions(-) rename c/common/test/rules/{castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected => castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected} (100%) rename c/common/test/rules/{castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.clang => castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.clang} (100%) rename c/common/test/rules/{castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.gcc => castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.gcc} (100%) rename c/common/test/rules/{castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.qcc => castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.qcc} (100%) rename c/common/test/rules/{castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql => castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql} (63%) rename c/common/test/rules/{castcharbeforeconvertingtolargersizes_shared => castcharbeforeconvertingtolargersizes}/test.c (100%) create mode 100644 cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.qll delete mode 100644 cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.qll rename cpp/common/test/rules/{castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected => castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected} (100%) rename cpp/common/test/rules/{castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql => castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql} (63%) rename cpp/common/test/rules/{castcharbeforeconvertingtolargersizes_shared => castcharbeforeconvertingtolargersizes}/test.cpp (100%) diff --git a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql index 1f2af0b588..394df49d99 100644 --- a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql +++ b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql @@ -14,9 +14,9 @@ import cpp import codingstandards.c.cert -import codingstandards.cpp.rules.castcharbeforeconvertingtolargersizes_shared.CastCharBeforeConvertingToLargerSizes_shared +import codingstandards.cpp.rules.castcharbeforeconvertingtolargersizes.CastCharBeforeConvertingToLargerSizes -class CastCharBeforeConvertingToLargerSizesQuery extends CastCharBeforeConvertingToLargerSizes_sharedSharedQuery +class CastCharBeforeConvertingToLargerSizesQuery extends CastCharBeforeConvertingToLargerSizesSharedQuery { CastCharBeforeConvertingToLargerSizesQuery() { this = Strings3Package::castCharBeforeConvertingToLargerSizesQuery() diff --git a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.testref b/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.testref index fefb98580c..0e13e05dc3 100644 --- a/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.testref +++ b/c/cert/test/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.testref @@ -1 +1 @@ -c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql \ No newline at end of file +c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql \ No newline at end of file diff --git a/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected similarity index 100% rename from c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected rename to c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected diff --git a/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.clang b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.clang similarity index 100% rename from c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.clang rename to c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.clang diff --git a/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.gcc b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.gcc similarity index 100% rename from c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.gcc rename to c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.gcc diff --git a/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.qcc b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.qcc similarity index 100% rename from c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected.qcc rename to c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected.qcc diff --git a/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql similarity index 63% rename from c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql rename to c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql index 2aceff89c0..2a1e49774f 100644 --- a/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql +++ b/c/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql @@ -1,4 +1,4 @@ // GENERATED FILE - DO NOT MODIFY -import codingstandards.cpp.rules.castcharbeforeconvertingtolargersizes_shared.CastCharBeforeConvertingToLargerSizes_shared +import codingstandards.cpp.rules.castcharbeforeconvertingtolargersizes.CastCharBeforeConvertingToLargerSizes -class TestFileQuery extends CastCharBeforeConvertingToLargerSizes_sharedSharedQuery, TestQuery { } +class TestFileQuery extends CastCharBeforeConvertingToLargerSizesSharedQuery, TestQuery { } diff --git a/c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/test.c b/c/common/test/rules/castcharbeforeconvertingtolargersizes/test.c similarity index 100% rename from c/common/test/rules/castcharbeforeconvertingtolargersizes_shared/test.c rename to c/common/test/rules/castcharbeforeconvertingtolargersizes/test.c diff --git a/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.qll b/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.qll new file mode 100644 index 0000000000..5d396f9a42 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.qll @@ -0,0 +1,27 @@ +/** + * Provides a library which includes a `problems` predicate for reporting.... + */ + + import cpp + import codingstandards.cpp.Customizations + import codingstandards.cpp.Exclusions + + abstract class CastCharBeforeConvertingToLargerSizesSharedQuery extends Query { } + + Query getQuery() { result instanceof CastCharBeforeConvertingToLargerSizesSharedQuery } + + query predicate problems(Cast c, string message) { + not isExcluded(c, getQuery()) and + // find cases where there is a conversion happening wherein the + // base type is a char + c.getExpr().getType() instanceof CharType and + not c.getExpr().getType() instanceof UnsignedCharType and + // it's a bigger type + c.getType().getSize() > c.getExpr().getType().getSize() and + // and it's some kind of integer type + c.getType().getUnderlyingType() instanceof IntegralType and + not c.isFromTemplateInstantiation(_) and + message = + "Expression not converted to `unsigned char` before converting to a larger integer type." + } + \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.qll b/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.qll deleted file mode 100644 index 3ef9033910..0000000000 --- a/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.qll +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Provides a library which includes a `problems` predicate for reporting.... - */ - -import cpp -import codingstandards.cpp.Customizations -import codingstandards.cpp.Exclusions - -abstract class CastCharBeforeConvertingToLargerSizes_sharedSharedQuery extends Query { } - -Query getQuery() { result instanceof CastCharBeforeConvertingToLargerSizes_sharedSharedQuery } - -query predicate problems(Cast c, string message) { - not isExcluded(c, getQuery()) and - // find cases where there is a conversion happening wherein the - // base type is a char - c.getExpr().getType() instanceof CharType and - not c.getExpr().getType() instanceof UnsignedCharType and - // it's a bigger type - c.getType().getSize() > c.getExpr().getType().getSize() and - // and it's some kind of integer type - c.getType().getUnderlyingType() instanceof IntegralType and - not c.isFromTemplateInstantiation(_) and - message = - "Expression not converted to `unsigned char` before converting to a larger integer type." -} diff --git a/cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected similarity index 100% rename from cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.expected rename to cpp/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.expected diff --git a/cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql similarity index 63% rename from cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql rename to cpp/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql index 2aceff89c0..2a1e49774f 100644 --- a/cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/CastCharBeforeConvertingToLargerSizes_shared.ql +++ b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.ql @@ -1,4 +1,4 @@ // GENERATED FILE - DO NOT MODIFY -import codingstandards.cpp.rules.castcharbeforeconvertingtolargersizes_shared.CastCharBeforeConvertingToLargerSizes_shared +import codingstandards.cpp.rules.castcharbeforeconvertingtolargersizes.CastCharBeforeConvertingToLargerSizes -class TestFileQuery extends CastCharBeforeConvertingToLargerSizes_sharedSharedQuery, TestQuery { } +class TestFileQuery extends CastCharBeforeConvertingToLargerSizesSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/test.cpp b/cpp/common/test/rules/castcharbeforeconvertingtolargersizes/test.cpp similarity index 100% rename from cpp/common/test/rules/castcharbeforeconvertingtolargersizes_shared/test.cpp rename to cpp/common/test/rules/castcharbeforeconvertingtolargersizes/test.cpp diff --git a/rule_packages/c/Strings3.json b/rule_packages/c/Strings3.json index b0131fb55b..1cecf390ec 100644 --- a/rule_packages/c/Strings3.json +++ b/rule_packages/c/Strings3.json @@ -12,7 +12,7 @@ "precision": "very-high", "severity": "error", "short_name": "CastCharBeforeConvertingToLargerSizes", - "shared_implementation_short_name": "CastCharBeforeConvertingToLargerSizes_shared", + "shared_implementation_short_name": "CastCharBeforeConvertingToLargerSizes", "tags": [ "correctness", "security" From 946d5dfcc98f602be23a7cdfc3a0c10dcb258c30 Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Thu, 25 Jul 2024 20:26:02 +0200 Subject: [PATCH 034/628] Fix formatting --- .../CastCharBeforeConvertingToLargerSizes.qll | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.qll b/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.qll index 5d396f9a42..66f1006d17 100644 --- a/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.qll +++ b/cpp/common/src/codingstandards/cpp/rules/castcharbeforeconvertingtolargersizes/CastCharBeforeConvertingToLargerSizes.qll @@ -2,26 +2,25 @@ * Provides a library which includes a `problems` predicate for reporting.... */ - import cpp - import codingstandards.cpp.Customizations - import codingstandards.cpp.Exclusions - - abstract class CastCharBeforeConvertingToLargerSizesSharedQuery extends Query { } - - Query getQuery() { result instanceof CastCharBeforeConvertingToLargerSizesSharedQuery } - - query predicate problems(Cast c, string message) { - not isExcluded(c, getQuery()) and - // find cases where there is a conversion happening wherein the - // base type is a char - c.getExpr().getType() instanceof CharType and - not c.getExpr().getType() instanceof UnsignedCharType and - // it's a bigger type - c.getType().getSize() > c.getExpr().getType().getSize() and - // and it's some kind of integer type - c.getType().getUnderlyingType() instanceof IntegralType and - not c.isFromTemplateInstantiation(_) and - message = - "Expression not converted to `unsigned char` before converting to a larger integer type." - } - \ No newline at end of file +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class CastCharBeforeConvertingToLargerSizesSharedQuery extends Query { } + +Query getQuery() { result instanceof CastCharBeforeConvertingToLargerSizesSharedQuery } + +query predicate problems(Cast c, string message) { + not isExcluded(c, getQuery()) and + // find cases where there is a conversion happening wherein the + // base type is a char + c.getExpr().getType() instanceof CharType and + not c.getExpr().getType() instanceof UnsignedCharType and + // it's a bigger type + c.getType().getSize() > c.getExpr().getType().getSize() and + // and it's some kind of integer type + c.getType().getUnderlyingType() instanceof IntegralType and + not c.isFromTemplateInstantiation(_) and + message = + "Expression not converted to `unsigned char` before converting to a larger integer type." +} From 94d711461dd6c7df5578614a854c8a423dee866b Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 3 Sep 2024 15:54:23 +0200 Subject: [PATCH 035/628] Update expected test results after merge from main --- ...sedPointerToRestrictQualifiedParamShared.expected | 12 ------------ .../A18-5-8/UnnecessaryUseOfDynamicStorage.expected | 7 ++++--- .../test/rules/M0-1-2/InfeasiblePath.expected | 3 --- .../ConstLikeReturnValue.expected | 10 +++++----- 4 files changed, 9 insertions(+), 23 deletions(-) diff --git a/c/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.expected b/c/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.expected index 1c8a649094..4d4c20a39c 100644 --- a/c/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.expected +++ b/c/common/test/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.expected @@ -1,15 +1,3 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:103,36-44) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:118,51-59) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:119,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:121,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:127,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:132,40-48) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:146,41-49) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:147,7-15) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:150,43-51) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:151,9-17) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:158,43-51) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassAliasedPointerToRestrictQualifiedParam.ql:159,9-17) | test.c:59:3:59:6 | call to copy | Call to 'copy' passes an $@ to a $@ (pointer value derived from a pair of address-of expressions ($@, $@). | test.c:59:13:59:15 | & ... | aliased pointer | test.c:59:8:59:10 | & ... | restrict-qualified parameter | test.c:59:8:59:10 | & ... | addressof1 | test.c:59:13:59:15 | & ... | addressof2 | | test.c:65:3:65:6 | call to copy | Call to 'copy' passes an $@ to a $@ (pointer value derived from a pair of address-of expressions ($@, $@). | test.c:65:15:65:19 | & ... | aliased pointer | test.c:65:8:65:12 | & ... | restrict-qualified parameter | test.c:65:8:65:12 | & ... | addressof1 | test.c:65:15:65:19 | & ... | addressof2 | | test.c:67:3:67:6 | call to copy | Call to 'copy' passes an $@ to a $@ (pointer value derived from a pair of address-of expressions ($@, $@). | test.c:67:15:67:16 | px | aliased pointer | test.c:67:8:67:12 | & ... | restrict-qualified parameter | test.c:67:8:67:12 | & ... | addressof1 | test.c:63:13:63:17 | & ... | addressof2 | diff --git a/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected b/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected index 6ab75d989e..68cab835fa 100644 --- a/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected +++ b/cpp/autosar/test/rules/A18-5-8/UnnecessaryUseOfDynamicStorage.expected @@ -1,7 +1,8 @@ WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:55,34-42) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:57,26-34) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:71,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:76,41-54) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:58,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:60,26-34) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:74,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnnecessaryUseOfDynamicStorage.ql:79,41-54) | test.cpp:17:17:17:29 | new | StructA object of size 8 bytes does not appear to outlive the function, but is created on the heap instead of the stack. | | test.cpp:21:17:21:32 | new[] | StructA[] object of size 800 bytes does not appear to outlive the function, but is created on the heap instead of the stack. | | test.cpp:35:20:35:44 | call to make_shared | StructA object of size 8 bytes does not appear to outlive the function, but is created on the heap instead of the stack. | diff --git a/cpp/autosar/test/rules/M0-1-2/InfeasiblePath.expected b/cpp/autosar/test/rules/M0-1-2/InfeasiblePath.expected index 9cb237e8b3..d0a819a794 100644 --- a/cpp/autosar/test/rules/M0-1-2/InfeasiblePath.expected +++ b/cpp/autosar/test/rules/M0-1-2/InfeasiblePath.expected @@ -2,9 +2,6 @@ | test.cpp:7:7:7:22 | ... <= ... | The false path is infeasible because a (max value: 4294967295) is always less than or equal to 4294967295 (minimum value: 4294967295). | | test.cpp:15:7:15:13 | ... < ... | The false path is infeasible because l1 (max value: 2) is always less than l2 (minimum value: 10). | | test.cpp:19:9:19:14 | ... < ... | The false path is infeasible because a (max value: 1) is always less than l2 (minimum value: 10). | -| test.cpp:33:7:33:7 | 0 | The path is unreachable in a template. | | test.cpp:77:9:77:14 | ... < ... | The true path is infeasible because 0 (max value: 0) is always less than or equal to a (minimum value: 0). | | test.cpp:80:9:80:15 | ... >= ... | The false path is infeasible because 0 (max value: 0) is always less than or equal to a (minimum value: 0). | | test.cpp:86:9:86:14 | ... < ... | The true path is infeasible because 0 (max value: 0) is always less than or equal to a (minimum value: 0). | -| test.cpp:117:7:117:7 | 0 | The path is unreachable in a template. | -| test.cpp:123:7:123:8 | ! ... | The path is unreachable in a template. | diff --git a/cpp/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.expected b/cpp/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.expected index b02aa464bb..2caa0d197c 100644 --- a/cpp/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.expected +++ b/cpp/common/test/rules/constlikereturnvalue/ConstLikeReturnValue.expected @@ -3,11 +3,11 @@ problems | test.cpp:67:5:67:9 | conv4 | test.cpp:64:11:64:20 | call to localeconv | test.cpp:67:5:67:9 | conv4 | The object returned by the function localeconv should not be modified. | | test.cpp:76:5:76:8 | conv | test.cpp:72:25:72:34 | call to localeconv | test.cpp:76:5:76:8 | conv | The object returned by the function localeconv should not be modified. | edges -| test.cpp:8:18:8:22 | c_str | test.cpp:11:8:11:12 | c_str | -| test.cpp:18:16:18:21 | call to getenv | test.cpp:24:9:24:12 | env1 | -| test.cpp:24:9:24:12 | env1 | test.cpp:8:18:8:22 | c_str | -| test.cpp:64:11:64:20 | call to localeconv | test.cpp:67:5:67:9 | conv4 | -| test.cpp:72:25:72:34 | call to localeconv | test.cpp:76:5:76:8 | conv | +| test.cpp:8:18:8:22 | c_str | test.cpp:11:8:11:12 | c_str | provenance | | +| test.cpp:18:16:18:21 | call to getenv | test.cpp:24:9:24:12 | env1 | provenance | | +| test.cpp:24:9:24:12 | env1 | test.cpp:8:18:8:22 | c_str | provenance | | +| test.cpp:64:11:64:20 | call to localeconv | test.cpp:67:5:67:9 | conv4 | provenance | | +| test.cpp:72:25:72:34 | call to localeconv | test.cpp:76:5:76:8 | conv | provenance | | nodes | test.cpp:8:18:8:22 | c_str | semmle.label | c_str | | test.cpp:11:8:11:12 | c_str | semmle.label | c_str | From 8461696679fad63de78bcb71301b4980724f4a9f Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Fri, 13 Sep 2024 16:43:41 +0200 Subject: [PATCH 036/628] Remove data flow imports from queries that do not actually use it --- .../rules/CON30-C/CleanUpThreadSpecificStorage.ql | 1 - .../AppropriateThreadObjectStorageDurations.ql | 1 - .../ThreadObjectStorageDurationsNotInitialized.ql | 1 - c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.ql | 1 + .../rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql | 1 - c/cert/src/rules/ERR30-C/SetlocaleMightSetErrno.ql | 1 + ...ndenceOnOrderOfFunctionArgumentsForSideEffects.ql | 1 - .../SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql | 2 +- .../CON30-C/CleanUpThreadSpecificStorage.expected | 12 ++++++------ .../AppropriateThreadObjectStorageDurations.expected | 12 ++++++------ ...readObjectStorageDurationsNotInitialized.expected | 6 +++--- .../rules/ERR30-C/ErrnoReadBeforeReturn.expected | 2 +- .../rules/ERR30-C/SetlocaleMightSetErrno.expected | 2 +- c/common/src/codingstandards/c/Errno.qll | 1 - .../RULE-17-7/ValueReturnedByAFunctionNotUsed.ql | 1 - .../RULE-19-1/ObjectCopiedToAnOverlappingObject.ql | 1 - .../src/rules/A18-5-2/DoNotUseNonPlacementNew.ql | 1 - .../A8-4-4/FunctionReturnMultipleValueCondition.ql | 1 - .../PointerToAVirtualBaseClassCastToAPointer.ql | 1 - .../lifetimes/lifetimeprofile/LifetimeProfile.qll | 1 - .../AccessOfUndefinedMemberThroughNullPointer.qll | 1 - .../UnusedReturnValue.ql | 1 - .../deviations_basic_test/UnusedReturnValue.ql | 1 - .../deviations_report_deviated/UnusedReturnValue.ql | 1 - 24 files changed, 20 insertions(+), 34 deletions(-) diff --git a/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql b/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql index d55f1326bf..69b1b333be 100644 --- a/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql +++ b/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql @@ -15,7 +15,6 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Concurrency -import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.dataflow.DataFlow module TssCreateToTssDeleteConfig implements DataFlow::ConfigSig { diff --git a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql index 71138f4ff8..78b5a090b2 100644 --- a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql +++ b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql @@ -15,7 +15,6 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Concurrency -import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.commons.Alloc diff --git a/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql b/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql index ddcddb8dc5..fc75cb94ff 100644 --- a/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql +++ b/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql @@ -16,7 +16,6 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Concurrency -import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.dataflow.DataFlow from TSSGetFunctionCall tsg, ThreadedFunction tf diff --git a/c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.ql b/c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.ql index df8519f13f..527529cc30 100644 --- a/c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.ql +++ b/c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.ql @@ -14,6 +14,7 @@ import cpp import codingstandards.c.cert import codingstandards.c.Errno +import semmle.code.cpp.dataflow.DataFlow /** * A call to an `OutOfBandErrnoSettingFunction` diff --git a/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql b/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql index dd2e2175f7..17714c646f 100644 --- a/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql +++ b/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql @@ -14,7 +14,6 @@ import cpp import codingstandards.c.cert import codingstandards.c.Errno -import semmle.code.cpp.dataflow.DataFlow /** * A call to an `OutOfBandErrnoSettingFunction` diff --git a/c/cert/src/rules/ERR30-C/SetlocaleMightSetErrno.ql b/c/cert/src/rules/ERR30-C/SetlocaleMightSetErrno.ql index 899fa49e60..9c94284841 100644 --- a/c/cert/src/rules/ERR30-C/SetlocaleMightSetErrno.ql +++ b/c/cert/src/rules/ERR30-C/SetlocaleMightSetErrno.ql @@ -13,6 +13,7 @@ import cpp import codingstandards.c.cert import codingstandards.c.Errno +import semmle.code.cpp.dataflow.DataFlow class SetlocaleFunctionCall extends FunctionCall { SetlocaleFunctionCall() { this.getTarget().hasGlobalName("setlocale") } diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql index fb14515c61..a761ec7f48 100644 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql @@ -14,7 +14,6 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.SideEffect -import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.valuenumbering.GlobalValueNumbering diff --git a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql index 54f555d7cb..5945da57f4 100644 --- a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql +++ b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.FgetsErrorManagement import codingstandards.cpp.Dereferenced -import semmle.code.cpp.dataflow.TaintTracking +import semmle.code.cpp.dataflow.DataFlow /* * CFG nodes that follows a successful call to `fgets` diff --git a/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected b/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected index 2706474f29..047ed12e8e 100644 --- a/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected +++ b/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected @@ -1,9 +1,9 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:21,46-54) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:22,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:31,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:41,35-43) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:49,36-44) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:51,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:20,46-54) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:21,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:30,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:40,35-43) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:48,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:50,36-44) | test.c:27:3:27:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | | test.c:49:3:49:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | | test.c:71:3:71:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | diff --git a/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected b/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected index 25cb74d7fa..7e4cf71c21 100644 --- a/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected +++ b/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected @@ -1,11 +1,11 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,29-37) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,54-62) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:35,62-70) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:27,29-37) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:27,54-62) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:34,62-70) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:39,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:39,30-38) WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:40,5-13) WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:40,30-38) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:41,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:41,30-38) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,3-16) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:27,3-16) | test.c:23:3:23:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:23:24:23:29 | & ... | Shared object | | test.c:74:3:74:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:74:24:74:24 | p | Shared object | | test.c:85:3:85:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:85:24:85:24 | p | Shared object | diff --git a/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected b/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected index d6b6548581..f8e86fbb51 100644 --- a/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected +++ b/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected @@ -1,6 +1,6 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:28,38-46) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:27,38-46) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:30,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:30,30-38) WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:31,5-13) WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:31,30-38) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:32,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:32,30-38) | test.c:14:7:14:13 | call to tss_get | Call to a thread specific storage function from within a threaded context on an object that may not be owned by this thread. | diff --git a/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected b/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected index 659a731d7c..e925901b47 100644 --- a/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected +++ b/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected @@ -1,4 +1,4 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ErrnoReadBeforeReturn.ql:40,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ErrnoReadBeforeReturn.ql:41,7-15) | test.c:69:7:69:11 | * ... | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | | test.c:69:7:69:11 | call to __errno_location | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | | test.c:70:5:70:10 | call to perror | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | diff --git a/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected b/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected index d20f4a4e34..489bfc6bb0 100644 --- a/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected +++ b/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected @@ -1,3 +1,3 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (SetlocaleMightSetErrno.ql:64,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (SetlocaleMightSetErrno.ql:65,7-15) | test.c:98:3:98:11 | call to setlocale | Do not read `errno` before checking the return value of a call to `setlocale`. | | test.c:104:7:104:15 | call to setlocale | The value of `errno` may be different than `0` when `setlocale` is called. The following `errno` check might be invalid. | diff --git a/c/common/src/codingstandards/c/Errno.qll b/c/common/src/codingstandards/c/Errno.qll index d606593a1e..768927f505 100644 --- a/c/common/src/codingstandards/c/Errno.qll +++ b/c/common/src/codingstandards/c/Errno.qll @@ -1,7 +1,6 @@ /** Provides a library for errno-setting functions. */ import cpp -import semmle.code.cpp.dataflow.DataFlow /** * An errno-setting function diff --git a/c/misra/src/rules/RULE-17-7/ValueReturnedByAFunctionNotUsed.ql b/c/misra/src/rules/RULE-17-7/ValueReturnedByAFunctionNotUsed.ql index 3b224544f2..5907d00769 100644 --- a/c/misra/src/rules/RULE-17-7/ValueReturnedByAFunctionNotUsed.ql +++ b/c/misra/src/rules/RULE-17-7/ValueReturnedByAFunctionNotUsed.ql @@ -13,7 +13,6 @@ import cpp import codingstandards.c.misra -import semmle.code.cpp.dataflow.DataFlow from Call c where diff --git a/c/misra/src/rules/RULE-19-1/ObjectCopiedToAnOverlappingObject.ql b/c/misra/src/rules/RULE-19-1/ObjectCopiedToAnOverlappingObject.ql index fe1226dcea..0e276773dc 100644 --- a/c/misra/src/rules/RULE-19-1/ObjectCopiedToAnOverlappingObject.ql +++ b/c/misra/src/rules/RULE-19-1/ObjectCopiedToAnOverlappingObject.ql @@ -13,7 +13,6 @@ import cpp import codingstandards.c.misra import semmle.code.cpp.valuenumbering.GlobalValueNumbering -import semmle.code.cpp.dataflow.DataFlow /** * Offset in bytes of a field access diff --git a/cpp/autosar/src/rules/A18-5-2/DoNotUseNonPlacementNew.ql b/cpp/autosar/src/rules/A18-5-2/DoNotUseNonPlacementNew.ql index 1320d6e486..3cfccbf11e 100644 --- a/cpp/autosar/src/rules/A18-5-2/DoNotUseNonPlacementNew.ql +++ b/cpp/autosar/src/rules/A18-5-2/DoNotUseNonPlacementNew.ql @@ -15,7 +15,6 @@ import cpp import codingstandards.cpp.autosar -import semmle.code.cpp.dataflow.DataFlow from NewOrNewArrayExpr na where diff --git a/cpp/autosar/src/rules/A8-4-4/FunctionReturnMultipleValueCondition.ql b/cpp/autosar/src/rules/A8-4-4/FunctionReturnMultipleValueCondition.ql index ff0040f26f..03f0c3cea6 100644 --- a/cpp/autosar/src/rules/A8-4-4/FunctionReturnMultipleValueCondition.ql +++ b/cpp/autosar/src/rules/A8-4-4/FunctionReturnMultipleValueCondition.ql @@ -16,7 +16,6 @@ import cpp import codingstandards.cpp.autosar -import semmle.code.cpp.dataflow.DataFlow abstract class OutputValue extends Element { abstract string getOutputName(); diff --git a/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql b/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql index d24c4d35df..086aa40ae7 100644 --- a/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql +++ b/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql @@ -15,7 +15,6 @@ import cpp import codingstandards.cpp.autosar -import semmle.code.cpp.dataflow.DataFlow from Cast cast, VirtualBaseClass castFrom, Class castTo where diff --git a/cpp/common/src/codingstandards/cpp/lifetimes/lifetimeprofile/LifetimeProfile.qll b/cpp/common/src/codingstandards/cpp/lifetimes/lifetimeprofile/LifetimeProfile.qll index 354dccdc56..b02f51380e 100644 --- a/cpp/common/src/codingstandards/cpp/lifetimes/lifetimeprofile/LifetimeProfile.qll +++ b/cpp/common/src/codingstandards/cpp/lifetimes/lifetimeprofile/LifetimeProfile.qll @@ -1,5 +1,4 @@ import cpp -private import semmle.code.cpp.dataflow.DataFlow private import semmle.code.cpp.controlflow.Nullness private import codingstandards.cpp.Dereferenced private import codingstandards.cpp.Expr diff --git a/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll b/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll index e0fb382008..b213087c5c 100644 --- a/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll +++ b/cpp/common/src/codingstandards/cpp/rules/accessofundefinedmemberthroughnullpointer/AccessOfUndefinedMemberThroughNullPointer.qll @@ -7,7 +7,6 @@ import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Nullness import codingstandards.cpp.Expr -import semmle.code.cpp.dataflow.DataFlow import NullPointerToPointerMemberExpressionFlow::PathGraph abstract class AccessOfUndefinedMemberThroughNullPointerSharedQuery extends Query { } diff --git a/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql b/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql index 38b75bda3c..469a7f7f73 100644 --- a/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql +++ b/cpp/common/test/deviations/deviation_permits_basic_test/UnusedReturnValue.ql @@ -16,7 +16,6 @@ import cpp import codingstandards.cpp.CodingStandards -import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.exclusions.cpp.RuleMetadata /* This is a copy of an AUTOSAR rule, which we are using for testing purposes. */ diff --git a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql index 38b75bda3c..469a7f7f73 100644 --- a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql +++ b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.ql @@ -16,7 +16,6 @@ import cpp import codingstandards.cpp.CodingStandards -import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.exclusions.cpp.RuleMetadata /* This is a copy of an AUTOSAR rule, which we are using for testing purposes. */ diff --git a/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql b/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql index 38b75bda3c..469a7f7f73 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql +++ b/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.ql @@ -16,7 +16,6 @@ import cpp import codingstandards.cpp.CodingStandards -import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.exclusions.cpp.RuleMetadata /* This is a copy of an AUTOSAR rule, which we are using for testing purposes. */ From 71570a0ee3720e50d53370790b7174752e9869c1 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Mon, 16 Sep 2024 14:48:15 +0200 Subject: [PATCH 037/628] Fix expected test results after import changes --- ...OfFunctionArgumentsForSideEffects.expected | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected index 6567ef6fd1..ec791fe3e4 100644 --- a/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected +++ b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected @@ -1,25 +1,25 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:24,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:24,59-67) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:27,33-41) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:27,57-65) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,33-41) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,59-67) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:40,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:40,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:40,53-61) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:43,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:43,57-65) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:52,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:52,55-63) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:59,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:59,57-65) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:71,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:71,55-63) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:24,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:27,7-20) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,7-20) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:43,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:52,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:59,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:71,5-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:23,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:23,59-67) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:26,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:26,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:30,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:30,59-67) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:39,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:39,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:39,53-61) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:42,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:42,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:51,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:51,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:58,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:58,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:70,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:70,55-63) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:23,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:26,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:30,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:42,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:51,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:58,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:70,5-18) | test.c:20:3:20:4 | call to f1 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.c:20:6:20:7 | call to f2 | call to f2 | test.c:20:12:20:13 | call to f3 | call to f3 | From 3387893fc378ac8b7c670745538ac15eade0372d Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 24 Sep 2024 09:03:08 +0200 Subject: [PATCH 038/628] Adapt to `sourceLocationPrefix` change in `qltest` --- .../cpp/deviations/Deviations.qll | 8 ++++-- .../ListDeviationRecords.expected | 4 +-- .../InvalidDeviationPermits.expected | 4 +-- .../InvalidDeviationRecords.expected | 28 +++++++++---------- ...InvalidGuidelineRecategorizations.expected | 10 +++---- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll b/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll index 4dfadd12eb..403a5b61c6 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll @@ -365,17 +365,19 @@ class DeviationRecord extends XmlElement { /** Gets a path to which this deviation applies. */ string getADeviationPath() { - ( + exists(string res | if exists(getPathAContainer()) then // Use the path, which will be relative to this file, if specified - result = getPathAContainer().getRelativePath() + res = getPathAContainer().getRelativePath() else ( // Otherwise, if no code identifier was supplied, it applies to the parent container of the // file itself not exists(getCodeIdentifier()) and - result = this.getFile().getParentContainer().getRelativePath() + res = this.getFile().getParentContainer().getRelativePath() ) + | + if res = "" then result = "(root)" else result = res ) } diff --git a/cpp/common/test/deviations/deviations_basic_test/ListDeviationRecords.expected b/cpp/common/test/deviations/deviations_basic_test/ListDeviationRecords.expected index 3a095d8fb9..5115cc8a70 100644 --- a/cpp/common/test/deviations/deviations_basic_test/ListDeviationRecords.expected +++ b/cpp/common/test/deviations/deviations_basic_test/ListDeviationRecords.expected @@ -1,3 +1,3 @@ -| A0-1-1 | cpp/autosar/useless-assignment | Applies to the following file paths: deviations/deviations_basic_test | | This useless assignment is required. | | | -| A0-1-2 | cpp/autosar/unused-return-value | Applies to the following file paths: deviations/deviations_basic_test/nested/nested1,deviations/deviations_basic_test/nested/nested2 | | Unused return value. | | | +| A0-1-1 | cpp/autosar/useless-assignment | Applies to the following file paths: (root) | | This useless assignment is required. | | | +| A0-1-2 | cpp/autosar/unused-return-value | Applies to the following file paths: nested/nested1,nested/nested2 | | Unused return value. | | | | A0-4-2 | cpp/autosar/type-long-double-used | Identified by the use of the code-identifier: a-0-4-2-deviation | | long double is required for interaction with third-party libraries. | | | diff --git a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationPermits.expected b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationPermits.expected index 433dc8a342..609d517c05 100644 --- a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationPermits.expected +++ b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationPermits.expected @@ -1,2 +1,2 @@ -| coding-standards.xml:100:7:103:33 | deviation-permits-entry | deviations/invalid_deviations/coding-standards.xml: Deviation permit does not specify a permit identifier. | -| coding-standards.xml:104:7:107:33 | deviation-permits-entry | deviations/invalid_deviations/coding-standards.xml: Deviation permit specifies unknown property `invalid-property`. | +| coding-standards.xml:100:7:103:33 | deviation-permits-entry | coding-standards.xml: Deviation permit does not specify a permit identifier. | +| coding-standards.xml:104:7:107:33 | deviation-permits-entry | coding-standards.xml: Deviation permit specifies unknown property `invalid-property`. | diff --git a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationRecords.expected b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationRecords.expected index c4f66eeaf5..2cd438c5c6 100644 --- a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationRecords.expected +++ b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationRecords.expected @@ -1,14 +1,14 @@ -| coding-standards.xml:5:7:5:27 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: No rule-id and query-id specified for this deviation record. | -| coding-standards.xml:6:7:8:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: The rule-id `bad rule id` for this deviation matches none of the available queries. | -| coding-standards.xml:9:7:11:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A query-id of `bad rule id` is specified for this deviation, but not rule-id is specified. | -| coding-standards.xml:15:7:17:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A query-id of `cpp/autosar/useless-assignment` is specified for this deviation, but not rule-id is specified. | -| coding-standards.xml:22:7:26:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A deviation `raised-by` is specified without providing an `approved-by`. | -| coding-standards.xml:22:7:26:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A deviation `raised-by` is specified without providing both a `name` and `date`. | -| coding-standards.xml:27:7:33:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A deviation `raised-by` is specified without providing an `approved-by`. | -| coding-standards.xml:27:7:33:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A deviation `raised-by` is specified without providing both a `name` and `date`. | -| coding-standards.xml:34:7:41:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A deviation `raised-by` is specified without providing an `approved-by`. | -| coding-standards.xml:42:7:50:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A deviation `approved-by` is specified without providing both a `name` and `date`. | -| coding-standards.xml:51:7:61:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: A deviation `approved-by` is specified without providing both a `name` and `date`. | -| coding-standards.xml:74:7:78:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: There is no deviation permit with id `non-existing-permit`. | -| coding-standards.xml:79:7:81:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: No rule-id and query-id specified for this deviation record. | -| coding-standards.xml:85:7:88:26 | deviations-entry | deviations/invalid_deviations/coding-standards.xml: The deviation is applied to a query with the rule category 'mandatory' that does not permit a deviation. | +| coding-standards.xml:5:7:5:27 | deviations-entry | coding-standards.xml: No rule-id and query-id specified for this deviation record. | +| coding-standards.xml:6:7:8:26 | deviations-entry | coding-standards.xml: The rule-id `bad rule id` for this deviation matches none of the available queries. | +| coding-standards.xml:9:7:11:26 | deviations-entry | coding-standards.xml: A query-id of `bad rule id` is specified for this deviation, but not rule-id is specified. | +| coding-standards.xml:15:7:17:26 | deviations-entry | coding-standards.xml: A query-id of `cpp/autosar/useless-assignment` is specified for this deviation, but not rule-id is specified. | +| coding-standards.xml:22:7:26:26 | deviations-entry | coding-standards.xml: A deviation `raised-by` is specified without providing an `approved-by`. | +| coding-standards.xml:22:7:26:26 | deviations-entry | coding-standards.xml: A deviation `raised-by` is specified without providing both a `name` and `date`. | +| coding-standards.xml:27:7:33:26 | deviations-entry | coding-standards.xml: A deviation `raised-by` is specified without providing an `approved-by`. | +| coding-standards.xml:27:7:33:26 | deviations-entry | coding-standards.xml: A deviation `raised-by` is specified without providing both a `name` and `date`. | +| coding-standards.xml:34:7:41:26 | deviations-entry | coding-standards.xml: A deviation `raised-by` is specified without providing an `approved-by`. | +| coding-standards.xml:42:7:50:26 | deviations-entry | coding-standards.xml: A deviation `approved-by` is specified without providing both a `name` and `date`. | +| coding-standards.xml:51:7:61:26 | deviations-entry | coding-standards.xml: A deviation `approved-by` is specified without providing both a `name` and `date`. | +| coding-standards.xml:74:7:78:26 | deviations-entry | coding-standards.xml: There is no deviation permit with id `non-existing-permit`. | +| coding-standards.xml:79:7:81:26 | deviations-entry | coding-standards.xml: No rule-id and query-id specified for this deviation record. | +| coding-standards.xml:85:7:88:26 | deviations-entry | coding-standards.xml: The deviation is applied to a query with the rule category 'mandatory' that does not permit a deviation. | diff --git a/cpp/common/test/guideline_recategorizations/InvalidGuidelineRecategorizations.expected b/cpp/common/test/guideline_recategorizations/InvalidGuidelineRecategorizations.expected index 971c70a9b6..32a9837e46 100644 --- a/cpp/common/test/guideline_recategorizations/InvalidGuidelineRecategorizations.expected +++ b/cpp/common/test/guideline_recategorizations/InvalidGuidelineRecategorizations.expected @@ -1,5 +1,5 @@ -| invalid/coding-standards.xml:5:7:8:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'required' to 'advisory'.' for rule A0-1-1. | -| invalid/coding-standards.xml:9:7:12:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'required' to 'disapplied'.' for rule A0-1-2. | -| invalid/coding-standards.xml:13:7:16:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Unknown rule id 'A1-4-3'.' for rule A1-4-3. | -| invalid/coding-standards.xml:17:7:20:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'mandatory' to 'required'.' for rule RULE-13-6. | -| invalid/coding-standards.xml:21:7:24:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'rule' to 'required'.' for rule CON50-CPP. | +| invalid/coding-standards.xml:5:7:8:43 | guideline-recategorizations-entry | invalid/coding-standards.xml: 'Invalid recategorization from 'required' to 'advisory'.' for rule A0-1-1. | +| invalid/coding-standards.xml:9:7:12:43 | guideline-recategorizations-entry | invalid/coding-standards.xml: 'Invalid recategorization from 'required' to 'disapplied'.' for rule A0-1-2. | +| invalid/coding-standards.xml:13:7:16:43 | guideline-recategorizations-entry | invalid/coding-standards.xml: 'Unknown rule id 'A1-4-3'.' for rule A1-4-3. | +| invalid/coding-standards.xml:17:7:20:43 | guideline-recategorizations-entry | invalid/coding-standards.xml: 'Invalid recategorization from 'mandatory' to 'required'.' for rule RULE-13-6. | +| invalid/coding-standards.xml:21:7:24:43 | guideline-recategorizations-entry | invalid/coding-standards.xml: 'Invalid recategorization from 'rule' to 'required'.' for rule CON50-CPP. | From 9b1667ed924ca28ad54139ad015ab702fb67aa2f Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 4 Oct 2024 14:38:07 +0200 Subject: [PATCH 039/628] Fix `isDeviated` predicate --- .../cpp/deviations/Deviations.qll | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll b/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll index 403a5b61c6..99b9a33fe6 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll @@ -363,20 +363,23 @@ class DeviationRecord extends XmlElement { result.getRelativePath() = getAChild("paths").getAChild("paths-entry").getTextValue() } + private string getADeviationPath0() { + if exists(getPathAContainer()) + then + // Use the path, which will be relative to this file, if specified + result = getPathAContainer().getRelativePath() + else ( + // Otherwise, if no code identifier was supplied, it applies to the parent container of the + // file itself + not exists(getCodeIdentifier()) and + result = this.getFile().getParentContainer().getRelativePath() + ) + } + /** Gets a path to which this deviation applies. */ string getADeviationPath() { exists(string res | - if exists(getPathAContainer()) - then - // Use the path, which will be relative to this file, if specified - res = getPathAContainer().getRelativePath() - else ( - // Otherwise, if no code identifier was supplied, it applies to the parent container of the - // file itself - not exists(getCodeIdentifier()) and - res = this.getFile().getParentContainer().getRelativePath() - ) - | + res = getADeviationPath0() and if res = "" then result = "(root)" else result = res ) } @@ -384,6 +387,6 @@ class DeviationRecord extends XmlElement { cached predicate isDeviated(Query query, string deviationPath) { query = getQuery() and - deviationPath = getADeviationPath() + deviationPath = getADeviationPath0() } } From 6de14caa4d36f6fd9d19a97987c8e1ef55004fc1 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 3 Oct 2024 15:38:08 -0700 Subject: [PATCH 040/628] Implement Language4 package, banning obsolete language features. Many of the cases outlined in the amendment are covered by other rules. Add support for new cases where possible (was not possible for ID 3, storage class specifiers not at beginning of declaration, or ID 2, which is a feature of the implementation not determinable by static analysis), and reference existing rules in one comprehensive test for maximal clarity that those parts of rule 1-5 are indeed supported by our existing queries. --- .../RULE-1-5/CallToReallocWithSizeZero.ql | 24 +++++++ .../InvalidDefineOrUndefOfStdBoolMacro.ql | 31 +++++++++ .../UseOfObsoleteMacroAtomicVarInit.ql | 24 +++++++ .../CallToReallocWithSizeZero.expected | 1 + .../RULE-1-5/CallToReallocWithSizeZero.qlref | 1 + .../FunctionTypesNotInPrototypeForm.expected | 2 + .../FunctionTypesNotInPrototypeForm.qlref | 1 + ...nvalidDefineOrUndefOfStdBoolMacro.expected | 6 ++ .../InvalidDefineOrUndefOfStdBoolMacro.qlref | 1 + ...llocDeallocFunctionsOfStdlibhUsed.expected | 3 + ...ryAllocDeallocFunctionsOfStdlibhUsed.qlref | 1 + ...aticSpecifierObjectRedeclarationC.expected | 1 + ...gStaticSpecifierObjectRedeclarationC.qlref | 1 + ...rdLibraryInputoutputFunctionsUsed.expected | 3 + ...ndardLibraryInputoutputFunctionsUsed.qlref | 1 + .../UseOfObsoleteMacroAtomicVarInit.expected | 1 + .../UseOfObsoleteMacroAtomicVarInit.qlref | 1 + c/misra/test/rules/RULE-1-5/options | 1 + c/misra/test/rules/RULE-1-5/test.c | 63 +++++++++++++++++++ .../cpp/exclusions/c/Language4.qll | 61 ++++++++++++++++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + rule_packages/c/Language4.json | 47 ++++++++++++++ 22 files changed, 278 insertions(+) create mode 100644 c/misra/src/rules/RULE-1-5/CallToReallocWithSizeZero.ql create mode 100644 c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql create mode 100644 c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql create mode 100644 c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.expected create mode 100644 c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.qlref create mode 100644 c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.expected create mode 100644 c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.qlref create mode 100644 c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected create mode 100644 c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.qlref create mode 100644 c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected create mode 100644 c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.qlref create mode 100644 c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.expected create mode 100644 c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.qlref create mode 100644 c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected create mode 100644 c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.qlref create mode 100644 c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected create mode 100644 c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.qlref create mode 100644 c/misra/test/rules/RULE-1-5/options create mode 100644 c/misra/test/rules/RULE-1-5/test.c create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll create mode 100644 rule_packages/c/Language4.json diff --git a/c/misra/src/rules/RULE-1-5/CallToReallocWithSizeZero.ql b/c/misra/src/rules/RULE-1-5/CallToReallocWithSizeZero.ql new file mode 100644 index 0000000000..224ca2a6bf --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/CallToReallocWithSizeZero.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/call-to-realloc-with-size-zero + * @name RULE-1-5: Disallowed size argument value equal to zero in call to realloc + * @description Invoking realloc with a size argument set to zero is implementation-defined behavior + * and declared as an obsolete feature in C18. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-1-5 + * correctness + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import semmle.code.cpp.rangeanalysis.new.RangeAnalysis + +from FunctionCall call, Expr arg +where + not isExcluded(call, Language4Package::callToReallocWithSizeZeroQuery()) and + call.getTarget().hasGlobalOrStdName("realloc") and + arg = call.getArgument(1) and + upperBound(arg) = 0 +select arg, "Calling realloc with size zero results in implementation-defined behavior." diff --git a/c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql b/c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql new file mode 100644 index 0000000000..3d33103988 --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql @@ -0,0 +1,31 @@ +/** + * @id c/misra/invalid-define-or-undef-of-std-bool-macro + * @name RULE-1-5: Programs may not undefine or redefine the macros bool, true, or false + * @description Directives that undefine and/or redefine the standard boolean macros has been + * declared an obsolescent language feature since C99. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-1-5 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +string getABoolMacroName() { result = ["true", "false", "bool"] } + +from PreprocessorDirective directive, string opString, string macroName +where + not isExcluded(directive, Language4Package::invalidDefineOrUndefOfStdBoolMacroQuery()) and + macroName = getABoolMacroName() and + ( + macroName = directive.(Macro).getName() and + opString = "define" + or + macroName = directive.(PreprocessorUndef).getName() and + opString = "undefine" + ) +select directive, "Invalid " + opString + " of boolean standard macro " + macroName diff --git a/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql b/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql new file mode 100644 index 0000000000..38dd7c0386 --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/use-of-obsolete-macro-atomic-var-init + * @name RULE-1-5: Disallowed usage of obsolete macro ATOMIC_VAR_INIT compiled as C18 + * @description The macro ATOMIC_VAR_INIT is has been declared an obsolescent language feature since + * C18. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-1-5 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from MacroInvocation invoke, Compilation c, string flag +where + not isExcluded(invoke, Language4Package::useOfObsoleteMacroAtomicVarInitQuery()) and + invoke.getMacroName() = "ATOMIC_VAR_INIT" and + flag = c.getAnArgument() and + flag.regexpMatch("-std=c1[78]") +select invoke, "Usage of macro ATOMIC_VAR_INIT() is considered obsolete for c version " + flag diff --git a/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.expected b/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.expected new file mode 100644 index 0000000000..0e58d0cd0d --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.expected @@ -0,0 +1 @@ +| test.c:13:14:13:14 | 0 | Calling realloc with size zero results in implementation-defined behavior. | diff --git a/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.qlref b/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.qlref new file mode 100644 index 0000000000..218be6b3ef --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.qlref @@ -0,0 +1 @@ +rules/RULE-1-5/CallToReallocWithSizeZero.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.expected b/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.expected new file mode 100644 index 0000000000..9f9157ca8e --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.expected @@ -0,0 +1,2 @@ +| test.c:40:6:40:7 | f2 | Function f2 does not specify void for no parameters present. | +| test.c:44:5:44:6 | f5 | Function f5 declares parameter in unsupported declaration list. | \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.qlref b/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.qlref new file mode 100644 index 0000000000..0a6121b324 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.qlref @@ -0,0 +1 @@ +rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected b/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected new file mode 100644 index 0000000000..a29c5efe56 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected @@ -0,0 +1,6 @@ +| test.c:23:1:23:14 | #define true 3 | Invalid define of boolean standard macro true | +| test.c:24:1:24:15 | #define false 3 | Invalid define of boolean standard macro false | +| test.c:25:1:25:18 | #define bool int * | Invalid define of boolean standard macro bool | +| test.c:26:1:26:11 | #undef true | Invalid undefine of boolean standard macro true | +| test.c:27:1:27:12 | #undef false | Invalid undefine of boolean standard macro false | +| test.c:28:1:28:11 | #undef bool | Invalid undefine of boolean standard macro bool | diff --git a/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.qlref b/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.qlref new file mode 100644 index 0000000000..5b112609cc --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.qlref @@ -0,0 +1 @@ +rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected b/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected new file mode 100644 index 0000000000..3f8fa3cf3f --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected @@ -0,0 +1,3 @@ +| test.c:10:12:10:17 | call to malloc | Use of banned dynamic memory allocation. | +| test.c:13:3:13:9 | call to realloc | Use of banned dynamic memory allocation. | +| test.c:16:3:16:9 | call to realloc | Use of banned dynamic memory allocation. | diff --git a/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.qlref b/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.qlref new file mode 100644 index 0000000000..8f64b81ced --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.qlref @@ -0,0 +1 @@ +rules/RULE-21-3/MemoryAllocDeallocFunctionsOfStdlibhUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.expected b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.expected new file mode 100644 index 0000000000..4c3d4614fa --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.expected @@ -0,0 +1 @@ +| test.c:37:12:37:13 | declaration of g5 | The redeclaration of $@ with internal linkage misses the static specifier. | test.c:36:12:36:13 | definition of g5 | g5 | diff --git a/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.qlref b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.qlref new file mode 100644 index 0000000000..70b6073e14 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.qlref @@ -0,0 +1 @@ +rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected b/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected new file mode 100644 index 0000000000..ca49894238 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected @@ -0,0 +1,3 @@ +| test.c:57:3:57:8 | call to ungetc | Call to banned function ungetc. | +| test.c:60:3:60:7 | call to fread | Call to banned function fread. | +| test.c:62:3:62:8 | call to ungetc | Call to banned function ungetc. | diff --git a/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.qlref b/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.qlref new file mode 100644 index 0000000000..0a8cd754ef --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.qlref @@ -0,0 +1 @@ +rules/RULE-21-6/StandardLibraryInputoutputFunctionsUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected new file mode 100644 index 0000000000..6fe4cee5f4 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected @@ -0,0 +1 @@ +| test.c:30:18:30:36 | ATOMIC_VAR_INIT(value) | Usage of macro ATOMIC_VAR_INIT() is considered obsolete for c version -std=c17 | diff --git a/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.qlref b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.qlref new file mode 100644 index 0000000000..9a54fdc83a --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.qlref @@ -0,0 +1 @@ +rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/options b/c/misra/test/rules/RULE-1-5/options new file mode 100644 index 0000000000..2ba2218a05 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/options @@ -0,0 +1 @@ +semmle-extractor-options:-std=c17 -I../../../../common/test/includes/standard-library \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/test.c b/c/misra/test/rules/RULE-1-5/test.c new file mode 100644 index 0000000000..43faa71f3c --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/test.c @@ -0,0 +1,63 @@ +// Compiled with -std=c17 + +#include "stdatomic.h" +#include "stdbool.h" +#include "stdio.h" +#include "stdlib.h" + +void f1(void) { + // malloc() is not obsolete, but banned by Rule 21.3 + int *t = malloc(10); // COMPLIANT[False Negative] + + // Obsolete usage of realloc. + realloc(t, 0); // NON-COMPLIANT + + // Valid usage of realloc, but all use of realloc is banned by Rule 21.3 + realloc(t, 20); // NON-COMPLIANT +} + +extern const int g1; // COMPLIANT +const extern int g2; // NON-COMPLIANT + +#define MY_TRUE 3 // COMPLIANT +#define true 3 // NON-COMPLIANT +#define false 3 // NON-COMPLIANT +#define bool int * // NON-COMPLIANT +#undef true // NON-COMPLIANT +#undef false // NON-COMPLIANT +#undef bool // NON-COMPLIANT + +_Atomic int g3 = ATOMIC_VAR_INIT(18); // NON-COMPLIANT +_Atomic int g4 = 18; // COMPLIANT + +// The following cases are already covered by other rules: + +// Rule 8.8: +static int g5 = 3; // COMPLIANT +extern int g5; // NON-COMPLIANT + +// Rule 8.2: +void f2(); // NON-COMPLIANT +void f3(void); // COMPLIANT + +void f4(int p1) {}; // COMPLIANT +int f5(x) // NON_COMPLIANT +int x; +{ + return 1; +} + +// Rule 21.6 covers the below cases: +void f6(void) { + // `gets` was removed from C11. + // gets(stdin); // NON_COMPLIANT + + FILE *file = fopen("", 0); + // Obsolete usage of ungetc. + ungetc('c', file); // NON-COMPLIANT + + char buf[10]; + fread(buf, sizeof(buf), 10, file); + // This is not an obsolete usage of ungetc, but ungetc isn't allowed. + ungetc('c', file); // NON-COMPLIANT[FALSE NEGATIVE] +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll new file mode 100644 index 0000000000..f26cae3e9a --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll @@ -0,0 +1,61 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Language4Query = + TUseOfObsoleteMacroAtomicVarInitQuery() or + TInvalidDefineOrUndefOfStdBoolMacroQuery() or + TCallToReallocWithSizeZeroQuery() + +predicate isLanguage4QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `useOfObsoleteMacroAtomicVarInit` query + Language4Package::useOfObsoleteMacroAtomicVarInitQuery() and + queryId = + // `@id` for the `useOfObsoleteMacroAtomicVarInit` query + "c/misra/use-of-obsolete-macro-atomic-var-init" and + ruleId = "RULE-1-5" and + category = "required" + or + query = + // `Query` instance for the `invalidDefineOrUndefOfStdBoolMacro` query + Language4Package::invalidDefineOrUndefOfStdBoolMacroQuery() and + queryId = + // `@id` for the `invalidDefineOrUndefOfStdBoolMacro` query + "c/misra/invalid-define-or-undef-of-std-bool-macro" and + ruleId = "RULE-1-5" and + category = "required" + or + query = + // `Query` instance for the `callToReallocWithSizeZero` query + Language4Package::callToReallocWithSizeZeroQuery() and + queryId = + // `@id` for the `callToReallocWithSizeZero` query + "c/misra/call-to-realloc-with-size-zero" and + ruleId = "RULE-1-5" and + category = "required" +} + +module Language4Package { + Query useOfObsoleteMacroAtomicVarInitQuery() { + //autogenerate `Query` type + result = + // `Query` type for `useOfObsoleteMacroAtomicVarInit` query + TQueryC(TLanguage4PackageQuery(TUseOfObsoleteMacroAtomicVarInitQuery())) + } + + Query invalidDefineOrUndefOfStdBoolMacroQuery() { + //autogenerate `Query` type + result = + // `Query` type for `invalidDefineOrUndefOfStdBoolMacro` query + TQueryC(TLanguage4PackageQuery(TInvalidDefineOrUndefOfStdBoolMacroQuery())) + } + + Query callToReallocWithSizeZeroQuery() { + //autogenerate `Query` type + result = + // `Query` type for `callToReallocWithSizeZero` query + TQueryC(TLanguage4PackageQuery(TCallToReallocWithSizeZeroQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index b10fbf0a2f..cff145d562 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -39,6 +39,7 @@ import InvalidMemory2 import Language1 import Language2 import Language3 +import Language4 import Memory1 import Memory2 import Memory3 @@ -112,6 +113,7 @@ newtype TCQuery = TLanguage1PackageQuery(Language1Query q) or TLanguage2PackageQuery(Language2Query q) or TLanguage3PackageQuery(Language3Query q) or + TLanguage4PackageQuery(Language4Query q) or TMemory1PackageQuery(Memory1Query q) or TMemory2PackageQuery(Memory2Query q) or TMemory3PackageQuery(Memory3Query q) or @@ -185,6 +187,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isLanguage1QueryMetadata(query, queryId, ruleId, category) or isLanguage2QueryMetadata(query, queryId, ruleId, category) or isLanguage3QueryMetadata(query, queryId, ruleId, category) or + isLanguage4QueryMetadata(query, queryId, ruleId, category) or isMemory1QueryMetadata(query, queryId, ruleId, category) or isMemory2QueryMetadata(query, queryId, ruleId, category) or isMemory3QueryMetadata(query, queryId, ruleId, category) or diff --git a/rule_packages/c/Language4.json b/rule_packages/c/Language4.json new file mode 100644 index 0000000000..ff85927a61 --- /dev/null +++ b/rule_packages/c/Language4.json @@ -0,0 +1,47 @@ +{ + "MISRA-C-2012": { + "RULE-1-5": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The macro ATOMIC_VAR_INIT is has been declared an obsolescent language feature since C18.", + "kind": "problem", + "name": "Disallowed usage of obsolete macro ATOMIC_VAR_INIT compiled as C18", + "precision": "very-high", + "severity": "recommendation", + "short_name": "UseOfObsoleteMacroAtomicVarInit", + "tags": [ + "maintainability", + "readability" + ] + }, + { + "description": "Directives that undefine and/or redefine the standard boolean macros has been declared an obsolescent language feature since C99.", + "kind": "problem", + "name": "Programs may not undefine or redefine the macros bool, true, or false", + "precision": "very-high", + "severity": "warning", + "short_name": "InvalidDefineOrUndefOfStdBoolMacro", + "tags": [ + "maintainability", + "readability" + ] + }, + { + "description": "Invoking realloc with a size argument set to zero is implementation-defined behavior and declared as an obsolete feature in C18.", + "kind": "problem", + "name": "Disallowed size argument value equal to zero in call to realloc", + "precision": "very-high", + "severity": "error", + "short_name": "CallToReallocWithSizeZero", + "tags": [ + "correctness" + ] + } + ], + "title": "Obsolencent language features shall not be used" + } + } +} \ No newline at end of file From 3adf181c92efb89e3d8fc4fa4b58f0ebb076a712 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 3 Oct 2024 15:49:44 -0700 Subject: [PATCH 041/628] Add full stops to query messages. --- .../RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql | 2 +- .../RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql | 3 ++- .../InvalidDefineOrUndefOfStdBoolMacro.expected | 12 ++++++------ .../UseOfObsoleteMacroAtomicVarInit.expected | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql b/c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql index 3d33103988..8b6abe47dd 100644 --- a/c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql +++ b/c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql @@ -28,4 +28,4 @@ where macroName = directive.(PreprocessorUndef).getName() and opString = "undefine" ) -select directive, "Invalid " + opString + " of boolean standard macro " + macroName +select directive, "Invalid " + opString + " of boolean standard macro '" + macroName + "'." diff --git a/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql b/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql index 38dd7c0386..82bde8471a 100644 --- a/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql +++ b/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql @@ -21,4 +21,5 @@ where invoke.getMacroName() = "ATOMIC_VAR_INIT" and flag = c.getAnArgument() and flag.regexpMatch("-std=c1[78]") -select invoke, "Usage of macro ATOMIC_VAR_INIT() is considered obsolete for c version " + flag +select invoke, + "Usage of macro ATOMIC_VAR_INIT() is considered obsolete for c version '" + flag + "'." diff --git a/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected b/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected index a29c5efe56..e2a072d2b4 100644 --- a/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected +++ b/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected @@ -1,6 +1,6 @@ -| test.c:23:1:23:14 | #define true 3 | Invalid define of boolean standard macro true | -| test.c:24:1:24:15 | #define false 3 | Invalid define of boolean standard macro false | -| test.c:25:1:25:18 | #define bool int * | Invalid define of boolean standard macro bool | -| test.c:26:1:26:11 | #undef true | Invalid undefine of boolean standard macro true | -| test.c:27:1:27:12 | #undef false | Invalid undefine of boolean standard macro false | -| test.c:28:1:28:11 | #undef bool | Invalid undefine of boolean standard macro bool | +| test.c:23:1:23:14 | #define true 3 | Invalid define of boolean standard macro 'true'. | +| test.c:24:1:24:15 | #define false 3 | Invalid define of boolean standard macro 'false'. | +| test.c:25:1:25:18 | #define bool int * | Invalid define of boolean standard macro 'bool'. | +| test.c:26:1:26:11 | #undef true | Invalid undefine of boolean standard macro 'true'. | +| test.c:27:1:27:12 | #undef false | Invalid undefine of boolean standard macro 'false'. | +| test.c:28:1:28:11 | #undef bool | Invalid undefine of boolean standard macro 'bool'. | diff --git a/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected index 6fe4cee5f4..c38a6263a9 100644 --- a/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected +++ b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected @@ -1 +1 @@ -| test.c:30:18:30:36 | ATOMIC_VAR_INIT(value) | Usage of macro ATOMIC_VAR_INIT() is considered obsolete for c version -std=c17 | +| test.c:30:18:30:36 | ATOMIC_VAR_INIT(value) | Usage of macro ATOMIC_VAR_INIT() is considered obsolete for c version '-std=c17'. | From 31dc8bc08c49e8872f6ebf79fc7bf46059a172b5 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 3 Oct 2024 15:56:04 -0700 Subject: [PATCH 042/628] Fix test.c format --- .../StandardLibraryInputoutputFunctionsUsed.expected | 6 +++--- c/misra/test/rules/RULE-1-5/test.c | 8 +++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected b/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected index ca49894238..d0cf1351c7 100644 --- a/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected +++ b/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected @@ -1,3 +1,3 @@ -| test.c:57:3:57:8 | call to ungetc | Call to banned function ungetc. | -| test.c:60:3:60:7 | call to fread | Call to banned function fread. | -| test.c:62:3:62:8 | call to ungetc | Call to banned function ungetc. | +| test.c:55:3:55:8 | call to ungetc | Call to banned function ungetc. | +| test.c:58:3:58:7 | call to fread | Call to banned function fread. | +| test.c:60:3:60:8 | call to ungetc | Call to banned function ungetc. | diff --git a/c/misra/test/rules/RULE-1-5/test.c b/c/misra/test/rules/RULE-1-5/test.c index 43faa71f3c..51399e32c6 100644 --- a/c/misra/test/rules/RULE-1-5/test.c +++ b/c/misra/test/rules/RULE-1-5/test.c @@ -40,12 +40,10 @@ extern int g5; // NON-COMPLIANT void f2(); // NON-COMPLIANT void f3(void); // COMPLIANT -void f4(int p1) {}; // COMPLIANT -int f5(x) // NON_COMPLIANT +void f4(int p1){}; // COMPLIANT +int f5(x) // NON_COMPLIANT int x; -{ - return 1; -} +{ return 1; } // Rule 21.6 covers the below cases: void f6(void) { From d077885f68d65ee72c17614aa41c066ddf4c7c3b Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 4 Oct 2024 07:51:44 -0700 Subject: [PATCH 043/628] Add tag misra c 2012 amendment 3 --- c/misra/src/rules/RULE-1-5/CallToReallocWithSizeZero.ql | 1 + .../rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql | 1 + .../rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql | 1 + rule_packages/c/Language4.json | 9 ++++++--- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/c/misra/src/rules/RULE-1-5/CallToReallocWithSizeZero.ql b/c/misra/src/rules/RULE-1-5/CallToReallocWithSizeZero.ql index 224ca2a6bf..2ea90e8b12 100644 --- a/c/misra/src/rules/RULE-1-5/CallToReallocWithSizeZero.ql +++ b/c/misra/src/rules/RULE-1-5/CallToReallocWithSizeZero.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-1-5 * correctness + * external/misra/c/2012/amendment3 * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql b/c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql index 8b6abe47dd..9d10522ecf 100644 --- a/c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql +++ b/c/misra/src/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-1-5 * maintainability * readability + * external/misra/c/2012/amendment3 * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql b/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql index 82bde8471a..b2fb5f0167 100644 --- a/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql +++ b/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql @@ -9,6 +9,7 @@ * @tags external/misra/id/rule-1-5 * maintainability * readability + * external/misra/c/2012/amendment3 * external/misra/obligation/required */ diff --git a/rule_packages/c/Language4.json b/rule_packages/c/Language4.json index ff85927a61..a9f5ddde92 100644 --- a/rule_packages/c/Language4.json +++ b/rule_packages/c/Language4.json @@ -14,7 +14,8 @@ "short_name": "UseOfObsoleteMacroAtomicVarInit", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/amendment3" ] }, { @@ -26,7 +27,8 @@ "short_name": "InvalidDefineOrUndefOfStdBoolMacro", "tags": [ "maintainability", - "readability" + "readability", + "external/misra/c/2012/amendment3" ] }, { @@ -37,7 +39,8 @@ "severity": "error", "short_name": "CallToReallocWithSizeZero", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/amendment3" ] } ], From e27e49a004f4ac240535d9cc4971c3261d32208b Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 4 Oct 2024 12:10:22 -0700 Subject: [PATCH 044/628] Add implementation scope to Language4.json --- rule_packages/c/Language4.json | 5 ++++- schemas/rule-package.schema.json | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/rule_packages/c/Language4.json b/rule_packages/c/Language4.json index a9f5ddde92..0ba6bfcc55 100644 --- a/rule_packages/c/Language4.json +++ b/rule_packages/c/Language4.json @@ -44,7 +44,10 @@ ] } ], - "title": "Obsolencent language features shall not be used" + "title": "Obsolencent language features shall not be used", + "implementation_scope": { + "description": "Usage of obsolescent language features that are already disallowed by Rule 8.2, Rule 8.8, and 21.6 are not redundantly checked by this rule." + } } } } \ No newline at end of file diff --git a/schemas/rule-package.schema.json b/schemas/rule-package.schema.json index b27815163e..087a6087ea 100644 --- a/schemas/rule-package.schema.json +++ b/schemas/rule-package.schema.json @@ -207,6 +207,18 @@ }, "title": { "type": "string" + }, + "implementation_scope": { + "type": "object", + "properties": { + "description": { + "type": "string" + } + }, + "required": [ + "description" + ], + "additionalProperties": false } }, "required": [ From cca63e439ff2d3bf9a0dd9124a77c6f311838095 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 4 Oct 2024 12:22:22 -0700 Subject: [PATCH 045/628] Report ATOMIC_VAR_INIT for all C versions. --- .../RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql | 8 +++----- .../RULE-1-5/CallToReallocWithSizeZero.expected | 2 +- .../FunctionTypesNotInPrototypeForm.expected | 4 ++-- .../InvalidDefineOrUndefOfStdBoolMacro.expected | 12 ++++++------ ...MemoryAllocDeallocFunctionsOfStdlibhUsed.expected | 6 +++--- ...ssingStaticSpecifierObjectRedeclarationC.expected | 2 +- .../StandardLibraryInputoutputFunctionsUsed.expected | 6 +++--- .../UseOfObsoleteMacroAtomicVarInit.expected | 2 +- c/misra/test/rules/RULE-1-5/options | 1 - c/misra/test/rules/RULE-1-5/test.c | 2 -- 10 files changed, 20 insertions(+), 25 deletions(-) delete mode 100644 c/misra/test/rules/RULE-1-5/options diff --git a/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql b/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql index b2fb5f0167..e8abf1bbfb 100644 --- a/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql +++ b/c/misra/src/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.ql @@ -16,11 +16,9 @@ import cpp import codingstandards.c.misra -from MacroInvocation invoke, Compilation c, string flag +from MacroInvocation invoke where not isExcluded(invoke, Language4Package::useOfObsoleteMacroAtomicVarInitQuery()) and - invoke.getMacroName() = "ATOMIC_VAR_INIT" and - flag = c.getAnArgument() and - flag.regexpMatch("-std=c1[78]") + invoke.getMacroName() = "ATOMIC_VAR_INIT" select invoke, - "Usage of macro ATOMIC_VAR_INIT() is considered obsolete for c version '" + flag + "'." + "Usage of macro ATOMIC_VAR_INIT() is declared obscelescent in C18, and discouraged in earlier C versions." diff --git a/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.expected b/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.expected index 0e58d0cd0d..89e54a38c2 100644 --- a/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.expected +++ b/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.expected @@ -1 +1 @@ -| test.c:13:14:13:14 | 0 | Calling realloc with size zero results in implementation-defined behavior. | +| test.c:11:14:11:14 | 0 | Calling realloc with size zero results in implementation-defined behavior. | diff --git a/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.expected b/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.expected index 9f9157ca8e..29faec8b55 100644 --- a/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.expected +++ b/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.expected @@ -1,2 +1,2 @@ -| test.c:40:6:40:7 | f2 | Function f2 does not specify void for no parameters present. | -| test.c:44:5:44:6 | f5 | Function f5 declares parameter in unsupported declaration list. | \ No newline at end of file +| test.c:38:6:38:7 | f2 | Function f2 does not specify void for no parameters present. | +| test.c:42:5:42:6 | f5 | Function f5 declares parameter in unsupported declaration list. | \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected b/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected index e2a072d2b4..7a6ca9824e 100644 --- a/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected +++ b/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected @@ -1,6 +1,6 @@ -| test.c:23:1:23:14 | #define true 3 | Invalid define of boolean standard macro 'true'. | -| test.c:24:1:24:15 | #define false 3 | Invalid define of boolean standard macro 'false'. | -| test.c:25:1:25:18 | #define bool int * | Invalid define of boolean standard macro 'bool'. | -| test.c:26:1:26:11 | #undef true | Invalid undefine of boolean standard macro 'true'. | -| test.c:27:1:27:12 | #undef false | Invalid undefine of boolean standard macro 'false'. | -| test.c:28:1:28:11 | #undef bool | Invalid undefine of boolean standard macro 'bool'. | +| test.c:21:1:21:14 | #define true 3 | Invalid define of boolean standard macro 'true'. | +| test.c:22:1:22:15 | #define false 3 | Invalid define of boolean standard macro 'false'. | +| test.c:23:1:23:18 | #define bool int * | Invalid define of boolean standard macro 'bool'. | +| test.c:24:1:24:11 | #undef true | Invalid undefine of boolean standard macro 'true'. | +| test.c:25:1:25:12 | #undef false | Invalid undefine of boolean standard macro 'false'. | +| test.c:26:1:26:11 | #undef bool | Invalid undefine of boolean standard macro 'bool'. | diff --git a/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected b/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected index 3f8fa3cf3f..de87fc8542 100644 --- a/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected +++ b/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected @@ -1,3 +1,3 @@ -| test.c:10:12:10:17 | call to malloc | Use of banned dynamic memory allocation. | -| test.c:13:3:13:9 | call to realloc | Use of banned dynamic memory allocation. | -| test.c:16:3:16:9 | call to realloc | Use of banned dynamic memory allocation. | +| test.c:8:12:8:17 | call to malloc | Use of banned dynamic memory allocation. | +| test.c:11:3:11:9 | call to realloc | Use of banned dynamic memory allocation. | +| test.c:14:3:14:9 | call to realloc | Use of banned dynamic memory allocation. | diff --git a/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.expected b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.expected index 4c3d4614fa..48275eb504 100644 --- a/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.expected +++ b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.expected @@ -1 +1 @@ -| test.c:37:12:37:13 | declaration of g5 | The redeclaration of $@ with internal linkage misses the static specifier. | test.c:36:12:36:13 | definition of g5 | g5 | +| test.c:35:12:35:13 | declaration of g5 | The redeclaration of $@ with internal linkage misses the static specifier. | test.c:34:12:34:13 | definition of g5 | g5 | diff --git a/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected b/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected index d0cf1351c7..396b181150 100644 --- a/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected +++ b/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected @@ -1,3 +1,3 @@ -| test.c:55:3:55:8 | call to ungetc | Call to banned function ungetc. | -| test.c:58:3:58:7 | call to fread | Call to banned function fread. | -| test.c:60:3:60:8 | call to ungetc | Call to banned function ungetc. | +| test.c:53:3:53:8 | call to ungetc | Call to banned function ungetc. | +| test.c:56:3:56:7 | call to fread | Call to banned function fread. | +| test.c:58:3:58:8 | call to ungetc | Call to banned function ungetc. | diff --git a/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected index c38a6263a9..bc903de094 100644 --- a/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected +++ b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected @@ -1 +1 @@ -| test.c:30:18:30:36 | ATOMIC_VAR_INIT(value) | Usage of macro ATOMIC_VAR_INIT() is considered obsolete for c version '-std=c17'. | +| test.c:28:18:28:36 | ATOMIC_VAR_INIT(value) | Usage of macro ATOMIC_VAR_INIT() is declared obscelescent in C18, and discouraged in earlier C versions. | diff --git a/c/misra/test/rules/RULE-1-5/options b/c/misra/test/rules/RULE-1-5/options deleted file mode 100644 index 2ba2218a05..0000000000 --- a/c/misra/test/rules/RULE-1-5/options +++ /dev/null @@ -1 +0,0 @@ -semmle-extractor-options:-std=c17 -I../../../../common/test/includes/standard-library \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/test.c b/c/misra/test/rules/RULE-1-5/test.c index 51399e32c6..4709381898 100644 --- a/c/misra/test/rules/RULE-1-5/test.c +++ b/c/misra/test/rules/RULE-1-5/test.c @@ -1,5 +1,3 @@ -// Compiled with -std=c17 - #include "stdatomic.h" #include "stdbool.h" #include "stdio.h" From 794e97ab06f22edcad8759ae167463ffdd9d0aa9 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 4 Oct 2024 12:42:55 -0700 Subject: [PATCH 046/628] Reuse implementation_scope schema, detailed items for 1.5 --- rule_packages/c/Language4.json | 12 +++++++++- schemas/rule-package.schema.json | 38 ++++++++++++++------------------ 2 files changed, 28 insertions(+), 22 deletions(-) diff --git a/rule_packages/c/Language4.json b/rule_packages/c/Language4.json index 0ba6bfcc55..54708d73da 100644 --- a/rule_packages/c/Language4.json +++ b/rule_packages/c/Language4.json @@ -46,7 +46,17 @@ ], "title": "Obsolencent language features shall not be used", "implementation_scope": { - "description": "Usage of obsolescent language features that are already disallowed by Rule 8.2, Rule 8.8, and 21.6 are not redundantly checked by this rule." + "description": "Not all items from Appendix F are covered by this rule. Some are not supportable and some are covered already by other rules.", + "items": [ + "Appendix F, item ID 1 is covered by Rule 8.8 and not reported as part of this implementation of Rule 1.5.", + "Appendix F, item ID 2 refers to compiler behavior which cannot be statically analyzed.", + "Appendix F, item ID 3, which states that storage-class specifiers may not be used except in the beginning of a declaration, is not supportable without additional changes to the CodeQL CLI.", + "Appendix F, item ID 6 is reported for all C versions, though the macro ATOMIC_VAR_INIT was not officially declared obsolescent until C18.", + "Appendix F, item IDs 4 and 5 are covered by Rule 8.2 and not reported as part of this implementation of Rule 1.5.", + "Appendix F, item IDs 8 and 9 is covered by Rule 21.6 and not reported as part of this implementation of Rule 1.5.", + "Appendix F, item ID 10 is checked by this implementation of 1.5, though it is a redundant subset of cases reported by Rule 21.3.", + "Appendix F, item ID 10 is reported for all C versions, as realloc() with a size argument of zero was implementation-defined behavior in C99 and C11." + ] } } } diff --git a/schemas/rule-package.schema.json b/schemas/rule-package.schema.json index 087a6087ea..63cbbf3ac5 100644 --- a/schemas/rule-package.schema.json +++ b/schemas/rule-package.schema.json @@ -209,16 +209,7 @@ "type": "string" }, "implementation_scope": { - "type": "object", - "properties": { - "description": { - "type": "string" - } - }, - "required": [ - "description" - ], - "additionalProperties": false + "$ref": "#/$defs/implementation_scope" } }, "required": [ @@ -360,6 +351,20 @@ "minLength": 1 }, "implementation_scope": { + "$ref": "#/$defs/implementation_scope" + } + }, + "required": [ + "description", + "name", + "precision", + "severity", + "short_name", + "tags" + ] + }, + "implementation_scope": { + "$id": "/schemas/implementation_scope", "type": "object", "properties": { "description": { @@ -374,17 +379,8 @@ }, "required": [ "description" - ] + ], + "additionalProperties": false } - }, - "required": [ - "description", - "name", - "precision", - "severity", - "short_name", - "tags" - ] - } } } \ No newline at end of file From 38a467ddd5c08caa083cbf66a220b6190cbda6d6 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 4 Oct 2024 12:52:25 -0700 Subject: [PATCH 047/628] Add cross-linking comments to tests referencing other rules. --- ...moryAllocDeallocFunctionsOfStdlibhUsed.expected | 10 +++++----- c/misra/test/rules/RULE-21-3/test.c | 5 +++++ ...tandardLibraryInputoutputFunctionsUsed.expected | 14 +++++++------- c/misra/test/rules/RULE-21-6/test.c | 5 +++++ .../FunctionTypesNotInPrototypeForm.expected | 8 ++++---- c/misra/test/rules/RULE-8-2/test.c | 5 +++++ ...ingStaticSpecifierObjectRedeclarationC.expected | 2 +- c/misra/test/rules/RULE-8-8/test.c | 5 +++++ 8 files changed, 37 insertions(+), 17 deletions(-) diff --git a/c/misra/test/rules/RULE-21-3/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected b/c/misra/test/rules/RULE-21-3/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected index 0215c2e5b8..e9ea6daecc 100644 --- a/c/misra/test/rules/RULE-21-3/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected +++ b/c/misra/test/rules/RULE-21-3/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected @@ -1,5 +1,5 @@ -| test.c:8:15:8:20 | call to malloc | Use of banned dynamic memory allocation. | -| test.c:9:15:9:20 | call to calloc | Use of banned dynamic memory allocation. | -| test.c:10:8:10:14 | call to realloc | Use of banned dynamic memory allocation. | -| test.c:11:3:11:6 | call to free | Use of banned dynamic memory deallocation. | -| test.c:12:3:12:6 | call to free | Use of banned dynamic memory deallocation. | +| test.c:13:15:13:20 | call to malloc | Use of banned dynamic memory allocation. | +| test.c:14:15:14:20 | call to calloc | Use of banned dynamic memory allocation. | +| test.c:15:8:15:14 | call to realloc | Use of banned dynamic memory allocation. | +| test.c:16:3:16:6 | call to free | Use of banned dynamic memory deallocation. | +| test.c:17:3:17:6 | call to free | Use of banned dynamic memory deallocation. | diff --git a/c/misra/test/rules/RULE-21-3/test.c b/c/misra/test/rules/RULE-21-3/test.c index d9aee3a322..fd4543faaf 100644 --- a/c/misra/test/rules/RULE-21-3/test.c +++ b/c/misra/test/rules/RULE-21-3/test.c @@ -1,3 +1,8 @@ +// Note: A subset of these cases are also tested in c/misra/test/rules/RULE-1-5 +// via a MemoryAllocDeallocFunctionsOfStdlibhUsed.qlref and .expected file in +// that directory. Changes to these tests may require updating the test code or +// expectations in that directory as well. + #include #include void f2(); diff --git a/c/misra/test/rules/RULE-21-6/StandardLibraryInputoutputFunctionsUsed.expected b/c/misra/test/rules/RULE-21-6/StandardLibraryInputoutputFunctionsUsed.expected index 0dee7e9b3d..672480db33 100644 --- a/c/misra/test/rules/RULE-21-6/StandardLibraryInputoutputFunctionsUsed.expected +++ b/c/misra/test/rules/RULE-21-6/StandardLibraryInputoutputFunctionsUsed.expected @@ -1,7 +1,7 @@ -| test.c:8:10:8:14 | call to scanf | Call to banned function scanf. | -| test.c:9:5:9:10 | call to printf | Call to banned function printf. | -| test.c:16:16:16:21 | call to fgetwc | Call to banned function fgetwc. | -| test.c:17:5:17:12 | call to putwchar | Call to banned function putwchar. | -| test.c:22:7:22:10 | call to puts | Call to banned function puts. | -| test.c:24:7:24:10 | call to puts | Call to banned function puts. | -| test.c:26:5:26:8 | call to puts | Call to banned function puts. | +| test.c:13:10:13:14 | call to scanf | Call to banned function scanf. | +| test.c:14:5:14:10 | call to printf | Call to banned function printf. | +| test.c:21:16:21:21 | call to fgetwc | Call to banned function fgetwc. | +| test.c:22:5:22:12 | call to putwchar | Call to banned function putwchar. | +| test.c:27:7:27:10 | call to puts | Call to banned function puts. | +| test.c:29:7:29:10 | call to puts | Call to banned function puts. | +| test.c:31:5:31:8 | call to puts | Call to banned function puts. | diff --git a/c/misra/test/rules/RULE-21-6/test.c b/c/misra/test/rules/RULE-21-6/test.c index 0ae580164e..b66bb9b6b7 100644 --- a/c/misra/test/rules/RULE-21-6/test.c +++ b/c/misra/test/rules/RULE-21-6/test.c @@ -1,3 +1,8 @@ +// Note: A subset of these cases are also tested in c/misra/test/rules/RULE-1-5 +// via a StandardLibraryInputoutputFunctionsUsed.qlref and .expected file in +// that directory. Changes to these tests may require updating the test code or +// expectations in that directory as well. + #include #include #include diff --git a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected b/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected index f2c08897b8..1264797088 100644 --- a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected +++ b/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected @@ -1,4 +1,4 @@ -| test.c:3:6:3:7 | f1 | Function f1 declares parameter that is unnamed. | -| test.c:4:6:4:7 | f2 | Function f2 does not specify void for no parameters present. | -| test.c:5:6:5:7 | f3 | Function f3 does not specify void for no parameters present. | -| test.c:7:5:7:6 | f5 | Function f5 declares parameter in unsupported declaration list. | +| test.c:8:6:8:7 | f1 | Function f1 declares parameter that is unnamed. | +| test.c:9:6:9:7 | f2 | Function f2 does not specify void for no parameters present. | +| test.c:10:6:10:7 | f3 | Function f3 does not specify void for no parameters present. | +| test.c:12:5:12:6 | f5 | Function f5 declares parameter in unsupported declaration list. | diff --git a/c/misra/test/rules/RULE-8-2/test.c b/c/misra/test/rules/RULE-8-2/test.c index c254a221d9..1ed64c0011 100644 --- a/c/misra/test/rules/RULE-8-2/test.c +++ b/c/misra/test/rules/RULE-8-2/test.c @@ -1,3 +1,8 @@ +// Note: A subset of these cases are also tested in c/misra/test/rules/RULE-1-5 +// via a FunctionTypesNotInPrototypeForm.qlref and .expected file in that +// directory. Changes to these tests may require updating the test code or +// expectations in that directory as well. + void f(int x); // COMPLIANT void f0(void); // COMPLIANT void f1(int); // NON_COMPLIANT diff --git a/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.expected b/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.expected index 34a7723bcd..9c357cf38f 100644 --- a/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.expected +++ b/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.expected @@ -1 +1 @@ -| test.c:2:12:2:12 | declaration of g | The redeclaration of $@ with internal linkage misses the static specifier. | test.c:1:12:1:12 | definition of g | g | +| test.c:7:12:7:12 | declaration of g | The redeclaration of $@ with internal linkage misses the static specifier. | test.c:6:12:6:12 | definition of g | g | diff --git a/c/misra/test/rules/RULE-8-8/test.c b/c/misra/test/rules/RULE-8-8/test.c index d98d71c6f0..ba78432a40 100644 --- a/c/misra/test/rules/RULE-8-8/test.c +++ b/c/misra/test/rules/RULE-8-8/test.c @@ -1,3 +1,8 @@ +// Note: A subset of these cases are also tested in c/misra/test/rules/RULE-1-5 +// via a MissingStaticSpecifierObjectRedeclarationC.qlref and .expected file in +// that directory. Changes to these tests may require updating the test code or +// expectations in that directory as well. + static int g = 0; extern int g; // NON_COMPLIANT From 730341f99138ca5451dc62e8db19d77a980266d7 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 4 Oct 2024 13:03:25 -0700 Subject: [PATCH 048/628] Fix rule schema for implementation_scope in queries. --- schemas/rule-package.schema.json | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/schemas/rule-package.schema.json b/schemas/rule-package.schema.json index 63cbbf3ac5..a43deb2141 100644 --- a/schemas/rule-package.schema.json +++ b/schemas/rule-package.schema.json @@ -351,7 +351,7 @@ "minLength": 1 }, "implementation_scope": { - "$ref": "#/$defs/implementation_scope" + "$ref": "/schemas/implementation_scope" } }, "required": [ @@ -363,24 +363,24 @@ "tags" ] }, - "implementation_scope": { + "implementation_scope": { "$id": "/schemas/implementation_scope", - "type": "object", - "properties": { - "description": { - "kind": "string" - }, - "items": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "description" - ], - "additionalProperties": false + "type": "object", + "properties": { + "description": { + "kind": "string" + }, + "items": { + "type": "array", + "items": { + "type": "string" + } } + }, + "required": [ + "description" + ], + "additionalProperties": false + } } } \ No newline at end of file From cf5dc696022020aa61781dbe03585a285496a96a Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 16 Oct 2024 11:01:33 +0200 Subject: [PATCH 049/628] Update expected test results after merging `main` --- ...rrayFunctionArgumentNumberOfElements.expected | 12 ++++++------ ...mpUsedToCompareNullTerminatedStrings.expected | 8 ++++---- ...penForReadAndWriteOnDifferentStreams.expected | 2 +- .../AttemptToWriteToAReadOnlyStream.expected | 12 ++++++------ ...BeComparedWithUnmodifiedReturnValues.expected | 16 ++++++++-------- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected b/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected index cb4422f5f1..174c6aa40f 100644 --- a/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected +++ b/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected @@ -1,9 +1,9 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:47,36-44) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:48,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:50,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:55,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:71,28-36) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:71,51-59) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:48,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:49,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:51,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:56,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:72,28-36) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:72,51-59) | test.c:18:6:18:6 | 0 | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | | test.c:19:6:19:7 | ar | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | | test.c:21:6:21:9 | ar2p | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | diff --git a/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected b/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected index cf45b21eb4..5ae49919a9 100644 --- a/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected +++ b/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected @@ -1,7 +1,7 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:22,54-62) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:23,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:49,20-28) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:57,43-56) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:23,54-62) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:24,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:50,20-28) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:58,43-56) edges | test.c:12:13:12:15 | a | test.c:14:10:14:10 | a | provenance | | | test.c:12:13:12:15 | a | test.c:23:13:23:13 | a | provenance | | diff --git a/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected b/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected index 6360b21973..0365f4980d 100644 --- a/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected +++ b/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected @@ -1,4 +1,4 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (FileOpenForReadAndWriteOnDifferentStreams.ql:38,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (FileOpenForReadAndWriteOnDifferentStreams.ql:39,9-17) | test.c:6:14:6:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:5:14:5:18 | call to fopen | here | | test.c:17:14:17:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:16:14:16:18 | call to fopen | here | | test.c:33:14:33:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:32:14:32:18 | call to fopen | here | diff --git a/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected b/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected index 88dca316a2..dbf08e3d3d 100644 --- a/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected +++ b/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected @@ -1,8 +1,8 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:18,32-40) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:19,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:24,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:30,21-29) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:32,6-14) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:35,28-36) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:19,32-40) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:20,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:25,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:31,21-29) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:33,6-14) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:36,28-36) | test.c:10:3:10:9 | call to fprintf | Attempt to write to a $@ opened as read-only. | test.c:9:14:9:18 | call to fopen | stream | | test.c:15:3:15:9 | call to fprintf | Attempt to write to a $@ opened as read-only. | test.c:18:14:18:18 | call to fopen | stream | diff --git a/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected index a7ee20c0b0..83a10a46fb 100644 --- a/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected +++ b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected @@ -1,10 +1,10 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:22,28-36) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:23,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:27,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:36,23-31) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:41,17-25) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:50,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:58,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:58,46-54) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:23,28-36) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:24,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:28,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:37,23-31) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:42,17-25) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:51,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:59,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:59,46-54) | test.c:6:7:6:20 | ... != ... | The check is not reliable as the type of the return value of $@ is converted. | test.c:5:14:5:20 | call to getchar | call to getchar | | test.c:13:7:13:15 | ... != ... | The check is not reliable as the type of the return value of $@ is converted. | test.c:12:14:12:20 | call to getchar | call to getchar | From 2778d662e2cf701b351b2466916e9e0f03dd31f8 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Wed, 16 Oct 2024 13:12:54 +0200 Subject: [PATCH 050/628] Update test results after QL library changes --- .../identifierhidden/IdentifierHidden.expected | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/cpp/common/test/rules/identifierhidden/IdentifierHidden.expected b/cpp/common/test/rules/identifierhidden/IdentifierHidden.expected index fd657590ef..47d191d758 100644 --- a/cpp/common/test/rules/identifierhidden/IdentifierHidden.expected +++ b/cpp/common/test/rules/identifierhidden/IdentifierHidden.expected @@ -4,10 +4,21 @@ | test.cpp:23:13:23:15 | id1 | Variable is hiding variable $@. | test.cpp:1:5:1:7 | id1 | id1 | | test.cpp:26:12:26:14 | id1 | Variable is hiding variable $@. | test.cpp:1:5:1:7 | id1 | id1 | | test.cpp:27:14:27:16 | id1 | Variable is hiding variable $@. | test.cpp:26:12:26:14 | id1 | id1 | +| test.cpp:48:11:48:11 | i | Variable is hiding variable $@. | test.cpp:58:16:58:16 | i | i | +| test.cpp:48:11:48:11 | i | Variable is hiding variable $@. | test.cpp:75:16:75:16 | i | i | +| test.cpp:50:9:50:9 | i | Variable is hiding variable $@. | test.cpp:58:16:58:16 | i | i | +| test.cpp:50:9:50:9 | i | Variable is hiding variable $@. | test.cpp:75:16:75:16 | i | i | +| test.cpp:53:12:53:12 | i | Variable is hiding variable $@. | test.cpp:58:16:58:16 | i | i | +| test.cpp:53:12:53:12 | i | Variable is hiding variable $@. | test.cpp:75:16:75:16 | i | i | +| test.cpp:65:11:65:11 | i | Variable is hiding variable $@. | test.cpp:58:16:58:16 | i | i | | test.cpp:65:11:65:11 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i | +| test.cpp:65:11:65:11 | i | Variable is hiding variable $@. | test.cpp:75:16:75:16 | i | i | +| test.cpp:67:9:67:9 | i | Variable is hiding variable $@. | test.cpp:58:16:58:16 | i | i | | test.cpp:67:9:67:9 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i | +| test.cpp:67:9:67:9 | i | Variable is hiding variable $@. | test.cpp:75:16:75:16 | i | i | +| test.cpp:70:12:70:12 | i | Variable is hiding variable $@. | test.cpp:58:16:58:16 | i | i | | test.cpp:70:12:70:12 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i | -| test.cpp:75:16:75:16 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i | +| test.cpp:70:12:70:12 | i | Variable is hiding variable $@. | test.cpp:75:16:75:16 | i | i | | test.cpp:86:9:86:9 | b | Variable is hiding variable $@. | test.cpp:80:11:80:11 | b | b | | test.cpp:94:9:94:17 | globalvar | Variable is hiding variable $@. | test.cpp:91:5:91:13 | globalvar | globalvar | | test.cpp:113:11:113:11 | b | Variable is hiding variable $@. | test.cpp:107:13:107:13 | b | b | From dd475bef82a8d41d74bcfed2d2515dd64f921859 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 16 Oct 2024 16:51:21 -0700 Subject: [PATCH 051/628] Implement InvalidMemory, Rule 18-8 amendment. --- amendments.csv | 2 +- ...DoNotModifyObjectsWithTemporaryLifetime.ql | 13 +- ...ointersToVariablyModifiedArrayTypesUsed.ql | 123 ++++++++++++++ .../RULE-18-8/VariableLengthArrayTypesUsed.ql | 39 ++--- ...rayToPointerConversionOfTemporaryObject.ql | 86 ++++++++++ ...eLValueSubscriptedWithTemporaryLifetime.ql | 60 +++++++ ...sToVariablyModifiedArrayTypesUsed.expected | 17 ++ ...tersToVariablyModifiedArrayTypesUsed.qlref | 1 + c/misra/test/rules/RULE-18-10/test.c | 95 +++++++++++ .../VariableLengthArrayTypesUsed.expected | 10 +- c/misra/test/rules/RULE-18-8/test.c | 30 +++- ...ointerConversionOfTemporaryObject.expected | 30 ++++ ...ToPointerConversionOfTemporaryObject.qlref | 1 + ...eSubscriptedWithTemporaryLifetime.expected | 15 ++ ...alueSubscriptedWithTemporaryLifetime.qlref | 1 + c/misra/test/rules/RULE-18-9/test.c | 151 ++++++++++++++++++ ...0-rule-18-8-vla-rule-changes-amendment4.md | 4 + .../src/codingstandards/cpp/Clvalues.qll | 17 ++ .../cpp/VariablyModifiedTypes.qll | 143 +++++++++++++++++ .../cpp/exclusions/c/InvalidMemory3.qll | 61 +++++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + .../cpp/lifetimes/CLifetimes.qll | 48 ++++++ rule_packages/c/InvalidMemory3.json | 59 +++++++ 23 files changed, 958 insertions(+), 51 deletions(-) create mode 100644 c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql create mode 100644 c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql create mode 100644 c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql create mode 100644 c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.expected create mode 100644 c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.qlref create mode 100644 c/misra/test/rules/RULE-18-10/test.c create mode 100644 c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected create mode 100644 c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.qlref create mode 100644 c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected create mode 100644 c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.qlref create mode 100644 c/misra/test/rules/RULE-18-9/test.c create mode 100644 change_notes/2024-10-10-rule-18-8-vla-rule-changes-amendment4.md create mode 100644 cpp/common/src/codingstandards/cpp/Clvalues.qll create mode 100644 cpp/common/src/codingstandards/cpp/VariablyModifiedTypes.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/InvalidMemory3.qll create mode 100644 cpp/common/src/codingstandards/cpp/lifetimes/CLifetimes.qll create mode 100644 rule_packages/c/InvalidMemory3.json diff --git a/amendments.csv b/amendments.csv index cd0085493e..ce285a29ba 100644 --- a/amendments.csv +++ b/amendments.csv @@ -15,7 +15,7 @@ c,MISRA-C-2012,Amendment4,RULE-11-3,Yes,Expand,No,Easy c,MISRA-C-2012,Amendment4,RULE-11-8,Yes,Expand,No,Easy c,MISRA-C-2012,Amendment4,RULE-13-2,Yes,Expand,No,Very Hard c,MISRA-C-2012,Amendment4,RULE-18-6,Yes,Expand,No,Medium -c,MISRA-C-2012,Amendment4,RULE-18-8,Yes,Split,No,Easy +c,MISRA-C-2012,Amendment4,RULE-18-8,Yes,Split,Yes,Easy c,MISRA-C-2012,Corrigendum2,RULE-2-2,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-2-7,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-3-1,Yes,Refine,No,Easy diff --git a/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql b/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql index 2d66b8643c..6a018ed8c4 100644 --- a/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql +++ b/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql @@ -13,18 +13,7 @@ import cpp import codingstandards.c.cert - -/** - * A struct or union type that contains an array type - */ -class StructOrUnionTypeWithArrayField extends Struct { - StructOrUnionTypeWithArrayField() { - this.getAField().getUnspecifiedType() instanceof ArrayType - or - // nested struct or union containing an array type - this.getAField().getUnspecifiedType().(Struct) instanceof StructOrUnionTypeWithArrayField - } -} +import codingstandards.cpp.lifetimes.CLifetimes // Note: Undefined behavior is possible regardless of whether the accessed field from the returned // struct is an array or a scalar (i.e. arithmetic and pointer types) member, according to the standard. diff --git a/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql b/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql new file mode 100644 index 0000000000..5a4edb4a98 --- /dev/null +++ b/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql @@ -0,0 +1,123 @@ +/** + * @id c/misra/pointers-to-variably-modified-array-types-used + * @name RULE-18-10: Pointers to variably-modified array types shall not be used + * @description Pointers to variably-modified array types shall not be used, as these pointer types + * are frequently incompatible with other fixed or variably sized arrays, resulting in + * undefined behavior. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-18-10 + * external/misra/c/2012/amendment4 + * correctness + * security + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.VariablyModifiedTypes + +/** + * Check that the declaration entry, which may be a parameter or a variable + * etc., seems to subsume the location of `inner`, including the declaration + * type text. + * + * The location of the `DeclarationEntry` itself points to the _identifier_ + * that is declared. This range will not include the type of the declaration. + * + * For parameters, the `before` and `end` `Location` objects will be + * constrained to the closest earlier element (parameter or function body), + * these values can therefore be captured and inspected for debugging. + * + * For declarations which occur in statements, the `before` and `end` + * `Location` objects will be both constrained to be equal, and equal to, + * the `Location` of the containing `DeclStmt`. + */ +predicate declarationSubsumes( + DeclarationEntry entry, Location inner, Location before, Location after +) { + inner.getFile() = entry.getLocation().getFile() and + ( + exists(ParameterDeclarationEntry param, FunctionDeclarationEntry func, int i | + param = entry and + func = param.getFunctionDeclarationEntry() and + func.getParameterDeclarationEntry(i) = param and + before = entry.getLocation() and + ( + after = func.getParameterDeclarationEntry(i + 1).getLocation() + or + not exists(ParameterDeclarationEntry afterParam | + afterParam = func.getParameterDeclarationEntry(i + 1) + ) and + after = func.getBlock().getLocation() + ) + ) and + before.isBefore(inner, _) and + inner.isBefore(after, _) + or + exists(DeclStmt s | + s.getADeclaration() = entry.getDeclaration() and + before = s.getLocation() and + after = before and + before.subsumes(inner) + ) + ) +} + +/** + * A declaration involving a pointer to a variably-modified type. + */ +class InvalidDeclaration extends DeclarationEntry { + Expr sizeExpr; + CandidateVlaType vlaType; + + // `before` and `after` are captured for debugging, see doc comment for + // `declarationSubsumes`. + Location before; + Location after; + + InvalidDeclaration() { + sizeExpr = any(VlaDimensionStmt vla).getDimensionExpr() and + declarationSubsumes(this, sizeExpr.getLocation(), before, after) and + ( + if this instanceof ParameterDeclarationEntry + then vlaType = this.getType().(VariablyModifiedTypeIfAdjusted).getInnerVlaType() + else vlaType = this.getType().(VariablyModifiedTypeIfUnadjusted).getInnerVlaType() + ) + // Capture only pointers to VLA types, not raw VLA types. + and not vlaType = this.getType() + } + + Expr getSizeExpr() { result = sizeExpr } + + CandidateVlaType getVlaType() { result = vlaType } +} + +from InvalidDeclaration v, string declstr, string adjuststr, string relationstr +where + not isExcluded(v, InvalidMemory3Package::pointersToVariablyModifiedArrayTypesUsedQuery()) and + ( + if v instanceof ParameterDeclarationEntry + then declstr = "Parameter " + else + if v instanceof VariableDeclarationEntry + then declstr = "Variable " + else declstr = "Declaration " + ) and + ( + if + v instanceof ParameterDeclarationEntry and + v.getType() instanceof ParameterAdjustedVariablyModifiedType + then adjuststr = "adjusted to" + else adjuststr = "declared with" + ) and + ( + if v.getType().(PointerType).getBaseType() instanceof CandidateVlaType + then relationstr = "pointer to" + else relationstr = "with inner" + ) +select v, + declstr + v.getName() + " is " + adjuststr + " variably-modified type, " + relationstr + + " variable length array of non constant size $@ and element type '" + + v.getVlaType().getVariableBaseType() + "'", v.getSizeExpr(), v.getSizeExpr().toString() diff --git a/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql b/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql index a7c25ed35e..96fbf697af 100644 --- a/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql +++ b/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql @@ -15,34 +15,15 @@ import cpp import codingstandards.c.misra -/** - * A variable length array (VLA) - * ie an array where the size - * is not an integer constant expression - */ -class VariableLengthArray extends VariableDeclarationEntry { - VariableLengthArray() { - //VLAs will not have: static/extern specifiers (compilation error) - not this.hasSpecifier("static") and - not this.hasSpecifier("extern") and - //VLAs are not allowed to be initialized - not this.getDeclaration().hasInitializer() and - exists(ArrayType a | - //a.hasArraySize() does not catch multidimensional VLAs like a[1][] - a.toString().matches("%[]%") and - this.getUnspecifiedType() = a and - //variable length array is one declared in block or function prototype - ( - this.getDeclaration().getParentScope() instanceof Function or - this.getDeclaration().getParentScope() instanceof BlockStmt - ) - ) - } -} - -from VariableLengthArray v +from VlaDeclStmt v, Expr size, ArrayType arrayType, string typeStr where not isExcluded(v, Declarations7Package::variableLengthArrayTypesUsedQuery()) and - //an exception, argv in : int main(int argc, char *argv[]) - not v.getDeclaration().getParentScope().(Function).hasName("main") -select v, "Variable length array declared." + size = v.getVlaDimensionStmt(0).getDimensionExpr() and + ( + arrayType = v.getVariable().getType() + or + arrayType = v.getType().getUnspecifiedType() + ) and + typeStr = arrayType.getBaseType().toString() +select v, "Variable length array of element type '" + typeStr + "' with non-constant size $@.", + size, size.toString() diff --git a/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql b/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql new file mode 100644 index 0000000000..7df4e5371c --- /dev/null +++ b/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql @@ -0,0 +1,86 @@ +/** + * @id c/misra/array-to-pointer-conversion-of-temporary-object + * @name RULE-18-9: An object with temporary lifetime shall not undergo array to pointer conversion + * @description Modifying or accessing elements of an array with temporary lifetime that has been + * converted to a pointer will result in undefined behavior. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-18-9 + * external/misra/c/2012/amendment3 + * correctness + * security + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.lifetimes.CLifetimes + +/** + * Get the expression(s) whose value is "used" by this expression. + * + * For instance, `(x)` does not use any values, but `x + y` uses `x` and `y`. + * + * A pointer-to-array conversion does not need to be flagged if the result of + * that conversion is not used or stored. + */ +Expr usedValuesOf(Expr expr) { + result = expr.(BinaryOperation).getLeftOperand() + or + result = expr.(BinaryOperation).getRightOperand() + or + result = expr.(UnaryOperation).getOperand() + or + result = expr.(ConditionalExpr).getCondition() + or + result = expr.(Call).getAnArgument() +} + +/** + * Get the expression(s) whose value is stored by this declaration. + * + * A pointer-to-array conversion does not need to be flagged if the result of + * that conversion is not used or stored. + */ +predicate isStored(Expr e) { + e = any(VariableDeclarationEntry d).getDeclaration().getInitializer().getExpr() + or + e = any(ClassAggregateLiteral l).getAFieldExpr(_) +} + +/** + * Find expressions that defer their value directly to an inner expression + * value. + * + * When an array is on the rhs of a comma expr, or in the then/else branch of a + * ternary expr, and the result us used as a pointer, then the ArrayToPointer + * conversion is marked inside comma expr/ternary expr, on the operands. These + * conversions are only non-compliant if they flow into an operation or store. + * + * Full flow analysis with localFlowStep should not be necessary, and may cast a + * wider net than needed for some queries, potentially resulting in false + * positives. + */ +Expr temporaryObjectFlowStep(Expr e) { + e = result.(CommaExpr).getRightOperand() + or + e = result.(ConditionalExpr).getThen() + or + e = result.(ConditionalExpr).getElse() +} + +from + TemporaryLifetimeArrayAccess fa, TemporaryLifetimeExpr temporary, + ArrayToPointerConversion conversion +where + not isExcluded(conversion, InvalidMemory3Package::arrayToPointerConversionOfTemporaryObjectQuery()) and + fa.getTemporary() = temporary and + conversion.getExpr() = fa and + ( + temporaryObjectFlowStep*(conversion.getExpr()) = usedValuesOf(any(Expr e)) + or + isStored(temporaryObjectFlowStep*(conversion.getExpr())) + ) +select conversion, "Array to pointer conversion of array $@ from temporary object $@", + fa.getTarget(), fa.getTarget().getName(), temporary, temporary.toString() diff --git a/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql b/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql new file mode 100644 index 0000000000..468e44f3bb --- /dev/null +++ b/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql @@ -0,0 +1,60 @@ +/** + * @id c/misra/modifiable-l-value-subscripted-with-temporary-lifetime + * @name RULE-18-9: Usage of the subscript operator on an object with temporary lifetime shall not return a modifiable value + * @description Modifying elements of an array with temporary lifetime will result in undefined + * behavior. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-18-9 + * external/misra/c/2012/amendment3 + * correctness + * security + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.lifetimes.CLifetimes + +class TemporaryLifetimeArrayExpr extends ArrayExpr { + TemporaryLifetimeArrayAccess member; + Type elementType; + + TemporaryLifetimeArrayExpr() { + member = getArrayBase() and + elementType = member.getType().(ArrayType).getBaseType() + or + exists(TemporaryLifetimeArrayExpr inner | + inner = getArrayBase() and + member = inner.getMember() and + elementType = inner.getElementType().(ArrayType).getBaseType() + ) + } + + TemporaryLifetimeArrayAccess getMember() { result = member } + + Type getElementType() { result = elementType } +} + +predicate usedAsModifiableLvalue(Expr expr) { + exists(Assignment parent | parent.getLValue() = expr) + or + exists(CrementOperation parent | parent.getOperand() = expr) + or + exists(AddressOfExpr parent | parent.getOperand() = expr) + or + exists(FieldAccess parent | parent.getQualifier() = expr and usedAsModifiableLvalue(parent)) + +} + +from TemporaryLifetimeArrayExpr expr, TemporaryLifetimeArrayAccess member +where + not isExcluded(expr, + InvalidMemory3Package::modifiableLValueSubscriptedWithTemporaryLifetimeQuery()) and + member = expr.getMember() and + not expr.isUnevaluated() and + usedAsModifiableLvalue(expr) +select expr, + "Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ ", + member, member.getTarget().getName(), member.getTemporary(), member.getTemporary().toString() diff --git a/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.expected b/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.expected new file mode 100644 index 0000000000..87cb3de5c7 --- /dev/null +++ b/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.expected @@ -0,0 +1,17 @@ +| test.c:17:11:17:12 | definition of p5 | Parameter p5 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int' | test.c:17:15:17:16 | p0 | p0 | +| test.c:18:11:18:12 | definition of p6 | Parameter p6 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:18:18:18:19 | p0 | p0 | +| test.c:19:11:19:12 | definition of p7 | Parameter p7 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int[2]' | test.c:19:15:19:16 | p0 | p0 | +| test.c:20:11:20:12 | definition of p8 | Parameter p8 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int[]' | test.c:20:15:20:16 | p0 | p0 | +| test.c:20:11:20:12 | definition of p8 | Parameter p8 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int[]' | test.c:20:19:20:20 | p0 | p0 | +| test.c:24:12:24:13 | definition of p9 | Parameter p9 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int *' | test.c:24:16:24:17 | p0 | p0 | +| test.c:25:13:25:15 | definition of p10 | Parameter p10 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int *' | test.c:25:18:25:19 | p0 | p0 | +| test.c:28:12:28:14 | definition of p11 | Parameter p11 is adjusted to variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:28:21:28:22 | p0 | p0 | +| test.c:32:17:32:19 | definition of p13 | Parameter p13 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'const int' | test.c:32:22:32:23 | p0 | p0 | +| test.c:33:18:33:20 | definition of p14 | Parameter p14 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:33:23:33:24 | p0 | p0 | +| test.c:40:12:40:14 | definition of p17 | Parameter p17 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:40:24:40:25 | p0 | p0 | +| test.c:41:14:41:16 | definition of p18 | Parameter p18 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:41:27:41:28 | p0 | p0 | +| test.c:68:9:68:11 | definition of p27 | Parameter p27 is adjusted to variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:68:13:68:14 | p0 | p0 | +| test.c:68:9:68:11 | definition of p27 | Parameter p27 is adjusted to variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:68:17:68:18 | p0 | p0 | +| test.c:74:8:74:9 | definition of l3 | Variable l3 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int' | test.c:74:12:74:13 | p0 | p0 | +| test.c:79:15:79:16 | definition of l4 | Variable l4 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int' | test.c:79:19:79:20 | p0 | p0 | +| test.c:84:17:84:19 | declaration of td3 | Declaration td3 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:84:22:84:23 | p0 | p0 | diff --git a/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.qlref b/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.qlref new file mode 100644 index 0000000000..1a60cfacca --- /dev/null +++ b/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.qlref @@ -0,0 +1 @@ +rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-10/test.c b/c/misra/test/rules/RULE-18-10/test.c new file mode 100644 index 0000000000..cf90e256e7 --- /dev/null +++ b/c/misra/test/rules/RULE-18-10/test.c @@ -0,0 +1,95 @@ +#define CONSTANT 1 + +int g1[3]; // COMPLIANT +int (*g2)[3]; // COMPLIANT +int (*g3)[CONSTANT]; // COMPLIANT + +void f1( + int p0, + + // Basic fixed length array types: + int p1[3], // COMPLIANT + int (*p2)[3], // COMPLIANT + int (*p3)[2][3], // COMPLIANT + int (*p4)[CONSTANT], // COMPLIANT + + // Basic pointers to VMTs: + int (*p5)[p0], // NON-COMPLIANT + int (*p6)[2][p0], // NON-COMPLIANT + int (*p7)[p0][2], // NON-COMPLIANT + int (*p8)[p0][p0], // NON-COMPLIANT + + // Types referring to pointers to VMTs: + // - pointer to pointer to VMT + int(*(*p9)[p0]), // NON-COMPLIANT + int(*(**p10)[p0]), // NON-COMPLIANT + + // - array of pointers to VMT + int (*(p11[3]))[p0], // NON-COMPLIANT + + // - const VMTs, const array-to-pointer adjustment + const int p12[p0], // COMPLIANT + const int (*p13)[p0], // NON-COMPLIANT + int (* const p14)[p0], // NON-COMPLIANT + + // - function types with argument that is a pointer to a VMT + int p15(int (*inner)[p0]), // NON-COMPLIANT[FALSE_NEGATIVE] + int (*p16)(int (*inner)[p0]), // NON-COMPLIANT[FALSE_NEGATIVE] + + // - function types that returns a pointer to a VMT + int (*(p17(void)))[p0], // NON-COMPLIANT + int (*((*p18)(void)))[p0], // NON-COMPLIANT + + // - structs cannot contain a VMT as a member. + struct { + int g1[3]; // COMPLIANT + int(*g2)[3]; // COMPLIANT + int(*g3)[CONSTANT]; // COMPLIANT + // Pointer to VMT (`int (*g4)[p0]`) is not allowed. + } p19, + + // - unions cannot contain a VMT as a member. + union { + int g1[3]; // COMPLIANT + int(*g2)[3]; // COMPLIANT + int(*g3)[CONSTANT]; // COMPLIANT + // Pointer to VMT (`int (*g4)[p0]`) is not allowed. + } p20, + + // Unknown array length types: + int p21[], // COMPLIANT + int p22[][], // COMPLIANT + int (*p23)[], // COMPLIANT + int (*p24)[2][], // COMPLIANT + int (*p25)[][2], // COMPLIANT + + // VLA types that are rewritten as pointers: + int p26[p0], // COMPLIANT + int p27[p0][p0] // NON-COMPLIANT +) { + // Local variables may contain pointers to VMTs: + int l0[p0]; // COMPLIANT + int(*l1)[]; // COMPLIANT + int(*l2)[3]; // COMPLIANT + int(*l3)[p0]; // NON-COMPLIANT + + int l6[10] = p23; + + // A pointer to a VMT may be declared `static`. + static int(*l4)[p0]; // NON-COMPLIANT + + // Block scope typedefs may refer to VMTs + typedef int (*td1)[3]; // COMPLIANT + typedef int (*td2)[]; // COMPLIANT + typedef int (*td3)[p0]; // NON-COMPLIANT + + td3 l5; // NON-COMPLIANT +} + +// Function prototypes may contain VMTs using '*' syntax: +void f2(int (*p1)[3], // COMPLIANT + int (*p2)[*], // NON-COMPLIANT[FALSE_NEGATIVE] + int (*p3)[2][*], // NON-COMPLIANT[FALSE_NEGATIVE] + int (*p4)[*][2], // NON-COMPLIANT[FALSE_NEGATIVE] + int (*p5)[*][*] // NON-COMPLIANT[FALSE_NEGATIVE] +); \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-8/VariableLengthArrayTypesUsed.expected b/c/misra/test/rules/RULE-18-8/VariableLengthArrayTypesUsed.expected index e9721ce642..24856619bf 100644 --- a/c/misra/test/rules/RULE-18-8/VariableLengthArrayTypesUsed.expected +++ b/c/misra/test/rules/RULE-18-8/VariableLengthArrayTypesUsed.expected @@ -1,5 +1,5 @@ -| test.c:3:19:3:20 | definition of pa | Variable length array declared. | -| test.c:6:7:6:8 | definition of a1 | Variable length array declared. | -| test.c:7:7:7:8 | definition of a2 | Variable length array declared. | -| test.c:8:7:8:8 | definition of a3 | Variable length array declared. | -| test.c:14:20:14:21 | definition of pa | Variable length array declared. | +| test.c:6:7:6:7 | VLA declaration | Variable length array of element type 'int' with non-constant size $@. | test.c:6:10:6:14 | ... + ... | ... + ... | +| test.c:7:7:7:7 | VLA declaration | Variable length array of element type 'int' with non-constant size $@. | test.c:7:10:7:10 | n | n | +| test.c:8:7:8:7 | VLA declaration | Variable length array of element type 'int[]' with non-constant size $@. | test.c:8:13:8:13 | n | n | +| test.c:12:7:12:7 | VLA declaration | Variable length array of element type 'int[1]' with non-constant size $@. | test.c:12:10:12:10 | n | n | +| test.c:18:15:18:15 | VLA declaration | Variable length array of element type 'int' with non-constant size $@. | test.c:18:26:18:26 | n | n | diff --git a/c/misra/test/rules/RULE-18-8/test.c b/c/misra/test/rules/RULE-18-8/test.c index 3a0a040f6d..c2f6027216 100644 --- a/c/misra/test/rules/RULE-18-8/test.c +++ b/c/misra/test/rules/RULE-18-8/test.c @@ -1,7 +1,7 @@ #define TEST 1 -void f(int n, int pa[1][n]) { // NON_COMPLIANT - int a[1]; // COMPLIANT +void f(int n) { + int a[1]; // COMPLIANT int x = 1; int a1[1 + x]; // NON_COMPLIANT - not integer constant expr int a2[n]; // NON_COMPLIANT @@ -9,7 +9,29 @@ void f(int n, int pa[1][n]) { // NON_COMPLIANT int a4[] = {1}; // COMPLIANT - not a VLA int a5[TEST]; // COMPLIANT int a6[1 + 1]; // COMPLIANT + int a7[n][1]; // NON_COMPLIANT + int(*a8)[n]; // COMPLIANT - pointer to VLA, see RULE-18-10 + + extern int e1[]; // COMPLIANT + + // A typedef is not a VLA. However, `VlaDeclStmt`s match the typedef. + typedef int vlaTypedef[n]; // COMPLIANT[FALSE_POSITIVE] + vlaTypedef t1; // NON_COMPLIANT[FALSE_NEGATIVE] } -void f1(int n, int pa[n]) { // NON_COMPLIANT -} \ No newline at end of file +void f1(int n, + // Parameter array types are adjusted to pointers + int p1[n], // COMPLIANT + // Pointers to variably-modified types are not VLAs. + int p2[n][n], + int p3[], // array of unknown length is converted to pointer + int p4[][] // array of unknown length are not VLAs. +) {} + +struct s { + // Structs must have at least one non-flexible array member. + int foo; + + // Flexible array members are not VLAs. + int flexibleArrayMember[]; // COMPLIANT +}; \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected b/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected new file mode 100644 index 0000000000..7d760dc4a6 --- /dev/null +++ b/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected @@ -0,0 +1,30 @@ +| test.c:45:3:45:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:45:3:45:8 | call to get_s1 | call to get_s1 | +| test.c:46:3:46:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:46:3:46:8 | call to get_s1 | call to get_s1 | +| test.c:47:7:47:24 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:47:7:47:12 | call to get_s1 | call to get_s1 | +| test.c:48:4:48:21 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:48:4:48:9 | call to get_s1 | call to get_s1 | +| test.c:49:4:49:21 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:49:4:49:9 | call to get_s1 | call to get_s1 | +| test.c:50:3:50:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:50:3:50:8 | call to get_s1 | call to get_s1 | +| test.c:51:3:51:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:51:3:51:8 | call to get_s1 | call to get_s1 | +| test.c:52:3:52:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:52:3:52:8 | call to get_s1 | call to get_s1 | +| test.c:53:3:53:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:53:3:53:8 | call to get_s1 | call to get_s1 | +| test.c:54:3:54:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:54:3:54:8 | call to get_s1 | call to get_s1 | +| test.c:55:8:55:25 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:55:8:55:13 | call to get_s1 | call to get_s1 | +| test.c:56:3:56:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:56:3:56:8 | call to get_s1 | call to get_s1 | +| test.c:57:8:57:25 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:57:8:57:13 | call to get_s1 | call to get_s1 | +| test.c:58:3:58:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:58:3:58:8 | call to get_s1 | call to get_s1 | +| test.c:59:3:59:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:59:3:59:8 | call to get_s1 | call to get_s1 | +| test.c:60:15:60:32 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:60:15:60:20 | call to get_s1 | call to get_s1 | +| test.c:61:16:61:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:61:16:61:21 | call to get_s1 | call to get_s1 | +| test.c:62:23:62:40 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:62:23:62:28 | call to get_s1 | call to get_s1 | +| test.c:63:7:63:24 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:63:7:63:12 | call to get_s1 | call to get_s1 | +| test.c:64:16:64:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:64:16:64:21 | call to get_s1 | call to get_s1 | +| test.c:65:15:65:32 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:65:15:65:20 | call to get_s1 | call to get_s1 | +| test.c:66:16:66:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:66:16:66:21 | call to get_s1 | call to get_s1 | +| test.c:67:23:67:40 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:67:23:67:28 | call to get_s1 | call to get_s1 | +| test.c:89:3:89:30 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:89:12:89:20 | member_s1 | member_s1 | +| test.c:90:3:90:36 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:90:3:90:26 | access to array | access to array | +| test.c:91:15:91:42 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:91:24:91:32 | member_s1 | member_s1 | +| test.c:92:15:92:48 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:92:15:92:38 | access to array | access to array | +| test.c:111:15:111:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:111:16:111:22 | ... = ... | ... = ... | +| test.c:113:15:113:37 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:113:16:113:26 | ... ? ... : ... | ... ? ... : ... | +| test.c:114:15:114:31 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:114:16:114:20 | ... , ... | ... , ... | diff --git a/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.qlref b/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.qlref new file mode 100644 index 0000000000..d2db40e77c --- /dev/null +++ b/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.qlref @@ -0,0 +1 @@ +rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected b/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected new file mode 100644 index 0000000000..ae140dcd59 --- /dev/null +++ b/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected @@ -0,0 +1,15 @@ +| test.c:80:3:80:17 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:80:12:80:14 | arr | arr | test.c:80:3:80:8 | call to get_s1 | call to get_s1 | +| test.c:81:3:81:17 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:81:12:81:14 | arr | arr | test.c:81:3:81:8 | call to get_s1 | call to get_s1 | +| test.c:82:3:82:17 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:82:12:82:14 | arr | arr | test.c:82:3:82:8 | call to get_s1 | call to get_s1 | +| test.c:83:3:83:17 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:83:12:83:14 | arr | arr | test.c:83:3:83:8 | call to get_s1 | call to get_s1 | +| test.c:84:5:84:19 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:84:14:84:16 | arr | arr | test.c:84:5:84:10 | call to get_s1 | call to get_s1 | +| test.c:93:3:93:27 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:93:22:93:24 | arr | arr | test.c:93:12:93:20 | member_s1 | member_s1 | +| test.c:94:3:94:27 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:94:22:94:24 | arr | arr | test.c:94:3:94:20 | access to array | access to array | +| test.c:137:3:137:23 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:137:12:137:20 | arr_union | arr_union | test.c:137:3:137:8 | call to get_s3 | call to get_s3 | +| test.c:138:3:138:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:138:12:138:21 | arr_struct | arr_struct | test.c:138:3:138:8 | call to get_s3 | call to get_s3 | +| test.c:139:3:139:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:139:12:139:21 | arr_struct | arr_struct | test.c:139:3:139:8 | call to get_s3 | call to get_s3 | +| test.c:140:3:140:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:140:12:140:21 | arr_struct | arr_struct | test.c:140:3:140:8 | call to get_s3 | call to get_s3 | +| test.c:141:3:141:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:141:12:141:21 | arr_struct | arr_struct | test.c:141:3:141:8 | call to get_s3 | call to get_s3 | +| test.c:142:4:142:25 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:142:13:142:22 | arr_struct | arr_struct | test.c:142:4:142:9 | call to get_s3 | call to get_s3 | +| test.c:146:3:146:22 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:146:12:146:16 | arr2d | arr2d | test.c:146:3:146:8 | call to get_s3 | call to get_s3 | +| test.c:147:4:147:20 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:147:13:147:17 | arr2d | arr2d | test.c:147:4:147:9 | call to get_s3 | call to get_s3 | diff --git a/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.qlref b/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.qlref new file mode 100644 index 0000000000..c1fb0bd2d4 --- /dev/null +++ b/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.qlref @@ -0,0 +1 @@ +rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-9/test.c b/c/misra/test/rules/RULE-18-9/test.c new file mode 100644 index 0000000000..f2fb44fdc9 --- /dev/null +++ b/c/misra/test/rules/RULE-18-9/test.c @@ -0,0 +1,151 @@ +struct s1 { + int m1; + const int const_arr[10]; + int arr[10]; +}; + +struct s1 get_s1(); + +struct s2 { + struct s1 member_s1; + struct s1 const const_s1_arr[10]; + struct s1 *s1ptr; + struct s1 s1_arr[10]; +}; + +struct s2 get_s2(); +struct s2 *get_s2_ptr(); + +void use_int(int x) {} +void use_int_ptr(int *x) {} + +void f(void) { + struct s1 l1; + + // Auto lifetime, allowed: + l1.const_arr + 1; // COMPLIANT + l1.const_arr - 1; // COMPLIANT + &l1.const_arr; // COMPLIANT + use_int_ptr(l1.const_arr); // COMPLIANT + l1.arr[0] = 1; // COMPLIANT + + // Extern lifetime, allowed: + extern struct s1 g1; + g1.const_arr + 1; // COMPLIANT + g1.const_arr - 1; // COMPLIANT + &g1.const_arr; // COMPLIANT + use_int_ptr(g1.const_arr); // COMPLIANT + g1.arr[0] = 1; // COMPLIANT + + // Temporary lifetime, no conversion: + get_s1().const_arr; // COMPLIANT - not used as a value. + get_s1().m1 + 1; // COMPLIANT - not an array. + + // Temporary lifetime, array to pointer conversions: + get_s1().const_arr + 1; // NON-COMPLIANT + get_s1().const_arr - 1; // NON-COMPLIANT + 1 + get_s1().const_arr; // NON-COMPLIANT + *get_s1().const_arr; // NON-COMPLIANT + !get_s1().const_arr; // NON-COMPLIANT + get_s1().const_arr < 1; // NON-COMPLIANT + get_s1().const_arr <= 1; // NON-COMPLIANT + get_s1().const_arr > 1; // NON-COMPLIANT + get_s1().const_arr >= 1; // NON-COMPLIANT + get_s1().const_arr == 1; // NON-COMPLIANT + 1 == get_s1().const_arr; // NON-COMPLIANT + get_s1().const_arr && 1; // NON-COMPLIANT + 1 && get_s1().const_arr; // NON-COMPLIANT + get_s1().const_arr || 1; // NON-COMPLIANT + get_s1().const_arr ? 1 : 1; // NON-COMPLIANT + use_int_ptr(get_s1().const_arr); // NON-COMPLIANT + use_int_ptr((get_s1().const_arr)); // NON-COMPLIANT + use_int_ptr((void *)get_s1().const_arr); // NON-COMPLIANT + (1, get_s1().const_arr) + 1; // NON-COMPLIANT + int *local = get_s1().const_arr; // NON-COMPLIANT + (struct s1){get_s1().const_arr}; // NON-COMPLIANT + (struct s2){{get_s1().const_arr}}; // NON-COMPLIANT + struct s1 local2 = {get_s1().const_arr}; // NON-COMPLIANT + + // Results are not 'used' as a value. + (void *)get_s1().const_arr; // COMPLIANT + sizeof(get_s1().const_arr); // COMPLIANT + get_s1().const_arr, 1; // COMPLIANT + 1, get_s1().const_arr; // COMPLIANT + (get_s1().const_arr); // COMPLIANT + + get_s1().const_arr[0]; // COMPLIANT - subscripted value not modifiable + get_s1().arr[0]; // COMPLIANT - subscripted value not used as modifiable + use_int(get_s1().const_arr[0]); // COMPLIANT + use_int(get_s1().arr[0]); // COMPLIANT + get_s1().arr[0] = 1; // NON-COMPLIANT + get_s1().arr[0] -= 1; // NON-COMPLIANT + get_s1().arr[0]--; // NON-COMPLIANT + get_s1().arr[0]++; // NON-COMPLIANT + &(get_s1().arr[0]); // NON-COMPLIANT + + struct s2 l2; + + // Deeper accesses: + get_s2().member_s1.const_arr + 1; // NON-COMPLIANT + get_s2().const_s1_arr[0].const_arr + 1; // NON-COMPLIANT + use_int_ptr(get_s2().member_s1.const_arr); // NON-COMPLIANT + use_int_ptr(get_s2().const_s1_arr[0].const_arr); // NON-COMPLIANT + get_s2().member_s1.arr[0] = 1; // NON-COMPLIANT + get_s2().s1_arr[0].arr[0] = 1; // NON-COMPLIANT + get_s2().member_s1.const_arr[0]; // COMPLIANT + get_s2().const_s1_arr[0].const_arr[0]; // COMPLIANT + get_s2().s1_arr[0].const_arr[0]; // COMPLIANT + get_s2().s1ptr->const_arr[0]; // COMPLIANT + use_int(get_s2().member_s1.const_arr[0]); // COMPLIANT + use_int(get_s2().const_s1_arr[0].const_arr[0]); // COMPLIANT + use_int(get_s2().s1ptr->const_arr[0]); // COMPLIANT + + // Pointer members of a struct don't have temporary lifetime. + get_s2().s1ptr->const_arr + 1; // COMPLIANT + use_int_ptr(get_s2().s1ptr->const_arr); // COMPLIANT + get_s2().s1ptr->arr[0] = 1; // COMPLIANT + get_s2_ptr()->member_s1.const_arr + 1; // COMPLIANT + get_s2_ptr()->member_s1.arr[0] = 1; // COMPLIANT + + // Other types of non-lvalue types + use_int_ptr((l1 = l1).const_arr); // NON-COMPLIANT + use_int_ptr(((struct s1)l1).const_arr); // NON-COMPLIANT[FALSE_NEGATIVE] + use_int_ptr((1 ? l1 : l1).const_arr); // NON-COMPLIANT + use_int_ptr((0, l1).const_arr); // NON-COMPLIANT + use_int_ptr((l2.s1ptr++)->const_arr); // COMPLIANT + use_int_ptr((--l2.s1ptr)->const_arr); // COMPLIANT +} + +// Additional modifiable lvalue tests +struct s3 { + struct s4 { + struct s5 { + struct s6 { + int x; + } m1; + } m1; + } arr_struct[1]; + + union u1 { + int x; + } arr_union[1]; + + int arr2d[1][1]; +} get_s3(); + +void f2(void) { + get_s3().arr_union[0].x = 1; // NON_COMPLIANT + get_s3().arr_struct[0] = (struct s4){0}; // NON_COMPLIANT + get_s3().arr_struct[0].m1 = (struct s5){0}; // NON_COMPLIANT + get_s3().arr_struct[0].m1.m1 = (struct s6){0}; // NON_COMPLIANT + get_s3().arr_struct[0].m1.m1.x = 1; // NON_COMPLIANT + &get_s3().arr_struct[0].m1.m1.x; // NON_COMPLIANT + get_s3().arr_struct[0].m1.m1.x + 1; // COMPLIANT + + get_s3().arr2d[1][1] + 1; // COMPLIANT + get_s3().arr2d[1][1] = 1; // NON_COMPLIANT + &get_s3().arr2d[1]; // NON_COMPLIANT + // The following cases are missing an ArrayToPointerConversion + use_int_ptr(get_s3().arr2d[1]); // NON_COMPLIANT[FALSE NEGATIVE] + get_s3().arr2d[1] + 1; // NON_COMPLIANT[FALSE NEGATIVE] +} \ No newline at end of file diff --git a/change_notes/2024-10-10-rule-18-8-vla-rule-changes-amendment4.md b/change_notes/2024-10-10-rule-18-8-vla-rule-changes-amendment4.md new file mode 100644 index 0000000000..f465836052 --- /dev/null +++ b/change_notes/2024-10-10-rule-18-8-vla-rule-changes-amendment4.md @@ -0,0 +1,4 @@ +- `RULE-18-8` - `VariableLengthArrayTypesUsed.ql`: + - Implement changes declared in MISRA C 2012 Amendment 4. This rule now only bans the use of VLA objects. Rules restricting the use of VLA types -- specifically, pointers to VLA types -- are now implemented in `RULE-18-10`. +- `EXP-35-C` - `DoNotModifyObjectsWithTemporaryLifetime.ql` + - Refactor component into a shared library, should not have any effect on rule results. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Clvalues.qll b/cpp/common/src/codingstandards/cpp/Clvalues.qll new file mode 100644 index 0000000000..2e330e0732 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Clvalues.qll @@ -0,0 +1,17 @@ +import cpp + +/** + * An lvalue in C (as opposed to C++). + * + * Note that `Expr.isLValue()` matches for C++ lvalues, which is a larger set + * than the set of C lvalues. + */ +predicate isCLValue(Expr expr) { + expr instanceof PointerFieldAccess + or + expr.isLValue() and + not expr instanceof ConditionalExpr and + not expr instanceof AssignExpr and + not expr instanceof CommaExpr and + not exists(Cast c | c = expr.getConversion*()) +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/VariablyModifiedTypes.qll b/cpp/common/src/codingstandards/cpp/VariablyModifiedTypes.qll new file mode 100644 index 0000000000..730a52d763 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/VariablyModifiedTypes.qll @@ -0,0 +1,143 @@ +import cpp + +/** + * A candidate to be a variably length array type (VLA). + * + * This class represents a candidate only, for a few reasons. + * + * Firstly, the `ArrayType` class does not know when it has variable size, so + * this class matches all array types with unknown size, including `x[]` which + * is not a VLA. To determine the difference, we must compare locations between + * where * these types are declared, and the location of `VlaDecl`s etc. + * + * Secondly, function parameters of array type are adjusted into pointers. This + * means that while a parameter type can be a `CandidateVlaType`, that + * parameter is not a VLA. + */ +class CandidateVlaType extends ArrayType { + CandidateVlaType() { not hasArraySize() } + + Type getVariableBaseType() { result = this.getBaseType() } +} + +/** + * A type that is a variably modified type (VMT) if it does not undergo + * parameter type adjustment. + * + * A variably modified type is a VLA type, or a type containing a VMT type, for + * instance, a pointer to a VLA or a pointer to a pointer to a VLA. + * + * Function parameters and function type parameters of type `T[]` are adjusted + * to type `T*`, which can turn VMTs into non-VMTs. To check if a parameter + * type is a VMT, use `VariablyModifiedTypeIfAdjusted`. + */ +class VariablyModifiedTypeIfUnadjusted extends Type { + CandidateVlaType innerVlaType; + + VariablyModifiedTypeIfUnadjusted() { + // Take care that `int[x][y]` only matches for `innerVlaType = int[y]`. + if this instanceof CandidateVlaType + then innerVlaType = this + else innerVlaType = this.(NoAdjustmentVariablyModifiedType).getInnerVlaType() + } + + CandidateVlaType getInnerVlaType() { result = innerVlaType } +} + +/** + * A type that is a variably modified type (VMT) if it undergoes parameter type + * adjustment. + * + * A variably modified type is a VLA type, or a type containing a VMT type, for + * instance, a pointer to a VLA or a pointer to a pointer to a VLA. + * + * Function parameters and function type parameters of type `T[]` are adjusted + * to type `T*`, which can turn VMTs into non-VMTs. To check if a non-parameter + * type (for instance, the type of a local variable) is a VMT, use + * `VariablyModifiedTypeIfUnadjusted`. + */ +class VariablyModifiedTypeIfAdjusted extends Type { + CandidateVlaType innerVlaType; + + VariablyModifiedTypeIfAdjusted() { + innerVlaType = this.(ParameterAdjustedVariablyModifiedType).getInnerVlaType() + or + innerVlaType = this.(NoAdjustmentVariablyModifiedType).getInnerVlaType() + } + + CandidateVlaType getInnerVlaType() { result = innerVlaType } +} + +/** + * A variably modified type candidate which is unaffected by parameter type + * adjustment (from `T[]` to `*T`). + * + * Parameter adjustment (from `T[]` to `*T`) occurs on all function parameter + * types for exactly one level of depth. + * + * A variably-modified type (VMT) is a type which includes an inner type that is + * a VLA type. That is to say, a pointer to a VLA is a VMT, and a pointer to a + * VMT is a VMT. + * + * Note: This class does *not* match all VLA types. While VLA types *are* VMTs, + * VMTs can be parameter-adjusted to pointers, which are not VLA types. This + * class *will* match multidimensional VLAs, as those are adjusted to pointers + * to VLAs, and pointers to VLAs are VMTs. + */ +class NoAdjustmentVariablyModifiedType extends Type { + CandidateVlaType vlaType; + + NoAdjustmentVariablyModifiedType() { + exists(Type innerType | + ( + innerType = this.(PointerType).getBaseType() + or + innerType = this.(ArrayType).getBaseType() + or + innerType = this.(RoutineType).getReturnType() + or + innerType = this.(RoutineType).getAParameterType() + or + innerType = this.(FunctionPointerType).getReturnType() + or + innerType = this.(TypedefType).getBaseType() + or + innerType = this.(SpecifiedType).getBaseType() + ) and + vlaType = innerType.(VariablyModifiedTypeIfUnadjusted).getInnerVlaType() + ) + or + vlaType = + this.(FunctionPointerType) + .getAParameterType() + .(VariablyModifiedTypeIfAdjusted) + .getInnerVlaType() + or + vlaType = + this.(RoutineType).getAParameterType().(VariablyModifiedTypeIfAdjusted).getInnerVlaType() + } + + CandidateVlaType getInnerVlaType() { result = vlaType } +} + +/** + * An array type that adjusts to a variably-modified type (a type which is or + * contains a VLA type) when it is a parameter type. + * + * A variably-modified type (VMT) is a VLA type or a type which has an inner type + * that is a VMT type, for instance, a pointer to a VLA type. + * + * Parameter adjustment occurs on all function parameter types, changing type + * `T[]` to `*T` for exactly one level of depth. Therefore, a VLA type will not + * be a VLA type/VMT after parameter adjustment, unless it is an array of VMTs, + * such that it parameter adjustment produces a pointer to a VMT. + */ +class ParameterAdjustedVariablyModifiedType extends ArrayType { + CandidateVlaType innerVlaType; + + ParameterAdjustedVariablyModifiedType() { + innerVlaType = getBaseType().(VariablyModifiedTypeIfUnadjusted).getInnerVlaType() + } + + CandidateVlaType getInnerVlaType() { result = innerVlaType } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/InvalidMemory3.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/InvalidMemory3.qll new file mode 100644 index 0000000000..c4e39882ec --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/InvalidMemory3.qll @@ -0,0 +1,61 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype InvalidMemory3Query = + TPointersToVariablyModifiedArrayTypesUsedQuery() or + TArrayToPointerConversionOfTemporaryObjectQuery() or + TModifiableLValueSubscriptedWithTemporaryLifetimeQuery() + +predicate isInvalidMemory3QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `pointersToVariablyModifiedArrayTypesUsed` query + InvalidMemory3Package::pointersToVariablyModifiedArrayTypesUsedQuery() and + queryId = + // `@id` for the `pointersToVariablyModifiedArrayTypesUsed` query + "c/misra/pointers-to-variably-modified-array-types-used" and + ruleId = "RULE-18-10" and + category = "mandatory" + or + query = + // `Query` instance for the `arrayToPointerConversionOfTemporaryObject` query + InvalidMemory3Package::arrayToPointerConversionOfTemporaryObjectQuery() and + queryId = + // `@id` for the `arrayToPointerConversionOfTemporaryObject` query + "c/misra/array-to-pointer-conversion-of-temporary-object" and + ruleId = "RULE-18-9" and + category = "required" + or + query = + // `Query` instance for the `modifiableLValueSubscriptedWithTemporaryLifetime` query + InvalidMemory3Package::modifiableLValueSubscriptedWithTemporaryLifetimeQuery() and + queryId = + // `@id` for the `modifiableLValueSubscriptedWithTemporaryLifetime` query + "c/misra/modifiable-l-value-subscripted-with-temporary-lifetime" and + ruleId = "RULE-18-9" and + category = "required" +} + +module InvalidMemory3Package { + Query pointersToVariablyModifiedArrayTypesUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `pointersToVariablyModifiedArrayTypesUsed` query + TQueryC(TInvalidMemory3PackageQuery(TPointersToVariablyModifiedArrayTypesUsedQuery())) + } + + Query arrayToPointerConversionOfTemporaryObjectQuery() { + //autogenerate `Query` type + result = + // `Query` type for `arrayToPointerConversionOfTemporaryObject` query + TQueryC(TInvalidMemory3PackageQuery(TArrayToPointerConversionOfTemporaryObjectQuery())) + } + + Query modifiableLValueSubscriptedWithTemporaryLifetimeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `modifiableLValueSubscriptedWithTemporaryLifetime` query + TQueryC(TInvalidMemory3PackageQuery(TModifiableLValueSubscriptedWithTemporaryLifetimeQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 581585da5c..ca2097f073 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -37,6 +37,7 @@ import IO4 import IntegerOverflow import InvalidMemory1 import InvalidMemory2 +import InvalidMemory3 import Language1 import Language2 import Language3 @@ -111,6 +112,7 @@ newtype TCQuery = TIntegerOverflowPackageQuery(IntegerOverflowQuery q) or TInvalidMemory1PackageQuery(InvalidMemory1Query q) or TInvalidMemory2PackageQuery(InvalidMemory2Query q) or + TInvalidMemory3PackageQuery(InvalidMemory3Query q) or TLanguage1PackageQuery(Language1Query q) or TLanguage2PackageQuery(Language2Query q) or TLanguage3PackageQuery(Language3Query q) or @@ -185,6 +187,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isIntegerOverflowQueryMetadata(query, queryId, ruleId, category) or isInvalidMemory1QueryMetadata(query, queryId, ruleId, category) or isInvalidMemory2QueryMetadata(query, queryId, ruleId, category) or + isInvalidMemory3QueryMetadata(query, queryId, ruleId, category) or isLanguage1QueryMetadata(query, queryId, ruleId, category) or isLanguage2QueryMetadata(query, queryId, ruleId, category) or isLanguage3QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/lifetimes/CLifetimes.qll b/cpp/common/src/codingstandards/cpp/lifetimes/CLifetimes.qll new file mode 100644 index 0000000000..d27034f50d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/lifetimes/CLifetimes.qll @@ -0,0 +1,48 @@ +import cpp +import codingstandards.cpp.Clvalues + +/** + * A struct or union type that contains an array type. + */ +class StructOrUnionTypeWithArrayField extends Struct { + StructOrUnionTypeWithArrayField() { + this.getAField().getUnspecifiedType() instanceof ArrayType + or + // nested struct or union containing an array type + this.getAField().getUnspecifiedType().(Struct) instanceof StructOrUnionTypeWithArrayField + } +} + +/** + * A non-lvalue expression with struct or or union type that has a field member + * of array type, has a temporary lifetime. + * + * The array members are also part of that object, and thus also have temporary + * lifetime. + */ +class TemporaryLifetimeExpr extends Expr { + TemporaryLifetimeExpr() { + getUnconverted().getUnspecifiedType() instanceof StructOrUnionTypeWithArrayField and + not isCLValue(this) + or + this.(ArrayExpr).getArrayBase() instanceof TemporaryLifetimeArrayAccess + } +} + +/** + * A field access on a temporary object that returns an array member. + */ +class TemporaryLifetimeArrayAccess extends FieldAccess { + // The temporary lifetime object which owns the array that is returned. + TemporaryLifetimeExpr temporary; + + TemporaryLifetimeArrayAccess() { + getQualifier().getUnconverted() = temporary and + getUnspecifiedType() instanceof ArrayType + } + + /** + * Get the temporary lifetime object which own the array that is returned. + */ + Expr getTemporary() { result = temporary } +} diff --git a/rule_packages/c/InvalidMemory3.json b/rule_packages/c/InvalidMemory3.json new file mode 100644 index 0000000000..feeb8b2b47 --- /dev/null +++ b/rule_packages/c/InvalidMemory3.json @@ -0,0 +1,59 @@ +{ + "MISRA-C-2012": { + "RULE-18-10": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Pointers to variably-modified array types shall not be used, as these pointer types are frequently incompatible with other fixed or variably sized arrays, resulting in undefined behavior.", + "kind": "problem", + "name": "Pointers to variably-modified array types shall not be used", + "precision": "high", + "severity": "error", + "short_name": "PointersToVariablyModifiedArrayTypesUsed", + "tags": [ + "external/misra/c/2012/amendment4", + "correctness", + "security" + ] + } + ], + "title": "Pointers to variably-modified array types shall not be used" + }, + "RULE-18-9": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Modifying or accessing elements of an array with temporary lifetime that has been converted to a pointer will result in undefined behavior.", + "kind": "problem", + "name": "An object with temporary lifetime shall not undergo array to pointer conversion", + "precision": "high", + "severity": "error", + "short_name": "ArrayToPointerConversionOfTemporaryObject", + "tags": [ + "external/misra/c/2012/amendment3", + "correctness", + "security" + ] + }, + { + "description": "Modifying elements of an array with temporary lifetime will result in undefined behavior.", + "kind": "problem", + "name": "Usage of the subscript operator on an object with temporary lifetime shall not return a modifiable value", + "precision": "high", + "severity": "error", + "short_name": "ModifiableLValueSubscriptedWithTemporaryLifetime", + "tags": [ + "external/misra/c/2012/amendment3", + "correctness", + "security" + ] + } + ], + "title": "An object with temporary lifetime shall not undergo array to pointer conversion" + } + } +} \ No newline at end of file From 5b5777f324fe95090641e5cd8eb922b176377f6a Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 16 Oct 2024 17:03:59 -0700 Subject: [PATCH 052/628] Fix formatting --- ...PointersToVariablyModifiedArrayTypesUsed.ql | 11 +++++------ ...leLValueSubscriptedWithTemporaryLifetime.ql | 1 - ...rsToVariablyModifiedArrayTypesUsed.expected | 4 ++-- c/misra/test/rules/RULE-18-10/test.c | 18 +++++++++--------- .../src/codingstandards/cpp/Clvalues.qll | 2 +- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql b/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql index 5a4edb4a98..fec8f5d2e1 100644 --- a/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql +++ b/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql @@ -22,14 +22,14 @@ import codingstandards.cpp.VariablyModifiedTypes * Check that the declaration entry, which may be a parameter or a variable * etc., seems to subsume the location of `inner`, including the declaration * type text. - * + * * The location of the `DeclarationEntry` itself points to the _identifier_ * that is declared. This range will not include the type of the declaration. - * + * * For parameters, the `before` and `end` `Location` objects will be * constrained to the closest earlier element (parameter or function body), * these values can therefore be captured and inspected for debugging. - * + * * For declarations which occur in statements, the `before` and `end` * `Location` objects will be both constrained to be equal, and equal to, * the `Location` of the containing `DeclStmt`. @@ -71,7 +71,6 @@ predicate declarationSubsumes( class InvalidDeclaration extends DeclarationEntry { Expr sizeExpr; CandidateVlaType vlaType; - // `before` and `after` are captured for debugging, see doc comment for // `declarationSubsumes`. Location before; @@ -84,9 +83,9 @@ class InvalidDeclaration extends DeclarationEntry { if this instanceof ParameterDeclarationEntry then vlaType = this.getType().(VariablyModifiedTypeIfAdjusted).getInnerVlaType() else vlaType = this.getType().(VariablyModifiedTypeIfUnadjusted).getInnerVlaType() - ) + ) and // Capture only pointers to VLA types, not raw VLA types. - and not vlaType = this.getType() + not vlaType = this.getType() } Expr getSizeExpr() { result = sizeExpr } diff --git a/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql b/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql index 468e44f3bb..f8a341b9bd 100644 --- a/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql +++ b/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql @@ -45,7 +45,6 @@ predicate usedAsModifiableLvalue(Expr expr) { exists(AddressOfExpr parent | parent.getOperand() = expr) or exists(FieldAccess parent | parent.getQualifier() = expr and usedAsModifiableLvalue(parent)) - } from TemporaryLifetimeArrayExpr expr, TemporaryLifetimeArrayAccess member diff --git a/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.expected b/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.expected index 87cb3de5c7..76b3da5eb0 100644 --- a/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.expected +++ b/c/misra/test/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.expected @@ -7,11 +7,11 @@ | test.c:25:13:25:15 | definition of p10 | Parameter p10 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int *' | test.c:25:18:25:19 | p0 | p0 | | test.c:28:12:28:14 | definition of p11 | Parameter p11 is adjusted to variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:28:21:28:22 | p0 | p0 | | test.c:32:17:32:19 | definition of p13 | Parameter p13 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'const int' | test.c:32:22:32:23 | p0 | p0 | -| test.c:33:18:33:20 | definition of p14 | Parameter p14 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:33:23:33:24 | p0 | p0 | +| test.c:33:17:33:19 | definition of p14 | Parameter p14 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:33:22:33:23 | p0 | p0 | | test.c:40:12:40:14 | definition of p17 | Parameter p17 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:40:24:40:25 | p0 | p0 | | test.c:41:14:41:16 | definition of p18 | Parameter p18 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:41:27:41:28 | p0 | p0 | | test.c:68:9:68:11 | definition of p27 | Parameter p27 is adjusted to variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:68:13:68:14 | p0 | p0 | | test.c:68:9:68:11 | definition of p27 | Parameter p27 is adjusted to variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:68:17:68:18 | p0 | p0 | | test.c:74:8:74:9 | definition of l3 | Variable l3 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int' | test.c:74:12:74:13 | p0 | p0 | | test.c:79:15:79:16 | definition of l4 | Variable l4 is declared with variably-modified type, pointer to variable length array of non constant size $@ and element type 'int' | test.c:79:19:79:20 | p0 | p0 | -| test.c:84:17:84:19 | declaration of td3 | Declaration td3 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:84:22:84:23 | p0 | p0 | +| test.c:84:16:84:18 | declaration of td3 | Declaration td3 is declared with variably-modified type, with inner variable length array of non constant size $@ and element type 'int' | test.c:84:21:84:22 | p0 | p0 | diff --git a/c/misra/test/rules/RULE-18-10/test.c b/c/misra/test/rules/RULE-18-10/test.c index cf90e256e7..dbddbecec8 100644 --- a/c/misra/test/rules/RULE-18-10/test.c +++ b/c/misra/test/rules/RULE-18-10/test.c @@ -21,16 +21,16 @@ void f1( // Types referring to pointers to VMTs: // - pointer to pointer to VMT - int(*(*p9)[p0]), // NON-COMPLIANT + int(*(*p9)[p0]), // NON-COMPLIANT int(*(**p10)[p0]), // NON-COMPLIANT // - array of pointers to VMT int (*(p11[3]))[p0], // NON-COMPLIANT // - const VMTs, const array-to-pointer adjustment - const int p12[p0], // COMPLIANT - const int (*p13)[p0], // NON-COMPLIANT - int (* const p14)[p0], // NON-COMPLIANT + const int p12[p0], // COMPLIANT + const int (*p13)[p0], // NON-COMPLIANT + int (*const p14)[p0], // NON-COMPLIANT // - function types with argument that is a pointer to a VMT int p15(int (*inner)[p0]), // NON-COMPLIANT[FALSE_NEGATIVE] @@ -58,7 +58,7 @@ void f1( // Unknown array length types: int p21[], // COMPLIANT - int p22[][], // COMPLIANT + int p22[][], // COMPLIANT int (*p23)[], // COMPLIANT int (*p24)[2][], // COMPLIANT int (*p25)[][2], // COMPLIANT @@ -68,7 +68,7 @@ void f1( int p27[p0][p0] // NON-COMPLIANT ) { // Local variables may contain pointers to VMTs: - int l0[p0]; // COMPLIANT + int l0[p0]; // COMPLIANT int(*l1)[]; // COMPLIANT int(*l2)[3]; // COMPLIANT int(*l3)[p0]; // NON-COMPLIANT @@ -79,9 +79,9 @@ void f1( static int(*l4)[p0]; // NON-COMPLIANT // Block scope typedefs may refer to VMTs - typedef int (*td1)[3]; // COMPLIANT - typedef int (*td2)[]; // COMPLIANT - typedef int (*td3)[p0]; // NON-COMPLIANT + typedef int(*td1)[3]; // COMPLIANT + typedef int(*td2)[]; // COMPLIANT + typedef int(*td3)[p0]; // NON-COMPLIANT td3 l5; // NON-COMPLIANT } diff --git a/cpp/common/src/codingstandards/cpp/Clvalues.qll b/cpp/common/src/codingstandards/cpp/Clvalues.qll index 2e330e0732..73fcd65eb1 100644 --- a/cpp/common/src/codingstandards/cpp/Clvalues.qll +++ b/cpp/common/src/codingstandards/cpp/Clvalues.qll @@ -14,4 +14,4 @@ predicate isCLValue(Expr expr) { not expr instanceof AssignExpr and not expr instanceof CommaExpr and not exists(Cast c | c = expr.getConversion*()) -} \ No newline at end of file +} From b7783606813a27a79cfec71e6fc1de62a980f5df Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 17 Oct 2024 15:05:20 -0700 Subject: [PATCH 053/628] Use shared queries / generally report obsolescent features even if redundant. Redundant reports should not be a common user issue; these features are obsolescent and likely rarely used and less often to be excepted. Implement ungetc() on a zero-offset stream and specific banning of gets(), as the redundant rules for those obsolescent features report a far wider set of issues than banned by RULE-1-5. Implementation of banning ungetc() on a zero-offset stream is not thorough or comprehensive. This should be fine. False positives should not create any user issues because the call of the function overall is banned. And false negatives should not be an issue, for the same reason. --- ...tionTypesNotInPrototypeFormShared.expected | 4 + ...esNotInPrototypeFormShared.expected.clang} | 0 .../FunctionTypesNotInPrototypeFormShared.ql | 4 + .../test.c | 5 -- .../test.c.clang | 0 ...pecifierObjectRedeclarationShared.expected | 1 + ...taticSpecifierObjectRedeclarationShared.ql | 5 ++ .../test.c | 8 ++ .../RULE-1-5/CallToObsolescentFunctionGets.ql | 22 +++++ ...FunctionTypesNotInPrototypeFormObsolete.ql | 23 +++++ ...taticSpecifierFuncRedeclarationObsolete.ql | 23 +++++ ...ticSpecifierObjectRedeclarationObsolete.ql | 23 +++++ .../UngetcCallOnStreamPositionZero.ql | 69 +++++++++++++++ .../FunctionTypesNotInPrototypeForm.ql | 46 ++-------- ...singStaticSpecifierObjectRedeclarationC.ql | 17 ++-- .../CallToObsolescentFunctionGets.expected | 1 + .../CallToObsolescentFunctionGets.qlref | 1 + .../FunctionTypesNotInPrototypeForm.expected | 2 - .../FunctionTypesNotInPrototypeForm.qlref | 1 - ...ionTypesNotInPrototypeFormObsolete.testref | 1 + ...llocDeallocFunctionsOfStdlibhUsed.expected | 3 - ...ryAllocDeallocFunctionsOfStdlibhUsed.qlref | 1 - ...SpecifierFuncRedeclarationObsolete.testref | 1 + ...aticSpecifierObjectRedeclarationC.expected | 1 - ...gStaticSpecifierObjectRedeclarationC.qlref | 1 - ...ecifierObjectRedeclarationObsolete.testref | 1 + ...rdLibraryInputoutputFunctionsUsed.expected | 3 - ...ndardLibraryInputoutputFunctionsUsed.qlref | 1 - .../UngetcCallOnStreamPositionZero.expected | 1 + .../UngetcCallOnStreamPositionZero.qlref | 1 + c/misra/test/rules/RULE-1-5/test.c | 27 ++---- .../FunctionTypesNotInPrototypeForm.expected | 4 - .../FunctionTypesNotInPrototypeForm.qlref | 1 - .../FunctionTypesNotInPrototypeForm.testref | 1 + ...aticSpecifierObjectRedeclarationC.expected | 1 - ...gStaticSpecifierObjectRedeclarationC.qlref | 1 - ...taticSpecifierObjectRedeclarationC.testref | 1 + c/misra/test/rules/RULE-8-8/test.c | 13 --- .../cpp/exclusions/c/Language4.qll | 85 +++++++++++++++++++ .../FunctionTypesNotInPrototypeFormShared.qll | 54 ++++++++++++ ...aticSpecifierObjectRedeclarationShared.qll | 27 ++++++ rule_packages/c/Declarations4.json | 1 + rule_packages/c/Declarations5.json | 1 + rule_packages/c/Language4.json | 77 ++++++++++++++++- 44 files changed, 450 insertions(+), 114 deletions(-) create mode 100644 c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.expected rename c/{misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected.clang => common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.expected.clang} (100%) create mode 100644 c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.ql rename c/{misra/test/rules/RULE-8-2 => common/test/rules/functiontypesnotinprototypeformshared}/test.c (50%) rename c/{misra/test/rules/RULE-8-2 => common/test/rules/functiontypesnotinprototypeformshared}/test.c.clang (100%) create mode 100644 c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.expected create mode 100644 c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.ql create mode 100644 c/common/test/rules/missingstaticspecifierobjectredeclarationshared/test.c create mode 100644 c/misra/src/rules/RULE-1-5/CallToObsolescentFunctionGets.ql create mode 100644 c/misra/src/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.ql create mode 100644 c/misra/src/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.ql create mode 100644 c/misra/src/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.ql create mode 100644 c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql create mode 100644 c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.expected create mode 100644 c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.qlref delete mode 100644 c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.expected delete mode 100644 c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.qlref create mode 100644 c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.testref delete mode 100644 c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected delete mode 100644 c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.qlref create mode 100644 c/misra/test/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.testref delete mode 100644 c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.expected delete mode 100644 c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.qlref create mode 100644 c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.testref delete mode 100644 c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected delete mode 100644 c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.qlref create mode 100644 c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected create mode 100644 c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.qlref delete mode 100644 c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected delete mode 100644 c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.qlref create mode 100644 c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.testref delete mode 100644 c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.expected delete mode 100644 c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.qlref create mode 100644 c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.testref delete mode 100644 c/misra/test/rules/RULE-8-8/test.c create mode 100644 cpp/common/src/codingstandards/cpp/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.qll diff --git a/c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.expected b/c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.expected new file mode 100644 index 0000000000..f2c08897b8 --- /dev/null +++ b/c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.expected @@ -0,0 +1,4 @@ +| test.c:3:6:3:7 | f1 | Function f1 declares parameter that is unnamed. | +| test.c:4:6:4:7 | f2 | Function f2 does not specify void for no parameters present. | +| test.c:5:6:5:7 | f3 | Function f3 does not specify void for no parameters present. | +| test.c:7:5:7:6 | f5 | Function f5 declares parameter in unsupported declaration list. | diff --git a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected.clang b/c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.expected.clang similarity index 100% rename from c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected.clang rename to c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.expected.clang diff --git a/c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.ql b/c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.ql new file mode 100644 index 0000000000..25d273354d --- /dev/null +++ b/c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.functiontypesnotinprototypeformshared.FunctionTypesNotInPrototypeFormShared + +class TestFileQuery extends FunctionTypesNotInPrototypeFormSharedSharedQuery, TestQuery { } diff --git a/c/misra/test/rules/RULE-8-2/test.c b/c/common/test/rules/functiontypesnotinprototypeformshared/test.c similarity index 50% rename from c/misra/test/rules/RULE-8-2/test.c rename to c/common/test/rules/functiontypesnotinprototypeformshared/test.c index 1ed64c0011..c254a221d9 100644 --- a/c/misra/test/rules/RULE-8-2/test.c +++ b/c/common/test/rules/functiontypesnotinprototypeformshared/test.c @@ -1,8 +1,3 @@ -// Note: A subset of these cases are also tested in c/misra/test/rules/RULE-1-5 -// via a FunctionTypesNotInPrototypeForm.qlref and .expected file in that -// directory. Changes to these tests may require updating the test code or -// expectations in that directory as well. - void f(int x); // COMPLIANT void f0(void); // COMPLIANT void f1(int); // NON_COMPLIANT diff --git a/c/misra/test/rules/RULE-8-2/test.c.clang b/c/common/test/rules/functiontypesnotinprototypeformshared/test.c.clang similarity index 100% rename from c/misra/test/rules/RULE-8-2/test.c.clang rename to c/common/test/rules/functiontypesnotinprototypeformshared/test.c.clang diff --git a/c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.expected b/c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.expected new file mode 100644 index 0000000000..34a7723bcd --- /dev/null +++ b/c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.expected @@ -0,0 +1 @@ +| test.c:2:12:2:12 | declaration of g | The redeclaration of $@ with internal linkage misses the static specifier. | test.c:1:12:1:12 | definition of g | g | diff --git a/c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.ql b/c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.ql new file mode 100644 index 0000000000..3d6d2019fb --- /dev/null +++ b/c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.ql @@ -0,0 +1,5 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.missingstaticspecifierobjectredeclarationshared.MissingStaticSpecifierObjectRedeclarationShared + +class TestFileQuery extends MissingStaticSpecifierObjectRedeclarationSharedSharedQuery, TestQuery { +} diff --git a/c/common/test/rules/missingstaticspecifierobjectredeclarationshared/test.c b/c/common/test/rules/missingstaticspecifierobjectredeclarationshared/test.c new file mode 100644 index 0000000000..d98d71c6f0 --- /dev/null +++ b/c/common/test/rules/missingstaticspecifierobjectredeclarationshared/test.c @@ -0,0 +1,8 @@ +static int g = 0; +extern int g; // NON_COMPLIANT + +static int g1; +static int g1 = 0; // COMPLIANT + +int g2; +int g2 = 0; // COMPLIANT diff --git a/c/misra/src/rules/RULE-1-5/CallToObsolescentFunctionGets.ql b/c/misra/src/rules/RULE-1-5/CallToObsolescentFunctionGets.ql new file mode 100644 index 0000000000..4994c4ea6e --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/CallToObsolescentFunctionGets.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/call-to-obsolescent-function-gets + * @name RULE-1-5: Disallowed usage of obsolescent function 'gets' + * @description The function 'gets' is an obsolescent language feature which was removed in C11. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-1-5 + * external/misra/c/2012/amendment3 + * security + * maintainability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from FunctionCall fc +where + not isExcluded(fc, Language4Package::callToObsolescentFunctionGetsQuery()) and + fc.getTarget().hasGlobalOrStdName("gets") +select fc, "Call to obsolescent function 'gets'." diff --git a/c/misra/src/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.ql b/c/misra/src/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.ql new file mode 100644 index 0000000000..8f0e626bc8 --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/function-types-not-in-prototype-form-obsolete + * @name RULE-1-5: Function types shall be in prototype form with named parameters + * @description The use of non-prototype format parameter type declarators is an obsolescent + * language feature. + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/misra/id/rule-1-5 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.functiontypesnotinprototypeformshared.FunctionTypesNotInPrototypeFormShared + +class FunctionTypesNotInPrototypeFormObsoleteQuery extends FunctionTypesNotInPrototypeFormSharedSharedQuery { + FunctionTypesNotInPrototypeFormObsoleteQuery() { + this = Language4Package::functionTypesNotInPrototypeFormObsoleteQuery() + } +} diff --git a/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.ql b/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.ql new file mode 100644 index 0000000000..5a70e0287a --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/missing-static-specifier-func-redeclaration-obsolete + * @name RULE-1-5: If a function has internal linkage then all re-declarations shall include the static storage class + * @description Declaring a function with internal linkage without the static storage class + * specifier is an obselescent feature. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-1-5 + * readability + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.missingstaticspecifierfunctionredeclarationshared.MissingStaticSpecifierFunctionRedeclarationShared + +class MissingStaticSpecifierFuncRedeclarationObsoleteQuery extends MissingStaticSpecifierFunctionRedeclarationSharedSharedQuery { + MissingStaticSpecifierFuncRedeclarationObsoleteQuery() { + this = Language4Package::missingStaticSpecifierFuncRedeclarationObsoleteQuery() + } +} diff --git a/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.ql b/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.ql new file mode 100644 index 0000000000..5e32d57c6a --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/missing-static-specifier-object-redeclaration-obsolete + * @name RULE-1-5: If an object has internal linkage then all re-declarations shall include the static storage class + * @description Declaring an identifier with internal linkage without the static storage class + * specifier is an obselescent feature. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-1-5 + * readability + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.missingstaticspecifierobjectredeclarationshared.MissingStaticSpecifierObjectRedeclarationShared + +class MissingStaticSpecifierObjectRedeclarationObsoleteQuery extends MissingStaticSpecifierObjectRedeclarationSharedSharedQuery { + MissingStaticSpecifierObjectRedeclarationObsoleteQuery() { + this = Language4Package::missingStaticSpecifierObjectRedeclarationObsoleteQuery() + } +} diff --git a/c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql b/c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql new file mode 100644 index 0000000000..a973442203 --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql @@ -0,0 +1,69 @@ +/** + * @id c/misra/ungetc-call-on-stream-position-zero + * @name RULE-1-5: Disallowed obsolescent usage of 'ungetc' on a file stream at position zero + * @description Calling the function 'ungetc' on a file stream with a position of zero is an + * obsolescent language feature. + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/misra/id/rule-1-5 + * external/misra/c/2012/amendment3 + * security + * maintainability + * external/misra/obligation/required + */ + +import cpp +import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.controlflow.Dominance +import codingstandards.c.misra + +/** + * This is an inconclusive list, which is adequate, as RULE-21-3 provides + * assurance we won't have false negatives, or care too much about false + * positives. + */ +class MoveStreamPositionCall extends FunctionCall { + Expr streamArgument; + + MoveStreamPositionCall() { + getTarget().hasGlobalOrStdName("fgetc") and + streamArgument = getArgument(0) + or + getTarget().hasGlobalOrStdName("getc") and + streamArgument = getArgument(0) + or + getTarget().hasGlobalOrStdName("fget") and + streamArgument = getArgument(2) + or + getTarget().hasGlobalOrStdName("fscanf") and + streamArgument = getArgument(0) + or + getTarget().hasGlobalOrStdName("fsetpos") and + streamArgument = getArgument(0) + or + getTarget().hasGlobalOrStdName("fseek") and + streamArgument = getArgument(0) + or + getTarget().hasGlobalOrStdName("fread") and + streamArgument = getArgument(3) + } + + Expr getStreamArgument() { result = streamArgument } +} + +from FunctionCall ungetc, DataFlow::Node file +where + not isExcluded(ungetc, Language4Package::ungetcCallOnStreamPositionZeroQuery()) and + // ungetc() called on file stream + ungetc.getTarget().hasGlobalOrStdName("ungetc") and + DataFlow::localFlow(file, DataFlow::exprNode(ungetc.getArgument(1))) and + // ungetc() is not dominated by a fread() etc to that file stream + not exists(MoveStreamPositionCall moveStreamCall | + DataFlow::localFlow(file, DataFlow::exprNode(moveStreamCall.getStreamArgument())) and + dominates(moveStreamCall, ungetc) + ) + // the file stream is the root of the local data flow + and not DataFlow::localFlow(any(DataFlow::Node n | not n = file), file) +select ungetc, "Obsolescent call to ungetc on file stream $@ at position zero.", file, + file.toString() diff --git a/c/misra/src/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql b/c/misra/src/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql index 73294d776b..1136dd714e 100644 --- a/c/misra/src/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql +++ b/c/misra/src/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql @@ -14,46 +14,10 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.Identifiers +import codingstandards.cpp.rules.functiontypesnotinprototypeformshared.FunctionTypesNotInPrototypeFormShared -/** - * `Parameter`s without names - */ -class UnnamedParameter extends Parameter { - UnnamedParameter() { not this.isNamed() } +class FunctionTypesNotInPrototypeFormQuery extends FunctionTypesNotInPrototypeFormSharedSharedQuery { + FunctionTypesNotInPrototypeFormQuery() { + this = Declarations4Package::functionTypesNotInPrototypeFormQuery() + } } - -/* - * This is a copy of the private `hasZeroParamDecl` predicate from the standard set of - * queries as of the `codeql-cli/2.11.2` tag in `github/codeql`. - */ - -predicate hasZeroParamDecl(Function f) { - exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - not fde.isImplicit() and - not fde.hasVoidParamList() and - fde.getNumberOfParameters() = 0 and - not fde.isDefinition() - ) -} - -from Function f, string msg -where - not isExcluded(f, Declarations4Package::functionTypesNotInPrototypeFormQuery()) and - f instanceof InterestingIdentifiers and - ( - f.getAParameter() instanceof UnnamedParameter and - msg = "Function " + f + " declares parameter that is unnamed." - or - hasZeroParamDecl(f) and - msg = "Function " + f + " does not specify void for no parameters present." - or - //parameters declared in declaration list (not in function signature) - //have placeholder file location associated only - exists(Parameter p | - p.getFunction() = f and - not p.getFile() = f.getFile() and - msg = "Function " + f + " declares parameter in unsupported declaration list." - ) - ) -select f, msg diff --git a/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql b/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql index 65c878e883..6f731c636f 100644 --- a/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql +++ b/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql @@ -14,15 +14,10 @@ import cpp import codingstandards.c.misra +import codingstandards.cpp.rules.missingstaticspecifierobjectredeclarationshared.MissingStaticSpecifierObjectRedeclarationShared -from VariableDeclarationEntry redeclaration, VariableDeclarationEntry de -where - not isExcluded(redeclaration, - Declarations5Package::missingStaticSpecifierObjectRedeclarationCQuery()) and - //following implies de != redeclaration - de.hasSpecifier("static") and - not redeclaration.hasSpecifier("static") and - de.getDeclaration().isTopLevel() and - redeclaration.getDeclaration() = de.getDeclaration() -select redeclaration, "The redeclaration of $@ with internal linkage misses the static specifier.", - de, de.getName() +class MissingStaticSpecifierObjectRedeclarationCQuery extends MissingStaticSpecifierObjectRedeclarationSharedSharedQuery { + MissingStaticSpecifierObjectRedeclarationCQuery() { + this = Declarations5Package::missingStaticSpecifierObjectRedeclarationCQuery() + } +} diff --git a/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.expected b/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.expected new file mode 100644 index 0000000000..6e0088f4ac --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.expected @@ -0,0 +1 @@ +| test.c:36:3:36:6 | call to gets | Call to obsolescent function 'gets'. | diff --git a/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.qlref b/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.qlref new file mode 100644 index 0000000000..1a2ec096cf --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.qlref @@ -0,0 +1 @@ +rules/RULE-1-5/CallToObsolescentFunctionGets.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.expected b/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.expected deleted file mode 100644 index 29faec8b55..0000000000 --- a/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.expected +++ /dev/null @@ -1,2 +0,0 @@ -| test.c:38:6:38:7 | f2 | Function f2 does not specify void for no parameters present. | -| test.c:42:5:42:6 | f5 | Function f5 declares parameter in unsupported declaration list. | \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.qlref b/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.qlref deleted file mode 100644 index 0a6121b324..0000000000 --- a/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeForm.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.testref b/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.testref new file mode 100644 index 0000000000..1a6a69fc24 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.testref @@ -0,0 +1 @@ +c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected b/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected deleted file mode 100644 index de87fc8542..0000000000 --- a/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.expected +++ /dev/null @@ -1,3 +0,0 @@ -| test.c:8:12:8:17 | call to malloc | Use of banned dynamic memory allocation. | -| test.c:11:3:11:9 | call to realloc | Use of banned dynamic memory allocation. | -| test.c:14:3:14:9 | call to realloc | Use of banned dynamic memory allocation. | diff --git a/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.qlref b/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.qlref deleted file mode 100644 index 8f64b81ced..0000000000 --- a/c/misra/test/rules/RULE-1-5/MemoryAllocDeallocFunctionsOfStdlibhUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-21-3/MemoryAllocDeallocFunctionsOfStdlibhUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.testref b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.testref new file mode 100644 index 0000000000..7d9f2ebc04 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.testref @@ -0,0 +1 @@ +c/common/test/rules/missingstaticspecifierfunctionredeclarationshared/MissingStaticSpecifierFunctionRedeclarationShared.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.expected b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.expected deleted file mode 100644 index 48275eb504..0000000000 --- a/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.expected +++ /dev/null @@ -1 +0,0 @@ -| test.c:35:12:35:13 | declaration of g5 | The redeclaration of $@ with internal linkage misses the static specifier. | test.c:34:12:34:13 | definition of g5 | g5 | diff --git a/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.qlref b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.qlref deleted file mode 100644 index 70b6073e14..0000000000 --- a/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationC.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.testref b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.testref new file mode 100644 index 0000000000..23ed7c9fc5 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.testref @@ -0,0 +1 @@ +c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected b/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected deleted file mode 100644 index 396b181150..0000000000 --- a/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.expected +++ /dev/null @@ -1,3 +0,0 @@ -| test.c:53:3:53:8 | call to ungetc | Call to banned function ungetc. | -| test.c:56:3:56:7 | call to fread | Call to banned function fread. | -| test.c:58:3:58:8 | call to ungetc | Call to banned function ungetc. | diff --git a/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.qlref b/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.qlref deleted file mode 100644 index 0a8cd754ef..0000000000 --- a/c/misra/test/rules/RULE-1-5/StandardLibraryInputoutputFunctionsUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-21-6/StandardLibraryInputoutputFunctionsUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected new file mode 100644 index 0000000000..4dd298197f --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected @@ -0,0 +1 @@ +| test.c:40:3:40:8 | call to ungetc | Obsolescent call to ungetc on file stream $@ at position zero. | test.c:38:16:38:20 | call to fopen | call to fopen | diff --git a/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.qlref b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.qlref new file mode 100644 index 0000000000..8c28919dcb --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.qlref @@ -0,0 +1 @@ +rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/test.c b/c/misra/test/rules/RULE-1-5/test.c index 4709381898..7632e0a727 100644 --- a/c/misra/test/rules/RULE-1-5/test.c +++ b/c/misra/test/rules/RULE-1-5/test.c @@ -4,8 +4,8 @@ #include "stdlib.h" void f1(void) { - // malloc() is not obsolete, but banned by Rule 21.3 - int *t = malloc(10); // COMPLIANT[False Negative] + // malloc() is not obsolete, though it is banned by Rule 21.3 + int *t = malloc(10); // COMPLIANT // Obsolete usage of realloc. realloc(t, 0); // NON-COMPLIANT @@ -28,25 +28,12 @@ const extern int g2; // NON-COMPLIANT _Atomic int g3 = ATOMIC_VAR_INIT(18); // NON-COMPLIANT _Atomic int g4 = 18; // COMPLIANT -// The following cases are already covered by other rules: - -// Rule 8.8: -static int g5 = 3; // COMPLIANT -extern int g5; // NON-COMPLIANT - -// Rule 8.2: -void f2(); // NON-COMPLIANT -void f3(void); // COMPLIANT - -void f4(int p1){}; // COMPLIANT -int f5(x) // NON_COMPLIANT -int x; -{ return 1; } +// `gets` was removed from C11. +extern char* gets(FILE *stream); // Rule 21.6 covers the below cases: void f6(void) { - // `gets` was removed from C11. - // gets(stdin); // NON_COMPLIANT + gets(stdin); // NON_COMPLIANT FILE *file = fopen("", 0); // Obsolete usage of ungetc. @@ -54,6 +41,6 @@ void f6(void) { char buf[10]; fread(buf, sizeof(buf), 10, file); - // This is not an obsolete usage of ungetc, but ungetc isn't allowed. - ungetc('c', file); // NON-COMPLIANT[FALSE NEGATIVE] + // This is not an obsolete usage of ungetc, though ungetc isn't allowed by 21-3. + ungetc('c', file); // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected b/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected deleted file mode 100644 index 1264797088..0000000000 --- a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.expected +++ /dev/null @@ -1,4 +0,0 @@ -| test.c:8:6:8:7 | f1 | Function f1 declares parameter that is unnamed. | -| test.c:9:6:9:7 | f2 | Function f2 does not specify void for no parameters present. | -| test.c:10:6:10:7 | f3 | Function f3 does not specify void for no parameters present. | -| test.c:12:5:12:6 | f5 | Function f5 declares parameter in unsupported declaration list. | diff --git a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.qlref b/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.qlref deleted file mode 100644 index 0a6121b324..0000000000 --- a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-8-2/FunctionTypesNotInPrototypeForm.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.testref b/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.testref new file mode 100644 index 0000000000..1a6a69fc24 --- /dev/null +++ b/c/misra/test/rules/RULE-8-2/FunctionTypesNotInPrototypeForm.testref @@ -0,0 +1 @@ +c/common/test/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.expected b/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.expected deleted file mode 100644 index 9c357cf38f..0000000000 --- a/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.expected +++ /dev/null @@ -1 +0,0 @@ -| test.c:7:12:7:12 | declaration of g | The redeclaration of $@ with internal linkage misses the static specifier. | test.c:6:12:6:12 | definition of g | g | diff --git a/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.qlref b/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.qlref deleted file mode 100644 index 70b6073e14..0000000000 --- a/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.testref b/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.testref new file mode 100644 index 0000000000..23ed7c9fc5 --- /dev/null +++ b/c/misra/test/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.testref @@ -0,0 +1 @@ +c/common/test/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-8/test.c b/c/misra/test/rules/RULE-8-8/test.c deleted file mode 100644 index ba78432a40..0000000000 --- a/c/misra/test/rules/RULE-8-8/test.c +++ /dev/null @@ -1,13 +0,0 @@ -// Note: A subset of these cases are also tested in c/misra/test/rules/RULE-1-5 -// via a MissingStaticSpecifierObjectRedeclarationC.qlref and .expected file in -// that directory. Changes to these tests may require updating the test code or -// expectations in that directory as well. - -static int g = 0; -extern int g; // NON_COMPLIANT - -static int g1; -static int g1 = 0; // COMPLIANT - -int g2; -int g2 = 0; // COMPLIANT diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll index f26cae3e9a..7bca9feefc 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll @@ -4,11 +4,43 @@ import RuleMetadata import codingstandards.cpp.exclusions.RuleMetadata newtype Language4Query = + TMissingStaticSpecifierFuncRedeclarationObsoleteQuery() or + TMissingStaticSpecifierObjectRedeclarationObsoleteQuery() or + TFunctionTypesNotInPrototypeFormObsoleteQuery() or TUseOfObsoleteMacroAtomicVarInitQuery() or TInvalidDefineOrUndefOfStdBoolMacroQuery() or + TCallToObsolescentFunctionGetsQuery() or + TUngetcCallOnStreamPositionZeroQuery() or TCallToReallocWithSizeZeroQuery() predicate isLanguage4QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `missingStaticSpecifierFuncRedeclarationObsolete` query + Language4Package::missingStaticSpecifierFuncRedeclarationObsoleteQuery() and + queryId = + // `@id` for the `missingStaticSpecifierFuncRedeclarationObsolete` query + "c/misra/missing-static-specifier-func-redeclaration-obsolete" and + ruleId = "RULE-1-5" and + category = "required" + or + query = + // `Query` instance for the `missingStaticSpecifierObjectRedeclarationObsolete` query + Language4Package::missingStaticSpecifierObjectRedeclarationObsoleteQuery() and + queryId = + // `@id` for the `missingStaticSpecifierObjectRedeclarationObsolete` query + "c/misra/missing-static-specifier-object-redeclaration-obsolete" and + ruleId = "RULE-1-5" and + category = "required" + or + query = + // `Query` instance for the `functionTypesNotInPrototypeFormObsolete` query + Language4Package::functionTypesNotInPrototypeFormObsoleteQuery() and + queryId = + // `@id` for the `functionTypesNotInPrototypeFormObsolete` query + "c/misra/function-types-not-in-prototype-form-obsolete" and + ruleId = "RULE-1-5" and + category = "required" + or query = // `Query` instance for the `useOfObsoleteMacroAtomicVarInit` query Language4Package::useOfObsoleteMacroAtomicVarInitQuery() and @@ -27,6 +59,24 @@ predicate isLanguage4QueryMetadata(Query query, string queryId, string ruleId, s ruleId = "RULE-1-5" and category = "required" or + query = + // `Query` instance for the `callToObsolescentFunctionGets` query + Language4Package::callToObsolescentFunctionGetsQuery() and + queryId = + // `@id` for the `callToObsolescentFunctionGets` query + "c/misra/call-to-obsolescent-function-gets" and + ruleId = "RULE-1-5" and + category = "required" + or + query = + // `Query` instance for the `ungetcCallOnStreamPositionZero` query + Language4Package::ungetcCallOnStreamPositionZeroQuery() and + queryId = + // `@id` for the `ungetcCallOnStreamPositionZero` query + "c/misra/ungetc-call-on-stream-position-zero" and + ruleId = "RULE-1-5" and + category = "required" + or query = // `Query` instance for the `callToReallocWithSizeZero` query Language4Package::callToReallocWithSizeZeroQuery() and @@ -38,6 +88,27 @@ predicate isLanguage4QueryMetadata(Query query, string queryId, string ruleId, s } module Language4Package { + Query missingStaticSpecifierFuncRedeclarationObsoleteQuery() { + //autogenerate `Query` type + result = + // `Query` type for `missingStaticSpecifierFuncRedeclarationObsolete` query + TQueryC(TLanguage4PackageQuery(TMissingStaticSpecifierFuncRedeclarationObsoleteQuery())) + } + + Query missingStaticSpecifierObjectRedeclarationObsoleteQuery() { + //autogenerate `Query` type + result = + // `Query` type for `missingStaticSpecifierObjectRedeclarationObsolete` query + TQueryC(TLanguage4PackageQuery(TMissingStaticSpecifierObjectRedeclarationObsoleteQuery())) + } + + Query functionTypesNotInPrototypeFormObsoleteQuery() { + //autogenerate `Query` type + result = + // `Query` type for `functionTypesNotInPrototypeFormObsolete` query + TQueryC(TLanguage4PackageQuery(TFunctionTypesNotInPrototypeFormObsoleteQuery())) + } + Query useOfObsoleteMacroAtomicVarInitQuery() { //autogenerate `Query` type result = @@ -52,6 +123,20 @@ module Language4Package { TQueryC(TLanguage4PackageQuery(TInvalidDefineOrUndefOfStdBoolMacroQuery())) } + Query callToObsolescentFunctionGetsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `callToObsolescentFunctionGets` query + TQueryC(TLanguage4PackageQuery(TCallToObsolescentFunctionGetsQuery())) + } + + Query ungetcCallOnStreamPositionZeroQuery() { + //autogenerate `Query` type + result = + // `Query` type for `ungetcCallOnStreamPositionZero` query + TQueryC(TLanguage4PackageQuery(TUngetcCallOnStreamPositionZeroQuery())) + } + Query callToReallocWithSizeZeroQuery() { //autogenerate `Query` type result = diff --git a/cpp/common/src/codingstandards/cpp/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.qll b/cpp/common/src/codingstandards/cpp/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.qll new file mode 100644 index 0000000000..ecc84f8651 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/functiontypesnotinprototypeformshared/FunctionTypesNotInPrototypeFormShared.qll @@ -0,0 +1,54 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The use of non-prototype format parameter type declarators is an obsolescent + * language feature. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Identifiers + +abstract class FunctionTypesNotInPrototypeFormSharedSharedQuery extends Query { } + +/** + * `Parameter`s without names + */ +class UnnamedParameter extends Parameter { + UnnamedParameter() { not this.isNamed() } +} + +/* + * This is a copy of the private `hasZeroParamDecl` predicate from the standard set of + * queries as of the `codeql-cli/2.11.2` tag in `github/codeql`. + */ +predicate hasZeroParamDecl(Function f) { + exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + not fde.isImplicit() and + not fde.hasVoidParamList() and + fde.getNumberOfParameters() = 0 and + not fde.isDefinition() + ) +} + +Query getQuery() { result instanceof FunctionTypesNotInPrototypeFormSharedSharedQuery } + +query predicate problems(Function f, string msg) { +not isExcluded(f, getQuery()) and + f instanceof InterestingIdentifiers and + ( + f.getAParameter() instanceof UnnamedParameter and + msg = "Function " + f + " declares parameter that is unnamed." + or + hasZeroParamDecl(f) and + msg = "Function " + f + " does not specify void for no parameters present." + or + //parameters declared in declaration list (not in function signature) + //have placeholder file location associated only + exists(Parameter p | + p.getFunction() = f and + not p.getFile() = f.getFile() and + msg = "Function " + f + " declares parameter in unsupported declaration list." + ) + ) +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.qll b/cpp/common/src/codingstandards/cpp/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.qll new file mode 100644 index 0000000000..90f28e6cc8 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/missingstaticspecifierobjectredeclarationshared/MissingStaticSpecifierObjectRedeclarationShared.qll @@ -0,0 +1,27 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Declaring an identifier with internal linkage without the static storage class + * specifier is an obselescent feature. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class MissingStaticSpecifierObjectRedeclarationSharedSharedQuery extends Query { } + +Query getQuery() { result instanceof MissingStaticSpecifierObjectRedeclarationSharedSharedQuery } + +query predicate problems( + VariableDeclarationEntry redeclaration, string message, VariableDeclarationEntry de, + string deString +) { + not isExcluded(redeclaration, getQuery()) and + //following implies de != redeclaration + de.hasSpecifier("static") and + not redeclaration.hasSpecifier("static") and + de.getDeclaration().isTopLevel() and + redeclaration.getDeclaration() = de.getDeclaration() and + message = "The redeclaration of $@ with internal linkage misses the static specifier." and + deString = de.getName() +} diff --git a/rule_packages/c/Declarations4.json b/rule_packages/c/Declarations4.json index 06475706f4..dedc6a73d4 100644 --- a/rule_packages/c/Declarations4.json +++ b/rule_packages/c/Declarations4.json @@ -12,6 +12,7 @@ "precision": "medium", "severity": "error", "short_name": "FunctionTypesNotInPrototypeForm", + "shared_implementation_short_name": "FunctionTypesNotInPrototypeFormShared", "tags": [ "correctness", "external/misra/c/2012/third-edition-first-revision" diff --git a/rule_packages/c/Declarations5.json b/rule_packages/c/Declarations5.json index 1106a1d705..36591e575b 100644 --- a/rule_packages/c/Declarations5.json +++ b/rule_packages/c/Declarations5.json @@ -71,6 +71,7 @@ "precision": "very-high", "severity": "warning", "short_name": "MissingStaticSpecifierObjectRedeclarationC", + "shared_implementation_short_name": "MissingStaticSpecifierObjectRedeclarationShared", "tags": [ "readability", "external/misra/c/2012/third-edition-first-revision" diff --git a/rule_packages/c/Language4.json b/rule_packages/c/Language4.json index 54708d73da..8698407b5f 100644 --- a/rule_packages/c/Language4.json +++ b/rule_packages/c/Language4.json @@ -5,6 +5,48 @@ "obligation": "required" }, "queries": [ + { + "description": "Declaring a function with internal linkage without the static storage class specifier is an obselescent feature.", + "kind": "problem", + "name": "If a function has internal linkage then all re-declarations shall include the static storage class", + "precision": "very-high", + "severity": "warning", + "short_name": "MissingStaticSpecifierFuncRedeclarationObsolete", + "shared_implementation_short_name": "MissingStaticSpecifierFunctionRedeclarationShared", + "tags": [ + "readability", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "Declaring an identifier with internal linkage without the static storage class specifier is an obselescent feature.", + "kind": "problem", + "name": "If an object has internal linkage then all re-declarations shall include the static storage class", + "precision": "very-high", + "severity": "warning", + "short_name": "MissingStaticSpecifierObjectRedeclarationObsolete", + "shared_implementation_short_name": "MissingStaticSpecifierObjectRedeclarationShared", + "tags": [ + "readability", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "The use of non-prototype format parameter type declarators is an obsolescent language feature.", + "kind": "problem", + "name": "Function types shall be in prototype form with named parameters", + "precision": "medium", + "severity": "error", + "short_name": "FunctionTypesNotInPrototypeFormObsolete", + "shared_implementation_short_name": "FunctionTypesNotInPrototypeFormShared", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ], + "implementation_scope": { + "description": "This query does not check for implicitly typed parameters and checks function declarations and definitions but not function pointer types." + } + }, { "description": "The macro ATOMIC_VAR_INIT is has been declared an obsolescent language feature since C18.", "kind": "problem", @@ -31,6 +73,32 @@ "external/misra/c/2012/amendment3" ] }, + { + "description": "The function 'gets' is an obsolescent language feature which was removed in C11.", + "kind": "problem", + "name": "Disallowed usage of obsolescent function 'gets'", + "precision": "very-high", + "severity": "error", + "short_name": "CallToObsolescentFunctionGets", + "tags": [ + "external/misra/c/2012/amendment3", + "security", + "maintainability" + ] + }, + { + "description": "Calling the function 'ungetc' on a file stream with a position of zero is an obsolescent language feature.", + "kind": "problem", + "name": "Disallowed obsolescent usage of 'ungetc' on a file stream at position zero", + "precision": "medium", + "severity": "error", + "short_name": "UngetcCallOnStreamPositionZero", + "tags": [ + "external/misra/c/2012/amendment3", + "security", + "maintainability" + ] + }, { "description": "Invoking realloc with a size argument set to zero is implementation-defined behavior and declared as an obsolete feature in C18.", "kind": "problem", @@ -48,13 +116,14 @@ "implementation_scope": { "description": "Not all items from Appendix F are covered by this rule. Some are not supportable and some are covered already by other rules.", "items": [ - "Appendix F, item ID 1 is covered by Rule 8.8 and not reported as part of this implementation of Rule 1.5.", + "Appendix F, item ID 1 is reported by both Rule 8.8 and by this implementation of Rule 1.5.", "Appendix F, item ID 2 refers to compiler behavior which cannot be statically analyzed.", "Appendix F, item ID 3, which states that storage-class specifiers may not be used except in the beginning of a declaration, is not supportable without additional changes to the CodeQL CLI.", + "Appendix F, item IDs 4 and 5 are reported by both Rule 8.2 and by this implementation of Rule 1.5.", "Appendix F, item ID 6 is reported for all C versions, though the macro ATOMIC_VAR_INIT was not officially declared obsolescent until C18.", - "Appendix F, item IDs 4 and 5 are covered by Rule 8.2 and not reported as part of this implementation of Rule 1.5.", - "Appendix F, item IDs 8 and 9 is covered by Rule 21.6 and not reported as part of this implementation of Rule 1.5.", - "Appendix F, item ID 10 is checked by this implementation of 1.5, though it is a redundant subset of cases reported by Rule 21.3.", + "Appendix F, item ID 8 is reported by both Rule 21.6 and by this implementation of Rule 1.5.", + "Appendix F, item ID 9 is reported by this implementation of 1.5, though all uses of ungetc() are also reported by Rule 21.3.", + "Appendix F, item ID 10 is reported by this implementation of 1.5, though all uses of realloc() are also reported by Rule 21.3.", "Appendix F, item ID 10 is reported for all C versions, as realloc() with a size argument of zero was implementation-defined behavior in C99 and C11." ] } From 1908bbf71887d9a1e118f36276cdc6ffadeb1ffc Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 17 Oct 2024 16:25:08 -0700 Subject: [PATCH 054/628] Format queries and tests --- .../RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.ql | 3 ++- .../MissingStaticSpecifierFuncRedeclarationObsolete.ql | 3 ++- .../MissingStaticSpecifierObjectRedeclarationObsolete.ql | 3 ++- .../MissingStaticSpecifierObjectRedeclarationC.ql | 3 ++- .../RULE-1-5/UngetcCallOnStreamPositionZero.expected | 9 ++++++++- c/misra/test/rules/RULE-1-5/test.c | 5 +++-- 6 files changed, 19 insertions(+), 7 deletions(-) diff --git a/c/misra/src/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.ql b/c/misra/src/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.ql index 8f0e626bc8..645285f438 100644 --- a/c/misra/src/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.ql +++ b/c/misra/src/rules/RULE-1-5/FunctionTypesNotInPrototypeFormObsolete.ql @@ -16,7 +16,8 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.rules.functiontypesnotinprototypeformshared.FunctionTypesNotInPrototypeFormShared -class FunctionTypesNotInPrototypeFormObsoleteQuery extends FunctionTypesNotInPrototypeFormSharedSharedQuery { +class FunctionTypesNotInPrototypeFormObsoleteQuery extends FunctionTypesNotInPrototypeFormSharedSharedQuery +{ FunctionTypesNotInPrototypeFormObsoleteQuery() { this = Language4Package::functionTypesNotInPrototypeFormObsoleteQuery() } diff --git a/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.ql b/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.ql index 5a70e0287a..ba800885ef 100644 --- a/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.ql +++ b/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierFuncRedeclarationObsolete.ql @@ -16,7 +16,8 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.rules.missingstaticspecifierfunctionredeclarationshared.MissingStaticSpecifierFunctionRedeclarationShared -class MissingStaticSpecifierFuncRedeclarationObsoleteQuery extends MissingStaticSpecifierFunctionRedeclarationSharedSharedQuery { +class MissingStaticSpecifierFuncRedeclarationObsoleteQuery extends MissingStaticSpecifierFunctionRedeclarationSharedSharedQuery +{ MissingStaticSpecifierFuncRedeclarationObsoleteQuery() { this = Language4Package::missingStaticSpecifierFuncRedeclarationObsoleteQuery() } diff --git a/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.ql b/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.ql index 5e32d57c6a..9f9953aa6f 100644 --- a/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.ql +++ b/c/misra/src/rules/RULE-1-5/MissingStaticSpecifierObjectRedeclarationObsolete.ql @@ -16,7 +16,8 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.rules.missingstaticspecifierobjectredeclarationshared.MissingStaticSpecifierObjectRedeclarationShared -class MissingStaticSpecifierObjectRedeclarationObsoleteQuery extends MissingStaticSpecifierObjectRedeclarationSharedSharedQuery { +class MissingStaticSpecifierObjectRedeclarationObsoleteQuery extends MissingStaticSpecifierObjectRedeclarationSharedSharedQuery +{ MissingStaticSpecifierObjectRedeclarationObsoleteQuery() { this = Language4Package::missingStaticSpecifierObjectRedeclarationObsoleteQuery() } diff --git a/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql b/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql index 6f731c636f..877ef19d2a 100644 --- a/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql +++ b/c/misra/src/rules/RULE-8-8/MissingStaticSpecifierObjectRedeclarationC.ql @@ -16,7 +16,8 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.rules.missingstaticspecifierobjectredeclarationshared.MissingStaticSpecifierObjectRedeclarationShared -class MissingStaticSpecifierObjectRedeclarationCQuery extends MissingStaticSpecifierObjectRedeclarationSharedSharedQuery { +class MissingStaticSpecifierObjectRedeclarationCQuery extends MissingStaticSpecifierObjectRedeclarationSharedSharedQuery +{ MissingStaticSpecifierObjectRedeclarationCQuery() { this = Declarations5Package::missingStaticSpecifierObjectRedeclarationCQuery() } diff --git a/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected index 4dd298197f..3a6f6bc821 100644 --- a/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected +++ b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected @@ -1 +1,8 @@ -| test.c:40:3:40:8 | call to ungetc | Obsolescent call to ungetc on file stream $@ at position zero. | test.c:38:16:38:20 | call to fopen | call to fopen | +edges +| test.c:38:16:38:20 | call to fopen indirection | test.c:40:15:40:18 | file indirection | +nodes +| test.c:38:16:38:20 | call to fopen indirection | semmle.label | call to fopen indirection | +| test.c:40:15:40:18 | file indirection | semmle.label | file indirection | +subpaths +#select +| test.c:40:15:40:18 | file indirection | test.c:38:16:38:20 | call to fopen indirection | test.c:40:15:40:18 | file indirection | Obsolescent call to ungetc on file stream $@ at position zero. | test.c:38:16:38:20 | call to fopen indirection | call to fopen indirection | diff --git a/c/misra/test/rules/RULE-1-5/test.c b/c/misra/test/rules/RULE-1-5/test.c index 7632e0a727..38d701c44b 100644 --- a/c/misra/test/rules/RULE-1-5/test.c +++ b/c/misra/test/rules/RULE-1-5/test.c @@ -29,7 +29,7 @@ _Atomic int g3 = ATOMIC_VAR_INIT(18); // NON-COMPLIANT _Atomic int g4 = 18; // COMPLIANT // `gets` was removed from C11. -extern char* gets(FILE *stream); +extern char *gets(FILE *stream); // Rule 21.6 covers the below cases: void f6(void) { @@ -41,6 +41,7 @@ void f6(void) { char buf[10]; fread(buf, sizeof(buf), 10, file); - // This is not an obsolete usage of ungetc, though ungetc isn't allowed by 21-3. + // This is not an obsolete usage of ungetc, though ungetc isn't allowed by + // 21-3. ungetc('c', file); // COMPLIANT } \ No newline at end of file From fd9eb8a0ee86cd53ec1c82c202756aba71c9140a Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 17 Oct 2024 16:25:30 -0700 Subject: [PATCH 055/628] Remodel ungetc() query as a sanitization/path problem --- .../UngetcCallOnStreamPositionZero.ql | 42 ++++++++++++------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql b/c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql index a973442203..8a1615d08c 100644 --- a/c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql +++ b/c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql @@ -3,7 +3,7 @@ * @name RULE-1-5: Disallowed obsolescent usage of 'ungetc' on a file stream at position zero * @description Calling the function 'ungetc' on a file stream with a position of zero is an * obsolescent language feature. - * @kind problem + * @kind path-problem * @precision medium * @problem.severity error * @tags external/misra/id/rule-1-5 @@ -52,18 +52,30 @@ class MoveStreamPositionCall extends FunctionCall { Expr getStreamArgument() { result = streamArgument } } -from FunctionCall ungetc, DataFlow::Node file +module FilePositionZeroFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { + node.asIndirectExpr().(FunctionCall).getTarget().hasGlobalOrStdName("fopen") + } + + predicate isSink(DataFlow::Node node) { + exists(FunctionCall fc | + fc.getTarget().hasGlobalOrStdName("ungetc") and + node.asIndirectExpr() = fc.getArgument(1) + ) + } + + predicate isBarrierIn(DataFlow::Node node) { + exists(MoveStreamPositionCall fc | node.asIndirectExpr() = fc.getStreamArgument()) + } +} + +module FilePositionZeroFlow = DataFlow::Global; + +import FilePositionZeroFlow::PathGraph + +from FilePositionZeroFlow::PathNode sink, FilePositionZeroFlow::PathNode source where - not isExcluded(ungetc, Language4Package::ungetcCallOnStreamPositionZeroQuery()) and - // ungetc() called on file stream - ungetc.getTarget().hasGlobalOrStdName("ungetc") and - DataFlow::localFlow(file, DataFlow::exprNode(ungetc.getArgument(1))) and - // ungetc() is not dominated by a fread() etc to that file stream - not exists(MoveStreamPositionCall moveStreamCall | - DataFlow::localFlow(file, DataFlow::exprNode(moveStreamCall.getStreamArgument())) and - dominates(moveStreamCall, ungetc) - ) - // the file stream is the root of the local data flow - and not DataFlow::localFlow(any(DataFlow::Node n | not n = file), file) -select ungetc, "Obsolescent call to ungetc on file stream $@ at position zero.", file, - file.toString() + not isExcluded(sink.getNode().asExpr(), Language4Package::ungetcCallOnStreamPositionZeroQuery()) and + FilePositionZeroFlow::flowPath(source, sink) +select sink.getNode(), source, sink, + "Obsolescent call to ungetc on file stream $@ at position zero.", source, source.toString() From 46b272ac2833b15984686eb6cb5569d03cfe177b Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 17 Oct 2024 16:30:12 -0700 Subject: [PATCH 056/628] Fix query metadata --- c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql | 2 +- rule_packages/c/Language4.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql b/c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql index 8a1615d08c..6a10c94030 100644 --- a/c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql +++ b/c/misra/src/rules/RULE-1-5/UngetcCallOnStreamPositionZero.ql @@ -4,7 +4,7 @@ * @description Calling the function 'ungetc' on a file stream with a position of zero is an * obsolescent language feature. * @kind path-problem - * @precision medium + * @precision high * @problem.severity error * @tags external/misra/id/rule-1-5 * external/misra/c/2012/amendment3 diff --git a/rule_packages/c/Language4.json b/rule_packages/c/Language4.json index 8698407b5f..fb448bd8a3 100644 --- a/rule_packages/c/Language4.json +++ b/rule_packages/c/Language4.json @@ -88,9 +88,9 @@ }, { "description": "Calling the function 'ungetc' on a file stream with a position of zero is an obsolescent language feature.", - "kind": "problem", + "kind": "path-problem", "name": "Disallowed obsolescent usage of 'ungetc' on a file stream at position zero", - "precision": "medium", + "precision": "high", "severity": "error", "short_name": "UngetcCallOnStreamPositionZero", "tags": [ From f59040284efd42e5f59d0996ad4a8dbae8b44341 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 18 Oct 2024 14:45:31 -0700 Subject: [PATCH 057/628] Implement alignment package for MISRA-C 2012 amendment 3 --- ...clarationOfObjectWithUnmatchedAlignment.ql | 47 +++++++++ .../RedeclarationOfObjectWithoutAlignment.ql | 99 +++++++++++++++++++ .../rules/RULE-8-16/AlignmentWithSizeZero.ql | 24 +++++ ...eThanOneAlignmentSpecifierOnDeclaration.ql | 35 +++++++ ...ionOfObjectWithUnmatchedAlignment.expected | 8 ++ ...rationOfObjectWithUnmatchedAlignment.qlref | 1 + ...clarationOfObjectWithoutAlignment.expected | 2 + ...edeclarationOfObjectWithoutAlignment.qlref | 1 + c/misra/test/rules/RULE-8-15/test.c | 35 +++++++ .../RULE-8-16/AlignmentWithSizeZero.expected | 4 + .../RULE-8-16/AlignmentWithSizeZero.qlref | 1 + c/misra/test/rules/RULE-8-16/test.c | 14 +++ ...neAlignmentSpecifierOnDeclaration.expected | 6 ++ ...anOneAlignmentSpecifierOnDeclaration.qlref | 1 + c/misra/test/rules/RULE-8-17/test.c | 16 +++ .../cpp/exclusions/c/Alignment.qll | 78 +++++++++++++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + rule_packages/c/Alignment.json | 79 +++++++++++++++ 18 files changed, 454 insertions(+) create mode 100644 c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql create mode 100644 c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql create mode 100644 c/misra/src/rules/RULE-8-16/AlignmentWithSizeZero.ql create mode 100644 c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql create mode 100644 c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected create mode 100644 c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.qlref create mode 100644 c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.expected create mode 100644 c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.qlref create mode 100644 c/misra/test/rules/RULE-8-15/test.c create mode 100644 c/misra/test/rules/RULE-8-16/AlignmentWithSizeZero.expected create mode 100644 c/misra/test/rules/RULE-8-16/AlignmentWithSizeZero.qlref create mode 100644 c/misra/test/rules/RULE-8-16/test.c create mode 100644 c/misra/test/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.expected create mode 100644 c/misra/test/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.qlref create mode 100644 c/misra/test/rules/RULE-8-17/test.c create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Alignment.qll create mode 100644 rule_packages/c/Alignment.json diff --git a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql new file mode 100644 index 0000000000..74fc68d04d --- /dev/null +++ b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql @@ -0,0 +1,47 @@ +/** + * @id c/misra/redeclaration-of-object-with-unmatched-alignment + * @name RULE-8-15: Alignment should match between all declarations of an object + * @description All declarations of an object with an explicit alignment specification shall specify + * the same alignment. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-15 + * extern/misra/c/2012/amendment3 + * readability + * maintainability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +predicate lexicallyEqualExpr(Expr a, Expr b) { + a.toString() = b.toString() and + a.getNumChild() = b.getNumChild() and + forall(Expr aChild, Expr bChild, int i | + aChild = a.getChild(i) and + bChild = b.getChild(i) and + i < a.getNumChild() + | + lexicallyEqualExpr(aChild, bChild) + ) +} + +predicate lexicallyEqual(AttributeArgument a, AttributeArgument b) { + lexicallyEqualExpr(a.getValueConstant(), b.getValueConstant()) or + a.getValueType() = b.getValueType() +} + +from Attribute alignment, Attribute mismatched, string variable +where + not isExcluded(alignment, AlignmentPackage::redeclarationOfObjectWithUnmatchedAlignmentQuery()) and + alignment.hasName("_Alignas") and + mismatched.hasName("_Alignas") and + exists(Variable v | + v.getAnAttribute() = alignment and v.getAnAttribute() = mismatched and v.getName() = variable + ) and + not lexicallyEqual(alignment.getArgument(0), mismatched.getArgument(0)) +select alignment, + "Variable " + variable + " declared with lexically different _Alignof() values '$@' and '$@'", + alignment, alignment.getArgument(0).toString(), mismatched, mismatched.getArgument(0).toString() diff --git a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql new file mode 100644 index 0000000000..9af3839e16 --- /dev/null +++ b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql @@ -0,0 +1,99 @@ +/** + * @id c/misra/redeclaration-of-object-without-alignment + * @name RULE-8-15: Alignment should match between all declarations of an object + * @description An object declared with an explicit alignment shall be explicitly aligned in all + * declarations. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-15 + * extern/misra/c/2012/amendment3 + * readability + * maintainability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +/** + * Performance optimization; start query by joining attributes to declarations + * rather than locations. + * + * Including the entry location also speeds up search. + */ +newtype TAttributeDeclLocation = + TAttributeDeclLocationInfo( + Attribute attribute, DeclarationEntry entry, Location entryLocation + ) { + entry.getDeclaration().(Variable).getAnAttribute() = attribute and + entryLocation = entry.getLocation() + } + +/** + * Get a DeclarationEntry along with its explicitly declared Attributes. + * + * DeclarationEntry does not have a method for getting Attributes by default, + * because an attribute declared on any DeclarationEntry affects all others, + * and attributes really belong to the declared variable rather than the + * declaration itself. + * + * In order to support this rule, we find for each attribute + * - A declaration entry which + * - corresponds to a variable associated with this attribute + * - is in the same file as this attribute + * - has identifier location after the attribute declaration + * - has no other declaration entry between this one and the attribute. + * + * This should give us a highly reliable means of finding which attributes are + * associated with which `DeclarationEntry`s. + * + * One note of caution: the associated `Variable` must be treated with caution, + * as there are multiple instances of that `Variable` if it is declared + * multiple times, they equal each other, and `getLocation()` on each variable + * returns every location result. This class must act on `DeclarationEntry`s to + * deliver reliable results. + */ +class DeclarationEntryAttribute extends Attribute { + DeclarationEntry declarationEntry; + Location location; + Location declLocation; + File file; + TAttributeDeclLocation locInfo; + + DeclarationEntryAttribute() { + locInfo = TAttributeDeclLocationInfo(this, declarationEntry, declLocation) and + file = getFile() and + location = getLocation() and + declLocation = declarationEntry.getLocation() and + declarationEntry.getDeclaration().(Variable).getAnAttribute() = this and + declarationEntry.getFile() = file and + location.isBefore(declLocation, _) and + not exists(TAttributeDeclLocation blocInfo, DeclarationEntry betterFit, Location blocation | + blocInfo = TAttributeDeclLocationInfo(this, betterFit, blocation) and + not betterFit = declarationEntry and + blocation = betterFit.getLocation() and + betterFit.getFile() = file and + betterFit.getDeclaration() = declarationEntry.getDeclaration() and + blocation.isBefore(declLocation, _) and + location.isBefore(blocation, _) + ) + } + + DeclarationEntry getDeclarationEntry() { result = declarationEntry } +} + +from DeclarationEntry unaligned, DeclarationEntry aligned, DeclarationEntryAttribute attribute +where + not isExcluded(unaligned, AlignmentPackage::redeclarationOfObjectWithoutAlignmentQuery()) and + attribute.hasName("_Alignas") and + attribute.getDeclarationEntry() = aligned and + aligned.getDeclaration() = unaligned.getDeclaration() and + not exists(DeclarationEntryAttribute matchingAlignment | + matchingAlignment.hasName("_Alignas") and + matchingAlignment.getDeclarationEntry() = unaligned + ) +select unaligned, + "Variable " + unaligned.getName() + + " declared without explicit alignment to match $@ with alignment $@", aligned, + "other definition", attribute, attribute.toString() diff --git a/c/misra/src/rules/RULE-8-16/AlignmentWithSizeZero.ql b/c/misra/src/rules/RULE-8-16/AlignmentWithSizeZero.ql new file mode 100644 index 0000000000..52d282c4a2 --- /dev/null +++ b/c/misra/src/rules/RULE-8-16/AlignmentWithSizeZero.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/alignment-with-size-zero + * @name RULE-8-16: The alignment specification of zero should not appear in an object declaration + * @description A declaration shall not have an alignment of size zero. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-16 + * extern/misra/c/2012/amendment3 + * readability + * maintainability + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +from Attribute a, Variable v +where + not isExcluded(a, AlignmentPackage::alignmentWithSizeZeroQuery()) and + a.hasName("_Alignas") and + a.getArgument(0).getValueInt() = 0 and + v.getAnAttribute() = a +select a.getArgument(0), "Invalid alignof() size set to zero for variable $@.", v, v.getName() diff --git a/c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql b/c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql new file mode 100644 index 0000000000..f7952d1266 --- /dev/null +++ b/c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql @@ -0,0 +1,35 @@ +/** + * @id c/misra/more-than-one-alignment-specifier-on-declaration + * @name RULE-8-17: At most one explicit alignment specifier should appear in an object declaration + * @description While C permits the usage of multiple alignment specifiers, doing so reduces + * readability and may obscure the intent of the declaration. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-17 + * extern/misra/c/2012/amendment3 + * readability + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +from Variable v, Attribute first, Attribute last +where + not isExcluded(v, AlignmentPackage::moreThanOneAlignmentSpecifierOnDeclarationQuery()) and + first = v.getAnAttribute() and + last = v.getAnAttribute() and + first != last and + first.hasName("_Alignas") and + last.hasName("_Alignas") and + not exists(Attribute beforeFirst | + beforeFirst.getLocation().isBefore(first.getLocation(), _) and + v.getAnAttribute() = beforeFirst + ) and + not exists(Attribute afterLast | + last.getLocation().isBefore(afterLast.getLocation(), _) and + v.getAnAttribute() = afterLast + ) +select v, "Variable " + v.getName() + " contains more than one alignment specifier, $@ and $@", + first, first.toString(), last, last.toString() diff --git a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected new file mode 100644 index 0000000000..83a27f9074 --- /dev/null +++ b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected @@ -0,0 +1,8 @@ +| test.c:18:8:18:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@' | test.c:18:8:18:15 | alignas(...) | int | test.c:19:8:19:15 | alignas(...) | 4 | +| test.c:19:8:19:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@' | test.c:19:8:19:15 | alignas(...) | 4 | test.c:18:8:18:15 | alignas(...) | int | +| test.c:22:8:22:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@' | test.c:22:8:22:15 | alignas(...) | ... * ... | test.c:23:8:23:15 | alignas(...) | 32 | +| test.c:23:8:23:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@' | test.c:23:8:23:15 | alignas(...) | 32 | test.c:22:8:22:15 | alignas(...) | ... * ... | +| test.c:28:8:28:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@' | test.c:28:8:28:15 | alignas(...) | ... * ... | test.c:29:8:29:15 | alignas(...) | ... * ... | +| test.c:29:8:29:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@' | test.c:29:8:29:15 | alignas(...) | ... * ... | test.c:28:8:28:15 | alignas(...) | ... * ... | +| test.c:34:8:34:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@' | test.c:34:8:34:15 | alignas(...) | signed int | test.c:35:8:35:15 | alignas(...) | unsigned int | +| test.c:35:8:35:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@' | test.c:35:8:35:15 | alignas(...) | unsigned int | test.c:34:8:34:15 | alignas(...) | signed int | diff --git a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.qlref b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.qlref new file mode 100644 index 0000000000..08648fd168 --- /dev/null +++ b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.qlref @@ -0,0 +1 @@ +rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.expected b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.expected new file mode 100644 index 0000000000..e9b91d33a4 --- /dev/null +++ b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.expected @@ -0,0 +1,2 @@ +| test.c:5:12:5:13 | declaration of g2 | Variable g2 declared without explicit alignment to match $@ with alignment $@ | test.c:4:25:4:26 | declaration of g2 | other definition | test.c:4:8:4:15 | alignas(...) | alignas(...) | +| test.c:7:12:7:13 | declaration of g3 | Variable g3 declared without explicit alignment to match $@ with alignment $@ | test.c:8:25:8:26 | declaration of g3 | other definition | test.c:8:8:8:15 | alignas(...) | alignas(...) | diff --git a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.qlref b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.qlref new file mode 100644 index 0000000000..f5f13e2125 --- /dev/null +++ b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.qlref @@ -0,0 +1 @@ +rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-15/test.c b/c/misra/test/rules/RULE-8-15/test.c new file mode 100644 index 0000000000..f97a79d5b6 --- /dev/null +++ b/c/misra/test/rules/RULE-8-15/test.c @@ -0,0 +1,35 @@ +extern _Alignas(16) int g1; // COMPLIANT +extern _Alignas(16) int g1; // COMPLIANT + +extern _Alignas(16) int g2; +extern int g2; // NON_COMPLIANT + +extern int g3; // NON_COMPLIANT +extern _Alignas(16) int g3; + +// Does not compile on clang: +// extern _Alignas(16) int g4; // COMPLIANT +// extern _Alignas(32) int g4; // COMPLIANT + +extern int g5; // COMPLIANT +extern int g5; // COMPLIANT + +// Spec says elements must be lexically identical after macro expansion +extern _Alignas(int) int g6; // NON_COMPLIANT +extern _Alignas(4) int g6; // NON_COMPLIANT + +#define THIRTY_TWO 32 +extern _Alignas(16 * 2) int g7; // NON_COMPLIANT +extern _Alignas(32) int g7; // NON_COMPLIANT + +extern _Alignas(THIRTY_TWO) int g8; // COMPLIANT +extern _Alignas(32) int g8; // COMPLIANT + +extern _Alignas(16 * 2) int g9; // NON_COMPLIANT +extern _Alignas(2 * 16) int g9; // NON_COMPLIANT + +extern _Alignas(int) int g10; // COMPLIANT +extern _Alignas(int) int g10; // COMPLIANT + +extern _Alignas(signed int) int g11; // NON_COMPLIANT +extern _Alignas(unsigned int) int g11; // NON_COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-16/AlignmentWithSizeZero.expected b/c/misra/test/rules/RULE-8-16/AlignmentWithSizeZero.expected new file mode 100644 index 0000000000..4daa3475ed --- /dev/null +++ b/c/misra/test/rules/RULE-8-16/AlignmentWithSizeZero.expected @@ -0,0 +1,4 @@ +| test.c:2:10:2:10 | 0 | Invalid alignof() size set to zero for variable $@. | test.c:2:17:2:18 | g2 | g2 | +| test.c:3:10:3:14 | ... - ... | Invalid alignof() size set to zero for variable $@. | test.c:3:21:3:22 | g3 | g3 | +| test.c:8:12:8:12 | 0 | Invalid alignof() size set to zero for variable $@. | test.c:8:19:8:20 | m2 | m2 | +| test.c:13:12:13:12 | 0 | Invalid alignof() size set to zero for variable $@. | test.c:13:19:13:20 | l2 | l2 | diff --git a/c/misra/test/rules/RULE-8-16/AlignmentWithSizeZero.qlref b/c/misra/test/rules/RULE-8-16/AlignmentWithSizeZero.qlref new file mode 100644 index 0000000000..c8e19d1fe5 --- /dev/null +++ b/c/misra/test/rules/RULE-8-16/AlignmentWithSizeZero.qlref @@ -0,0 +1 @@ +rules/RULE-8-16/AlignmentWithSizeZero.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-16/test.c b/c/misra/test/rules/RULE-8-16/test.c new file mode 100644 index 0000000000..3e96b7b8cc --- /dev/null +++ b/c/misra/test/rules/RULE-8-16/test.c @@ -0,0 +1,14 @@ +_Alignas(8) int g1; // COMPLIANT +_Alignas(0) int g2; // NON-COMPLIANT +_Alignas(8 - 8) int g3; // NON-COMPLIANT +_Alignas(float) int g4; // COMPLIANT + +struct s { + _Alignas(64) int m1; // COMPLIANT + _Alignas(0) int m2; // NON_COMPLIANT +}; + +void f() { + _Alignas(8) int l1; // COMPLIANT + _Alignas(0) int l2; // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.expected b/c/misra/test/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.expected new file mode 100644 index 0000000000..24707ca457 --- /dev/null +++ b/c/misra/test/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.expected @@ -0,0 +1,6 @@ +| test.c:2:30:2:31 | g2 | Variable g2 contains more than one alignment specifier, $@ and $@ | test.c:2:1:2:8 | alignas(...) | alignas(...) | test.c:2:13:2:20 | alignas(...) | alignas(...) | +| test.c:3:29:3:30 | g3 | Variable g3 contains more than one alignment specifier, $@ and $@ | test.c:3:1:3:8 | alignas(...) | alignas(...) | test.c:3:13:3:20 | alignas(...) | alignas(...) | +| test.c:4:35:4:36 | g4 | Variable g4 contains more than one alignment specifier, $@ and $@ | test.c:4:1:4:8 | alignas(...) | alignas(...) | test.c:4:17:4:24 | alignas(...) | alignas(...) | +| test.c:6:53:6:54 | g5 | Variable g5 contains more than one alignment specifier, $@ and $@ | test.c:5:1:5:8 | alignas(...) | alignas(...) | test.c:6:33:6:40 | alignas(...) | alignas(...) | +| test.c:10:35:10:36 | m2 | Variable m2 contains more than one alignment specifier, $@ and $@ | test.c:10:3:10:10 | alignas(...) | alignas(...) | test.c:10:18:10:25 | alignas(...) | alignas(...) | +| test.c:15:35:15:36 | l2 | Variable l2 contains more than one alignment specifier, $@ and $@ | test.c:15:3:15:10 | alignas(...) | alignas(...) | test.c:15:18:15:25 | alignas(...) | alignas(...) | diff --git a/c/misra/test/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.qlref b/c/misra/test/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.qlref new file mode 100644 index 0000000000..7ff11e8a61 --- /dev/null +++ b/c/misra/test/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.qlref @@ -0,0 +1 @@ +rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-17/test.c b/c/misra/test/rules/RULE-8-17/test.c new file mode 100644 index 0000000000..e2f8b2b44f --- /dev/null +++ b/c/misra/test/rules/RULE-8-17/test.c @@ -0,0 +1,16 @@ +_Alignas(8) int g1; // COMPLIANT +_Alignas(8) _Alignas(16) int g2; // NON-COMPLIANT +_Alignas(8) _Alignas(8) int g3; // NON-COMPLIANT +_Alignas(float) _Alignas(int) int g4; // NON-COMPLIANT +_Alignas(float) _Alignas(float) int g5; // NON-COMPLIANT +_Alignas(float) _Alignas(float) _Alignas(float) int g5; // NON-COMPLIANT + +struct s { + _Alignas(64) int m1; // COMPLIANT + _Alignas(long) _Alignas(16) int m2; // NON_COMPLIANT +}; + +void f() { + _Alignas(8) int l1; // COMPLIANT + _Alignas(long) _Alignas(16) int l2; // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Alignment.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Alignment.qll new file mode 100644 index 0000000000..9447abf636 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Alignment.qll @@ -0,0 +1,78 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype AlignmentQuery = + TRedeclarationOfObjectWithoutAlignmentQuery() or + TRedeclarationOfObjectWithUnmatchedAlignmentQuery() or + TAlignmentWithSizeZeroQuery() or + TMoreThanOneAlignmentSpecifierOnDeclarationQuery() + +predicate isAlignmentQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `redeclarationOfObjectWithoutAlignment` query + AlignmentPackage::redeclarationOfObjectWithoutAlignmentQuery() and + queryId = + // `@id` for the `redeclarationOfObjectWithoutAlignment` query + "c/misra/redeclaration-of-object-without-alignment" and + ruleId = "RULE-8-15" and + category = "required" + or + query = + // `Query` instance for the `redeclarationOfObjectWithUnmatchedAlignment` query + AlignmentPackage::redeclarationOfObjectWithUnmatchedAlignmentQuery() and + queryId = + // `@id` for the `redeclarationOfObjectWithUnmatchedAlignment` query + "c/misra/redeclaration-of-object-with-unmatched-alignment" and + ruleId = "RULE-8-15" and + category = "required" + or + query = + // `Query` instance for the `alignmentWithSizeZero` query + AlignmentPackage::alignmentWithSizeZeroQuery() and + queryId = + // `@id` for the `alignmentWithSizeZero` query + "c/misra/alignment-with-size-zero" and + ruleId = "RULE-8-16" and + category = "advisory" + or + query = + // `Query` instance for the `moreThanOneAlignmentSpecifierOnDeclaration` query + AlignmentPackage::moreThanOneAlignmentSpecifierOnDeclarationQuery() and + queryId = + // `@id` for the `moreThanOneAlignmentSpecifierOnDeclaration` query + "c/misra/more-than-one-alignment-specifier-on-declaration" and + ruleId = "RULE-8-17" and + category = "advisory" +} + +module AlignmentPackage { + Query redeclarationOfObjectWithoutAlignmentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `redeclarationOfObjectWithoutAlignment` query + TQueryC(TAlignmentPackageQuery(TRedeclarationOfObjectWithoutAlignmentQuery())) + } + + Query redeclarationOfObjectWithUnmatchedAlignmentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `redeclarationOfObjectWithUnmatchedAlignment` query + TQueryC(TAlignmentPackageQuery(TRedeclarationOfObjectWithUnmatchedAlignmentQuery())) + } + + Query alignmentWithSizeZeroQuery() { + //autogenerate `Query` type + result = + // `Query` type for `alignmentWithSizeZero` query + TQueryC(TAlignmentPackageQuery(TAlignmentWithSizeZeroQuery())) + } + + Query moreThanOneAlignmentSpecifierOnDeclarationQuery() { + //autogenerate `Query` type + result = + // `Query` type for `moreThanOneAlignmentSpecifierOnDeclaration` query + TQueryC(TAlignmentPackageQuery(TMoreThanOneAlignmentSpecifierOnDeclarationQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 3833533d50..51fe53cf6f 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -2,6 +2,7 @@ import cpp import codingstandards.cpp.exclusions.RuleMetadata //** Import packages for this language **/ +import Alignment import Banned import Banned2 import BitfieldTypes @@ -78,6 +79,7 @@ import Types2 /** The TQuery type representing this language * */ newtype TCQuery = + TAlignmentPackageQuery(AlignmentQuery q) or TBannedPackageQuery(BannedQuery q) or TBanned2PackageQuery(Banned2Query q) or TBitfieldTypesPackageQuery(BitfieldTypesQuery q) or @@ -154,6 +156,7 @@ newtype TCQuery = /** The metadata predicate * */ predicate isQueryMetadata(Query query, string queryId, string ruleId, string category) { + isAlignmentQueryMetadata(query, queryId, ruleId, category) or isBannedQueryMetadata(query, queryId, ruleId, category) or isBanned2QueryMetadata(query, queryId, ruleId, category) or isBitfieldTypesQueryMetadata(query, queryId, ruleId, category) or diff --git a/rule_packages/c/Alignment.json b/rule_packages/c/Alignment.json new file mode 100644 index 0000000000..1cbdf279fb --- /dev/null +++ b/rule_packages/c/Alignment.json @@ -0,0 +1,79 @@ +{ + "MISRA-C-2012": { + "RULE-8-15": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "An object declared with an explicit alignment shall be explicitly aligned in all declarations.", + "kind": "problem", + "name": "Alignment should match between all declarations of an object", + "precision": "very-high", + "severity": "error", + "short_name": "RedeclarationOfObjectWithoutAlignment", + "tags": [ + "extern/misra/c/2012/amendment3", + "readability", + "maintainability" + ] + }, + { + "description": "All declarations of an object with an explicit alignment specification shall specify the same alignment.", + "kind": "problem", + "name": "Alignment should match between all declarations of an object", + "precision": "very-high", + "severity": "error", + "short_name": "RedeclarationOfObjectWithUnmatchedAlignment", + "tags": [ + "extern/misra/c/2012/amendment3", + "readability", + "maintainability" + ] + } + ], + "title": "All declarations of an object with an explicit alignment specification shall specify the same alignment" + }, + "RULE-8-16": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "A declaration shall not have an alignment of size zero.", + "kind": "problem", + "name": "The alignment specification of zero should not appear in an object declaration", + "precision": "very-high", + "severity": "error", + "short_name": "AlignmentWithSizeZero", + "tags": [ + "extern/misra/c/2012/amendment3", + "readability", + "maintainability" + ] + } + ], + "title": "The alignment specification of zero should not appear in an object declaration" + }, + "RULE-8-17": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "While C permits the usage of multiple alignment specifiers, doing so reduces readability and may obscure the intent of the declaration.", + "kind": "problem", + "name": "At most one explicit alignment specifier should appear in an object declaration", + "precision": "very-high", + "severity": "error", + "short_name": "MoreThanOneAlignmentSpecifierOnDeclaration", + "tags": [ + "extern/misra/c/2012/amendment3", + "readability" + ] + } + ], + "title": "At most one explicit alignment specifier should appear in an object declaration" + } + } +} \ No newline at end of file From 7ae79abf9955cd785571cb83b3e59a6bfc201e9f Mon Sep 17 00:00:00 2001 From: Michael R Fairhurst Date: Fri, 18 Oct 2024 22:11:30 +0000 Subject: [PATCH 058/628] Add test for mismatched alignments on gcc --- ...fObjectWithUnmatchedAlignment.expected.gcc | 10 ++++++ c/misra/test/rules/RULE-8-15/test.c.gcc | 35 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected.gcc create mode 100644 c/misra/test/rules/RULE-8-15/test.c.gcc diff --git a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected.gcc b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected.gcc new file mode 100644 index 0000000000..f1054946a7 --- /dev/null +++ b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected.gcc @@ -0,0 +1,10 @@ +| test.c:11:8:11:15 | alignas(...) | Variable g4 declared with lexically different _Alignof() values '$@' and '$@' | test.c:11:8:11:15 | alignas(...) | 16 | test.c:12:8:12:15 | alignas(...) | 32 | +| test.c:12:8:12:15 | alignas(...) | Variable g4 declared with lexically different _Alignof() values '$@' and '$@' | test.c:12:8:12:15 | alignas(...) | 32 | test.c:11:8:11:15 | alignas(...) | 16 | +| test.c:18:8:18:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@' | test.c:18:8:18:15 | alignas(...) | int | test.c:19:8:19:15 | alignas(...) | 4 | +| test.c:19:8:19:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@' | test.c:19:8:19:15 | alignas(...) | 4 | test.c:18:8:18:15 | alignas(...) | int | +| test.c:22:8:22:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@' | test.c:22:8:22:15 | alignas(...) | ... * ... | test.c:23:8:23:15 | alignas(...) | 32 | +| test.c:23:8:23:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@' | test.c:23:8:23:15 | alignas(...) | 32 | test.c:22:8:22:15 | alignas(...) | ... * ... | +| test.c:28:8:28:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@' | test.c:28:8:28:15 | alignas(...) | ... * ... | test.c:29:8:29:15 | alignas(...) | ... * ... | +| test.c:29:8:29:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@' | test.c:29:8:29:15 | alignas(...) | ... * ... | test.c:28:8:28:15 | alignas(...) | ... * ... | +| test.c:34:8:34:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@' | test.c:34:8:34:15 | alignas(...) | signed int | test.c:35:8:35:15 | alignas(...) | unsigned int | +| test.c:35:8:35:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@' | test.c:35:8:35:15 | alignas(...) | unsigned int | test.c:34:8:34:15 | alignas(...) | signed int | diff --git a/c/misra/test/rules/RULE-8-15/test.c.gcc b/c/misra/test/rules/RULE-8-15/test.c.gcc new file mode 100644 index 0000000000..d0f53bf89a --- /dev/null +++ b/c/misra/test/rules/RULE-8-15/test.c.gcc @@ -0,0 +1,35 @@ +extern _Alignas(16) int g1; // COMPLIANT +extern _Alignas(16) int g1; // COMPLIANT + +extern _Alignas(16) int g2; +extern int g2; // NON_COMPLIANT + +extern int g3; // NON_COMPLIANT +extern _Alignas(16) int g3; + +// Does not compile on clang: +extern _Alignas(16) int g4; // COMPLIANT +extern _Alignas(32) int g4; // COMPLIANT + +extern int g5; // COMPLIANT +extern int g5; // COMPLIANT + +// Spec says elements must be lexically identical after macro expansion +extern _Alignas(int) int g6; // NON_COMPLIANT +extern _Alignas(4) int g6; // NON_COMPLIANT + +#define THIRTY_TWO 32 +extern _Alignas(16 * 2) int g7; // NON_COMPLIANT +extern _Alignas(32) int g7; // NON_COMPLIANT + +extern _Alignas(THIRTY_TWO) int g8; // COMPLIANT +extern _Alignas(32) int g8; // COMPLIANT + +extern _Alignas(16 * 2) int g9; // NON_COMPLIANT +extern _Alignas(2 * 16) int g9; // NON_COMPLIANT + +extern _Alignas(int) int g10; // COMPLIANT +extern _Alignas(int) int g10; // COMPLIANT + +extern _Alignas(signed int) int g11; // NON_COMPLIANT +extern _Alignas(unsigned int) int g11; // NON_COMPLIANT \ No newline at end of file From 9b325f63887e509063666d7e2b040df383f57d41 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 18 Oct 2024 15:20:25 -0700 Subject: [PATCH 059/628] Fix misra c amendment tag --- rule_packages/c/Alignment.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rule_packages/c/Alignment.json b/rule_packages/c/Alignment.json index 1cbdf279fb..edf06a09ca 100644 --- a/rule_packages/c/Alignment.json +++ b/rule_packages/c/Alignment.json @@ -13,7 +13,7 @@ "severity": "error", "short_name": "RedeclarationOfObjectWithoutAlignment", "tags": [ - "extern/misra/c/2012/amendment3", + "external/misra/c/2012/amendment3", "readability", "maintainability" ] @@ -26,7 +26,7 @@ "severity": "error", "short_name": "RedeclarationOfObjectWithUnmatchedAlignment", "tags": [ - "extern/misra/c/2012/amendment3", + "external/misra/c/2012/amendment3", "readability", "maintainability" ] @@ -47,7 +47,7 @@ "severity": "error", "short_name": "AlignmentWithSizeZero", "tags": [ - "extern/misra/c/2012/amendment3", + "external/misra/c/2012/amendment3", "readability", "maintainability" ] @@ -68,7 +68,7 @@ "severity": "error", "short_name": "MoreThanOneAlignmentSpecifierOnDeclaration", "tags": [ - "extern/misra/c/2012/amendment3", + "external/misra/c/2012/amendment3", "readability" ] } From feea1e4d97c0d9105e8355fb39eb94ea382e4c6c Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 18 Oct 2024 15:21:16 -0700 Subject: [PATCH 060/628] Fix query format --- .../RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql index 9af3839e16..9161c74a38 100644 --- a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql +++ b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql @@ -19,13 +19,11 @@ import codingstandards.c.misra /** * Performance optimization; start query by joining attributes to declarations * rather than locations. - * + * * Including the entry location also speeds up search. */ newtype TAttributeDeclLocation = - TAttributeDeclLocationInfo( - Attribute attribute, DeclarationEntry entry, Location entryLocation - ) { + TAttributeDeclLocationInfo(Attribute attribute, DeclarationEntry entry, Location entryLocation) { entry.getDeclaration().(Variable).getAnAttribute() = attribute and entryLocation = entry.getLocation() } From d214ba7b19415b80b36d3b5c01e9b1ff60c3b134 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 18 Oct 2024 15:28:52 -0700 Subject: [PATCH 061/628] Regenerate queries with updated metadata --- .../RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql | 2 +- .../rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql | 2 +- c/misra/src/rules/RULE-8-16/AlignmentWithSizeZero.ql | 2 +- .../RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql index 74fc68d04d..b17c1ef6c1 100644 --- a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql +++ b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql @@ -7,7 +7,7 @@ * @precision very-high * @problem.severity error * @tags external/misra/id/rule-8-15 - * extern/misra/c/2012/amendment3 + * external/misra/c/2012/amendment3 * readability * maintainability * external/misra/obligation/required diff --git a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql index 9161c74a38..986ab92f5a 100644 --- a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql +++ b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql @@ -7,7 +7,7 @@ * @precision very-high * @problem.severity error * @tags external/misra/id/rule-8-15 - * extern/misra/c/2012/amendment3 + * external/misra/c/2012/amendment3 * readability * maintainability * external/misra/obligation/required diff --git a/c/misra/src/rules/RULE-8-16/AlignmentWithSizeZero.ql b/c/misra/src/rules/RULE-8-16/AlignmentWithSizeZero.ql index 52d282c4a2..4a0cd9d50b 100644 --- a/c/misra/src/rules/RULE-8-16/AlignmentWithSizeZero.ql +++ b/c/misra/src/rules/RULE-8-16/AlignmentWithSizeZero.ql @@ -6,7 +6,7 @@ * @precision very-high * @problem.severity error * @tags external/misra/id/rule-8-16 - * extern/misra/c/2012/amendment3 + * external/misra/c/2012/amendment3 * readability * maintainability * external/misra/obligation/advisory diff --git a/c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql b/c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql index f7952d1266..3c89a190ec 100644 --- a/c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql +++ b/c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql @@ -7,7 +7,7 @@ * @precision very-high * @problem.severity error * @tags external/misra/id/rule-8-17 - * extern/misra/c/2012/amendment3 + * external/misra/c/2012/amendment3 * readability * external/misra/obligation/advisory */ From 9dc3c2a154d70f7171ed204907ed5173b95389b4 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 18 Oct 2024 18:15:06 -0700 Subject: [PATCH 062/628] Use range analysis to detect realloc() where size may be zero, vs, is exactly zero. --- ...SizeZero.ql => SizeInReallocCallIsZero.ql} | 17 +++++----- .../RULE-1-5/SizeInReallocCallMayBeZero.ql | 26 +++++++++++++++ .../CallToObsolescentFunctionGets.expected | 2 +- .../CallToReallocWithSizeZero.expected | 1 - .../RULE-1-5/CallToReallocWithSizeZero.qlref | 1 - ...nvalidDefineOrUndefOfStdBoolMacro.expected | 12 +++---- .../RULE-1-5/SizeInReallocCallIsZero.expected | 1 + .../RULE-1-5/SizeInReallocCallIsZero.qlref | 1 + .../SizeInReallocCallMayBeZero.expected | 1 + .../RULE-1-5/SizeInReallocCallMayBeZero.qlref | 1 + .../UngetcCallOnStreamPositionZero.expected | 8 ++--- .../UseOfObsoleteMacroAtomicVarInit.expected | 2 +- c/misra/test/rules/RULE-1-5/test.c | 9 ++--- .../src/codingstandards/cpp/Realloc.qll | 18 ++++++++++ .../cpp/exclusions/c/Language4.qll | 33 ++++++++++++++----- rule_packages/c/Language4.json | 16 +++++++-- 16 files changed, 113 insertions(+), 36 deletions(-) rename c/misra/src/rules/RULE-1-5/{CallToReallocWithSizeZero.ql => SizeInReallocCallIsZero.ql} (50%) create mode 100644 c/misra/src/rules/RULE-1-5/SizeInReallocCallMayBeZero.ql delete mode 100644 c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.expected delete mode 100644 c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.qlref create mode 100644 c/misra/test/rules/RULE-1-5/SizeInReallocCallIsZero.expected create mode 100644 c/misra/test/rules/RULE-1-5/SizeInReallocCallIsZero.qlref create mode 100644 c/misra/test/rules/RULE-1-5/SizeInReallocCallMayBeZero.expected create mode 100644 c/misra/test/rules/RULE-1-5/SizeInReallocCallMayBeZero.qlref create mode 100644 cpp/common/src/codingstandards/cpp/Realloc.qll diff --git a/c/misra/src/rules/RULE-1-5/CallToReallocWithSizeZero.ql b/c/misra/src/rules/RULE-1-5/SizeInReallocCallIsZero.ql similarity index 50% rename from c/misra/src/rules/RULE-1-5/CallToReallocWithSizeZero.ql rename to c/misra/src/rules/RULE-1-5/SizeInReallocCallIsZero.ql index 2ea90e8b12..2b5cdaa851 100644 --- a/c/misra/src/rules/RULE-1-5/CallToReallocWithSizeZero.ql +++ b/c/misra/src/rules/RULE-1-5/SizeInReallocCallIsZero.ql @@ -1,6 +1,6 @@ /** - * @id c/misra/call-to-realloc-with-size-zero - * @name RULE-1-5: Disallowed size argument value equal to zero in call to realloc + * @id c/misra/size-in-realloc-call-is-zero + * @name RULE-1-5: Size argument value in realloc call is equal zero * @description Invoking realloc with a size argument set to zero is implementation-defined behavior * and declared as an obsolete feature in C18. * @kind problem @@ -15,11 +15,12 @@ import cpp import codingstandards.c.misra import semmle.code.cpp.rangeanalysis.new.RangeAnalysis +import codingstandards.cpp.Realloc -from FunctionCall call, Expr arg +from ReallocCall call where - not isExcluded(call, Language4Package::callToReallocWithSizeZeroQuery()) and - call.getTarget().hasGlobalOrStdName("realloc") and - arg = call.getArgument(1) and - upperBound(arg) = 0 -select arg, "Calling realloc with size zero results in implementation-defined behavior." + not isExcluded(call, Language4Package::sizeInReallocCallIsZeroQuery()) and + call.sizeIsExactlyZero() +select call, + "Size argument '$@' may equal zero in realloc call, resulting in obsolescent and/or implementation-defined behavior.", + call.getSizeArgument(), call.getSizeArgument().toString() diff --git a/c/misra/src/rules/RULE-1-5/SizeInReallocCallMayBeZero.ql b/c/misra/src/rules/RULE-1-5/SizeInReallocCallMayBeZero.ql new file mode 100644 index 0000000000..3e883e45f4 --- /dev/null +++ b/c/misra/src/rules/RULE-1-5/SizeInReallocCallMayBeZero.ql @@ -0,0 +1,26 @@ +/** + * @id c/misra/size-in-realloc-call-may-be-zero + * @name RULE-1-5: Size argument value in realloc call may equal zero + * @description Invoking realloc with a size argument set to zero is implementation-defined behavior + * and declared as an obsolete feature in C18. + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/misra/id/rule-1-5 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Realloc + +from ReallocCall call +where + not isExcluded(call, Language4Package::sizeInReallocCallMayBeZeroQuery()) and + call.sizeMayBeZero() and + not call.sizeIsExactlyZero() +select call, + "Size argument '$@' equals zero in realloc call, resulting in obsolescent and/or implementation-defined behavior.", + call.getSizeArgument(), call.getSizeArgument().toString() diff --git a/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.expected b/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.expected index 6e0088f4ac..4c8fdc27cf 100644 --- a/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.expected +++ b/c/misra/test/rules/RULE-1-5/CallToObsolescentFunctionGets.expected @@ -1 +1 @@ -| test.c:36:3:36:6 | call to gets | Call to obsolescent function 'gets'. | +| test.c:37:3:37:6 | call to gets | Call to obsolescent function 'gets'. | diff --git a/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.expected b/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.expected deleted file mode 100644 index 89e54a38c2..0000000000 --- a/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.expected +++ /dev/null @@ -1 +0,0 @@ -| test.c:11:14:11:14 | 0 | Calling realloc with size zero results in implementation-defined behavior. | diff --git a/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.qlref b/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.qlref deleted file mode 100644 index 218be6b3ef..0000000000 --- a/c/misra/test/rules/RULE-1-5/CallToReallocWithSizeZero.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-1-5/CallToReallocWithSizeZero.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected b/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected index 7a6ca9824e..854b200553 100644 --- a/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected +++ b/c/misra/test/rules/RULE-1-5/InvalidDefineOrUndefOfStdBoolMacro.expected @@ -1,6 +1,6 @@ -| test.c:21:1:21:14 | #define true 3 | Invalid define of boolean standard macro 'true'. | -| test.c:22:1:22:15 | #define false 3 | Invalid define of boolean standard macro 'false'. | -| test.c:23:1:23:18 | #define bool int * | Invalid define of boolean standard macro 'bool'. | -| test.c:24:1:24:11 | #undef true | Invalid undefine of boolean standard macro 'true'. | -| test.c:25:1:25:12 | #undef false | Invalid undefine of boolean standard macro 'false'. | -| test.c:26:1:26:11 | #undef bool | Invalid undefine of boolean standard macro 'bool'. | +| test.c:22:1:22:14 | #define true 3 | Invalid define of boolean standard macro 'true'. | +| test.c:23:1:23:15 | #define false 3 | Invalid define of boolean standard macro 'false'. | +| test.c:24:1:24:18 | #define bool int * | Invalid define of boolean standard macro 'bool'. | +| test.c:25:1:25:11 | #undef true | Invalid undefine of boolean standard macro 'true'. | +| test.c:26:1:26:12 | #undef false | Invalid undefine of boolean standard macro 'false'. | +| test.c:27:1:27:11 | #undef bool | Invalid undefine of boolean standard macro 'bool'. | diff --git a/c/misra/test/rules/RULE-1-5/SizeInReallocCallIsZero.expected b/c/misra/test/rules/RULE-1-5/SizeInReallocCallIsZero.expected new file mode 100644 index 0000000000..7b05a5fc0a --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/SizeInReallocCallIsZero.expected @@ -0,0 +1 @@ +| test.c:14:3:14:9 | call to realloc | Size argument '$@' may equal zero in realloc call, resulting in obsolescent and/or implementation-defined behavior. | test.c:14:14:14:14 | 0 | 0 | diff --git a/c/misra/test/rules/RULE-1-5/SizeInReallocCallIsZero.qlref b/c/misra/test/rules/RULE-1-5/SizeInReallocCallIsZero.qlref new file mode 100644 index 0000000000..cef5e76d54 --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/SizeInReallocCallIsZero.qlref @@ -0,0 +1 @@ +rules/RULE-1-5/SizeInReallocCallIsZero.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/SizeInReallocCallMayBeZero.expected b/c/misra/test/rules/RULE-1-5/SizeInReallocCallMayBeZero.expected new file mode 100644 index 0000000000..f86ad4c57c --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/SizeInReallocCallMayBeZero.expected @@ -0,0 +1 @@ +| test.c:15:3:15:9 | call to realloc | Size argument '$@' equals zero in realloc call, resulting in obsolescent and/or implementation-defined behavior. | test.c:15:14:15:15 | p0 | p0 | diff --git a/c/misra/test/rules/RULE-1-5/SizeInReallocCallMayBeZero.qlref b/c/misra/test/rules/RULE-1-5/SizeInReallocCallMayBeZero.qlref new file mode 100644 index 0000000000..1287327c5d --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/SizeInReallocCallMayBeZero.qlref @@ -0,0 +1 @@ +rules/RULE-1-5/SizeInReallocCallMayBeZero.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected index 3a6f6bc821..98e7b34fbe 100644 --- a/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected +++ b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected @@ -1,8 +1,8 @@ edges -| test.c:38:16:38:20 | call to fopen indirection | test.c:40:15:40:18 | file indirection | +| test.c:39:16:39:20 | call to fopen indirection | test.c:41:15:41:18 | file indirection | nodes -| test.c:38:16:38:20 | call to fopen indirection | semmle.label | call to fopen indirection | -| test.c:40:15:40:18 | file indirection | semmle.label | file indirection | +| test.c:39:16:39:20 | call to fopen indirection | semmle.label | call to fopen indirection | +| test.c:41:15:41:18 | file indirection | semmle.label | file indirection | subpaths #select -| test.c:40:15:40:18 | file indirection | test.c:38:16:38:20 | call to fopen indirection | test.c:40:15:40:18 | file indirection | Obsolescent call to ungetc on file stream $@ at position zero. | test.c:38:16:38:20 | call to fopen indirection | call to fopen indirection | +| test.c:41:15:41:18 | file indirection | test.c:39:16:39:20 | call to fopen indirection | test.c:41:15:41:18 | file indirection | Obsolescent call to ungetc on file stream $@ at position zero. | test.c:39:16:39:20 | call to fopen indirection | call to fopen indirection | diff --git a/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected index bc903de094..edd607c52f 100644 --- a/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected +++ b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected @@ -1 +1 @@ -| test.c:28:18:28:36 | ATOMIC_VAR_INIT(value) | Usage of macro ATOMIC_VAR_INIT() is declared obscelescent in C18, and discouraged in earlier C versions. | +| test.c:29:18:29:36 | ATOMIC_VAR_INIT(value) | Usage of macro ATOMIC_VAR_INIT() is declared obscelescent in C18, and discouraged in earlier C versions. | diff --git a/c/misra/test/rules/RULE-1-5/test.c b/c/misra/test/rules/RULE-1-5/test.c index 38d701c44b..52144bad13 100644 --- a/c/misra/test/rules/RULE-1-5/test.c +++ b/c/misra/test/rules/RULE-1-5/test.c @@ -3,15 +3,16 @@ #include "stdio.h" #include "stdlib.h" -void f1(void) { +void f1(int p0) { // malloc() is not obsolete, though it is banned by Rule 21.3 int *t = malloc(10); // COMPLIANT - // Obsolete usage of realloc. - realloc(t, 0); // NON-COMPLIANT - // Valid usage of realloc, but all use of realloc is banned by Rule 21.3 realloc(t, 20); // NON-COMPLIANT + + // Obsolete usage of realloc. + realloc(t, 0); // NON-COMPLIANT + realloc(t, p0); // NON-COMPLIANT } extern const int g1; // COMPLIANT diff --git a/cpp/common/src/codingstandards/cpp/Realloc.qll b/cpp/common/src/codingstandards/cpp/Realloc.qll new file mode 100644 index 0000000000..71acb7d7b1 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Realloc.qll @@ -0,0 +1,18 @@ +import cpp +import codingstandards.cpp.CodingStandards + +class ReallocCall extends FunctionCall { + ReallocCall() { getTarget().hasGlobalOrStdName("realloc") } + + Expr getSizeArgument() { result = getArgument(1) } + + predicate sizeIsExactlyZero() { + upperBound(getSizeArgument().getConversion()) = 0 and + lowerBound(getSizeArgument().getConversion()) = 0 + } + + predicate sizeMayBeZero() { + upperBound(getSizeArgument().getConversion()) >= 0 and + lowerBound(getSizeArgument().getConversion()) <= 0 + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll index 7bca9feefc..b4391ff5c2 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Language4.qll @@ -11,7 +11,8 @@ newtype Language4Query = TInvalidDefineOrUndefOfStdBoolMacroQuery() or TCallToObsolescentFunctionGetsQuery() or TUngetcCallOnStreamPositionZeroQuery() or - TCallToReallocWithSizeZeroQuery() + TSizeInReallocCallMayBeZeroQuery() or + TSizeInReallocCallIsZeroQuery() predicate isLanguage4QueryMetadata(Query query, string queryId, string ruleId, string category) { query = @@ -78,11 +79,20 @@ predicate isLanguage4QueryMetadata(Query query, string queryId, string ruleId, s category = "required" or query = - // `Query` instance for the `callToReallocWithSizeZero` query - Language4Package::callToReallocWithSizeZeroQuery() and + // `Query` instance for the `sizeInReallocCallMayBeZero` query + Language4Package::sizeInReallocCallMayBeZeroQuery() and queryId = - // `@id` for the `callToReallocWithSizeZero` query - "c/misra/call-to-realloc-with-size-zero" and + // `@id` for the `sizeInReallocCallMayBeZero` query + "c/misra/size-in-realloc-call-may-be-zero" and + ruleId = "RULE-1-5" and + category = "required" + or + query = + // `Query` instance for the `sizeInReallocCallIsZero` query + Language4Package::sizeInReallocCallIsZeroQuery() and + queryId = + // `@id` for the `sizeInReallocCallIsZero` query + "c/misra/size-in-realloc-call-is-zero" and ruleId = "RULE-1-5" and category = "required" } @@ -137,10 +147,17 @@ module Language4Package { TQueryC(TLanguage4PackageQuery(TUngetcCallOnStreamPositionZeroQuery())) } - Query callToReallocWithSizeZeroQuery() { + Query sizeInReallocCallMayBeZeroQuery() { + //autogenerate `Query` type + result = + // `Query` type for `sizeInReallocCallMayBeZero` query + TQueryC(TLanguage4PackageQuery(TSizeInReallocCallMayBeZeroQuery())) + } + + Query sizeInReallocCallIsZeroQuery() { //autogenerate `Query` type result = - // `Query` type for `callToReallocWithSizeZero` query - TQueryC(TLanguage4PackageQuery(TCallToReallocWithSizeZeroQuery())) + // `Query` type for `sizeInReallocCallIsZero` query + TQueryC(TLanguage4PackageQuery(TSizeInReallocCallIsZeroQuery())) } } diff --git a/rule_packages/c/Language4.json b/rule_packages/c/Language4.json index fb448bd8a3..fdc11924f4 100644 --- a/rule_packages/c/Language4.json +++ b/rule_packages/c/Language4.json @@ -102,10 +102,22 @@ { "description": "Invoking realloc with a size argument set to zero is implementation-defined behavior and declared as an obsolete feature in C18.", "kind": "problem", - "name": "Disallowed size argument value equal to zero in call to realloc", + "name": "Size argument value in realloc call may equal zero", + "precision": "medium", + "severity": "error", + "short_name": "SizeInReallocCallMayBeZero", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "Invoking realloc with a size argument set to zero is implementation-defined behavior and declared as an obsolete feature in C18.", + "kind": "problem", + "name": "Size argument value in realloc call is equal zero", "precision": "very-high", "severity": "error", - "short_name": "CallToReallocWithSizeZero", + "short_name": "SizeInReallocCallIsZero", "tags": [ "correctness", "external/misra/c/2012/amendment3" From 66b4267e37592389e7f60510bf852abe4b0a7915 Mon Sep 17 00:00:00 2001 From: Fernando Jose Date: Tue, 22 Oct 2024 15:12:51 +0900 Subject: [PATCH 063/628] Fix #755. --- change_notes/2024-10-22-fix-fp-m6-5-3.md | 2 ++ cpp/common/src/codingstandards/cpp/Loops.qll | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 change_notes/2024-10-22-fix-fp-m6-5-3.md diff --git a/change_notes/2024-10-22-fix-fp-m6-5-3.md b/change_notes/2024-10-22-fix-fp-m6-5-3.md new file mode 100644 index 0000000000..0d8ca573d9 --- /dev/null +++ b/change_notes/2024-10-22-fix-fp-m6-5-3.md @@ -0,0 +1,2 @@ +- `M6-5-3` - `Loops.qll`: + - Fixes #755. Specifies that the access to the loop counter must be via non-const address. diff --git a/cpp/common/src/codingstandards/cpp/Loops.qll b/cpp/common/src/codingstandards/cpp/Loops.qll index bfd68c49a0..aa3dc64ea5 100644 --- a/cpp/common/src/codingstandards/cpp/Loops.qll +++ b/cpp/common/src/codingstandards/cpp/Loops.qll @@ -204,7 +204,7 @@ predicate isLoopCounterModifiedInCondition(ForStmt forLoop, VariableAccess loopC loopCounterAccess = getAnIterationVariable(forLoop).getAnAccess() and ( loopCounterAccess.isModified() or - loopCounterAccess.isAddressOfAccess() + loopCounterAccess.isAddressOfAccessNonConst() ) } @@ -219,7 +219,7 @@ predicate isLoopCounterModifiedInStatement( loopCounterAccess = loopCounter.getAnAccess() and ( loopCounterAccess.isModified() or - loopCounterAccess.isAddressOfAccess() + loopCounterAccess.isAddressOfAccessNonConst() ) and forLoop.getStmt().getChildStmt*() = loopCounterAccess.getEnclosingStmt() } From 92427e6161f563a67c751b0bfcd1f5b44e86a13c Mon Sep 17 00:00:00 2001 From: Fernando Jose Date: Tue, 22 Oct 2024 15:15:37 +0900 Subject: [PATCH 064/628] Fix sneaky typo in A18-1-1 test. --- cpp/autosar/test/rules/A18-1-1/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/autosar/test/rules/A18-1-1/test.cpp b/cpp/autosar/test/rules/A18-1-1/test.cpp index 90596780d9..0e9bffa3d7 100644 --- a/cpp/autosar/test/rules/A18-1-1/test.cpp +++ b/cpp/autosar/test/rules/A18-1-1/test.cpp @@ -11,6 +11,6 @@ int test_c_arrays() { int x[100]; // NON_COMPLIANT constexpr int a[]{0, 1, 2}; // NON_COMPLIANT - __func__; // COMPLAINT + __func__; // COMPLIANT return 0; -} \ No newline at end of file +} From a183198b68b2e27c72c4e79855bbf4c41905c2bb Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 23 Oct 2024 18:04:35 +0100 Subject: [PATCH 065/628] Ignore explicit casts when idenitying cvalues by parent --- ...ConvertedToDifferentUnderlyingType.expected | 8 +++++--- cpp/autosar/test/rules/M5-0-3/test.cpp | 18 ++++++++++++++++++ cpp/autosar/test/rules/M5-0-7/test.cpp | 9 +++++++++ cpp/autosar/test/rules/M5-0-8/test.cpp | 18 ++++++++++++++++++ ...plicitSignednessConversionOfCValue.expected | 6 +++--- cpp/autosar/test/rules/M5-0-9/test.cpp | 7 +++++++ cpp/common/src/codingstandards/cpp/Expr.qll | 12 ++++++++++-- 7 files changed, 70 insertions(+), 8 deletions(-) diff --git a/cpp/autosar/test/rules/M5-0-3/CvalueExpressionConvertedToDifferentUnderlyingType.expected b/cpp/autosar/test/rules/M5-0-3/CvalueExpressionConvertedToDifferentUnderlyingType.expected index 5782ac9849..773691efd1 100644 --- a/cpp/autosar/test/rules/M5-0-3/CvalueExpressionConvertedToDifferentUnderlyingType.expected +++ b/cpp/autosar/test/rules/M5-0-3/CvalueExpressionConvertedToDifferentUnderlyingType.expected @@ -1,3 +1,5 @@ -| test.cpp:11:8:11:14 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:11:8:11:14 | ... + ... | expression | -| test.cpp:11:8:11:14 | ... + ... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:11:8:11:14 | ... + ... | expression | -| test.cpp:13:8:13:13 | ... + ... | Implicit conversion converts cvalue $@ from signed short to signed int. | test.cpp:13:8:13:13 | ... + ... | expression | +| test.cpp:12:8:12:14 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:12:8:12:14 | ... + ... | expression | +| test.cpp:12:8:12:14 | ... + ... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:12:8:12:14 | ... + ... | expression | +| test.cpp:14:8:14:13 | ... + ... | Implicit conversion converts cvalue $@ from signed short to signed int. | test.cpp:14:8:14:13 | ... + ... | expression | +| test.cpp:23:13:23:19 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:23:13:23:19 | ... + ... | expression | +| test.cpp:30:12:30:18 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:30:12:30:18 | ... + ... | expression | diff --git a/cpp/autosar/test/rules/M5-0-3/test.cpp b/cpp/autosar/test/rules/M5-0-3/test.cpp index cb74512979..9f368bae3f 100644 --- a/cpp/autosar/test/rules/M5-0-3/test.cpp +++ b/cpp/autosar/test/rules/M5-0-3/test.cpp @@ -1,4 +1,5 @@ #include + void f1() { using std::int16_t; using std::int32_t; @@ -13,4 +14,21 @@ void f1() { l3 = l2 + 1; // NON_COMPLIANT l3 = static_cast(l2) + 1; // COMPLIANT l3 = l2 + 0x01ffff; // COMPLIANT +} + +void int16_arg(std::int16_t t); + +void test_func_call() { + std::int8_t l1; + int16_arg(l1 + l1); // NON_COMPLIANT + int16_arg(static_cast(l1 + l1)); // COMPLIANT +} + +std::int16_t test_return(int test) { + std::int8_t l1; + if (test > 0) { + return l1 + l1; // NON_COMPLIANT + } else { + return static_cast(l1 + l1); // COMPLIANT + } } \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-7/test.cpp b/cpp/autosar/test/rules/M5-0-7/test.cpp index 36a2259028..ecbddd6750 100644 --- a/cpp/autosar/test/rules/M5-0-7/test.cpp +++ b/cpp/autosar/test/rules/M5-0-7/test.cpp @@ -18,4 +18,13 @@ void f1() { s16a = static_cast(f32a / f32b); // NON_COMPLIANT s16a = static_cast(f32a); // COMPLIANT s16a = static_cast(f32a) / f32b; // COMPLIANT +} + +void int_arg(std::int32_t i); + +std::int16_t test_args() { + float f32a; + float f32b; + int_arg(static_cast(f32a)); // COMPLIANT - f32a is not a cvalue + return static_cast(f32a); // COMPLIANT - f32a is not a cvalue } \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-8/test.cpp b/cpp/autosar/test/rules/M5-0-8/test.cpp index 198bebed9f..ab785c661a 100644 --- a/cpp/autosar/test/rules/M5-0-8/test.cpp +++ b/cpp/autosar/test/rules/M5-0-8/test.cpp @@ -22,4 +22,22 @@ void f() { f64 = static_cast(1.0f + 1.0f); // NON_COMPLIANT f32 = static_cast(1.0f + 1); // COMPLIANT f64 = static_cast(1.0 + 1); // COMPLIANT; no suffix defines a double +} + +#include + +void function_args() { + std::vector v{0}; + + std::uint32_t u32{0}; + v.at(static_cast(u32)); // COMPLIANT - cast is not a cvalue + std::size_t st = + static_cast(u32); // COMPLIANT - cast is not a cvalue + v.at(st); +} + +std::size_t return_args() { + std::uint32_t u32{0}; + + return static_cast(u32); // COMPLIANT } \ No newline at end of file diff --git a/cpp/autosar/test/rules/M5-0-9/ExplicitSignednessConversionOfCValue.expected b/cpp/autosar/test/rules/M5-0-9/ExplicitSignednessConversionOfCValue.expected index b2619503b3..b7fc97f99c 100644 --- a/cpp/autosar/test/rules/M5-0-9/ExplicitSignednessConversionOfCValue.expected +++ b/cpp/autosar/test/rules/M5-0-9/ExplicitSignednessConversionOfCValue.expected @@ -1,3 +1,3 @@ -| test.cpp:16:8:16:35 | static_cast... | Explicit integral conversion converts the signedness of the $@ from unsigned to signed. | test.cpp:16:28:16:34 | ... + ... | cvalue | -| test.cpp:18:8:18:40 | static_cast... | Explicit integral conversion converts the signedness of the $@ from unsigned to signed. | test.cpp:18:28:18:39 | ... + ... | cvalue | -| test.cpp:20:8:20:35 | static_cast... | Explicit integral conversion converts the signedness of the $@ from unsigned to signed. | test.cpp:20:28:20:34 | ... * ... | cvalue | +| test.cpp:20:8:20:35 | static_cast... | Explicit integral conversion converts the signedness of the $@ from unsigned to signed. | test.cpp:20:28:20:34 | ... + ... | cvalue | +| test.cpp:22:8:22:40 | static_cast... | Explicit integral conversion converts the signedness of the $@ from unsigned to signed. | test.cpp:22:28:22:39 | ... + ... | cvalue | +| test.cpp:24:8:24:35 | static_cast... | Explicit integral conversion converts the signedness of the $@ from unsigned to signed. | test.cpp:24:28:24:34 | ... * ... | cvalue | diff --git a/cpp/autosar/test/rules/M5-0-9/test.cpp b/cpp/autosar/test/rules/M5-0-9/test.cpp index b46dbc390f..7b050d24de 100644 --- a/cpp/autosar/test/rules/M5-0-9/test.cpp +++ b/cpp/autosar/test/rules/M5-0-9/test.cpp @@ -1,4 +1,8 @@ #include + +void signed_arg(std::uint32_t s); +void unsigned_arg(std::uint32_t u); + void f() { using std::int16_t; using std::int32_t; @@ -22,4 +26,7 @@ void f() { i16 = static_cast(i16 / i8); // NON_COMPLIANT i8 = static_cast(u8) + static_cast(u8); // COMPLIANT + + unsigned(static_cast(i32)); // COMPLIANT - i32 is not a cvalue + signed(static_cast(u32)); // COMPLIANT - u32 is not a cvalue } \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Expr.qll b/cpp/common/src/codingstandards/cpp/Expr.qll index fe2877f849..51066cf4cb 100644 --- a/cpp/common/src/codingstandards/cpp/Expr.qll +++ b/cpp/common/src/codingstandards/cpp/Expr.qll @@ -148,9 +148,17 @@ module MisraExpr { private predicate isCValue(Expr e) { not e.isConstant() and ( - exists(ReturnStmt return | e = return.getExpr()) + exists(ReturnStmt return | + e = return.getExpr() and + // Only return statements which are not explicitly casted are considered + not exists(Cast c | not c.isImplicit() and c.getExpr() = e) + ) or - exists(Call call | e = call.getAnArgument()) + exists(FunctionCall call | + e = call.getAnArgument() and + // // Only function arguments which are not explicitly casted are considered + not exists(Cast c | not c.isImplicit() and c.getExpr() = e) + ) ) or isCValue(e.(ParenthesisExpr).getExpr()) From 1340cdbcef49a5f7b99fa65370a5fef97e5977db Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 24 Oct 2024 23:23:50 -0700 Subject: [PATCH 066/628] Implement RULE-2-8, project should not contain unused object definitions. Also add a new AlertReporting shared query library for deduplicating results across macro definitions/invocations/etc. Split __attribute__((unused)) variables (and similar) to a Strict pair of queries. --- .../rules/RULE-2-8/UnusedObjectDefinition.ql | 24 ++ .../RULE-2-8/UnusedObjectDefinitionInMacro.ql | 24 ++ .../UnusedObjectDefinitionInMacroStrict.ql | 27 ++ .../RULE-2-8/UnusedObjectDefinitionStrict.ql | 26 ++ .../RULE-2-8/UnusedObjectDefinition.expected | 8 + .../RULE-2-8/UnusedObjectDefinition.qlref | 1 + .../UnusedObjectDefinitionInMacro.expected | 2 + .../UnusedObjectDefinitionInMacro.qlref | 1 + ...usedObjectDefinitionInMacroStrict.expected | 2 + .../UnusedObjectDefinitionInMacroStrict.qlref | 1 + .../UnusedObjectDefinitionStrict.expected | 2 + .../UnusedObjectDefinitionStrict.qlref | 1 + c/misra/test/rules/RULE-2-8/test.c | 113 ++++++ .../codingstandards/cpp/AlertReporting.qll | 28 +- .../DeduplicateMacroResults.qll | 379 ++++++++++++++++++ .../cpp/deadcode/UnusedObjects.qll | 176 ++++++++ .../cpp/exclusions/c/DeadCode2.qll | 78 ++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + .../DeduplicateMacroResults.expected | 6 + .../alertreporting/DeduplicateMacroResults.ql | 32 ++ .../deduplicatemacroresults.cpp | 53 +++ rule_packages/c/DeadCode2.json | 66 +++ 22 files changed, 1050 insertions(+), 3 deletions(-) create mode 100644 c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql create mode 100644 c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacro.ql create mode 100644 c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.ql create mode 100644 c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql create mode 100644 c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected create mode 100644 c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.qlref create mode 100644 c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.expected create mode 100644 c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.qlref create mode 100644 c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.expected create mode 100644 c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.qlref create mode 100644 c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected create mode 100644 c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.qlref create mode 100644 c/misra/test/rules/RULE-2-8/test.c create mode 100644 cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll create mode 100644 cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/DeadCode2.qll create mode 100644 cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected create mode 100644 cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql create mode 100644 cpp/common/test/library/codingstandards/cpp/alertreporting/deduplicatemacroresults.cpp create mode 100644 rule_packages/c/DeadCode2.json diff --git a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql new file mode 100644 index 0000000000..420733d4ac --- /dev/null +++ b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/unused-object-definition + * @name RULE-2-8: A project should not contain unused object definitions + * @description Object definitions which are unused should be removed. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-2-8 + * maintainability + * performance + * external/misra/c/2012/amendment4 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.deadcode.UnusedObjects + +from ReportDeadObjectAtDefinition report +where + not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionQuery()) and + not report.hasAttrUnused() +select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(), + report.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacro.ql b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacro.ql new file mode 100644 index 0000000000..d5c339c157 --- /dev/null +++ b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacro.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/unused-object-definition-in-macro + * @name RULE-2-8: Project macros should not include unused object definitions + * @description Macros should not have unused object definitions. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-2-8 + * maintainability + * performance + * external/misra/c/2012/amendment4 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.deadcode.UnusedObjects + +from ReportDeadObjectInMacro report +where + not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionInMacroQuery()) and + not report.hasAttrUnused() +select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(), + report.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.ql b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.ql new file mode 100644 index 0000000000..7eead60424 --- /dev/null +++ b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.ql @@ -0,0 +1,27 @@ +/** + * @id c/misra/unused-object-definition-in-macro-strict + * @name RULE-2-8: Project macros should not include '__attribute__((unused))' object definitions + * @description A strict query which reports all unused object definitions in macros with + * '__attribute__((unused))'. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-2-8 + * maintainability + * performance + * external/misra/c/2012/amendment4 + * external/misra/c/strict + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.deadcode.UnusedObjects + +from ReportDeadObjectInMacro report +where + not isExcluded(report.getPrimaryElement(), + DeadCode2Package::unusedObjectDefinitionInMacroStrictQuery()) and + report.hasAttrUnused() +select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(), + report.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql new file mode 100644 index 0000000000..ad92c79481 --- /dev/null +++ b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql @@ -0,0 +1,26 @@ +/** + * @id c/misra/unused-object-definition-strict + * @name RULE-2-8: A project should not contain '__attribute__((unused))' object definitions + * @description A strict query which reports all unused object definitions with + * '__attribute__((unused))'. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-2-8 + * maintainability + * performance + * external/misra/c/2012/amendment4 + * external/misra/c/strict + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.deadcode.UnusedObjects + +from ReportDeadObjectAtDefinition report +where + not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionStrictQuery()) and + report.hasAttrUnused() +select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(), + report.getOptionalPlaceholderMessage() diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected new file mode 100644 index 0000000000..fc6f320539 --- /dev/null +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected @@ -0,0 +1,8 @@ +| test.c:6:5:6:6 | definition of g2 | Unused object definition 'g2'. | test.c:6:5:6:6 | test.c:6:5:6:6 | | +| test.c:9:5:9:6 | definition of g3 | Unused object definition 'g3'. | test.c:9:5:9:6 | test.c:9:5:9:6 | | +| test.c:20:7:20:8 | definition of l2 | Unused object definition 'l2'. | test.c:20:7:20:8 | test.c:20:7:20:8 | | +| test.c:27:7:27:8 | definition of l5 | Unused object definition 'l5'. | test.c:27:7:27:8 | test.c:27:7:27:8 | | +| test.c:37:10:37:11 | definition of g5 | Unused object definition 'g5'. | test.c:37:10:37:11 | test.c:37:10:37:11 | | +| test.c:45:9:45:10 | definition of g6 | Unused object definition 'g6'. | test.c:45:9:45:10 | test.c:45:9:45:10 | | +| test.c:51:5:51:6 | definition of g7 | Unused object definition 'g7'. | test.c:51:5:51:6 | test.c:51:5:51:6 | | +| test.c:64:3:64:18 | ONLY_DEF_VAR(x) | Unused object definition 'l2' from macro '$@'. | test.c:60:1:60:34 | test.c:60:1:60:34 | ONLY_DEF_VAR | diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.qlref b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.qlref new file mode 100644 index 0000000000..096c4c64f1 --- /dev/null +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.qlref @@ -0,0 +1 @@ +rules/RULE-2-8/UnusedObjectDefinition.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.expected b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.expected new file mode 100644 index 0000000000..c25c136789 --- /dev/null +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.expected @@ -0,0 +1,2 @@ +| test.c:68:1:71:5 | #define ALSO_DEF_VAR(x) int x = 0; while (1) ; | Macro 'ALSO_DEF_VAR' defines unused object of varied names, for example, '$@'. | test.c:73:16:73:17 | test.c:73:16:73:17 | l1 | +| test.c:77:1:82:3 | #define DEF_UNUSED_INNER_VAR() { int _v = 0; while (1) ; } | Macro 'DEF_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:77:1:82:3 | test.c:77:1:82:3 | (ignored) | diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.qlref b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.qlref new file mode 100644 index 0000000000..057e684fd0 --- /dev/null +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.qlref @@ -0,0 +1 @@ +rules/RULE-2-8/UnusedObjectDefinitionInMacro.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.expected b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.expected new file mode 100644 index 0000000000..2919c65cb7 --- /dev/null +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.expected @@ -0,0 +1,2 @@ +| test.c:94:1:97:5 | #define ALSO_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0; while (1) ; | Macro 'ALSO_DEF_ATTR_UNUSED_VAR' defines unused object of varied names, for example, '$@'. | test.c:99:28:99:29 | test.c:99:28:99:29 | l1 | +| test.c:104:1:109:3 | #define DEF_ATTR_UNUSED_INNER_VAR() { __attribute__((unused)) int _v = 0; while (1) ; } | Macro 'DEF_ATTR_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:104:1:109:3 | test.c:104:1:109:3 | (ignored) | diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.qlref b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.qlref new file mode 100644 index 0000000000..f04653dcb6 --- /dev/null +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.qlref @@ -0,0 +1 @@ +rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected new file mode 100644 index 0000000000..624368ac54 --- /dev/null +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected @@ -0,0 +1,2 @@ +| test.c:87:29:87:30 | definition of g8 | Unused object definition 'g8'. | test.c:87:29:87:30 | test.c:87:29:87:30 | | +| test.c:90:3:90:30 | ONLY_DEF_ATTR_UNUSED_VAR(x) | Unused object definition 'l2' from macro '$@'. | test.c:88:1:88:70 | test.c:88:1:88:70 | ONLY_DEF_ATTR_UNUSED_VAR | diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.qlref b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.qlref new file mode 100644 index 0000000000..4aa7269881 --- /dev/null +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.qlref @@ -0,0 +1 @@ +rules/RULE-2-8/UnusedObjectDefinitionStrict.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-8/test.c b/c/misra/test/rules/RULE-2-8/test.c new file mode 100644 index 0000000000..21a2479163 --- /dev/null +++ b/c/misra/test/rules/RULE-2-8/test.c @@ -0,0 +1,113 @@ +// Not a definition, only a declaration: +extern int g1; // COMPLIANT + +// Both declared + defined: +extern int g2; // COMPLIANT +int g2 = 1; // NON_COMPLIANT + +// Definition is only declaration: +int g3 = 1; // NON_COMPLIANT + +// Definition, but value is required for program to compile: +int g4 = 1; // COMPLIANT +void f1() { g4; } + +// Local variables: +void f2() { + int l1; // COMPLIANT + l1; + + int l2; // NON-COMPLIANT + + // Value is required for the program to compile: + int l3; // COMPLIANT + sizeof(l3); + + int l4, // COMPLIANT + l5; // NON-COMPLIANT + l4; +} + +// Struct fields are not objects: +struct s { + int x; // COMPLIANT +}; + +// Declaration of type struct is an object: +struct s g5; // NON-COMPLIANT + +// Struct fields are not objects: +union u { + int x; // COMPLIANT +}; + +// Declaration of type union is an object: +union u g6; // NON-COMPLIANT + +// Typedefs are not objects: +typedef int td1; // COMPLIANT + +// Declaration of typedef type object: +td1 g7; // NON-COMPLIANT + +// Function parameters are not objects: +void f3(int p) {} // COMPLIANT + +// Function type parameters are not objects: +typedef int td2(int x); // COMPLIANT + +// Macros that define unused vars tests: +#define ONLY_DEF_VAR(x) int x = 0; +void f4() { + ONLY_DEF_VAR(l1); // COMPLIANT + l1; + ONLY_DEF_VAR(l2); // NON-COMPLIANT +} + +// NON-COMPLIANT +#define ALSO_DEF_VAR(x) \ + int x = 0; \ + while (1) \ + ; +void f5() { + ALSO_DEF_VAR(l1); // COMPLIANT + ALSO_DEF_VAR(l2); // COMPLIANT +} + +#define DEF_UNUSED_INNER_VAR() \ + { \ + int _v = 0; \ + while (1) \ + ; \ + } // NON-COMPLIANT +void f6() { + DEF_UNUSED_INNER_VAR(); // COMPLIANT +} + +__attribute__((unused)) int g8 = 1; // NON-COMPLIANT +#define ONLY_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0; +void f7() { + ONLY_DEF_ATTR_UNUSED_VAR(l2); // NON-COMPLIANT +} + +// NON-COMPLIANT +#define ALSO_DEF_ATTR_UNUSED_VAR(x) \ + __attribute__((unused)) int x = 0; \ + while (1) \ + ; +void f8() { + ALSO_DEF_ATTR_UNUSED_VAR(l1); // COMPLIANT + ALSO_DEF_ATTR_UNUSED_VAR(l2); // COMPLIANT +} + +// NON-COMPLIANT +#define DEF_ATTR_UNUSED_INNER_VAR() \ + { \ + __attribute__((unused)) int _v = 0; \ + while (1) \ + ; \ + } + +void f9() { + DEF_ATTR_UNUSED_INNER_VAR(); // COMPLIANT +} diff --git a/cpp/common/src/codingstandards/cpp/AlertReporting.qll b/cpp/common/src/codingstandards/cpp/AlertReporting.qll index 4259e1b67d..3ef5315906 100644 --- a/cpp/common/src/codingstandards/cpp/AlertReporting.qll +++ b/cpp/common/src/codingstandards/cpp/AlertReporting.qll @@ -18,19 +18,24 @@ module MacroUnwrapper { } /** - * Gets the primary macro that generated the result element. + * Gets the primary macro invocation that generated the result element. */ - Macro getPrimaryMacro(ResultElement re) { + MacroInvocation getPrimaryMacroInvocation(ResultElement re) { exists(MacroInvocation mi | mi = getAMacroInvocation(re) and // No other more specific macro that expands to element not exists(MacroInvocation otherMi | otherMi = getAMacroInvocation(re) and otherMi.getParentInvocation() = mi ) and - result = mi.getMacro() + result = mi ) } + /** + * Gets the primary macro that generated the result element. + */ + Macro getPrimaryMacro(ResultElement re) { result = getPrimaryMacroInvocation(re).getMacro() } + /** * If a result element is expanded from a macro invocation, then return the "primary" macro that * generated the element, otherwise return the element itself. @@ -38,4 +43,21 @@ module MacroUnwrapper { Element unwrapElement(ResultElement re) { if exists(getPrimaryMacro(re)) then result = getPrimaryMacro(re) else result = re } + + /* Final class so we can extend it */ + final private class FinalMacroInvocation = MacroInvocation; + + /* A macro invocation that expands to create a `ResultElement` */ + class ResultMacroExpansion extends FinalMacroInvocation { + ResultElement re; + + ResultMacroExpansion() { re = getAnExpandedElement() } + + ResultElement getResultElement() { result = re } + } + + /* The most specific macro invocation that expands to create this `ResultElement`. */ + class PrimaryMacroExpansion extends ResultMacroExpansion { + PrimaryMacroExpansion() { this = getPrimaryMacroInvocation(re) } + } } diff --git a/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll b/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll new file mode 100644 index 0000000000..7c4e8ef41d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll @@ -0,0 +1,379 @@ +import codingstandards.cpp.AlertReporting + +/** + * A configuration for deduplicating query results inside of macros. + * + * See doc comment on `DeduplicateMacroResults` module. + */ +signature module DeduplicateMacroConfigSig { + /** + * Stringify the `ResultElement`. All `ResultElement`s that share an "identity" should stringify + * to the same string to get proper results. + */ + string describe(ResultElement re); +} + +/** + * A configuration for generating reports from reports that may or may not be duplicated across + * macro expansions. + * + * See doc comment on `DeduplicateMacroResults` module. + * + * This signature is used to parameterize the module `DeduplicateMacroResults::Report`. + */ +signature module MacroReportConfigSig { + /* Create a message to describe this macro, with a string describing its `ResultElement`. */ + bindingset[description] + string getMessageSameResultInAllExpansions(Macro m, string description); + + /* Create a message to describe this macro, using '$@' to describe an example `ResultElement`. */ + string getMessageVariedResultInAllExpansions(Macro m); + + /* + * Create a message to describe this macro expansion which produces a `ResultElement`, using '$@' + * to describe the relevant macro. + */ + + string getMessageResultInIsolatedExpansion(ResultElement element); +} + +/** + * A module for taking the results of `MacroUnwrapper` and consolidating them. + * + * The module `MacroUnwrapper` is great for simple alerts such as usage of banned functions. In + * such cases, reporting "call to 'foo()' in macro 'M'" will only have one result even if the macro + * is expanded multiple times. + * + * However, other queries may have a dynamic message which can vary per macro call site due to + * token manipulation (`a ## b`), for instance, "Macro 'M' defines unused object 'generated_name_x'" + * which will lead to hundreds of results if there are hundreds of such generated names. + * + * This module can be used to find and easily report non-compliant behavior, grouped by the macro + * it originates in, regardless of whether the messages will exactly match. + * + * ## General Usage + * + * To use this macro, define a class for the relevant behavior, and a means of stringifying + * relevant elements as a config, to parameterize the `DeduplicateMacroResults` module. + * + * ``` + * class InvalidFoo extends Foo { + * InvalidFoo() { ... } + * } + * + * module DeduplicateFooInMacrosConfig implements DeduplicateMacroConfigSig { + * string describe(InvalidFoo foo) { result = ... } + * } + * + * import DeduplicateMacroResults as DeduplicateFooInMacros; + * ``` + * + * This module exposes the following classes: + * - `PrimaryMacroSameResultElementInAllInvocations extends Macro`: Every invocation of this macro + * generates an `InvalidFoo` which stringifies to the same thing. Use the method + * `getResultElementDescription()` to get that shared string. + * - `PrimaryMacroDifferentResultElementInAllInvocations extends Macro`: Every invocation of this + * macro generates an `InvalidFoo`, but they do not all stringify to the same thing. Use the + * method `getExampleResultElement()` to get an *single* example `InvalidFoo` to help users fix + * and understand the issue. + * - `IsolatedMacroExpansionWithResultElement extends MacroInvocation`: An invocation of a macro + * which in this particular instance generates an `InvalidFoo`, while other invocations of the + * same macro do not. + * + * The three above classes all attempt to resolve to the most *specific* macro to the issue at + * hand. For instance, if macro `M1` calls macro `M2` which expands to an `InvalidFoo`, then the + * problem may be with `M2` (it is the most specific macro call here), or the problem may be with + * `M2` (if all expansions of `M2` generate an `InvalidFoo` but not all expansions of `M1` do so). + * + * ## Generating Report Objects + * + * This module also can be used to more easily report issues across these cases, by implementing + * `MacroReportConfigSig` and importing `DeduplicateMacroResults::Report::ReportResultInMacro`. + * + * ``` + * module InvalidFooInMacroReportConfig implements MacroReportConfigSig { + * + * // ***Take care that usage of $@ is correct in the following predicates***!!!! + * bindingset[description] + * string getMessageSameResultInAllExpansions(Macro m, string description) { + * result = "Macro " + m.getName() + " always has invalid foo " + description + * } + * + * string getMessageVariedResultInAllExpansions(Macro m) { + * result = "Macro " + m.getName() + " always has invalid foo, for example '$@'." + * } + * + * string getMessageResultInIsolatedExpansion(InvalidFoo foo) { + * result = "Invocation of macro $@ has invalid foo '" + foo.getName() + "'." + * } + * } + * + * import DeduplicateFooInMacros::Report as Report; + * + * from Report::ReportResultInMacro report + * where not excluded(report.getPrimaryElement(), ...) + * select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(), + * report.getOptionalPlaceholderMessage() + * ``` + * + * Note that this does *not* (currently) generate a result for elements not contained by a macro. + * To do report such cases, either add support for that in this module, or write a separate query + * that reports `InvalidFoo` cases where not `.isInMacroExpansion()`. + */ +module DeduplicateMacroResults< + ResultType ResultElement, DeduplicateMacroConfigSig Config> +{ + /* A final class so that we may extend Macro. */ + final private class FinalMacro = Macro; + + /* Helper final class import so that we may reference/extend it. */ + final private class ResultMacroExpansion = MacroUnwrapper::ResultMacroExpansion; + + /** + * A macro for which all of its invocations produce an element that is described the same way. + * + * This is not necessarily the "primary" / most specific macro for these result elements. + * This difference is captured in `PrimarySameResultElementInAllMacroInvocations`, and the two + * classes are only separate to avoid non-monotonic recursion. + */ + private class SameResultElementInAllMacroInvocations extends FinalMacro { + string resultElementDescription; + + SameResultElementInAllMacroInvocations() { + forex(MacroInvocation mi | mi = getAnInvocation() | + Config::describe(mi.(ResultMacroExpansion).getResultElement()) = resultElementDescription + ) + } + + string getResultElementDescription() { result = resultElementDescription } + + ResultElement getAResultElement() { + result = getAnInvocation().(ResultMacroExpansion).getResultElement() + } + } + + /** + * A macro for which all of its invocations produce an element that is described the same way. + * + * This is the necessarily the "primary" / most specific macro for these result elements. + */ + class PrimaryMacroSameResultElementInAllInvocations extends SameResultElementInAllMacroInvocations + { + PrimaryMacroSameResultElementInAllInvocations() { + not exists(MacroInvocation inner | + inner.getParentInvocation() = getAnInvocation() and + inner.getMacro() instanceof SameResultElementInAllMacroInvocations + ) + } + } + + /** + * A expansion that generates a `ResultElement` that is uniquely described by the config. + * + * This is used so that we can find a single example invocation site to report as an example for + * macros which generate an array of different `ResultElement`s that are described differently. + * + * For example, two macro invocations may be given the same arguments, and generate the same + * `ResultElement`, while a third macro invocation is unique and generates a unique + * `ResultElement`. We wish to direct the user to that unique example or we will show the user + * two different reports for one underlying issue. + */ + private class UniqueResultMacroExpansion extends ResultMacroExpansion { + UniqueResultMacroExpansion() { + not exists(ResultMacroExpansion other | + not this = other and + this.getMacroName() = other.getMacroName() and + Config::describe(this.getResultElement()) = Config::describe(other.getResultElement()) + ) + } + } + + /** + * A macro for which all of its invocations produce an element, but they are not all described the + * same way. + * + * This is not necessarily the "primary" / most specific macro for these result elements. + * This difference is captured in `PrimaryDiferentResultElementInAllMacroInvocations`, and the two + * classes are only separate to avoid non-monotonic recursion. + */ + private class DifferentResultElementInAllMacroInvocations extends FinalMacro { + ResultElement exampleResultElement; + + DifferentResultElementInAllMacroInvocations() { + forex(MacroInvocation mi | mi = getAnInvocation() | mi instanceof ResultMacroExpansion) and + count(getAnInvocation().(ResultMacroExpansion).getResultElement()) > 1 and + exists(string description | + description = + rank[1](Config::describe(getAnInvocation().(UniqueResultMacroExpansion).getResultElement()) + ) and + Config::describe(exampleResultElement) = description and + exampleResultElement = getAnInvocation().(ResultMacroExpansion).getResultElement() + ) + } + + ResultElement getExampleResultElement() { result = exampleResultElement } + + ResultElement getAResultElement() { + result = getAnInvocation().(ResultMacroExpansion).getResultElement() + } + } + + /** + * A macro for which all of its invocations produce an element, but they are not all described the + * same way. + * + * This is "primary" / most specific macro for these result elements. + */ + class PrimaryMacroDifferentResultElementInAllInvocations extends DifferentResultElementInAllMacroInvocations + { + PrimaryMacroDifferentResultElementInAllInvocations() { + not exists(MacroInvocation inner | + inner.getParentInvocation() = getAnInvocation() and + inner.getMacro() instanceof DifferentResultElementInAllMacroInvocations + ) + } + } + + /* + * Convenience predicate to know when invalid macro expansions have been reported at their macro + * definition. + */ + + private predicate reported(Macro macro) { + macro instanceof PrimaryMacroSameResultElementInAllInvocations or + macro instanceof PrimaryMacroDifferentResultElementInAllInvocations + } + + /** + * A macro invocation for which the target macro does not always produce a `ResultElement`, but + * this specific invocation of it does. + * + * This is "primary" / most specific macro for these result elements. It will also does not match + * `MacroInvocation`s inside of a `MacroInvocation` of a `Macro` which always produces a + * `ResultElement`, indicating that the real problem lies with that other `Macro` instead of with + * this particular invocation. + */ + class IsolatedMacroExpansionWithResultElement extends ResultMacroExpansion { + IsolatedMacroExpansionWithResultElement() { + not reported(getParentInvocation*().getMacro()) and + not exists(MacroInvocation inner | + reported(inner.getMacro()) and + inner.getParentInvocation*() = this + ) and + not exists(ResultMacroExpansion moreSpecific | + moreSpecific.getResultElement() = getResultElement() and + moreSpecific.getParentInvocation+() = this + ) + } + } + + /** + * A module for generating reports across the various cases of problematic macros, problematic + * macro invocations. + * + * See the doc comment for the `DeduplicateMacroResults` module for more info. + */ + module Report ReportConfig> { + newtype TReportResultInMacro = + TReportMacroResultWithSameName(PrimaryMacroSameResultElementInAllInvocations def) or + TReportMacroResultWithVariedName(PrimaryMacroDifferentResultElementInAllInvocations def) or + TReportIsolatedMacroResult(IsolatedMacroExpansionWithResultElement def) + + /** + * An instance of a `ResultElement` to be reported to a user. + * + * To show a report, use the following methods: + * - `report.getPrimaryElement()` + * - `report.getMessage()` + * - `report.getOptionalPlaceholderLocation()` + * - `report.getOptionalPlaceholderMessage()` + * + * The values returned by these methods are configured by the `MacroReportConfigSig` + * signature parameter. + */ + class ReportResultInMacro extends TReportResultInMacro { + string toString() { result = getMessage() } + + string getMessage() { + exists(PrimaryMacroDifferentResultElementInAllInvocations def | + this = TReportMacroResultWithVariedName(def) and + result = ReportConfig::getMessageVariedResultInAllExpansions(def) + ) + or + exists(PrimaryMacroSameResultElementInAllInvocations def | + this = TReportMacroResultWithSameName(def) and + result = + ReportConfig::getMessageSameResultInAllExpansions(def, def.getResultElementDescription()) + ) + or + exists(IsolatedMacroExpansionWithResultElement def | + this = TReportIsolatedMacroResult(def) and + result = ReportConfig::getMessageResultInIsolatedExpansion(def.getResultElement()) + ) + } + + Element getPrimaryElement() { + this = TReportMacroResultWithSameName(result) + or + this = TReportMacroResultWithVariedName(result) + or + this = TReportIsolatedMacroResult(result) + } + + Location getOptionalPlaceholderLocation() { + exists(PrimaryMacroDifferentResultElementInAllInvocations def | + this = TReportMacroResultWithVariedName(def) and + result = def.getExampleResultElement().getLocation() + ) + or + exists(PrimaryMacroSameResultElementInAllInvocations def | + this = TReportMacroResultWithSameName(def) and + result = def.getLocation() + ) + or + exists(IsolatedMacroExpansionWithResultElement def | + this = TReportIsolatedMacroResult(def) and + result = def.getMacro().getLocation() + ) + } + + string getOptionalPlaceholderMessage() { + exists(PrimaryMacroDifferentResultElementInAllInvocations def | + this = TReportMacroResultWithVariedName(def) and + result = Config::describe(def.getExampleResultElement()) + ) + or + this = TReportMacroResultWithSameName(_) and + result = "(ignored)" + or + this = TReportIsolatedMacroResult(_) and + result = getMacro().getName() + } + + Macro getMacro() { + this = TReportMacroResultWithVariedName(result) + or + this = TReportMacroResultWithSameName(result) + or + exists(IsolatedMacroExpansionWithResultElement def | + this = TReportIsolatedMacroResult(def) and + result = def.getMacro() + ) + } + + ResultMacroExpansion getAResultMacroExpansion() { + exists(PrimaryMacroDifferentResultElementInAllInvocations def | + this = TReportMacroResultWithVariedName(def) and + result = def.getAnInvocation() + ) + or + exists(PrimaryMacroSameResultElementInAllInvocations def | + this = TReportMacroResultWithSameName(def) and + result = def.getAnInvocation() + ) + or + this = TReportIsolatedMacroResult(result) + } + } + } +} diff --git a/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll b/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll new file mode 100644 index 0000000000..70944dfad4 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll @@ -0,0 +1,176 @@ +import cpp +import codingstandards.cpp.alertreporting.HoldsForAllCopies +import codingstandards.cpp.alertreporting.DeduplicateMacroResults + +/** + * An unused object definition is an object, meaning a place in memory, whose definition could be + * removed and the program would still compile. + * + * Technically, parameters may be considered objects, but they are covered by their own rule. + * Similarly, members of structs are an addressable place in memory, and may be considered objects. + * However, the member declaration is nothing but a layout offset, which is not an object. + * + * This therefore only reports variables (local or top level) which have a definition, and are + * unused. + */ +class UnusedObjectDefinition extends VariableDeclarationEntry { + UnusedObjectDefinition() { + not exists(VariableAccess access | access.getTarget() = getVariable()) and + getVariable().getDefinition() = this and + not this instanceof ParameterDeclarationEntry and + not getVariable() instanceof MemberVariable + } + + /* Dead objects with these attributes are reported in the "strict" queries. */ + predicate hasAttrUnused() { + getVariable().getAnAttribute().hasName(["unused", "used", "maybe_unused", "cleanup"]) + } +} + +/* Configuration to use the `DedupMacroResults` module to reduce alert noise */ +module UnusedObjectDefinitionDedupeConfig implements + DeduplicateMacroConfigSig +{ + string describe(UnusedObjectDefinition def) { result = def.getName() } +} + +import DeduplicateMacroResults as DeduplicateUnusedMacroObjects + +/** + * A macro invocation that only defines one unused variable. + * + * These are reported at the invocation site when the variable is unused. + */ +class MacroExpansionWithOnlyUnusedObjectDefinition extends MacroInvocation { + UnusedObjectDefinition unusedObject; + + MacroExpansionWithOnlyUnusedObjectDefinition() { + exists(DeclStmt stmt, Declaration decl | + stmt = getStmt() and + count(getStmt()) = 1 and + count(stmt.getADeclaration()) = 1 and + decl = stmt.getADeclaration() and + count(decl.getADeclarationEntry()) = 1 and + unusedObject = decl.getADeclarationEntry() + ) and + not exists(this.getParentInvocation()) + } + + UnusedObjectDefinition getUnusedObject() { result = unusedObject } +} + +/** + * An object definition which is not from a macro, and for which all copies are unused. + * + * Extends the `HoldForAllCopies::LogicalResultElement` class, because these dead objects are often + * duplicated across defines and sometimes aren't marked used due to extractor bugs. + */ +class SimpleDeadObjectDefinition extends HoldsForAllCopies::LogicalResultElement +{ + SimpleDeadObjectDefinition() { not getAnElementInstance().isInMacroExpansion() } + + string getName() { result = getAnElementInstance().getName() } +} + +/* Make a type for reporting these two results in one query */ +newtype TReportDeadObjectAtDefinition = + TSimpleDeadObjectDefinition(SimpleDeadObjectDefinition def) or + TMacroExpansionWithOnlyUnusedObject(MacroExpansionWithOnlyUnusedObjectDefinition def) + +/** + * Class to report simple dead object definitions, and dead objects from macros that do nothing but + * define an object. + * + * To report all cases, make sure to also use the `DeduplicateUnusedMacroObjects::Report` module. + * + * To report these cases, use the methods: + * - `getMessage()` + * - `getPrimaryElement()`, + * - `getOptionalPlaceholderLocation()` + * - `getOptionalPlaceholderMessage()` + */ +class ReportDeadObjectAtDefinition extends TReportDeadObjectAtDefinition { + string toString() { result = getMessage() } + + string getMessage() { + exists(MacroExpansionWithOnlyUnusedObjectDefinition def | + this = TMacroExpansionWithOnlyUnusedObject(def) and + result = "Unused object definition '" + def.getUnusedObject().getName() + "' from macro '$@'." + ) + or + exists(SimpleDeadObjectDefinition def | + this = TSimpleDeadObjectDefinition(def) and + result = "Unused object definition '" + def.getName() + "'." + ) + } + + predicate hasAttrUnused() { + exists(MacroExpansionWithOnlyUnusedObjectDefinition def | + this = TMacroExpansionWithOnlyUnusedObject(def) and + def.getUnusedObject().hasAttrUnused() + ) + or + exists(SimpleDeadObjectDefinition def | + this = TSimpleDeadObjectDefinition(def) and + def.getAnElementInstance().hasAttrUnused() + ) + } + + Element getPrimaryElement() { + this = TMacroExpansionWithOnlyUnusedObject(result) + or + exists(SimpleDeadObjectDefinition def | + this = TSimpleDeadObjectDefinition(def) and + result = def.getAnElementInstance() + ) + } + + Location getOptionalPlaceholderLocation() { + exists(MacroExpansionWithOnlyUnusedObjectDefinition def | + this = TMacroExpansionWithOnlyUnusedObject(def) and + result = def.getMacro().getLocation() + ) + or + exists(SimpleDeadObjectDefinition def | + this = TSimpleDeadObjectDefinition(def) and + result = def.getAnElementInstance().getLocation() + ) + } + + string getOptionalPlaceholderMessage() { + exists(MacroExpansionWithOnlyUnusedObjectDefinition def | + this = TMacroExpansionWithOnlyUnusedObject(def) and + result = def.getMacroName() + ) + or + this = TSimpleDeadObjectDefinition(_) and + result = "" + } +} + +/* Module config to use the `DeduplicateUnusedMacroObjects::Report` module */ +module ReportDeadObjectInMacroConfig implements MacroReportConfigSig { + bindingset[description] + string getMessageSameResultInAllExpansions(Macro m, string description) { + result = "Macro '" + m.getName() + "' defines unused object '" + description + "'." + } + + string getMessageVariedResultInAllExpansions(Macro m) { + result = "Macro '" + m.getName() + "' defines unused object of varied names, for example, '$@'." + } + + string getMessageResultInIsolatedExpansion(UnusedObjectDefinition unused) { + result = "Invocation of macro '$@' defines unused object '" + unused.getName() + "'." + } +} + +/* The object to report in queries of dead objects used in macros */ +class ReportDeadObjectInMacro extends DeduplicateUnusedMacroObjects::Report::ReportResultInMacro +{ + ReportDeadObjectInMacro() { + // `MacroExpansionWithOnlyUnusedObjectDefinition` is reported by class `ReportDeadObjectAtDefinition` + not getAResultMacroExpansion() instanceof MacroExpansionWithOnlyUnusedObjectDefinition + } + + predicate hasAttrUnused() { getAResultMacroExpansion().getResultElement().hasAttrUnused() } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/DeadCode2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/DeadCode2.qll new file mode 100644 index 0000000000..8f8edc03fa --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/DeadCode2.qll @@ -0,0 +1,78 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype DeadCode2Query = + TUnusedObjectDefinitionQuery() or + TUnusedObjectDefinitionInMacroQuery() or + TUnusedObjectDefinitionStrictQuery() or + TUnusedObjectDefinitionInMacroStrictQuery() + +predicate isDeadCode2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `unusedObjectDefinition` query + DeadCode2Package::unusedObjectDefinitionQuery() and + queryId = + // `@id` for the `unusedObjectDefinition` query + "c/misra/unused-object-definition" and + ruleId = "RULE-2-8" and + category = "advisory" + or + query = + // `Query` instance for the `unusedObjectDefinitionInMacro` query + DeadCode2Package::unusedObjectDefinitionInMacroQuery() and + queryId = + // `@id` for the `unusedObjectDefinitionInMacro` query + "c/misra/unused-object-definition-in-macro" and + ruleId = "RULE-2-8" and + category = "advisory" + or + query = + // `Query` instance for the `unusedObjectDefinitionStrict` query + DeadCode2Package::unusedObjectDefinitionStrictQuery() and + queryId = + // `@id` for the `unusedObjectDefinitionStrict` query + "c/misra/unused-object-definition-strict" and + ruleId = "RULE-2-8" and + category = "advisory" + or + query = + // `Query` instance for the `unusedObjectDefinitionInMacroStrict` query + DeadCode2Package::unusedObjectDefinitionInMacroStrictQuery() and + queryId = + // `@id` for the `unusedObjectDefinitionInMacroStrict` query + "c/misra/unused-object-definition-in-macro-strict" and + ruleId = "RULE-2-8" and + category = "advisory" +} + +module DeadCode2Package { + Query unusedObjectDefinitionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unusedObjectDefinition` query + TQueryC(TDeadCode2PackageQuery(TUnusedObjectDefinitionQuery())) + } + + Query unusedObjectDefinitionInMacroQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unusedObjectDefinitionInMacro` query + TQueryC(TDeadCode2PackageQuery(TUnusedObjectDefinitionInMacroQuery())) + } + + Query unusedObjectDefinitionStrictQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unusedObjectDefinitionStrict` query + TQueryC(TDeadCode2PackageQuery(TUnusedObjectDefinitionStrictQuery())) + } + + Query unusedObjectDefinitionInMacroStrictQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unusedObjectDefinitionInMacroStrict` query + TQueryC(TDeadCode2PackageQuery(TUnusedObjectDefinitionInMacroStrictQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 3833533d50..75aad6f02c 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -19,6 +19,7 @@ import Contracts5 import Contracts6 import Contracts7 import DeadCode +import DeadCode2 import Declarations1 import Declarations2 import Declarations3 @@ -95,6 +96,7 @@ newtype TCQuery = TContracts6PackageQuery(Contracts6Query q) or TContracts7PackageQuery(Contracts7Query q) or TDeadCodePackageQuery(DeadCodeQuery q) or + TDeadCode2PackageQuery(DeadCode2Query q) or TDeclarations1PackageQuery(Declarations1Query q) or TDeclarations2PackageQuery(Declarations2Query q) or TDeclarations3PackageQuery(Declarations3Query q) or @@ -171,6 +173,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isContracts6QueryMetadata(query, queryId, ruleId, category) or isContracts7QueryMetadata(query, queryId, ruleId, category) or isDeadCodeQueryMetadata(query, queryId, ruleId, category) or + isDeadCode2QueryMetadata(query, queryId, ruleId, category) or isDeclarations1QueryMetadata(query, queryId, ruleId, category) or isDeclarations2QueryMetadata(query, queryId, ruleId, category) or isDeclarations3QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected new file mode 100644 index 0000000000..eb55b83924 --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected @@ -0,0 +1,6 @@ +| deduplicatemacroresults.cpp:10:1:10:34 | SOMETIMES_HAS_RESULTS1(type,name) | Invocation of macro $@ has findme var 'g3'. | deduplicatemacroresults.cpp:6:1:6:52 | deduplicatemacroresults.cpp:6:1:6:52 | SOMETIMES_HAS_RESULTS1 | +| deduplicatemacroresults.cpp:13:1:13:34 | SOMETIMES_HAS_RESULTS2(type,name) | Invocation of macro $@ has findme var 'g5'. | deduplicatemacroresults.cpp:7:1:7:53 | deduplicatemacroresults.cpp:7:1:7:53 | SOMETIMES_HAS_RESULTS2 | +| deduplicatemacroresults.cpp:15:1:15:50 | #define ALWAYS_HAS_SAME_RESULT() extern findme g6; | Macro ALWAYS_HAS_SAME_RESULT always has findme var named g6 | deduplicatemacroresults.cpp:15:1:15:50 | deduplicatemacroresults.cpp:15:1:15:50 | (ignored) | +| deduplicatemacroresults.cpp:21:1:21:70 | #define ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name) extern findme name; | Macro ALWAYS_HAS_RESULT_VARIED_DESCRIPTION always has findme var, for example '$@'. | deduplicatemacroresults.cpp:23:38:23:39 | deduplicatemacroresults.cpp:23:38:23:39 | g7 | +| deduplicatemacroresults.cpp:30:1:31:50 | #define OUTER_ALWAYS_HAS_SAME_RESULT() extern INNER_SOMETIMES_HAS_RESULTS(findme, g10); | Macro OUTER_ALWAYS_HAS_SAME_RESULT always has findme var named g10 | deduplicatemacroresults.cpp:30:1:31:50 | deduplicatemacroresults.cpp:30:1:31:50 | (ignored) | +| deduplicatemacroresults.cpp:37:1:38:52 | #define OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name) INNER_SOMETIMES_HAS_RESULTS(findme, name ## suffix); | Macro OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION always has findme var, for example '$@'. | deduplicatemacroresults.cpp:40:44:40:47 | deduplicatemacroresults.cpp:40:44:40:47 | g11suffix | diff --git a/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql new file mode 100644 index 0000000000..cd999d72c9 --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql @@ -0,0 +1,32 @@ +import cpp +import codingstandards.cpp.alertreporting.DeduplicateMacroResults + +class FindMe extends VariableDeclarationEntry { + FindMe() { getType().toString() = "findme" } +} + +module FindMeDedupeConfig implements DeduplicateMacroConfigSig { + string describe(FindMe def) { result = def.getName() } +} + +module FindMeReportConfig implements MacroReportConfigSig { + bindingset[description] + string getMessageSameResultInAllExpansions(Macro m, string description) { + result = "Macro " + m.getName() + " always has findme var named " + description + } + + string getMessageVariedResultInAllExpansions(Macro m) { + result = "Macro " + m.getName() + " always has findme var, for example '$@'." + } + + string getMessageResultInIsolatedExpansion(FindMe f) { + result = "Invocation of macro $@ has findme var '" + f.getName() + "'." + } +} + +import DeduplicateMacroResults +import DeduplicateMacroResults::Report + +from ReportResultInMacro report +select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(), + report.getOptionalPlaceholderMessage() diff --git a/cpp/common/test/library/codingstandards/cpp/alertreporting/deduplicatemacroresults.cpp b/cpp/common/test/library/codingstandards/cpp/alertreporting/deduplicatemacroresults.cpp new file mode 100644 index 0000000000..3c5d8bca5b --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/alertreporting/deduplicatemacroresults.cpp @@ -0,0 +1,53 @@ +typedef struct { +} findme; + +findme g1; // ignore -- not in a macro + +#define SOMETIMES_HAS_RESULTS1(type, name) type name // ignore +#define SOMETIMES_HAS_RESULTS2(type, name) type name; // ignore + +SOMETIMES_HAS_RESULTS1(int, g2); // ignore +SOMETIMES_HAS_RESULTS1(findme, g3); // RESULT + +SOMETIMES_HAS_RESULTS2(int, g4) // ignore +SOMETIMES_HAS_RESULTS2(findme, g5) // RESULT + +#define ALWAYS_HAS_SAME_RESULT() extern findme g6; // RESULT + +ALWAYS_HAS_SAME_RESULT() // ignore +ALWAYS_HAS_SAME_RESULT() // ignore +ALWAYS_HAS_SAME_RESULT() // ignore + +#define ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name) extern findme name; // RESULT + +ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g7) // ignore +ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g8) // ignore +ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g9) // ignore +ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g9) // ignore +ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g9) // ignore + +#define INNER_SOMETIMES_HAS_RESULTS(type, name) type name; // ignore +#define OUTER_ALWAYS_HAS_SAME_RESULT() \ + extern INNER_SOMETIMES_HAS_RESULTS(findme, g10); // RESULT + +OUTER_ALWAYS_HAS_SAME_RESULT() // ignore +OUTER_ALWAYS_HAS_SAME_RESULT() // ignore + +// 'name ## suffix' required to work around extractor bug. +#define OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name) \ + INNER_SOMETIMES_HAS_RESULTS(findme, name##suffix); // RESULT + +OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g11) // ignore +OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g12) // ignore + +#define OUTER_OUTER_ALWAYS_HAS_SAME_RESULT() \ + OUTER_ALWAYS_HAS_SAME_RESULT(); // ignore +OUTER_OUTER_ALWAYS_HAS_SAME_RESULT() // ignore +OUTER_OUTER_ALWAYS_HAS_SAME_RESULT() // ignore + +// 'name ## suffix' required to work around extractor bug. +#define OUTER_OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name) \ + OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name##suffix); // ignore + +OUTER_OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g13) // ignore +OUTER_OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(g14) // ignore \ No newline at end of file diff --git a/rule_packages/c/DeadCode2.json b/rule_packages/c/DeadCode2.json new file mode 100644 index 0000000000..da114a2349 --- /dev/null +++ b/rule_packages/c/DeadCode2.json @@ -0,0 +1,66 @@ +{ + "MISRA-C-2012": { + "RULE-2-8": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Object definitions which are unused should be removed.", + "kind": "problem", + "name": "A project should not contain unused object definitions", + "precision": "very-high", + "severity": "recommendation", + "short_name": "UnusedObjectDefinition", + "tags": [ + "maintainability", + "performance", + "external/misra/c/2012/amendment4" + ] + }, + { + "description": "Macros should not have unused object definitions.", + "kind": "problem", + "name": "Project macros should not include unused object definitions", + "precision": "very-high", + "severity": "recommendation", + "short_name": "UnusedObjectDefinitionInMacro", + "tags": [ + "maintainability", + "performance", + "external/misra/c/2012/amendment4" + ] + }, + { + "description": "A strict query which reports all unused object definitions with '__attribute__((unused))'.", + "kind": "problem", + "name": "A project should not contain '__attribute__((unused))' object definitions", + "precision": "very-high", + "severity": "recommendation", + "short_name": "UnusedObjectDefinitionStrict", + "tags": [ + "maintainability", + "performance", + "external/misra/c/2012/amendment4", + "external/misra/c/strict" + ] + }, + { + "description": "A strict query which reports all unused object definitions in macros with '__attribute__((unused))'.", + "kind": "problem", + "name": "Project macros should not include '__attribute__((unused))' object definitions", + "precision": "very-high", + "severity": "recommendation", + "short_name": "UnusedObjectDefinitionInMacroStrict", + "tags": [ + "maintainability", + "performance", + "external/misra/c/2012/amendment4", + "external/misra/c/strict" + ] + } + ], + "title": "A project should not contain unused object definitions" + } + } +} \ No newline at end of file From ff562f9e93d803242cc0a8413277daad64f3d376 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 24 Oct 2024 23:31:58 -0700 Subject: [PATCH 067/628] Fix strict misra tag in rules schema --- schemas/rule-package.schema.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/schemas/rule-package.schema.json b/schemas/rule-package.schema.json index b27815163e..b27136634f 100644 --- a/schemas/rule-package.schema.json +++ b/schemas/rule-package.schema.json @@ -342,7 +342,8 @@ "external/misra/c/2012/third-edition-first-revision", "external/misra/c/2012/amendment2", "external/misra/c/2012/amendment3", - "external/misra/c/2012/amendment4" + "external/misra/c/2012/amendment4", + "external/misra/c/strict" ] }, "minLength": 1 From 8f81b4e7dcef93295bb1f486f12cdb4bf2bc9a03 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 27 Oct 2024 14:50:03 +0000 Subject: [PATCH 068/628] EssentialTypes: Correct handling of bitwise binary expressions They shouldn't have the standard type if either both the operands are signed or they are both unsigned. --- .../c/misra/EssentialTypes.qll | 49 +++- c/misra/test/c/misra/EssentialTypes.expected | 275 ++++++++++++++++++ c/misra/test/c/misra/test.c | 80 +++++ 3 files changed, 402 insertions(+), 2 deletions(-) diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 4783547ed2..4dbe8dbb34 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -192,8 +192,8 @@ class EssentialEqualityOperationExpr extends EssentialExpr, EqualityOperation { override Type getEssentialType() { result instanceof BoolType } } -class EssentialBinaryBitwiseOperationExpr extends EssentialExpr, BinaryBitwiseOperation { - EssentialBinaryBitwiseOperationExpr() { +class EssentialShiftOperationExpr extends EssentialExpr, BinaryBitwiseOperation { + EssentialShiftOperationExpr() { this instanceof LShiftExpr or this instanceof RShiftExpr } @@ -353,6 +353,51 @@ class EssentialBinaryArithmeticExpr extends EssentialExpr, BinaryArithmeticOpera } } +class EssentialBinaryBitwiseExpr extends EssentialExpr, BinaryBitwiseOperation { + EssentialBinaryBitwiseExpr() { + not this instanceof LShiftExpr and + not this instanceof RShiftExpr + } + + override Type getEssentialType() { + exists( + Type leftEssentialType, Type rightEssentialType, + EssentialTypeCategory leftEssentialTypeCategory, + EssentialTypeCategory rightEssentialTypeCategory + | + leftEssentialType = getEssentialType(getLeftOperand()) and + rightEssentialType = getEssentialType(getRightOperand()) and + leftEssentialTypeCategory = getEssentialTypeCategory(leftEssentialType) and + rightEssentialTypeCategory = getEssentialTypeCategory(rightEssentialType) + | + if + leftEssentialTypeCategory = EssentiallySignedType() and + rightEssentialTypeCategory = EssentiallySignedType() + then + if exists(getValue()) + then result = stlr(this) + else ( + if leftEssentialType.getSize() > rightEssentialType.getSize() + then result = leftEssentialType + else result = rightEssentialType + ) + else + if + leftEssentialTypeCategory = EssentiallyUnsignedType() and + rightEssentialTypeCategory = EssentiallyUnsignedType() + then + if exists(getValue()) + then result = utlr(this) + else ( + if leftEssentialType.getSize() > rightEssentialType.getSize() + then result = leftEssentialType + else result = rightEssentialType + ) + else result = this.getStandardType() + ) + } +} + /** * A named Enum type, as per D.5. */ diff --git a/c/misra/test/c/misra/EssentialTypes.expected b/c/misra/test/c/misra/EssentialTypes.expected index c0e010b8e4..19a7090fe9 100644 --- a/c/misra/test/c/misra/EssentialTypes.expected +++ b/c/misra/test/c/misra/EssentialTypes.expected @@ -90,3 +90,278 @@ | test.c:79:3:79:5 | 97 | char | char | essentially Character type | | test.c:80:3:80:6 | 10 | char | char | essentially Character type | | test.c:81:3:81:6 | 0 | char | char | essentially Character type | +| test.c:87:16:87:16 | 0 | signed char | signed char | essentially Signed type | +| test.c:87:16:87:16 | (uint8_t)... | uint8_t | uint8_t | essentially Unsigned type | +| test.c:88:18:88:18 | 0 | signed char | signed char | essentially Signed type | +| test.c:88:18:88:18 | (uint16_t)... | uint16_t | uint16_t | essentially Unsigned type | +| test.c:89:18:89:18 | 0 | signed char | signed char | essentially Signed type | +| test.c:89:18:89:18 | (uint32_t)... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:90:15:90:15 | 0 | signed char | signed char | essentially Signed type | +| test.c:90:15:90:15 | (int8_t)... | int8_t | int8_t | essentially Signed type | +| test.c:91:17:91:17 | 0 | signed char | signed char | essentially Signed type | +| test.c:91:17:91:17 | (int16_t)... | int16_t | int16_t | essentially Signed type | +| test.c:92:16:92:17 | 0 | signed char | signed char | essentially Signed type | +| test.c:94:3:94:4 | (int)... | int | int | essentially Signed type | +| test.c:94:3:94:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:94:3:94:9 | ... & ... | uint8_t | uint8_t | essentially Unsigned type | +| test.c:94:8:94:9 | (int)... | int | int | essentially Signed type | +| test.c:94:8:94:9 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:95:3:95:5 | (int)... | int | int | essentially Signed type | +| test.c:95:3:95:5 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:95:3:95:10 | ... & ... | uint16_t | uint16_t | essentially Unsigned type | +| test.c:95:9:95:10 | (int)... | int | int | essentially Signed type | +| test.c:95:9:95:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:96:3:96:4 | (int)... | int | int | essentially Signed type | +| test.c:96:3:96:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:96:3:96:10 | ... & ... | uint16_t | uint16_t | essentially Unsigned type | +| test.c:96:8:96:10 | (int)... | int | int | essentially Signed type | +| test.c:96:8:96:10 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:97:3:97:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:97:3:97:10 | ... & ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:97:9:97:10 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:97:9:97:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:98:3:98:4 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:98:3:98:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:98:3:98:10 | ... & ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:98:8:98:10 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:99:3:99:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:99:3:99:11 | ... & ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:99:9:99:11 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:99:9:99:11 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:100:3:100:5 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:100:3:100:5 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:100:3:100:11 | ... & ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:100:9:100:11 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:102:3:102:4 | (int)... | int | int | essentially Signed type | +| test.c:102:3:102:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:102:3:102:9 | ... \| ... | uint8_t | uint8_t | essentially Unsigned type | +| test.c:102:8:102:9 | (int)... | int | int | essentially Signed type | +| test.c:102:8:102:9 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:103:3:103:5 | (int)... | int | int | essentially Signed type | +| test.c:103:3:103:5 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:103:3:103:10 | ... \| ... | uint16_t | uint16_t | essentially Unsigned type | +| test.c:103:9:103:10 | (int)... | int | int | essentially Signed type | +| test.c:103:9:103:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:104:3:104:4 | (int)... | int | int | essentially Signed type | +| test.c:104:3:104:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:104:3:104:10 | ... \| ... | uint16_t | uint16_t | essentially Unsigned type | +| test.c:104:8:104:10 | (int)... | int | int | essentially Signed type | +| test.c:104:8:104:10 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:105:3:105:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:105:3:105:10 | ... \| ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:105:9:105:10 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:105:9:105:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:106:3:106:4 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:106:3:106:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:106:3:106:10 | ... \| ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:106:8:106:10 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:107:3:107:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:107:3:107:11 | ... \| ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:107:9:107:11 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:107:9:107:11 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:108:3:108:5 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:108:3:108:5 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:108:3:108:11 | ... \| ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:108:9:108:11 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:110:3:110:4 | (int)... | int | int | essentially Signed type | +| test.c:110:3:110:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:110:3:110:9 | ... ^ ... | uint8_t | uint8_t | essentially Unsigned type | +| test.c:110:8:110:9 | (int)... | int | int | essentially Signed type | +| test.c:110:8:110:9 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:111:3:111:5 | (int)... | int | int | essentially Signed type | +| test.c:111:3:111:5 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:111:3:111:10 | ... ^ ... | uint16_t | uint16_t | essentially Unsigned type | +| test.c:111:9:111:10 | (int)... | int | int | essentially Signed type | +| test.c:111:9:111:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:112:3:112:4 | (int)... | int | int | essentially Signed type | +| test.c:112:3:112:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:112:3:112:10 | ... ^ ... | uint16_t | uint16_t | essentially Unsigned type | +| test.c:112:8:112:10 | (int)... | int | int | essentially Signed type | +| test.c:112:8:112:10 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:113:3:113:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:113:3:113:10 | ... ^ ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:113:9:113:10 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:113:9:113:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:114:3:114:4 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:114:3:114:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:114:3:114:10 | ... ^ ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:114:8:114:10 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:115:3:115:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:115:3:115:11 | ... ^ ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:115:9:115:11 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:115:9:115:11 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:116:3:116:5 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:116:3:116:5 | u16 | uint16_t | uint16_t | essentially Unsigned type | +| test.c:116:3:116:11 | ... ^ ... | uint32_t | uint32_t | essentially Unsigned type | +| test.c:116:9:116:11 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:118:3:118:4 | (int)... | int | int | essentially Signed type | +| test.c:118:3:118:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:118:3:118:9 | ... & ... | int8_t | int8_t | essentially Signed type | +| test.c:118:8:118:9 | (int)... | int | int | essentially Signed type | +| test.c:118:8:118:9 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:119:3:119:5 | (int)... | int | int | essentially Signed type | +| test.c:119:3:119:5 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:119:3:119:10 | ... & ... | int16_t | int16_t | essentially Signed type | +| test.c:119:9:119:10 | (int)... | int | int | essentially Signed type | +| test.c:119:9:119:10 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:120:3:120:4 | (int)... | int | int | essentially Signed type | +| test.c:120:3:120:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:120:3:120:10 | ... & ... | int16_t | int16_t | essentially Signed type | +| test.c:120:8:120:10 | (int)... | int | int | essentially Signed type | +| test.c:120:8:120:10 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:121:3:121:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:121:3:121:10 | ... & ... | int32_t | int32_t | essentially Signed type | +| test.c:121:9:121:10 | (int)... | int | int | essentially Signed type | +| test.c:121:9:121:10 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:122:3:122:4 | (int)... | int | int | essentially Signed type | +| test.c:122:3:122:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:122:3:122:10 | ... & ... | int32_t | int32_t | essentially Signed type | +| test.c:122:8:122:10 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:123:3:123:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:123:3:123:11 | ... & ... | int32_t | int32_t | essentially Signed type | +| test.c:123:9:123:11 | (int)... | int | int | essentially Signed type | +| test.c:123:9:123:11 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:124:3:124:5 | (int)... | int | int | essentially Signed type | +| test.c:124:3:124:5 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:124:3:124:11 | ... & ... | int32_t | int32_t | essentially Signed type | +| test.c:124:9:124:11 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:126:3:126:4 | (int)... | int | int | essentially Signed type | +| test.c:126:3:126:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:126:3:126:9 | ... \| ... | int8_t | int8_t | essentially Signed type | +| test.c:126:8:126:9 | (int)... | int | int | essentially Signed type | +| test.c:126:8:126:9 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:127:3:127:5 | (int)... | int | int | essentially Signed type | +| test.c:127:3:127:5 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:127:3:127:10 | ... \| ... | int16_t | int16_t | essentially Signed type | +| test.c:127:9:127:10 | (int)... | int | int | essentially Signed type | +| test.c:127:9:127:10 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:128:3:128:4 | (int)... | int | int | essentially Signed type | +| test.c:128:3:128:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:128:3:128:10 | ... \| ... | int16_t | int16_t | essentially Signed type | +| test.c:128:8:128:10 | (int)... | int | int | essentially Signed type | +| test.c:128:8:128:10 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:129:3:129:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:129:3:129:10 | ... \| ... | int32_t | int32_t | essentially Signed type | +| test.c:129:9:129:10 | (int)... | int | int | essentially Signed type | +| test.c:129:9:129:10 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:130:3:130:4 | (int)... | int | int | essentially Signed type | +| test.c:130:3:130:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:130:3:130:10 | ... \| ... | int32_t | int32_t | essentially Signed type | +| test.c:130:8:130:10 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:131:3:131:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:131:3:131:11 | ... \| ... | int32_t | int32_t | essentially Signed type | +| test.c:131:9:131:11 | (int)... | int | int | essentially Signed type | +| test.c:131:9:131:11 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:132:3:132:5 | (int)... | int | int | essentially Signed type | +| test.c:132:3:132:5 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:132:3:132:11 | ... \| ... | int32_t | int32_t | essentially Signed type | +| test.c:132:9:132:11 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:134:3:134:4 | (int)... | int | int | essentially Signed type | +| test.c:134:3:134:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:134:3:134:9 | ... ^ ... | int8_t | int8_t | essentially Signed type | +| test.c:134:8:134:9 | (int)... | int | int | essentially Signed type | +| test.c:134:8:134:9 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:135:3:135:5 | (int)... | int | int | essentially Signed type | +| test.c:135:3:135:5 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:135:3:135:10 | ... ^ ... | int16_t | int16_t | essentially Signed type | +| test.c:135:9:135:10 | (int)... | int | int | essentially Signed type | +| test.c:135:9:135:10 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:136:3:136:4 | (int)... | int | int | essentially Signed type | +| test.c:136:3:136:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:136:3:136:10 | ... ^ ... | int16_t | int16_t | essentially Signed type | +| test.c:136:8:136:10 | (int)... | int | int | essentially Signed type | +| test.c:136:8:136:10 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:137:3:137:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:137:3:137:10 | ... ^ ... | int32_t | int32_t | essentially Signed type | +| test.c:137:9:137:10 | (int)... | int | int | essentially Signed type | +| test.c:137:9:137:10 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:138:3:138:4 | (int)... | int | int | essentially Signed type | +| test.c:138:3:138:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:138:3:138:10 | ... ^ ... | int32_t | int32_t | essentially Signed type | +| test.c:138:8:138:10 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:139:3:139:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:139:3:139:11 | ... ^ ... | int32_t | int32_t | essentially Signed type | +| test.c:139:9:139:11 | (int)... | int | int | essentially Signed type | +| test.c:139:9:139:11 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:140:3:140:5 | (int)... | int | int | essentially Signed type | +| test.c:140:3:140:5 | s16 | int16_t | int16_t | essentially Signed type | +| test.c:140:3:140:11 | ... ^ ... | int32_t | int32_t | essentially Signed type | +| test.c:140:9:140:11 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:142:3:142:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:142:3:142:11 | ... & ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:142:9:142:11 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:142:9:142:11 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:143:3:143:5 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:143:3:143:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:143:3:143:11 | ... & ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:143:9:143:11 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:144:3:144:4 | (int)... | int | int | essentially Signed type | +| test.c:144:3:144:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:144:3:144:10 | ... & ... | int | int | essentially Signed type | +| test.c:144:8:144:10 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:145:3:145:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:145:3:145:10 | ... & ... | int | int | essentially Signed type | +| test.c:145:9:145:10 | (int)... | int | int | essentially Signed type | +| test.c:145:9:145:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:146:3:146:4 | (int)... | int | int | essentially Signed type | +| test.c:146:3:146:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:146:3:146:9 | ... & ... | int | int | essentially Signed type | +| test.c:146:8:146:9 | (int)... | int | int | essentially Signed type | +| test.c:146:8:146:9 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:147:3:147:4 | (int)... | int | int | essentially Signed type | +| test.c:147:3:147:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:147:3:147:9 | ... & ... | int | int | essentially Signed type | +| test.c:147:8:147:9 | (int)... | int | int | essentially Signed type | +| test.c:147:8:147:9 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:149:3:149:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:149:3:149:11 | ... \| ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:149:9:149:11 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:149:9:149:11 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:150:3:150:5 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:150:3:150:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:150:3:150:11 | ... \| ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:150:9:150:11 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:151:3:151:4 | (int)... | int | int | essentially Signed type | +| test.c:151:3:151:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:151:3:151:10 | ... \| ... | int | int | essentially Signed type | +| test.c:151:8:151:10 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:152:3:152:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:152:3:152:10 | ... \| ... | int | int | essentially Signed type | +| test.c:152:9:152:10 | (int)... | int | int | essentially Signed type | +| test.c:152:9:152:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:153:3:153:4 | (int)... | int | int | essentially Signed type | +| test.c:153:3:153:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:153:3:153:9 | ... \| ... | int | int | essentially Signed type | +| test.c:153:8:153:9 | (int)... | int | int | essentially Signed type | +| test.c:153:8:153:9 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:154:3:154:4 | (int)... | int | int | essentially Signed type | +| test.c:154:3:154:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:154:3:154:9 | ... \| ... | int | int | essentially Signed type | +| test.c:154:8:154:9 | (int)... | int | int | essentially Signed type | +| test.c:154:8:154:9 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:156:3:156:5 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:156:3:156:11 | ... ^ ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:156:9:156:11 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:156:9:156:11 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:157:3:157:5 | (unsigned int)... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:157:3:157:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:157:3:157:11 | ... ^ ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:157:9:157:11 | u32 | uint32_t | uint32_t | essentially Unsigned type | +| test.c:158:3:158:4 | (int)... | int | int | essentially Signed type | +| test.c:158:3:158:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:158:3:158:10 | ... ^ ... | int | int | essentially Signed type | +| test.c:158:8:158:10 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:159:3:159:5 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:159:3:159:10 | ... ^ ... | int | int | essentially Signed type | +| test.c:159:9:159:10 | (int)... | int | int | essentially Signed type | +| test.c:159:9:159:10 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:160:3:160:4 | (int)... | int | int | essentially Signed type | +| test.c:160:3:160:4 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:160:3:160:9 | ... ^ ... | int | int | essentially Signed type | +| test.c:160:8:160:9 | (int)... | int | int | essentially Signed type | +| test.c:160:8:160:9 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:161:3:161:4 | (int)... | int | int | essentially Signed type | +| test.c:161:3:161:4 | s8 | int8_t | int8_t | essentially Signed type | +| test.c:161:3:161:9 | ... ^ ... | int | int | essentially Signed type | +| test.c:161:8:161:9 | (int)... | int | int | essentially Signed type | +| test.c:161:8:161:9 | u8 | uint8_t | uint8_t | essentially Unsigned type | diff --git a/c/misra/test/c/misra/test.c b/c/misra/test/c/misra/test.c index b3fdddd591..dcdfef4eb4 100644 --- a/c/misra/test/c/misra/test.c +++ b/c/misra/test/c/misra/test.c @@ -79,4 +79,84 @@ void testControlChar() { 'a'; // Essentially char '\n'; // Essentially char '\0'; // Essentially char +} + +#include + +void testBitwise() { + uint8_t u8 = 0; + uint16_t u16 = 0; + uint32_t u32 = 0; + int8_t s8 = 0; + int16_t s16 = 0; + int32_t s32 = 0; + + u8 & u8; // Essentially unsigned, char + u16 & u8; // Essentially unsigned, short + u8 & u16; // Essentially unsigned, short + u32 & u8; // Essentially unsigned, int + u8 & u32; // Essentially unsigned, int + u32 & u16; // Essentially unsigned, int + u16 & u32; // Essentially unsigned, int + + u8 | u8; // Essentially unsigned, char + u16 | u8; // Essentially unsigned, short + u8 | u16; // Essentially unsigned, short + u32 | u8; // Essentially unsigned, int + u8 | u32; // Essentially unsigned, int + u32 | u16; // Essentially unsigned, int + u16 | u32; // Essentially unsigned, int + + u8 ^ u8; // Essentially unsigned, char + u16 ^ u8; // Essentially unsigned, short + u8 ^ u16; // Essentially unsigned, short + u32 ^ u8; // Essentially unsigned, int + u8 ^ u32; // Essentially unsigned, int + u32 ^ u16; // Essentially unsigned, int + u16 ^ u32; // Essentially unsigned, int + + s8 & s8; // Essentially signed, char + s16 & s8; // Essentially signed, short + s8 & s16; // Essentially signed, short + s32 & s8; // Essentially signed, int + s8 & s32; // Essentially signed, int + s32 & s16; // Essentially signed, int + s16 & s32; // Essentially signed, int + + s8 | s8; // Essentially signed, char + s16 | s8; // Essentially signed, short + s8 | s16; // Essentially signed, short + s32 | s8; // Essentially signed, int + s8 | s32; // Essentially signed, int + s32 | s16; // Essentially signed, int + s16 | s32; // Essentially signed, int + + s8 ^ s8; // Essentially signed, char + s16 ^ s8; // Essentially signed, short + s8 ^ s16; // Essentially signed, short + s32 ^ s8; // Essentially signed, int + s8 ^ s32; // Essentially signed, int + s32 ^ s16; // Essentially signed, int + s16 ^ s32; // Essentially signed, int + + u32 & s32; // Essentially signed, int + s32 & u32; // Essentially signed, int + u8 & s32; // Essentially signed, int + s32 & u8; // Essentially signed, int + u8 & s8; // Essentially signed, int + s8 & u8; // Essentially signed, int + + u32 | s32; // Essentially signed, int + s32 | u32; // Essentially signed, int + u8 | s32; // Essentially signed, int + s32 | u8; // Essentially signed, int + u8 | s8; // Essentially signed, int + s8 | u8; // Essentially signed, int + + u32 ^ s32; // Essentially signed, int + s32 ^ u32; // Essentially signed, int + u8 ^ s32; // Essentially signed, int + s32 ^ u8; // Essentially signed, int + u8 ^ s8; // Essentially signed, int + s8 ^ u8; // Essentially signed, int } \ No newline at end of file From a5ed461557c57b44df2f6a420e6ecc1bd89cbed2 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 27 Oct 2024 15:28:27 +0000 Subject: [PATCH 069/628] EssentialTypes: Add test cases for shifts --- c/misra/test/c/misra/EssentialTypes.expected | 73 ++++++++++++++++++++ c/misra/test/c/misra/test.c | 38 ++++++++++ 2 files changed, 111 insertions(+) diff --git a/c/misra/test/c/misra/EssentialTypes.expected b/c/misra/test/c/misra/EssentialTypes.expected index 19a7090fe9..95976fe2ab 100644 --- a/c/misra/test/c/misra/EssentialTypes.expected +++ b/c/misra/test/c/misra/EssentialTypes.expected @@ -365,3 +365,76 @@ | test.c:161:3:161:9 | ... ^ ... | int | int | essentially Signed type | | test.c:161:8:161:9 | (int)... | int | int | essentially Signed type | | test.c:161:8:161:9 | u8 | uint8_t | uint8_t | essentially Unsigned type | +| test.c:165:16:165:17 | 1 | signed char | signed char | essentially Signed type | +| test.c:170:3:170:4 | 1 | unsigned char | unsigned char | essentially Unsigned type | +| test.c:170:3:170:9 | ... << ... | unsigned char | unsigned char | essentially Unsigned type | +| test.c:170:9:170:9 | 1 | signed char | signed char | essentially Signed type | +| test.c:171:3:171:6 | 256 | unsigned short | unsigned short | essentially Unsigned type | +| test.c:171:3:171:11 | ... << ... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:171:11:171:11 | 1 | signed char | signed char | essentially Signed type | +| test.c:172:3:172:8 | 65536 | unsigned int | unsigned int | essentially Unsigned type | +| test.c:172:3:172:13 | ... << ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:172:13:172:13 | 1 | signed char | signed char | essentially Signed type | +| test.c:173:3:173:4 | 2 | unsigned char | unsigned char | essentially Unsigned type | +| test.c:173:3:173:9 | ... >> ... | unsigned char | unsigned char | essentially Unsigned type | +| test.c:173:9:173:9 | 1 | signed char | signed char | essentially Signed type | +| test.c:174:3:174:8 | 32768 | unsigned short | unsigned short | essentially Unsigned type | +| test.c:174:3:174:13 | ... >> ... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:174:13:174:13 | 1 | signed char | signed char | essentially Signed type | +| test.c:175:3:175:13 | 2147483648 | unsigned int | unsigned int | essentially Unsigned type | +| test.c:175:3:175:18 | ... >> ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:175:18:175:18 | 1 | signed char | signed char | essentially Signed type | +| test.c:176:3:176:14 | 4294967295 | unsigned long | unsigned long | essentially Unsigned type | +| test.c:176:3:176:19 | ... << ... | unsigned long | unsigned long | essentially Unsigned type | +| test.c:176:3:176:19 | ... << ... | unsigned long | unsigned long long | essentially Unsigned type | +| test.c:176:3:176:19 | ... << ... | unsigned long long | unsigned long | essentially Unsigned type | +| test.c:176:3:176:19 | ... << ... | unsigned long long | unsigned long long | essentially Unsigned type | +| test.c:176:19:176:19 | 1 | signed char | signed char | essentially Signed type | +| test.c:181:3:181:6 | 256 | unsigned short | unsigned short | essentially Unsigned type | +| test.c:181:3:181:11 | ... >> ... | unsigned char | unsigned char | essentially Unsigned type | +| test.c:181:11:181:11 | 1 | signed char | signed char | essentially Signed type | +| test.c:182:3:182:8 | 65536 | unsigned int | unsigned int | essentially Unsigned type | +| test.c:182:3:182:13 | ... >> ... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:182:13:182:13 | 1 | signed char | signed char | essentially Signed type | +| test.c:183:3:183:13 | 4294967296 | unsigned long | unsigned long | essentially Unsigned type | +| test.c:183:3:183:18 | ... >> ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:183:18:183:18 | 1 | signed char | signed char | essentially Signed type | +| test.c:184:3:184:6 | 255 | unsigned char | unsigned char | essentially Unsigned type | +| test.c:184:3:184:11 | ... << ... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:184:11:184:11 | 1 | signed char | signed char | essentially Signed type | +| test.c:185:3:185:8 | 65535 | unsigned short | unsigned short | essentially Unsigned type | +| test.c:185:3:185:13 | ... << ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:185:13:185:13 | 1 | signed char | signed char | essentially Signed type | +| test.c:189:3:189:6 | 255 | unsigned char | unsigned char | essentially Unsigned type | +| test.c:189:3:189:13 | ... >> ... | unsigned char | unsigned char | essentially Unsigned type | +| test.c:189:11:189:13 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:190:3:190:8 | 65535 | unsigned short | unsigned short | essentially Unsigned type | +| test.c:190:3:190:15 | ... >> ... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:190:13:190:15 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:191:3:191:13 | 4294967295 | unsigned int | unsigned int | essentially Unsigned type | +| test.c:191:3:191:20 | ... >> ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:191:18:191:20 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:192:3:192:6 | 255 | unsigned char | unsigned char | essentially Unsigned type | +| test.c:192:3:192:13 | ... << ... | unsigned char | unsigned char | essentially Unsigned type | +| test.c:192:11:192:13 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:193:3:193:8 | 65535 | unsigned short | unsigned short | essentially Unsigned type | +| test.c:193:3:193:15 | ... << ... | unsigned short | unsigned short | essentially Unsigned type | +| test.c:193:13:193:15 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:194:3:194:13 | 4294967295 | unsigned int | unsigned int | essentially Unsigned type | +| test.c:194:3:194:20 | ... << ... | unsigned int | unsigned int | essentially Unsigned type | +| test.c:194:18:194:20 | s32 | int32_t | int32_t | essentially Signed type | +| test.c:197:3:197:5 | 257 | short | short | essentially Signed type | +| test.c:197:3:197:5 | 257 | short | signed short | essentially Signed type | +| test.c:197:3:197:5 | 257 | signed short | short | essentially Signed type | +| test.c:197:3:197:5 | 257 | signed short | signed short | essentially Signed type | +| test.c:197:3:197:10 | ... >> ... | int | int | essentially Signed type | +| test.c:197:10:197:10 | 1 | signed char | signed char | essentially Signed type | +| test.c:198:3:198:7 | 65537 | int | int | essentially Signed type | +| test.c:198:3:198:7 | 65537 | int | signed int | essentially Signed type | +| test.c:198:3:198:7 | 65537 | signed int | int | essentially Signed type | +| test.c:198:3:198:7 | 65537 | signed int | signed int | essentially Signed type | +| test.c:198:3:198:12 | ... >> ... | int | int | essentially Signed type | +| test.c:198:12:198:12 | 1 | signed char | signed char | essentially Signed type | +| test.c:199:3:199:12 | 4294967297 | long | long | essentially Signed type | +| test.c:199:3:199:17 | ... >> ... | long | long | essentially Signed type | +| test.c:199:17:199:17 | 1 | signed char | signed char | essentially Signed type | diff --git a/c/misra/test/c/misra/test.c b/c/misra/test/c/misra/test.c index dcdfef4eb4..e271a67e30 100644 --- a/c/misra/test/c/misra/test.c +++ b/c/misra/test/c/misra/test.c @@ -159,4 +159,42 @@ void testBitwise() { s32 ^ u8; // Essentially signed, int u8 ^ s8; // Essentially signed, int s8 ^ u8; // Essentially signed, int +} + +void testShifts() { + int32_t s32 = 1; + + // Left hand is unsigned and both are constants, so UTLR + // In these cases the UTLR is the same as the essential type of + // the left operand + 1U << 1; // Essentially unsigned char + 256U << 1; // Essentially unsigned short + 65536U << 1; // Essentially unsigned int + 2U >> 1; // Essentially unsigned char + 32768U >> 1; // Essentially unsigned short - 2^15 >> 1 = 2^14 + 2147483648U >> 1; // Essentially unsigned int - 2^31 >> 1 = 2^30 + 4294967295LU << 1; // Essentially unsigned long + + // Left hand is unsigned and both are constants, so UTLR + // In these cases the UTLR is not the same as the essential type of + // the left operand + 256U >> 1; // Essentially unsigned char + 65536U >> 1; // Essentially unsigned short + 4294967296U >> 1; // Essentially unsigned int + 255U << 1; // Essentially unsigned short + 65535U << 1; // Essentially unsigned int + + // Left hand is unsigned, but left isn't a constant, so essential type of left + // operand + 255U >> s32; // Essentially unsigned char + 65535U >> s32; // Essentially unsigned short + 4294967295U >> s32; // Essentially unsigned int + 255U << s32; // Essentially unsigned char + 65535U << s32; // Essentially unsigned short + 4294967295U << s32; // Essentially unsigned int + + // Left hand operand signed int, so result is standard type + 257 >> 1; // Essentially signed int + 65537 >> 1; // Essentially signed int + 4294967297 >> 1; // Essentially signed long } \ No newline at end of file From aba9528b7341251ee35555a32be7e04f5cfa226d Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 27 Oct 2024 15:41:21 +0000 Subject: [PATCH 070/628] RULE-10-3: Expand test cases for binary bitwise operators --- ...gnmentOfIncompatibleEssentialType.expected | 6 +++++ c/misra/test/rules/RULE-10-3/test.c | 25 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected b/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected index 3867abd0ca..b64f970bfe 100644 --- a/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected +++ b/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected @@ -131,3 +131,9 @@ | test.c:356:10:356:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | | test.c:357:10:357:10 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | | test.c:358:10:358:10 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:369:12:369:20 | ... & ... | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:370:12:370:20 | ... \| ... | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:371:12:371:20 | ... ^ ... | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:376:20:376:27 | ... & ... | Assignment of value of essentially Signed type of size 2 bytes to an object narrower essential type of size 1 bytes. | +| test.c:381:23:381:30 | ... & ... | Assignment of value of essentially Unsigned type of size 2 bytes to an object narrower essential type of size 1 bytes. | +| test.c:384:22:384:29 | ... & ... | Assignment of essentially Signed type value to an object of essentially Unsigned type. | diff --git a/c/misra/test/rules/RULE-10-3/test.c b/c/misra/test/rules/RULE-10-3/test.c index 30ab2985ae..f4ad487ae1 100644 --- a/c/misra/test/rules/RULE-10-3/test.c +++ b/c/misra/test/rules/RULE-10-3/test.c @@ -357,4 +357,29 @@ void testStructAssignment() { s1.f = s; // NON_COMPLIANT s1.f = u; // NON_COMPLIANT s1.f = f; // COMPLIANT +} + +void testBinaryBitwise() { + signed int s32 = 100; // COMPLIANT - wider + signed short s16 = 0; // COMPLIANT - wider + signed char s8 = 0; // COMPLIANT - wider + unsigned int u32 = 100; // COMPLIANT - by exception 1 + unsigned char u8 = 0; // COMPLIANT - by exception 1 + unsigned short u16 = 0; // COMPLIANT - by exception 1 + int x1 = s32 & u32; // NON_COMPLIANT - integer promotion to u32 + int x2 = s32 | u32; // NON_COMPLIANT - integer promotion to u32 + int x3 = s32 ^ u32; // NON_COMPLIANT - integer promotion to u32 + int x4 = s16 & s32; // COMPLIANT + int x5 = s16 & u16; // COMPLIANT + int x6 = s16 & s8; // COMPLIANT + signed short x7 = s16 & s8; // COMPLIANT + signed char x8 = s16 & s8; // NON_COMPLIANT + signed char x9 = s8 & s8; // COMPLIANT + signed short x10 = s8 & s8; // COMPLIANT + unsigned int x11 = u16 & u8; // COMPLIANT + unsigned short x12 = u16 & u8; // COMPLIANT + unsigned char x13 = u16 & u8; // NON_COMPLIANT + unsigned char x14 = u8 & u8; // COMPLIANT + unsigned short x15 = u8 & u8; // COMPLIANT + unsigned int x16 = s16 & s8; // NON_COMPLIANT } \ No newline at end of file From 5b753e0cbde1f57b22909fc05922e2c61ab032df Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 28 Oct 2024 08:47:04 -0700 Subject: [PATCH 071/628] Add change note --- change_notes/2024-10-28-essential-types-bitwise.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change_notes/2024-10-28-essential-types-bitwise.md diff --git a/change_notes/2024-10-28-essential-types-bitwise.md b/change_notes/2024-10-28-essential-types-bitwise.md new file mode 100644 index 0000000000..a382290351 --- /dev/null +++ b/change_notes/2024-10-28-essential-types-bitwise.md @@ -0,0 +1,2 @@ + - `RULE-10-1`, `RULE-10-3`, `RULE-10-4`, `RULE-10-5`, `RULE-10-6`, `RULE-10-7`, `RULE-10-8`, `RULE-12-2` - `OperandsOfAnInappropriateEssentialType.ql`, `AssignmentOfIncompatibleEssentialType.ql`, `OperandsWithMismatchedEssentialTypeCategory.ql`, `InappropriateEssentialTypeCast.ql`, `AssignmentToWiderEssentialType,ql`, `ImplicitConversionOfCompositeExpression.ql`, `InappropriateCastOfCompositeExpression.ql`: + - False positives and false negatives removed due to fixing incorrect essential type of the binary bitwise operations `^`, `|` and `&`. Previously the standard type was used, instead of applying the essential type rules which dictate that if both arguments have the same signedness, the essential type will have the same signedness and a rank equal to the larger of the two operands. \ No newline at end of file From 61d4ba36397e33de69e05362826c5e6ff11ecb87 Mon Sep 17 00:00:00 2001 From: Fernando Jose Date: Wed, 30 Oct 2024 14:02:40 +0900 Subject: [PATCH 072/628] Fix #629. --- change_notes/2024-10-30-fix-issue-629.md | 2 ++ ...DeclarationAndInitializationNotOnSeparateLines.ql | 4 ++-- cpp/autosar/test/rules/A7-1-7/test.cpp | 12 +++++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 change_notes/2024-10-30-fix-issue-629.md diff --git a/change_notes/2024-10-30-fix-issue-629.md b/change_notes/2024-10-30-fix-issue-629.md new file mode 100644 index 0000000000..1e7421f6f6 --- /dev/null +++ b/change_notes/2024-10-30-fix-issue-629.md @@ -0,0 +1,2 @@ +- `A7-1-7` - `IdentifierDeclarationAndInitializationNotOnSeparateLines.ql` + - Fixes #629. Adds brackets, excluding expressions statements in macros. diff --git a/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql b/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql index 8c10a0f80c..9cc593ecb1 100644 --- a/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql +++ b/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql @@ -19,7 +19,7 @@ import codingstandards.cpp.autosar class UniqueLineStmt extends Locatable { UniqueLineStmt() { not isAffectedByMacro() and - exists(Declaration d | + (exists(Declaration d | this = d.getADeclarationEntry() and not d instanceof Parameter and not d instanceof TemplateParameter and @@ -38,7 +38,7 @@ class UniqueLineStmt extends Locatable { or this instanceof ExprStmt and not exists(ForStmt f | f.getInitialization().getAChild*() = this) and - not exists(LambdaExpression l | l.getLambdaFunction().getBlock().getAChild*() = this) + not exists(LambdaExpression l | l.getLambdaFunction().getBlock().getAChild*() = this)) } } diff --git a/cpp/autosar/test/rules/A7-1-7/test.cpp b/cpp/autosar/test/rules/A7-1-7/test.cpp index 7c5a6263cf..80f6542b11 100644 --- a/cpp/autosar/test/rules/A7-1-7/test.cpp +++ b/cpp/autosar/test/rules/A7-1-7/test.cpp @@ -152,4 +152,14 @@ void example_function() { f1(); } // COMPLIANT // clang-format off typedef struct x { int y; } z; //COMPLIANT - for struct typedef and struct var //NON_COMPLIANT - for struct all on one line -// clang-format on \ No newline at end of file +// clang-format on + +#define foo(x, y) \ + x++; \ + y++; + +void test_foo() { + int a = 1; + int b = 1; + foo(a, b); // COMPLIANT +} From 525fba7fec474c0ac46c4ac162c2593804dea214 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 31 Oct 2024 15:37:02 -0700 Subject: [PATCH 073/628] Pack creation: load help from base reference For pull requests the current process attempts to load the help from the equivalent ref in the help repo. As most PRs do not add an equivalent branch on the help repo, this means that most PRs do not load any help at all, and the constructed artifacts are missing help. This is problematic during the release process, where we appear to use the artifacts built from the PR event, instead of the artifacts built from the branch itself, therefore using artifacts without any help included. This commit modifies the behaviour to fetch the help for the base ref for the pull request or merge group. This should ensure that help files are always loaded, regardless of where the artifacts are built. --- .github/workflows/code-scanning-pack-gen.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/code-scanning-pack-gen.yml b/.github/workflows/code-scanning-pack-gen.yml index ea13a4e76c..c665c4e6ea 100644 --- a/.github/workflows/code-scanning-pack-gen.yml +++ b/.github/workflows/code-scanning-pack-gen.yml @@ -68,11 +68,14 @@ jobs: - name: Determine ref for external help files id: determine-ref run: | - if [[ $GITHUB_EVENT_NAME == "pull_request" || $GITHUB_EVENT_NAME == "merge_group" ]]; then - echo "EXTERNAL_HELP_REF=$GITHUB_HEAD_REF" >> "$GITHUB_ENV" + if [[ $GITHUB_EVENT_NAME == "pull_request" ]]; then + EXTERNAL_HELP_REF="${{ github.event.pull_request.base.ref }}" + elif [[ $GITHUB_EVENT_NAME == "merge_group" ]]; then + EXTERNAL_HELP_REF="${{ github.event.merge_group.base_ref }}" else - echo "EXTERNAL_HELP_REF=$GITHUB_REF" >> "$GITHUB_ENV" + EXTERNAL_HELP_REF="$GITHUB_REF" fi + echo "EXTERNAL_HELP_REF=$EXTERNAL_HELP_REF" >> "$GITHUB_ENV" echo "Using ref $EXTERNAL_HELP_REF for external help files." - name: Checkout external help files From 839112f3c6d6516bdaf6bd698759f15f0ab914e9 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 31 Oct 2024 15:44:33 -0700 Subject: [PATCH 074/628] Do not continue on error for checkout of the help repo This is to avoid accidental errors when loading the reference. --- .github/workflows/code-scanning-pack-gen.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/code-scanning-pack-gen.yml b/.github/workflows/code-scanning-pack-gen.yml index c665c4e6ea..a217c5781e 100644 --- a/.github/workflows/code-scanning-pack-gen.yml +++ b/.github/workflows/code-scanning-pack-gen.yml @@ -79,7 +79,6 @@ jobs: echo "Using ref $EXTERNAL_HELP_REF for external help files." - name: Checkout external help files - continue-on-error: true id: checkout-external-help-files uses: actions/checkout@v4 with: From 98c76101502b0bc50e6e504d7bb20edb04161f2a Mon Sep 17 00:00:00 2001 From: Fernando Jose Date: Fri, 1 Nov 2024 08:17:21 +0900 Subject: [PATCH 075/628] Fix query formatting. --- ...tionAndInitializationNotOnSeparateLines.ql | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql b/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql index 9cc593ecb1..89aca8048e 100644 --- a/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql +++ b/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql @@ -19,26 +19,28 @@ import codingstandards.cpp.autosar class UniqueLineStmt extends Locatable { UniqueLineStmt() { not isAffectedByMacro() and - (exists(Declaration d | - this = d.getADeclarationEntry() and - not d instanceof Parameter and - not d instanceof TemplateParameter and - // TODO - Needs to be enhanced to solve issues with - // templated inner classes. - not d instanceof Function and - not d.isFromTemplateInstantiation(_) and - not d.(Variable).isCompilerGenerated() and - not exists(RangeBasedForStmt f | f.getADeclaration() = d) and - not exists(DeclStmt declStmt, ForStmt f | - f.getInitialization() = declStmt and - declStmt.getADeclaration() = d - ) and - not exists(LambdaCapture lc | lc.getField().getADeclarationEntry() = this) + ( + exists(Declaration d | + this = d.getADeclarationEntry() and + not d instanceof Parameter and + not d instanceof TemplateParameter and + // TODO - Needs to be enhanced to solve issues with + // templated inner classes. + not d instanceof Function and + not d.isFromTemplateInstantiation(_) and + not d.(Variable).isCompilerGenerated() and + not exists(RangeBasedForStmt f | f.getADeclaration() = d) and + not exists(DeclStmt declStmt, ForStmt f | + f.getInitialization() = declStmt and + declStmt.getADeclaration() = d + ) and + not exists(LambdaCapture lc | lc.getField().getADeclarationEntry() = this) + ) + or + this instanceof ExprStmt and + not exists(ForStmt f | f.getInitialization().getAChild*() = this) and + not exists(LambdaExpression l | l.getLambdaFunction().getBlock().getAChild*() = this) ) - or - this instanceof ExprStmt and - not exists(ForStmt f | f.getInitialization().getAChild*() = this) and - not exists(LambdaExpression l | l.getLambdaFunction().getBlock().getAChild*() = this)) } } From fb3c5e7cb804d69ba1caa7537c181ccd0bee73eb Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 31 Oct 2024 21:38:49 -0700 Subject: [PATCH 076/628] Implement Concurrency6 package -- split out Concurrency7 --- .../ThreadWasPreviouslyJoinedOrDetached.ql | 39 +--- ...hreadWasPreviouslyJoinedOrDetached.testref | 1 + .../includes/standard-library/stdatomic.h | 74 +++++++- .../JoinOrDetachThreadOnlyOnce.expected} | 0 .../JoinOrDetachThreadOnlyOnce.ql | 4 + .../rules/joinordetachthreadonlyonce}/test.c | 0 .../DIR-5-2/NotNoDeadlocksBetweenThreads.ql | 24 +++ .../DIR-5-3/BannedDynamicThreadCreation.ql | 29 +++ .../rules/DIR-5-3/ThreadCreatedByThread.ql | 45 +++++ .../AtomicAggregateObjectDirectlyAccessed.ql | 35 ++++ .../RULE-21-25/InvalidMemoryOrderArgument.ql | 176 ++++++++++++++++++ .../ThreadPreviouslyJoinedOrDetached.ql | 24 +++ .../NotNoDeadlocksBetweenThreads.testref | 1 + .../BannedDynamicThreadCreation.expected | 16 ++ .../DIR-5-3/BannedDynamicThreadCreation.qlref | 1 + .../DIR-5-3/ThreadCreatedByThread.expected | 14 ++ .../rules/DIR-5-3/ThreadCreatedByThread.qlref | 1 + c/misra/test/rules/DIR-5-3/test.c | 95 ++++++++++ ...icAggregateObjectDirectlyAccessed.expected | 4 + ...tomicAggregateObjectDirectlyAccessed.qlref | 1 + c/misra/test/rules/RULE-12-6/test.c | 59 ++++++ .../InvalidMemoryOrderArgument.expected | 99 ++++++++++ .../InvalidMemoryOrderArgument.qlref | 1 + c/misra/test/rules/RULE-21-25/test.c | 85 +++++++++ .../ThreadPreviouslyJoinedOrDetached.testref | 1 + ...hreadWasPreviouslyJoinedOrDetached.testref | 1 + .../src/codingstandards/cpp/Concurrency.qll | 31 ++- .../cpp/exclusions/c/Concurrency6.qll | 112 +++++++++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + .../JoinOrDetachThreadOnlyOnce.qll | 49 +++++ rule_packages/c/Concurrency5.json | 1 + rule_packages/c/Concurrency6.json | 132 +++++++++++++ rules.csv | 26 +-- 33 files changed, 1125 insertions(+), 59 deletions(-) create mode 100644 c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.testref rename c/{cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.expected => common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.expected} (100%) create mode 100644 c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.ql rename c/{cert/test/rules/CON39-C => common/test/rules/joinordetachthreadonlyonce}/test.c (100%) create mode 100644 c/misra/src/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.ql create mode 100644 c/misra/src/rules/DIR-5-3/BannedDynamicThreadCreation.ql create mode 100644 c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql create mode 100644 c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql create mode 100644 c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql create mode 100644 c/misra/src/rules/RULE-22-11/ThreadPreviouslyJoinedOrDetached.ql create mode 100644 c/misra/test/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.testref create mode 100644 c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected create mode 100644 c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.qlref create mode 100644 c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected create mode 100644 c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.qlref create mode 100644 c/misra/test/rules/DIR-5-3/test.c create mode 100644 c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected create mode 100644 c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.qlref create mode 100644 c/misra/test/rules/RULE-12-6/test.c create mode 100644 c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected create mode 100644 c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.qlref create mode 100644 c/misra/test/rules/RULE-21-25/test.c create mode 100644 c/misra/test/rules/RULE-22-11/ThreadPreviouslyJoinedOrDetached.testref create mode 100644 c/misra/test/rules/RULE-22-11/ThreadWasPreviouslyJoinedOrDetached.testref create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency6.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.qll create mode 100644 rule_packages/c/Concurrency6.json diff --git a/c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql b/c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql index a8dead535d..0604d2d483 100644 --- a/c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql +++ b/c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql @@ -14,37 +14,10 @@ import cpp import codingstandards.c.cert -import codingstandards.cpp.Concurrency +import codingstandards.cpp.rules.joinordetachthreadonlyonce.JoinOrDetachThreadOnlyOnce -// OK -// 1) Thread calls detach parent DOES NOT call join -// 2) Parent calls join, thread does NOT call detach() -// NOT OK -// 1) Thread calls detach, parent calls join -// 2) Thread calls detach twice, parent does not call join -// 3) Parent calls join twice, thread does not call detach -from C11ThreadCreateCall tcc -where - not isExcluded(tcc, Concurrency5Package::threadWasPreviouslyJoinedOrDetachedQuery()) and - // Note: These cases can be simplified but they are presented like this for clarity - // case 1 - calls to `thrd_join` and `thrd_detach` within the parent or - // within the parent / child CFG. - exists(C11ThreadWait tw, C11ThreadDetach dt | - tw = getAThreadContextAwareSuccessor(tcc) and - dt = getAThreadContextAwareSuccessor(tcc) - ) - or - // case 2 - multiple calls to `thrd_detach` within the threaded CFG. - exists(C11ThreadDetach dt1, C11ThreadDetach dt2 | - dt1 = getAThreadContextAwareSuccessor(tcc) and - dt2 = getAThreadContextAwareSuccessor(tcc) and - not dt1 = dt2 - ) - or - // case 3 - multiple calls to `thrd_join` within the threaded CFG. - exists(C11ThreadWait tw1, C11ThreadWait tw2 | - tw1 = getAThreadContextAwareSuccessor(tcc) and - tw2 = getAThreadContextAwareSuccessor(tcc) and - not tw1 = tw2 - ) -select tcc, "Thread may call join or detach after the thread is joined or detached." +class ThreadWasPreviouslyJoinedOrDetachedQuery extends JoinOrDetachThreadOnlyOnceSharedQuery { + ThreadWasPreviouslyJoinedOrDetachedQuery() { + this = Concurrency5Package::threadWasPreviouslyJoinedOrDetachedQuery() + } +} diff --git a/c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.testref b/c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.testref new file mode 100644 index 0000000000..61fa88fd08 --- /dev/null +++ b/c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.testref @@ -0,0 +1 @@ +c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.ql \ No newline at end of file diff --git a/c/common/test/includes/standard-library/stdatomic.h b/c/common/test/includes/standard-library/stdatomic.h index 66b74ae61a..49a5b3cfcd 100644 --- a/c/common/test/includes/standard-library/stdatomic.h +++ b/c/common/test/includes/standard-library/stdatomic.h @@ -1,9 +1,69 @@ -#define atomic_compare_exchange_weak(a, b, c) 0 -#define atomic_compare_exchange_weak_explicit(a, b, c, d, e) 0 -#define atomic_load(a) 0 -#define atomic_load_explicit(a, b) -#define atomic_store(a, b) 0 -#define atomic_store_explicit(a, b, c) 0 #define ATOMIC_VAR_INIT(value) (value) #define atomic_is_lock_free(obj) __c11_atomic_is_lock_free(sizeof(*(obj))) -typedef _Atomic(int) atomic_int; \ No newline at end of file +typedef _Atomic(int) atomic_int; + +#define __ATOMIC_RELAXED 0 +#define __ATOMIC_CONSUME 1 +#define __ATOMIC_ACQUIRE 2 +#define __ATOMIC_RELEASE 3 +#define __ATOMIC_ACQ_REL 4 +#define __ATOMIC_SEQ_CST 5 + +typedef enum memory_order { + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_consume = __ATOMIC_CONSUME, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST +} memory_order; + +void atomic_thread_fence(memory_order); +void atomic_signal_fence(memory_order); + +#define atomic_thread_fence(order) __c11_atomic_thread_fence(order) +#define atomic_signal_fence(order) __c11_atomic_signal_fence(order) + +#define atomic_store(object, desired) __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST) +#define atomic_store_explicit __c11_atomic_store + +#define atomic_load(object) __c11_atomic_load(object, __ATOMIC_SEQ_CST) +#define atomic_load_explicit __c11_atomic_load + +#define atomic_exchange(object, desired) __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST) +#define atomic_exchange_explicit __c11_atomic_exchange + +#define atomic_compare_exchange_strong(object, expected, desired) __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong + +#define atomic_compare_exchange_weak(object, expected, desired) __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak + +#define atomic_fetch_add(object, operand) __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_add_explicit __c11_atomic_fetch_add + +#define atomic_fetch_sub(object, operand) __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub + +#define atomic_fetch_or(object, operand) __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_or_explicit __c11_atomic_fetch_or + +#define atomic_fetch_xor(object, operand) __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor + +#define atomic_fetch_and(object, operand) __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_and_explicit __c11_atomic_fetch_and + +typedef struct atomic_flag { _Atomic(_Bool) _Value; } atomic_flag; + +_Bool atomic_flag_test_and_set(volatile atomic_flag *); +_Bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order); + +void atomic_flag_clear(volatile atomic_flag *); +void atomic_flag_clear_explicit(volatile atomic_flag *, memory_order); + +#define atomic_flag_test_and_set(object) __c11_atomic_exchange(&(object)->_Value, 1, __ATOMIC_SEQ_CST) +#define atomic_flag_test_and_set_explicit(object, order) __c11_atomic_exchange(&(object)->_Value, 1, order) + +#define atomic_flag_clear(object) __c11_atomic_store(&(object)->_Value, 0, __ATOMIC_SEQ_CST) +#define atomic_flag_clear_explicit(object, order) __c11_atomic_store(&(object)->_Value, 0, order) \ No newline at end of file diff --git a/c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.expected b/c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.expected similarity index 100% rename from c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.expected rename to c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.expected diff --git a/c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.ql b/c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.ql new file mode 100644 index 0000000000..87188403af --- /dev/null +++ b/c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.joinordetachthreadonlyonce.JoinOrDetachThreadOnlyOnce + +class TestFileQuery extends JoinOrDetachThreadOnlyOnceSharedQuery, TestQuery { } diff --git a/c/cert/test/rules/CON39-C/test.c b/c/common/test/rules/joinordetachthreadonlyonce/test.c similarity index 100% rename from c/cert/test/rules/CON39-C/test.c rename to c/common/test/rules/joinordetachthreadonlyonce/test.c diff --git a/c/misra/src/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.ql b/c/misra/src/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.ql new file mode 100644 index 0000000000..ffe30a2b6a --- /dev/null +++ b/c/misra/src/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/not-no-deadlocks-between-threads + * @name DIR-5-2: There shall be no deadlocks between threads + * @description Circular waits leading to thread deadlocks may be avoided by locking in a predefined + * order. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/dir-5-2 + * external/misra/c/2012/amendment4 + * correctness + * concurrency + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.preventdeadlockbylockinginpredefinedorder.PreventDeadlockByLockingInPredefinedOrder + +class NotNoDeadlocksBetweenThreadsQuery extends PreventDeadlockByLockingInPredefinedOrderSharedQuery { + NotNoDeadlocksBetweenThreadsQuery() { + this = Concurrency6Package::notNoDeadlocksBetweenThreadsQuery() + } +} diff --git a/c/misra/src/rules/DIR-5-3/BannedDynamicThreadCreation.ql b/c/misra/src/rules/DIR-5-3/BannedDynamicThreadCreation.ql new file mode 100644 index 0000000000..4bb526306b --- /dev/null +++ b/c/misra/src/rules/DIR-5-3/BannedDynamicThreadCreation.ql @@ -0,0 +1,29 @@ +/** + * @id c/misra/banned-dynamic-thread-creation + * @name DIR-5-3: There shall be no dynamic thread creation + * @description Creating threads outside of a well-defined program start-up phase creates + * uncertainty in program behavior and concurrency overhead costs. + * @kind problem + * @precision low + * @problem.severity error + * @tags external/misra/id/dir-5-3 + * external/misra/c/2012/amendment4 + * external/misra/c/audit + * correctness + * maintainability + * concurrency + * performance + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Concurrency + +from CThreadCreateCall tc, Function enclosingFunction +where + not isExcluded(tc, Concurrency6Package::bannedDynamicThreadCreationQuery()) and + enclosingFunction = tc.getEnclosingFunction() and + not enclosingFunction.getName() = "main" +select tc, "Possible dynamic creation of thread outside initialization in function '$@'.", + enclosingFunction, enclosingFunction.toString() diff --git a/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql b/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql new file mode 100644 index 0000000000..cf08a0c809 --- /dev/null +++ b/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql @@ -0,0 +1,45 @@ +/** + * @id c/misra/thread-created-by-thread + * @name DIR-5-3: Threads shall not be created by other threads + * @description Creating threads within threads creates uncertainty in program behavior and + * concurrency overhead costs. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/dir-5-3 + * external/misra/c/2012/amendment4 + * correctness + * maintainability + * concurrency + * performance + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Concurrency + +Function callers(Function f) { result = f.getACallToThisFunction().getEnclosingFunction() } + +class ThreadReachableFunction extends Function { + /* The root threaded function from which this function is reachable */ + Function threadRoot; + + ThreadReachableFunction() { + exists(CThreadCreateCall tc | + tc.getFunction() = callers*(this) and + threadRoot = tc.getFunction() + ) + } + + /* Get the root threaded function from which this function is reachable */ + Function getThreadRoot() { result = threadRoot } +} + +from CThreadCreateCall tc, ThreadReachableFunction enclosingFunction, Function threadRoot +where + not isExcluded(tc, Concurrency6Package::threadCreatedByThreadQuery()) and + enclosingFunction = tc.getEnclosingFunction() and + threadRoot = enclosingFunction.getThreadRoot() +select tc, "Thread creation call reachable from threaded function '$@'.", threadRoot, + threadRoot.toString() \ No newline at end of file diff --git a/c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql b/c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql new file mode 100644 index 0000000000..4e65fa3f91 --- /dev/null +++ b/c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql @@ -0,0 +1,35 @@ +/** + * @id c/misra/atomic-aggregate-object-directly-accessed + * @name RULE-12-6: Structure and union members of atomic objects shall not be directly accessed + * @description Accessing a member of an atomic structure or union results in undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-12-6 + * external/misra/c/2012/amendment4 + * correctness + * concurrency + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from Expr expr, Field field +where + not isExcluded(expr, Concurrency6Package::atomicAggregateObjectDirectlyAccessedQuery()) and + not expr.isUnevaluated() and + ( + exists(FieldAccess fa | + expr = fa and + fa.getQualifier().getUnderlyingType().hasSpecifier("atomic") and + field = fa.getTarget() + ) + or + exists(PointerFieldAccess fa | + expr = fa and + fa.getQualifier().getUnderlyingType().(PointerType).getBaseType().hasSpecifier("atomic") and + field = fa.getTarget() + ) + ) +select expr, "Invalid access to member '$@' on atomic struct or union.", field, field.getName() diff --git a/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql b/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql new file mode 100644 index 0000000000..4924c0df33 --- /dev/null +++ b/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql @@ -0,0 +1,176 @@ +/** + * @id c/misra/invalid-memory-order-argument + * @name RULE-21-25: All memory synchronization operations shall be executed in sequentially consistent order + * @description Only the memory ordering of 'memory_order_seq_cst' is fully portable and consistent. + * @kind path-problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-25 + * external/misra/c/2012/amendment4 + * correctness + * concurrency + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import semmle.code.cpp.dataflow.new.DataFlow + +/* A member of the set of memory orders defined in the `memory_order` enum */ +class MemoryOrder extends EnumConstant { + MemoryOrder() { getDeclaringEnum().getName() = "memory_order" } + + int getIntValue() { result = getValue().toInt() } +} + +/* This is the only standardized memory order, allowed by RULE-21-25. */ +class AllowedMemoryOrder extends MemoryOrder { + AllowedMemoryOrder() { getName() = "memory_order_seq_cst" } +} + +/* An expression referring to a memory order */ +class MemoryOrderConstantAccess extends EnumConstantAccess { + MemoryOrderConstantAccess() { getTarget() instanceof MemoryOrder } + + predicate isAllowedOrder() { getTarget() instanceof AllowedMemoryOrder } +} + +/* An expression with a constant value that equals a `MemoryOrder` constant */ +class MemoryOrderConstantExpr extends Expr { + MemoryOrder ord; + + MemoryOrderConstantExpr() { + if + this instanceof MemoryOrderConstantAccess + then + ord = this.(MemoryOrderConstantAccess).getTarget() + else + ord.getIntValue() = getValue().toInt() + } + + /* Get the name of the `MemoryOrder` this expression is valued as. */ + string getMemoryOrderString() { + result = ord.toString() + } +} + +/** + * A `stdatomic.h` function which accepts a `memory_order` value as a parameter. + */ +class MemoryOrderedStdAtomicFunction extends Function { + int orderParamIdx; + + MemoryOrderedStdAtomicFunction() { + exists(int baseParamIdx, int baseParams, string prefix, string suffix | + prefix = ["__", "__c11_"] and + suffix = ["", ".*", "_explicit"] and + ( + getName().regexpMatch(prefix + ["atomic_thread_fence", "atomic_signal_fence"] + suffix) and + baseParamIdx = 0 and + baseParams = 1 + or + getName() + .regexpMatch(prefix + ["atomic_load", "atomic_flag_clear", "atomic_flag_test_and_set"] + + suffix) and + baseParamIdx = 1 and + baseParams = 2 + or + getName().regexpMatch(prefix + ["atomic_store", "atomic_fetch_.*", "atomic_exchange"] + suffix) and + baseParamIdx = 2 and + baseParams = 3 + or + getName().regexpMatch(prefix + "atomic_compare_exchange_.*" + suffix) and + baseParamIdx = [3, 4] and + baseParams = 5 + ) and + ( + // GCC case, may have one or two inserted parameters, e.g.: + // __atomic_load(8, &repr->a, &desired, order) + // or + // __atomic_load_8(&repr->a, &desired, order) + prefix = "__" and + suffix = ".*" and + exists(int extraParams | + extraParams = getNumberOfParameters() - baseParams and + extraParams >= 0 and + orderParamIdx = baseParamIdx + extraParams + ) + or + // Clang case, no inserted parameters: + // __c11_atomic_load(object, order) + suffix = "" and + prefix = "__c11_" and + orderParamIdx = baseParamIdx + or + // Non-macro case, may occur in a subset of gcc/clang functions: + prefix = "" and + suffix = "_explicit" and + orderParamIdx = baseParamIdx + ) + ) + } + + int getOrderParameterIdx() { result = orderParamIdx } +} + +module MemoryOrderFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { + // Direct usage of memory order constant + exists(MemoryOrderConstantAccess constant | + node.asExpr() = constant and + not constant.isAllowedOrder() + ) + or + // A literal with a disallowed constant integer value + exists(Literal literal | + node.asExpr() = literal and + not literal.getValue().toInt() = any(AllowedMemoryOrder a).getValue().toInt() + ) + or + // Everything else: not a memory order constant or an integer valued literal, also exclude + // variables and functions, things that flow further back. + exists(Expr e | + node.asExpr() = e and + not e instanceof MemoryOrderConstantAccess and + not e instanceof Literal and + not e instanceof VariableAccess and + not e instanceof FunctionCall and + not DataFlow::localFlowStep(_, node) + ) + } + + predicate isSink(DataFlow::Node node) { + exists(FunctionCall fc | + node.asExpr() = + fc.getArgument(fc.getTarget().(MemoryOrderedStdAtomicFunction).getOrderParameterIdx()) + ) + } +} + +module MemoryOrderFlow = DataFlow::Global; + +import MemoryOrderFlow::PathGraph + +/** + * If the node is a memory order constant, or shares a value with a memory order constant, then + * return the name of that cnonstant. Otherwise, simply print the node. + */ +string describeMemoryOrderNode(DataFlow::Node node) { + if node.asExpr() instanceof MemoryOrderConstantExpr + then result = node.asExpr().(MemoryOrderConstantExpr).getMemoryOrderString() + else result = node.toString() +} + +from + Expr argument, Function function, string value, MemoryOrderFlow::PathNode source, + MemoryOrderFlow::PathNode sink +where + not isExcluded(argument, Concurrency6Package::invalidMemoryOrderArgumentQuery()) and + MemoryOrderFlow::flowPath(source, sink) and + argument = sink.getNode().asExpr() and + value = describeMemoryOrderNode(source.getNode()) and + // Double check that we didn't find flow from something equivalent to the allowed value. + not value = any(AllowedMemoryOrder e).getName() and + function.getACallToThisFunction().getAnArgument() = argument +select argument, source, sink, "Invalid memory order '$@' in call to function '$@'.", value, value, + function, function.toString() diff --git a/c/misra/src/rules/RULE-22-11/ThreadPreviouslyJoinedOrDetached.ql b/c/misra/src/rules/RULE-22-11/ThreadPreviouslyJoinedOrDetached.ql new file mode 100644 index 0000000000..1a6476b1a7 --- /dev/null +++ b/c/misra/src/rules/RULE-22-11/ThreadPreviouslyJoinedOrDetached.ql @@ -0,0 +1,24 @@ +/** + * @id c/misra/thread-previously-joined-or-detached + * @name RULE-22-11: A thread that was previously either joined or detached shall not be subsequently joined nor detached + * @description Joining or detaching a previously joined or detached thread can lead to undefined + * program behavior. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-11 + * external/misra/c/2012/amendment4 + * correctness + * concurrency + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.joinordetachthreadonlyonce.JoinOrDetachThreadOnlyOnce + +class ThreadPreviouslyJoinedOrDetachedQuery extends JoinOrDetachThreadOnlyOnceSharedQuery { + ThreadPreviouslyJoinedOrDetachedQuery() { + this = Concurrency6Package::threadPreviouslyJoinedOrDetachedQuery() + } +} diff --git a/c/misra/test/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.testref b/c/misra/test/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.testref new file mode 100644 index 0000000000..4625d1a24d --- /dev/null +++ b/c/misra/test/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.testref @@ -0,0 +1 @@ +c/common/test/rules/preventdeadlockbylockinginpredefinedorder/PreventDeadlockByLockingInPredefinedOrder.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected b/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected new file mode 100644 index 0000000000..ff829918fd --- /dev/null +++ b/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected @@ -0,0 +1,16 @@ +| test.c:37:3:37:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:36:6:36:34 | make_threads_called_from_main | make_threads_called_from_main | +| test.c:38:3:38:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:36:6:36:34 | make_threads_called_from_main | make_threads_called_from_main | +| test.c:46:3:46:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:45:6:45:51 | make_threads_called_from_func_called_from_main | make_threads_called_from_func_called_from_main | +| test.c:47:3:47:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:45:6:45:51 | make_threads_called_from_func_called_from_main | make_threads_called_from_func_called_from_main | +| test.c:56:3:56:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | +| test.c:57:3:57:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | +| test.c:65:3:65:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | +| test.c:66:3:66:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | +| test.c:74:3:74:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:73:6:73:39 | make_threads_called_from_thrd_func | make_threads_called_from_thrd_func | +| test.c:75:3:75:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:73:6:73:39 | make_threads_called_from_thrd_func | make_threads_called_from_thrd_func | +| test.c:83:3:83:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:82:6:82:59 | make_threads_called_from_func_called_from_pthread_thrd | make_threads_called_from_func_called_from_pthread_thrd | +| test.c:84:3:84:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:82:6:82:59 | make_threads_called_from_func_called_from_pthread_thrd | make_threads_called_from_func_called_from_pthread_thrd | +| test.c:88:3:88:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:87:6:87:47 | make_threads_called_from_main_pthread_thrd | make_threads_called_from_main_pthread_thrd | +| test.c:89:3:89:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:87:6:87:47 | make_threads_called_from_main_pthread_thrd | make_threads_called_from_main_pthread_thrd | +| test.c:93:3:93:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:92:6:92:38 | make_threads_not_called_by_anyone | make_threads_not_called_by_anyone | +| test.c:94:3:94:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:92:6:92:38 | make_threads_not_called_by_anyone | make_threads_not_called_by_anyone | diff --git a/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.qlref b/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.qlref new file mode 100644 index 0000000000..16c9614cec --- /dev/null +++ b/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.qlref @@ -0,0 +1 @@ +rules/DIR-5-3/BannedDynamicThreadCreation.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected b/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected new file mode 100644 index 0000000000..74be75ffeb --- /dev/null +++ b/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected @@ -0,0 +1,14 @@ +| test.c:56:3:56:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | +| test.c:57:3:57:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | +| test.c:65:3:65:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | +| test.c:66:3:66:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | +| test.c:74:3:74:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | +| test.c:75:3:75:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | +| test.c:83:3:83:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | +| test.c:83:3:83:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | +| test.c:84:3:84:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | +| test.c:84:3:84:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | +| test.c:88:3:88:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | +| test.c:88:3:88:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | +| test.c:89:3:89:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | +| test.c:89:3:89:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | diff --git a/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.qlref b/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.qlref new file mode 100644 index 0000000000..99cecb8311 --- /dev/null +++ b/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.qlref @@ -0,0 +1 @@ +rules/DIR-5-3/ThreadCreatedByThread.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-5-3/test.c b/c/misra/test/rules/DIR-5-3/test.c new file mode 100644 index 0000000000..294f79a276 --- /dev/null +++ b/c/misra/test/rules/DIR-5-3/test.c @@ -0,0 +1,95 @@ +#include "threads.h" +#include "pthread.h" + +thrd_t g1; // COMPLIANT +pthread_t g2; // COMPLIANT +thrd_t g3[10]; // COMPLIANT +pthread_t g4[10]; // COMPLIANT + +struct { + thrd_t m1; // COMPLIANT + pthread_t m2; // COMPLIANT +} g7; + +void* pthread_func(void* arg); +int thrd_func(void* arg); + +void make_threads_called_from_main(void); +void func_called_from_main(void); +void make_threads_called_from_func_called_from_main(void); +void make_threads_called_from_main_pthread_thrd(void); + +void main() { + // Main starting top level threads -- ok. + thrd_create(&g1, &thrd_func, NULL); // COMPLIANT + pthread_create(&g2, NULL, &pthread_func, NULL); // COMPLIANT + + // Starting thread in pool -- ok. + thrd_create(&g3[0], &thrd_func, NULL); // COMPLIANT + pthread_create(&g4[0], NULL, &pthread_func, NULL); // COMPLIANT + + make_threads_called_from_main(); + func_called_from_main(); + make_threads_called_from_main_pthread_thrd(); +} + +void make_threads_called_from_main() { + thrd_create(&g3[0], &thrd_func, NULL); // COMPLIANT + pthread_create(&g4[0], NULL, &pthread_func, NULL); // COMPLIANT +} + +void func_called_from_main() { + make_threads_called_from_func_called_from_main(); +} + +void make_threads_called_from_func_called_from_main() { + thrd_create(&g3[0], &thrd_func, NULL); // COMPLIANT + pthread_create(&g4[0], NULL, &pthread_func, NULL); // COMPLIANT +} + +void make_threads_called_from_pthread_func(void); +void make_threads_called_from_thrd_func(void); +void func_called_from_pthread_thrd(void); +void make_threads_called_from_func_called_from_pthread_thrd(void); + +void* pthread_func(void* arg) { + thrd_create(&g3[0], &thrd_func, NULL); // NON-COMPLIANT + pthread_create(&g4[0], NULL, &pthread_func, NULL); // NON-COMPLIANT + + make_threads_called_from_pthread_func(); + func_called_from_pthread_thrd(); + make_threads_called_from_main_pthread_thrd(); +} + +int thrd_func(void* arg) { + thrd_create(&g3[0], &thrd_func, NULL); // NON-COMPLIANT + pthread_create(&g4[0], NULL, &pthread_func, NULL); // NON-COMPLIANT + + make_threads_called_from_thrd_func(); + func_called_from_pthread_thrd(); + make_threads_called_from_main_pthread_thrd(); +} + +void make_threads_called_from_thrd_func(void) { + thrd_create(&g3[0], &thrd_func, NULL); // NON-COMPLIANT + pthread_create(&g4[0], NULL, &pthread_func, NULL); // NON-COMPLIANT +} + +void func_called_from_pthread_thrd(void) { + make_threads_called_from_func_called_from_pthread_thrd(); +} + +void make_threads_called_from_func_called_from_pthread_thrd(void) { + thrd_create(&g3[0], &thrd_func, NULL); // NON-COMPLIANT + pthread_create(&g4[0], NULL, &pthread_func, NULL); // NON-COMPLIANT +} + +void make_threads_called_from_main_pthread_thrd() { + thrd_create(&g3[0], &thrd_func, NULL); // NON-COMPLIANT + pthread_create(&g4[0], NULL, &pthread_func, NULL); // NON-COMPLIANT +} + +void make_threads_not_called_by_anyone() { + thrd_create(&g3[0], &thrd_func, NULL); // COMPLIANT + pthread_create(&g4[0], NULL, &pthread_func, NULL); // COMPLIANT +} diff --git a/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected b/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected new file mode 100644 index 0000000000..02159bef69 --- /dev/null +++ b/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected @@ -0,0 +1,4 @@ +| test.c:41:13:41:13 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:42:18:42:18 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:43:13:43:13 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:44:18:44:18 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | diff --git a/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.qlref b/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.qlref new file mode 100644 index 0000000000..2196eeace1 --- /dev/null +++ b/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.qlref @@ -0,0 +1 @@ +rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-12-6/test.c b/c/misra/test/rules/RULE-12-6/test.c new file mode 100644 index 0000000000..2b1eeb7568 --- /dev/null +++ b/c/misra/test/rules/RULE-12-6/test.c @@ -0,0 +1,59 @@ +#include "stdatomic.h" +#include "string.h" + +typedef struct s2 { + int x; +} s1; + +_Atomic s1 atomic_s1; +// A non-atomic pointer to an atomic s1 +_Atomic s1 *ptr_atomic_s1; +// An atomic pointer to a non-atomic s1 +s1 *_Atomic s1_atomic_ptr; + +_Atomic int g3; + +void takeCopy(s1 p1); + +void f1() { + s1 *l1; + l1 = atomic_load(&atomic_s1); // COMPLIANT + l1 = atomic_load(ptr_atomic_s1); // COMPLIANT + l1 = atomic_load(&s1_atomic_ptr); // COMPLIANT + l1->x = 4; // COMPLIANT + atomic_store(&atomic_s1, l1); // COMPLIANT + atomic_store(ptr_atomic_s1, l1); // COMPLIANT + atomic_store(&s1_atomic_ptr, l1); // COMPLIANT + + // Undefined behavior, but not banned by this rule. + memset(&atomic_s1, sizeof(atomic_s1), 0); // COMPLIANT + memset(ptr_atomic_s1, sizeof(*ptr_atomic_s1), 0); // COMPLIANT + + // OK: whole loads and stores are protected from data-races. + takeCopy(atomic_s1); // COMPLIANT + takeCopy(*ptr_atomic_s1); // COMPLIANT + atomic_s1 = (s1){0}; // COMPLIANT + *ptr_atomic_s1 = (s1){0}; // COMPLIANT + atomic_s1 = *l1; // COMPLIANT + ptr_atomic_s1 = l1; // COMPLIANT + + // Banned: circumvents data-race protection, results in UB. + atomic_s1.x; // NON-COMPLIANT + ptr_atomic_s1->x; // NON-COMPLIANT + atomic_s1.x = 0; // NON-COMPLIANT + ptr_atomic_s1->x = 0; // NON-COMPLIANT + + // OK: not evaluated. + sizeof(atomic_s1); // COMPLIANT + sizeof(ptr_atomic_s1); // COMPLIANT + sizeof(atomic_s1.x); // COMPLIANT + sizeof(ptr_atomic_s1->x); // COMPLIANT + + // All OK: not an atomic struct, but rather an atomic pointer to non-atomic + // struct. + memset(s1_atomic_ptr, sizeof(*s1_atomic_ptr), 0); // COMPLIANT + takeCopy(*s1_atomic_ptr); // COMPLIANT + *s1_atomic_ptr = (s1){0}; // COMPLIANT + s1_atomic_ptr = l1; // COMPLIANT + s1_atomic_ptr->x; // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected new file mode 100644 index 0000000000..07229ff975 --- /dev/null +++ b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected @@ -0,0 +1,99 @@ +edges +| test.c:4:5:4:6 | *g2 | test.c:53:33:53:34 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:54:29:54:30 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:55:42:55:43 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:56:35:56:36 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:57:36:57:37 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:58:54:58:55 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:59:58:59:59 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:60:52:60:53 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:61:56:61:57 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:62:37:62:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:63:37:63:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:64:36:64:37 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:65:37:65:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:66:37:66:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:67:23:67:24 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:68:23:68:24 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:71:23:71:24 | g2 | provenance | | +| test.c:4:10:4:29 | memory_order_relaxed | test.c:4:5:4:6 | *g2 | provenance | | +| test.c:5:5:5:6 | *g3 | test.c:72:23:72:24 | g3 | provenance | | +| test.c:5:10:5:29 | memory_order_acquire | test.c:5:5:5:6 | *g3 | provenance | | +| test.c:6:5:6:6 | *g4 | test.c:73:23:73:24 | g4 | provenance | | +| test.c:6:10:6:29 | memory_order_consume | test.c:6:5:6:6 | *g4 | provenance | | +| test.c:7:5:7:6 | *g5 | test.c:74:23:74:24 | g5 | provenance | | +| test.c:7:10:7:29 | memory_order_acq_rel | test.c:7:5:7:6 | *g5 | provenance | | +| test.c:8:5:8:6 | *g6 | test.c:75:23:75:24 | g6 | provenance | | +| test.c:8:10:8:29 | memory_order_release | test.c:8:5:8:6 | *g6 | provenance | | +nodes +| test.c:4:5:4:6 | *g2 | semmle.label | *g2 | +| test.c:4:10:4:29 | memory_order_relaxed | semmle.label | memory_order_relaxed | +| test.c:5:5:5:6 | *g3 | semmle.label | *g3 | +| test.c:5:10:5:29 | memory_order_acquire | semmle.label | memory_order_acquire | +| test.c:6:5:6:6 | *g4 | semmle.label | *g4 | +| test.c:6:10:6:29 | memory_order_consume | semmle.label | memory_order_consume | +| test.c:7:5:7:6 | *g5 | semmle.label | *g5 | +| test.c:7:10:7:29 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | +| test.c:8:5:8:6 | *g6 | semmle.label | *g6 | +| test.c:8:10:8:29 | memory_order_release | semmle.label | memory_order_release | +| test.c:16:29:16:48 | memory_order_relaxed | semmle.label | memory_order_relaxed | +| test.c:17:29:17:48 | memory_order_acquire | semmle.label | memory_order_acquire | +| test.c:18:29:18:48 | memory_order_consume | semmle.label | memory_order_consume | +| test.c:19:29:19:48 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | +| test.c:20:29:20:48 | memory_order_release | semmle.label | memory_order_release | +| test.c:53:33:53:34 | g2 | semmle.label | g2 | +| test.c:54:29:54:30 | g2 | semmle.label | g2 | +| test.c:55:42:55:43 | g2 | semmle.label | g2 | +| test.c:56:35:56:36 | g2 | semmle.label | g2 | +| test.c:57:36:57:37 | g2 | semmle.label | g2 | +| test.c:58:54:58:55 | g2 | semmle.label | g2 | +| test.c:59:58:59:59 | g2 | semmle.label | g2 | +| test.c:60:52:60:53 | g2 | semmle.label | g2 | +| test.c:61:56:61:57 | g2 | semmle.label | g2 | +| test.c:62:37:62:38 | g2 | semmle.label | g2 | +| test.c:63:37:63:38 | g2 | semmle.label | g2 | +| test.c:64:36:64:37 | g2 | semmle.label | g2 | +| test.c:65:37:65:38 | g2 | semmle.label | g2 | +| test.c:66:37:66:38 | g2 | semmle.label | g2 | +| test.c:67:23:67:24 | g2 | semmle.label | g2 | +| test.c:68:23:68:24 | g2 | semmle.label | g2 | +| test.c:71:23:71:24 | g2 | semmle.label | g2 | +| test.c:72:23:72:24 | g3 | semmle.label | g3 | +| test.c:73:23:73:24 | g4 | semmle.label | g4 | +| test.c:74:23:74:24 | g5 | semmle.label | g5 | +| test.c:75:23:75:24 | g6 | semmle.label | g6 | +| test.c:78:23:78:46 | ... * ... | semmle.label | ... * ... | +| test.c:79:23:79:23 | 1 | semmle.label | 1 | +| test.c:80:23:80:25 | 100 | semmle.label | 100 | +| test.c:81:23:81:28 | ... + ... | semmle.label | ... + ... | +subpaths +#select +| test.c:16:29:16:48 | memory_order_relaxed | test.c:16:29:16:48 | memory_order_relaxed | test.c:16:29:16:48 | memory_order_relaxed | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_load | __c11_atomic_load | +| test.c:17:29:17:48 | memory_order_acquire | test.c:17:29:17:48 | memory_order_acquire | test.c:17:29:17:48 | memory_order_acquire | Invalid memory order '$@' in call to function '$@'. | memory_order_acquire | memory_order_acquire | file://:0:0:0:0 | __c11_atomic_load | __c11_atomic_load | +| test.c:18:29:18:48 | memory_order_consume | test.c:18:29:18:48 | memory_order_consume | test.c:18:29:18:48 | memory_order_consume | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | file://:0:0:0:0 | __c11_atomic_load | __c11_atomic_load | +| test.c:19:29:19:48 | memory_order_acq_rel | test.c:19:29:19:48 | memory_order_acq_rel | test.c:19:29:19:48 | memory_order_acq_rel | Invalid memory order '$@' in call to function '$@'. | memory_order_acq_rel | memory_order_acq_rel | file://:0:0:0:0 | __c11_atomic_load | __c11_atomic_load | +| test.c:20:29:20:48 | memory_order_release | test.c:20:29:20:48 | memory_order_release | test.c:20:29:20:48 | memory_order_release | Invalid memory order '$@' in call to function '$@'. | memory_order_release | memory_order_release | file://:0:0:0:0 | __c11_atomic_load | __c11_atomic_load | +| test.c:53:33:53:34 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:53:33:53:34 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_store | __c11_atomic_store | +| test.c:54:29:54:30 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:54:29:54:30 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_load | __c11_atomic_load | +| test.c:55:42:55:43 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:55:42:55:43 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_exchange | __c11_atomic_exchange | +| test.c:56:35:56:36 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:56:35:56:36 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_store | __c11_atomic_store | +| test.c:57:36:57:37 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:57:36:57:37 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_exchange | __c11_atomic_exchange | +| test.c:58:54:58:55 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:58:54:58:55 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_compare_exchange_strong | __c11_atomic_compare_exchange_strong | +| test.c:59:58:59:59 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:59:58:59:59 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_compare_exchange_strong | __c11_atomic_compare_exchange_strong | +| test.c:60:52:60:53 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:60:52:60:53 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_compare_exchange_weak | __c11_atomic_compare_exchange_weak | +| test.c:61:56:61:57 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:61:56:61:57 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_compare_exchange_weak | __c11_atomic_compare_exchange_weak | +| test.c:62:37:62:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:62:37:62:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_fetch_add | __c11_atomic_fetch_add | +| test.c:63:37:63:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:63:37:63:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_fetch_sub | __c11_atomic_fetch_sub | +| test.c:64:36:64:37 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:64:36:64:37 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_fetch_or | __c11_atomic_fetch_or | +| test.c:65:37:65:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:65:37:65:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_fetch_xor | __c11_atomic_fetch_xor | +| test.c:66:37:66:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:66:37:66:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_fetch_and | __c11_atomic_fetch_and | +| test.c:67:23:67:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:67:23:67:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | +| test.c:68:23:68:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:68:23:68:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_signal_fence | __c11_atomic_signal_fence | +| test.c:71:23:71:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:71:23:71:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | +| test.c:72:23:72:24 | g3 | test.c:5:10:5:29 | memory_order_acquire | test.c:72:23:72:24 | g3 | Invalid memory order '$@' in call to function '$@'. | memory_order_acquire | memory_order_acquire | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | +| test.c:73:23:73:24 | g4 | test.c:6:10:6:29 | memory_order_consume | test.c:73:23:73:24 | g4 | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | +| test.c:74:23:74:24 | g5 | test.c:7:10:7:29 | memory_order_acq_rel | test.c:74:23:74:24 | g5 | Invalid memory order '$@' in call to function '$@'. | memory_order_acq_rel | memory_order_acq_rel | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | +| test.c:75:23:75:24 | g6 | test.c:8:10:8:29 | memory_order_release | test.c:75:23:75:24 | g6 | Invalid memory order '$@' in call to function '$@'. | memory_order_release | memory_order_release | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | +| test.c:79:23:79:23 | 1 | test.c:79:23:79:23 | 1 | test.c:79:23:79:23 | 1 | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | +| test.c:80:23:80:25 | 100 | test.c:80:23:80:25 | 100 | test.c:80:23:80:25 | 100 | Invalid memory order '$@' in call to function '$@'. | 100 | 100 | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | +| test.c:81:23:81:28 | ... + ... | test.c:81:23:81:28 | ... + ... | test.c:81:23:81:28 | ... + ... | Invalid memory order '$@' in call to function '$@'. | ... + ... | ... + ... | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | diff --git a/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.qlref b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.qlref new file mode 100644 index 0000000000..5c205adc24 --- /dev/null +++ b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.qlref @@ -0,0 +1 @@ +rules/RULE-21-25/InvalidMemoryOrderArgument.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-25/test.c b/c/misra/test/rules/RULE-21-25/test.c new file mode 100644 index 0000000000..51df24555c --- /dev/null +++ b/c/misra/test/rules/RULE-21-25/test.c @@ -0,0 +1,85 @@ +#include "stdatomic.h" + +int g1 = memory_order_seq_cst; +int g2 = memory_order_relaxed; +int g3 = memory_order_acquire; +int g4 = memory_order_consume; +int g5 = memory_order_acq_rel; +int g6 = memory_order_release; + +void f(int p) { + _Atomic int l1; + atomic_flag l2; + + // Directly specified values: + atomic_load_explicit(&l1, memory_order_seq_cst); // COMPLIANT + atomic_load_explicit(&l1, memory_order_relaxed); // NON-COMPLIANT + atomic_load_explicit(&l1, memory_order_acquire); // NON-COMPLIANT + atomic_load_explicit(&l1, memory_order_consume); // NON-COMPLIANT + atomic_load_explicit(&l1, memory_order_acq_rel); // NON-COMPLIANT + atomic_load_explicit(&l1, memory_order_release); // NON-COMPLIANT + + // Implicit values: + atomic_store(&l1, 0); // COMPLIANT + atomic_load(&l1); // COMPLIANT + atomic_flag_test_and_set(&l2); // COMPLIANT + atomic_flag_clear(&l2); // COMPLIANT + atomic_exchange(&l1, 0); // COMPLIANT + atomic_compare_exchange_strong(&l1, 0, 1); // COMPLIANT + atomic_compare_exchange_weak(&l1, 0, 1); // COMPLIANT + atomic_fetch_add(&l1, 0); // COMPLIANT + atomic_fetch_sub(&l1, 0); // COMPLIANT + atomic_fetch_or(&l1, 0); // COMPLIANT + atomic_fetch_xor(&l1, 0); // COMPLIANT + atomic_fetch_and(&l1, 0); // COMPLIANT + + // Compliant flowed values (one test per sink): + atomic_store_explicit(&l1, 0, g1); // COMPLIANT + atomic_load_explicit(&l1, g1); // COMPLIANT + atomic_flag_test_and_set_explicit(&l2, g1); // COMPLIANT + atomic_flag_clear_explicit(&l2, g1); // COMPLIANT + atomic_exchange_explicit(&l1, 0, g1); // COMPLIANT + atomic_compare_exchange_strong_explicit(&l1, 0, 1, g1, g1); // COMPLIANT + atomic_compare_exchange_weak_explicit(&l1, 0, 1, g1, g1); // COMPLIANT + atomic_fetch_add_explicit(&l1, 0, g1); // COMPLIANT + atomic_fetch_sub_explicit(&l1, 0, g1); // COMPLIANT + atomic_fetch_or_explicit(&l1, 0, g1); // COMPLIANT + atomic_fetch_xor_explicit(&l1, 0, g1); // COMPLIANT + atomic_fetch_and_explicit(&l1, 0, g1); // COMPLIANT + atomic_thread_fence(g1); // COMPLIANT + atomic_signal_fence(g1); // COMPLIANT + + // Non-compliant flowed values (one test per sink): + atomic_store_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_load_explicit(&l1, g2); // NON-COMPLIANT + atomic_flag_test_and_set_explicit(&l2, g2); // NON-COMPLIANT + atomic_flag_clear_explicit(&l2, g2); // NON-COMPLIANT + atomic_exchange_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_compare_exchange_strong_explicit(&l1, 0, 1, g2, g1); // NON-COMPLIANT + atomic_compare_exchange_strong_explicit(&l1, 0, 1, g1, g2); // NON-COMPLIANT + atomic_compare_exchange_weak_explicit(&l1, 0, 1, g2, g1); // NON-COMPLIANT + atomic_compare_exchange_weak_explicit(&l1, 0, 1, g1, g2); // NON-COMPLIANT + atomic_fetch_add_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_fetch_sub_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_fetch_or_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_fetch_xor_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_fetch_and_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_thread_fence(g2); // NON-COMPLIANT + atomic_signal_fence(g2); // NON-COMPLIANT + + // Non-compliant flowed values (one test per source): + atomic_thread_fence(g2); // NON-COMPLIANT + atomic_thread_fence(g3); // NON-COMPLIANT + atomic_thread_fence(g4); // NON-COMPLIANT + atomic_thread_fence(g5); // NON-COMPLIANT + atomic_thread_fence(g6); // NON-COMPLIANT + + // Computed flow sources: + atomic_thread_fence(memory_order_seq_cst * 1); // COMPLIANT + atomic_thread_fence(1); // NON-COMPLIANT + atomic_thread_fence(100); // NON-COMPLIANT + atomic_thread_fence(g1 + 1); // NON-COMPLIANT + + // No unsafe flow, currently accepted: + atomic_thread_fence(p); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-11/ThreadPreviouslyJoinedOrDetached.testref b/c/misra/test/rules/RULE-22-11/ThreadPreviouslyJoinedOrDetached.testref new file mode 100644 index 0000000000..61fa88fd08 --- /dev/null +++ b/c/misra/test/rules/RULE-22-11/ThreadPreviouslyJoinedOrDetached.testref @@ -0,0 +1 @@ +c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-11/ThreadWasPreviouslyJoinedOrDetached.testref b/c/misra/test/rules/RULE-22-11/ThreadWasPreviouslyJoinedOrDetached.testref new file mode 100644 index 0000000000..61fa88fd08 --- /dev/null +++ b/c/misra/test/rules/RULE-22-11/ThreadWasPreviouslyJoinedOrDetached.testref @@ -0,0 +1 @@ +c/common/test/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.ql \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Concurrency.qll b/cpp/common/src/codingstandards/cpp/Concurrency.qll index d856fa4515..ed7519dd5d 100644 --- a/cpp/common/src/codingstandards/cpp/Concurrency.qll +++ b/cpp/common/src/codingstandards/cpp/Concurrency.qll @@ -48,19 +48,38 @@ class ThreadConstructorCall extends ConstructorCall, ThreadCreationFunction { } /** - * Models a call to a thread constructor via `thrd_create`. + * Models a call to a thread creation via `thrd_create` or `pthread_create`. */ -class C11ThreadCreateCall extends ThreadCreationFunction { +class CThreadCreateCall extends FunctionCall { Function f; + int fArgIdx; - C11ThreadCreateCall() { - getTarget().getName() = "thrd_create" and + CThreadCreateCall() { + ( + getTarget().getName() = "thrd_create" and + fArgIdx = 1 + or + getTarget().getName() = "pthread_create" and + fArgIdx = 2 + ) and ( - f = getArgument(1).(FunctionAccess).getTarget() or - f = getArgument(1).(AddressOfExpr).getOperand().(FunctionAccess).getTarget() + f = getArgument(fArgIdx).(FunctionAccess).getTarget() or + f = getArgument(fArgIdx).(AddressOfExpr).getOperand().(FunctionAccess).getTarget() ) } + /** + * Returns the function that will be invoked by this thread. + */ + Function getFunction() { result = f } +} + +/** + * Models a call to a thread constructor via `thrd_create`. + */ +class C11ThreadCreateCall extends ThreadCreationFunction, CThreadCreateCall { + C11ThreadCreateCall() { getTarget().getName() = "thrd_create" } + /** * Returns the function that will be invoked by this thread. */ diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency6.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency6.qll new file mode 100644 index 0000000000..62d9f362fe --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency6.qll @@ -0,0 +1,112 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Concurrency6Query = + TNotNoDeadlocksBetweenThreadsQuery() or + TThreadCreatedByThreadQuery() or + TBannedDynamicThreadCreationQuery() or + TAtomicAggregateObjectDirectlyAccessedQuery() or + TInvalidMemoryOrderArgumentQuery() or + TThreadPreviouslyJoinedOrDetachedQuery() + +predicate isConcurrency6QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `notNoDeadlocksBetweenThreads` query + Concurrency6Package::notNoDeadlocksBetweenThreadsQuery() and + queryId = + // `@id` for the `notNoDeadlocksBetweenThreads` query + "c/misra/not-no-deadlocks-between-threads" and + ruleId = "DIR-5-2" and + category = "required" + or + query = + // `Query` instance for the `threadCreatedByThread` query + Concurrency6Package::threadCreatedByThreadQuery() and + queryId = + // `@id` for the `threadCreatedByThread` query + "c/misra/thread-created-by-thread" and + ruleId = "DIR-5-3" and + category = "required" + or + query = + // `Query` instance for the `bannedDynamicThreadCreation` query + Concurrency6Package::bannedDynamicThreadCreationQuery() and + queryId = + // `@id` for the `bannedDynamicThreadCreation` query + "c/misra/banned-dynamic-thread-creation" and + ruleId = "DIR-5-3" and + category = "required" + or + query = + // `Query` instance for the `atomicAggregateObjectDirectlyAccessed` query + Concurrency6Package::atomicAggregateObjectDirectlyAccessedQuery() and + queryId = + // `@id` for the `atomicAggregateObjectDirectlyAccessed` query + "c/misra/atomic-aggregate-object-directly-accessed" and + ruleId = "RULE-12-6" and + category = "required" + or + query = + // `Query` instance for the `invalidMemoryOrderArgument` query + Concurrency6Package::invalidMemoryOrderArgumentQuery() and + queryId = + // `@id` for the `invalidMemoryOrderArgument` query + "c/misra/invalid-memory-order-argument" and + ruleId = "RULE-21-25" and + category = "required" + or + query = + // `Query` instance for the `threadPreviouslyJoinedOrDetached` query + Concurrency6Package::threadPreviouslyJoinedOrDetachedQuery() and + queryId = + // `@id` for the `threadPreviouslyJoinedOrDetached` query + "c/misra/thread-previously-joined-or-detached" and + ruleId = "RULE-22-11" and + category = "required" +} + +module Concurrency6Package { + Query notNoDeadlocksBetweenThreadsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `notNoDeadlocksBetweenThreads` query + TQueryC(TConcurrency6PackageQuery(TNotNoDeadlocksBetweenThreadsQuery())) + } + + Query threadCreatedByThreadQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadCreatedByThread` query + TQueryC(TConcurrency6PackageQuery(TThreadCreatedByThreadQuery())) + } + + Query bannedDynamicThreadCreationQuery() { + //autogenerate `Query` type + result = + // `Query` type for `bannedDynamicThreadCreation` query + TQueryC(TConcurrency6PackageQuery(TBannedDynamicThreadCreationQuery())) + } + + Query atomicAggregateObjectDirectlyAccessedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `atomicAggregateObjectDirectlyAccessed` query + TQueryC(TConcurrency6PackageQuery(TAtomicAggregateObjectDirectlyAccessedQuery())) + } + + Query invalidMemoryOrderArgumentQuery() { + //autogenerate `Query` type + result = + // `Query` type for `invalidMemoryOrderArgument` query + TQueryC(TConcurrency6PackageQuery(TInvalidMemoryOrderArgumentQuery())) + } + + Query threadPreviouslyJoinedOrDetachedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadPreviouslyJoinedOrDetached` query + TQueryC(TConcurrency6PackageQuery(TThreadPreviouslyJoinedOrDetachedQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 3833533d50..ca06ec0912 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -11,6 +11,7 @@ import Concurrency2 import Concurrency3 import Concurrency4 import Concurrency5 +import Concurrency6 import Contracts1 import Contracts2 import Contracts3 @@ -87,6 +88,7 @@ newtype TCQuery = TConcurrency3PackageQuery(Concurrency3Query q) or TConcurrency4PackageQuery(Concurrency4Query q) or TConcurrency5PackageQuery(Concurrency5Query q) or + TConcurrency6PackageQuery(Concurrency6Query q) or TContracts1PackageQuery(Contracts1Query q) or TContracts2PackageQuery(Contracts2Query q) or TContracts3PackageQuery(Contracts3Query q) or @@ -163,6 +165,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isConcurrency3QueryMetadata(query, queryId, ruleId, category) or isConcurrency4QueryMetadata(query, queryId, ruleId, category) or isConcurrency5QueryMetadata(query, queryId, ruleId, category) or + isConcurrency6QueryMetadata(query, queryId, ruleId, category) or isContracts1QueryMetadata(query, queryId, ruleId, category) or isContracts2QueryMetadata(query, queryId, ruleId, category) or isContracts3QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.qll b/cpp/common/src/codingstandards/cpp/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.qll new file mode 100644 index 0000000000..5ccbe83c72 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/joinordetachthreadonlyonce/JoinOrDetachThreadOnlyOnce.qll @@ -0,0 +1,49 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Joining or detaching a previously joined or detached thread can lead to undefined + * program behavior. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Concurrency + +abstract class JoinOrDetachThreadOnlyOnceSharedQuery extends Query { } + +Query getQuery() { result instanceof JoinOrDetachThreadOnlyOnceSharedQuery } + +// OK +// 1) Thread calls detach parent DOES NOT call join +// 2) Parent calls join, thread does NOT call detach() +// NOT OK +// 1) Thread calls detach, parent calls join +// 2) Thread calls detach twice, parent does not call join +// 3) Parent calls join twice, thread does not call detach +query predicate problems(C11ThreadCreateCall tcc, string message) { + not isExcluded(tcc, getQuery()) and + message = "Thread may call join or detach after the thread is joined or detached." and + ( + // Note: These cases can be simplified but they are presented like this for clarity + // case 1 - calls to `thrd_join` and `thrd_detach` within the parent or + // within the parent / child CFG. + exists(C11ThreadWait tw, C11ThreadDetach dt | + tw = getAThreadContextAwareSuccessor(tcc) and + dt = getAThreadContextAwareSuccessor(tcc) + ) + or + // case 2 - multiple calls to `thrd_detach` within the threaded CFG. + exists(C11ThreadDetach dt1, C11ThreadDetach dt2 | + dt1 = getAThreadContextAwareSuccessor(tcc) and + dt2 = getAThreadContextAwareSuccessor(tcc) and + not dt1 = dt2 + ) + or + // case 3 - multiple calls to `thrd_join` within the threaded CFG. + exists(C11ThreadWait tw1, C11ThreadWait tw2 | + tw1 = getAThreadContextAwareSuccessor(tcc) and + tw2 = getAThreadContextAwareSuccessor(tcc) and + not tw1 = tw2 + ) + ) +} diff --git a/rule_packages/c/Concurrency5.json b/rule_packages/c/Concurrency5.json index 67707201fd..0cef2d8b3a 100644 --- a/rule_packages/c/Concurrency5.json +++ b/rule_packages/c/Concurrency5.json @@ -12,6 +12,7 @@ "precision": "high", "severity": "error", "short_name": "ThreadWasPreviouslyJoinedOrDetached", + "shared_implementation_short_name": "JoinOrDetachThreadOnlyOnce", "tags": [ "correctness", "concurrency" diff --git a/rule_packages/c/Concurrency6.json b/rule_packages/c/Concurrency6.json new file mode 100644 index 0000000000..cfb793877e --- /dev/null +++ b/rule_packages/c/Concurrency6.json @@ -0,0 +1,132 @@ +{ + "MISRA-C-2012": { + "DIR-5-2": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Circular waits leading to thread deadlocks may be avoided by locking in a predefined order.", + "kind": "problem", + "name": "There shall be no deadlocks between threads", + "precision": "very-high", + "severity": "error", + "short_name": "NotNoDeadlocksBetweenThreads", + "shared_implementation_short_name": "PreventDeadlockByLockingInPredefinedOrder", + "tags": [ + "external/misra/c/2012/amendment4", + "correctness", + "concurrency" + ] + } + ], + "title": "There shall be no deadlocks between threads" + }, + "DIR-5-3": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Creating threads within threads creates uncertainty in program behavior and concurrency overhead costs.", + "kind": "problem", + "name": "Threads shall not be created by other threads", + "precision": "high", + "severity": "error", + "short_name": "ThreadCreatedByThread", + "tags": [ + "external/misra/c/2012/amendment4", + "correctness", + "maintainability", + "concurrency", + "performance" + ] + }, + { + "description": "Creating threads outside of a well-defined program start-up phase creates uncertainty in program behavior and concurrency overhead costs.", + "kind": "problem", + "name": "There shall be no dynamic thread creation", + "precision": "low", + "severity": "error", + "short_name": "BannedDynamicThreadCreation", + "tags": [ + "external/misra/c/2012/amendment4", + "external/misra/c/audit", + "correctness", + "maintainability", + "concurrency", + "performance" + ] + } + ], + "title": "There shall be no dynamic thread creation" + }, + "RULE-12-6": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Accessing a member of an atomic structure or union results in undefined behavior.", + "kind": "problem", + "name": "Structure and union members of atomic objects shall not be directly accessed", + "precision": "very-high", + "severity": "error", + "short_name": "AtomicAggregateObjectDirectlyAccessed", + "tags": [ + "external/misra/c/2012/amendment4", + "correctness", + "concurrency" + ] + } + ], + "title": "Structure and union members of atomic objects shall not be directly accessed" + }, + "RULE-21-25": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Only the memory ordering of 'memory_order_seq_cst' is fully portable and consistent.", + "kind": "path-problem", + "name": "All memory synchronization operations shall be executed in sequentially consistent order", + "precision": "very-high", + "severity": "error", + "short_name": "InvalidMemoryOrderArgument", + "tags": [ + "external/misra/c/2012/amendment4", + "correctness", + "concurrency" + ] + } + ], + "title": "All memory synchronization operations shall be executed in sequentially consistent order" + }, + "RULE-22-11": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Joining or detaching a previously joined or detached thread can lead to undefined program behavior.", + "kind": "problem", + "name": "A thread that was previously either joined or detached shall not be subsequently joined nor detached", + "precision": "high", + "severity": "error", + "short_name": "ThreadPreviouslyJoinedOrDetached", + "shared_implementation_short_name": "JoinOrDetachThreadOnlyOnce", + "tags": [ + "external/misra/c/2012/amendment4", + "correctness", + "concurrency" + ], + "implementation_scope": { + "description": "This query considers problematic usages of join and detach irrespective of the execution of the program and other synchronization and interprocess communication mechanisms that may be used." + } + } + ], + "title": "A thread that was previously either joined or detached shall not be subsequently joined nor detached" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index 475ea1d66c..7648052954 100644 --- a/rules.csv +++ b/rules.csv @@ -617,7 +617,7 @@ c,MISRA-C-2012,DIR-4-12,Yes,Required,,,Dynamic memory allocation shall not be us c,MISRA-C-2012,DIR-4-13,No,Advisory,,,Functions which are designed to provide operations on a resource should be called in an appropriate sequence,,,,"Rule 22.1, 22.2 and 22.6 cover aspects of this rule. In other cases this is a design issue and needs to be checked manually." c,MISRA-C-2012,DIR-4-14,Yes,Required,,,The validity of values received from external sources shall be checked,,Contracts,Hard,This is supported by CodeQLs default C security queries. c,MISRA-C-2012,DIR-4-15,Yes,Required,,,Evaluation of floating-point expressions shall not lead to the undetected generation of infinities and NaNs,FLP32-C and FLP04-C,FloatingTypes2,Medium, -c,MISRA-C-2012,DIR-5-1,Yes,Required,,,There shall be no data races between threads,CON43-C and CON32-C,Concurrency6,Very Hard, +c,MISRA-C-2012,DIR-5-1,Yes,Required,,,There shall be no data races between threads,CON43-C and CON32-C,Concurrency7,Very Hard, c,MISRA-C-2012,DIR-5-2,Yes,Required,,,There shall be no deadlocks between threads,CON35-C,Concurrency6,Import, c,MISRA-C-2012,DIR-5-3,Yes,Required,,,There shall be no dynamic thread creation,,Concurrency6,Easy, c,MISRA-C-2012,RULE-1-1,No,Required,,,"The program shall contain no violations of the standard C syntax and constraints, and shall not exceed the implementation's translation limits",,,Easy,"This should be checked via the compiler output, rather than CodeQL, which adds unnecessary steps." @@ -678,7 +678,7 @@ c,MISRA-C-2012,RULE-9-3,Yes,Required,,,Arrays shall not be partially initialized c,MISRA-C-2012,RULE-9-4,Yes,Required,,,An element of an object shall not be initialized more than once,,Memory1,Medium, c,MISRA-C-2012,RULE-9-5,No,Required,,,Where designated initializers are used to initialize an array object the size of the array shall be specified explicitly,,,Medium, c,MISRA-C-2012,RULE-9-6,Yes,Required,,,An initializer using chained designators shall not contain initializers without designators,,Declarations9,Hard, -c,MISRA-C-2012,RULE-9-7,Yes,Mandatory,,,Atomic objects shall be appropriately initialized before being accessed,,Concurrency6,Hard, +c,MISRA-C-2012,RULE-9-7,Yes,Mandatory,,,Atomic objects shall be appropriately initialized before being accessed,,Concurrency7,Hard, c,MISRA-C-2012,RULE-10-1,Yes,Required,,,Operands shall not be of an inappropriate essential type,,EssentialTypes,Hard, c,MISRA-C-2012,RULE-10-2,Yes,Required,,,Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations,,EssentialTypes,Medium, c,MISRA-C-2012,RULE-10-3,Yes,Required,,,The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category,,EssentialTypes,Hard, @@ -790,8 +790,8 @@ c,MISRA-C-2012,RULE-21-21,Yes,Required,,,The Standard Library function system of c,MISRA-C-2012,RULE-21-22,Yes,Mandatory,,,All operand arguments to any type-generic macros in shall have an appropriate essential type,EXP37-C,EssentialTypes2,Hard, c,MISRA-C-2012,RULE-21-23,Yes,Required,,,All operand arguments to any multi-argument type-generic macros in shall have the same standard type,Rule-21-22,EssentialTypes2,Easy, c,MISRA-C-2012,RULE-21-24,Yes,Required,,,The random number generator functions of shall not be used,MSC30-C,Banned2,Easy, -c,MISRA-C-2012,RULE-21-25,Yes,Required,,,All memory synchronization operations shall be executed in sequentially consistent order,,Concurrency6,Medium, -c,MISRA-C-2012,RULE-21-26,Yes,Required,,,The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type,,Concurrency6,Hard, +c,MISRA-C-2012,RULE-21-25,Yes,Required,,,All memory synchronization operations shall be executed in sequentially consistent order,,Concurrency7,Medium, +c,MISRA-C-2012,RULE-21-26,Yes,Required,,,The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type,,Concurrency7,Hard, c,MISRA-C-2012,RULE-22-1,Yes,Required,,,All resources obtained dynamically by means of Standard Library functions shall be explicitly released,,Memory2,Hard, c,MISRA-C-2012,RULE-22-2,Yes,Mandatory,,,A block of memory shall only be freed if it was allocated by means of a Standard Library function,,Memory2,Hard, c,MISRA-C-2012,RULE-22-3,Yes,Required,,,The same file shall not be open for read and write access at the same time on different streams,,IO3,Hard, @@ -803,15 +803,15 @@ c,MISRA-C-2012,RULE-22-8,Yes,Required,,,The value of errno shall be set to zero c,MISRA-C-2012,RULE-22-9,Yes,Required,,,The value of errno shall be tested against zero after calling an errno-setting-function,,Contracts3,Medium, c,MISRA-C-2012,RULE-22-10,Yes,Required,,,The value of errno shall only be tested when the last function to be called was an errno-setting-function,,Contracts3,Medium, c,MISRA-C-2012,RULE-22-11,Yes,Required,,,A thread that was previously either joined or detached shall not be subsequently joined nor detached,CON39-C,Concurrency6,Import, -c,MISRA-C-2012,RULE-22-12,Yes,Mandatory,,,"Thread objects, thread synchronization objects, and thread-specific storage pointers shall only be accessed by the appropriate Standard Library functions",,Concurrency6,Medium, -c,MISRA-C-2012,RULE-22-13,Yes,Required,,,"Thread objects, thread synchronization objects, and thread specific storage pointers shall have appropriate storage duration",EXP54-CPP and CON34-C,Concurrency6,Medium, -c,MISRA-C-2012,RULE-22-14,Yes,Mandatory,,,Thread synchronization objects shall be initialized before being accessed,EXP53-CPP,Concurrency6,Hard, -c,MISRA-C-2012,RULE-22-15,Yes,Required,,,Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated,,Concurrency6,Hard, -c,MISRA-C-2012,RULE-22-16,Yes,Required,,,All mutex objects locked by a thread shall be explicitly unlocked by the same thread,MEM51-CPP,Concurrency6,Hard, -c,MISRA-C-2012,RULE-22-17,Yes,Required,,,No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked before,Rule 22.2,Concurrency6,Medium, -c,MISRA-C-2012,RULE-22-18,Yes,Required,,,Non-recursive mutexes shall not be recursively locked,CON56-CPP,Concurrency6,Medium, -c,MISRA-C-2012,RULE-22-19,Yes,Required,,,A condition variable shall be associated with at most one mutex object,,Concurrency6,Medium, -c,MISRA-C-2012,RULE-22-20,Yes,Mandatory,,,Thread-specific storage pointers shall be created before being accessed,,Concurrency6,Hard, +c,MISRA-C-2012,RULE-22-12,Yes,Mandatory,,,"Thread objects, thread synchronization objects, and thread-specific storage pointers shall only be accessed by the appropriate Standard Library functions",,Concurrency7,Medium, +c,MISRA-C-2012,RULE-22-13,Yes,Required,,,"Thread objects, thread synchronization objects, and thread specific storage pointers shall have appropriate storage duration",EXP54-CPP and CON34-C,Concurrency7,Medium, +c,MISRA-C-2012,RULE-22-14,Yes,Mandatory,,,Thread synchronization objects shall be initialized before being accessed,EXP53-CPP,Concurrency7,Hard, +c,MISRA-C-2012,RULE-22-15,Yes,Required,,,Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated,,Concurrency7,Hard, +c,MISRA-C-2012,RULE-22-16,Yes,Required,,,All mutex objects locked by a thread shall be explicitly unlocked by the same thread,MEM51-CPP,Concurrency7,Hard, +c,MISRA-C-2012,RULE-22-17,Yes,Required,,,No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked before,Rule 22.2,Concurrency7,Medium, +c,MISRA-C-2012,RULE-22-18,Yes,Required,,,Non-recursive mutexes shall not be recursively locked,CON56-CPP,Concurrency7,Medium, +c,MISRA-C-2012,RULE-22-19,Yes,Required,,,A condition variable shall be associated with at most one mutex object,,Concurrency7,Medium, +c,MISRA-C-2012,RULE-22-20,Yes,Mandatory,,,Thread-specific storage pointers shall be created before being accessed,,Concurrency7,Hard, c,MISRA-C-2012,RULE-23-1,Yes,Advisory,,,A generic selection should only be expanded from a macro,,Generics,Medium, c,MISRA-C-2012,RULE-23-2,Yes,Required,,,A generic selection that is not expanded from a macro shall not contain potential side effects in the controlling expression,,Generics,Hard, c,MISRA-C-2012,RULE-23-3,Yes,Advisory,,,A generic selection should contain at least one non-default association,,Generics,Easy, From 20bae2046c2d38fb4a8de54682d1d7f69922475e Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 31 Oct 2024 21:46:20 -0700 Subject: [PATCH 077/628] Fix format, remove unneeded test complexity --- .../BannedDynamicThreadCreation.expected | 32 +++++----- .../DIR-5-3/ThreadCreatedByThread.expected | 28 ++++----- c/misra/test/rules/DIR-5-3/test.c | 63 ++++++++----------- 3 files changed, 57 insertions(+), 66 deletions(-) diff --git a/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected b/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected index ff829918fd..fa12a62f41 100644 --- a/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected +++ b/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected @@ -1,16 +1,16 @@ -| test.c:37:3:37:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:36:6:36:34 | make_threads_called_from_main | make_threads_called_from_main | -| test.c:38:3:38:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:36:6:36:34 | make_threads_called_from_main | make_threads_called_from_main | -| test.c:46:3:46:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:45:6:45:51 | make_threads_called_from_func_called_from_main | make_threads_called_from_func_called_from_main | -| test.c:47:3:47:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:45:6:45:51 | make_threads_called_from_func_called_from_main | make_threads_called_from_func_called_from_main | -| test.c:56:3:56:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | -| test.c:57:3:57:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | -| test.c:65:3:65:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | -| test.c:66:3:66:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | -| test.c:74:3:74:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:73:6:73:39 | make_threads_called_from_thrd_func | make_threads_called_from_thrd_func | -| test.c:75:3:75:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:73:6:73:39 | make_threads_called_from_thrd_func | make_threads_called_from_thrd_func | -| test.c:83:3:83:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:82:6:82:59 | make_threads_called_from_func_called_from_pthread_thrd | make_threads_called_from_func_called_from_pthread_thrd | -| test.c:84:3:84:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:82:6:82:59 | make_threads_called_from_func_called_from_pthread_thrd | make_threads_called_from_func_called_from_pthread_thrd | -| test.c:88:3:88:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:87:6:87:47 | make_threads_called_from_main_pthread_thrd | make_threads_called_from_main_pthread_thrd | -| test.c:89:3:89:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:87:6:87:47 | make_threads_called_from_main_pthread_thrd | make_threads_called_from_main_pthread_thrd | -| test.c:93:3:93:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:92:6:92:38 | make_threads_not_called_by_anyone | make_threads_not_called_by_anyone | -| test.c:94:3:94:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:92:6:92:38 | make_threads_not_called_by_anyone | make_threads_not_called_by_anyone | +| test.c:28:3:28:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:27:6:27:34 | make_threads_called_from_main | make_threads_called_from_main | +| test.c:29:3:29:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:27:6:27:34 | make_threads_called_from_main | make_threads_called_from_main | +| test.c:37:3:37:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:36:6:36:51 | make_threads_called_from_func_called_from_main | make_threads_called_from_func_called_from_main | +| test.c:38:3:38:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:36:6:36:51 | make_threads_called_from_func_called_from_main | make_threads_called_from_func_called_from_main | +| test.c:47:3:47:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | +| test.c:48:3:48:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | +| test.c:56:3:56:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | +| test.c:57:3:57:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | +| test.c:65:3:65:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:64:6:64:39 | make_threads_called_from_thrd_func | make_threads_called_from_thrd_func | +| test.c:66:3:66:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:64:6:64:39 | make_threads_called_from_thrd_func | make_threads_called_from_thrd_func | +| test.c:74:3:74:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:73:6:73:59 | make_threads_called_from_func_called_from_pthread_thrd | make_threads_called_from_func_called_from_pthread_thrd | +| test.c:75:3:75:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:73:6:73:59 | make_threads_called_from_func_called_from_pthread_thrd | make_threads_called_from_func_called_from_pthread_thrd | +| test.c:79:3:79:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:78:6:78:47 | make_threads_called_from_main_pthread_thrd | make_threads_called_from_main_pthread_thrd | +| test.c:80:3:80:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:78:6:78:47 | make_threads_called_from_main_pthread_thrd | make_threads_called_from_main_pthread_thrd | +| test.c:84:3:84:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:83:6:83:38 | make_threads_not_called_by_anyone | make_threads_not_called_by_anyone | +| test.c:85:3:85:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:83:6:83:38 | make_threads_not_called_by_anyone | make_threads_not_called_by_anyone | diff --git a/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected b/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected index 74be75ffeb..5b73fd97aa 100644 --- a/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected +++ b/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected @@ -1,14 +1,14 @@ -| test.c:56:3:56:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | -| test.c:57:3:57:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | -| test.c:65:3:65:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | -| test.c:66:3:66:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | -| test.c:74:3:74:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | -| test.c:75:3:75:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | -| test.c:83:3:83:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | -| test.c:83:3:83:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | -| test.c:84:3:84:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | -| test.c:84:3:84:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | -| test.c:88:3:88:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | -| test.c:88:3:88:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | -| test.c:89:3:89:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:55:7:55:18 | pthread_func | pthread_func | -| test.c:89:3:89:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:64:5:64:13 | thrd_func | thrd_func | +| test.c:47:3:47:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | +| test.c:48:3:48:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | +| test.c:56:3:56:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | +| test.c:57:3:57:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | +| test.c:65:3:65:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | +| test.c:66:3:66:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | +| test.c:74:3:74:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | +| test.c:74:3:74:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | +| test.c:75:3:75:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | +| test.c:75:3:75:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | +| test.c:79:3:79:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | +| test.c:79:3:79:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | +| test.c:80:3:80:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | +| test.c:80:3:80:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | diff --git a/c/misra/test/rules/DIR-5-3/test.c b/c/misra/test/rules/DIR-5-3/test.c index 294f79a276..24e03d9a33 100644 --- a/c/misra/test/rules/DIR-5-3/test.c +++ b/c/misra/test/rules/DIR-5-3/test.c @@ -1,18 +1,11 @@ -#include "threads.h" #include "pthread.h" +#include "threads.h" -thrd_t g1; // COMPLIANT +thrd_t g1; // COMPLIANT pthread_t g2; // COMPLIANT -thrd_t g3[10]; // COMPLIANT -pthread_t g4[10]; // COMPLIANT -struct { - thrd_t m1; // COMPLIANT - pthread_t m2; // COMPLIANT -} g7; - -void* pthread_func(void* arg); -int thrd_func(void* arg); +void *pthread_func(void *arg); +int thrd_func(void *arg); void make_threads_called_from_main(void); void func_called_from_main(void); @@ -20,13 +13,11 @@ void make_threads_called_from_func_called_from_main(void); void make_threads_called_from_main_pthread_thrd(void); void main() { - // Main starting top level threads -- ok. - thrd_create(&g1, &thrd_func, NULL); // COMPLIANT + thrd_create(&g1, &thrd_func, NULL); // COMPLIANT pthread_create(&g2, NULL, &pthread_func, NULL); // COMPLIANT - // Starting thread in pool -- ok. - thrd_create(&g3[0], &thrd_func, NULL); // COMPLIANT - pthread_create(&g4[0], NULL, &pthread_func, NULL); // COMPLIANT + thrd_create(&g1, &thrd_func, NULL); // COMPLIANT + pthread_create(&g2, NULL, &pthread_func, NULL); // COMPLIANT make_threads_called_from_main(); func_called_from_main(); @@ -34,17 +25,17 @@ void main() { } void make_threads_called_from_main() { - thrd_create(&g3[0], &thrd_func, NULL); // COMPLIANT - pthread_create(&g4[0], NULL, &pthread_func, NULL); // COMPLIANT + thrd_create(&g1, &thrd_func, NULL); // COMPLIANT + pthread_create(&g2, NULL, &pthread_func, NULL); // COMPLIANT } void func_called_from_main() { - make_threads_called_from_func_called_from_main(); + make_threads_called_from_func_called_from_main(); } void make_threads_called_from_func_called_from_main() { - thrd_create(&g3[0], &thrd_func, NULL); // COMPLIANT - pthread_create(&g4[0], NULL, &pthread_func, NULL); // COMPLIANT + thrd_create(&g1, &thrd_func, NULL); // COMPLIANT + pthread_create(&g2, NULL, &pthread_func, NULL); // COMPLIANT } void make_threads_called_from_pthread_func(void); @@ -52,18 +43,18 @@ void make_threads_called_from_thrd_func(void); void func_called_from_pthread_thrd(void); void make_threads_called_from_func_called_from_pthread_thrd(void); -void* pthread_func(void* arg) { - thrd_create(&g3[0], &thrd_func, NULL); // NON-COMPLIANT - pthread_create(&g4[0], NULL, &pthread_func, NULL); // NON-COMPLIANT +void *pthread_func(void *arg) { + thrd_create(&g1, &thrd_func, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func, NULL); // NON-COMPLIANT make_threads_called_from_pthread_func(); func_called_from_pthread_thrd(); make_threads_called_from_main_pthread_thrd(); } -int thrd_func(void* arg) { - thrd_create(&g3[0], &thrd_func, NULL); // NON-COMPLIANT - pthread_create(&g4[0], NULL, &pthread_func, NULL); // NON-COMPLIANT +int thrd_func(void *arg) { + thrd_create(&g1, &thrd_func, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func, NULL); // NON-COMPLIANT make_threads_called_from_thrd_func(); func_called_from_pthread_thrd(); @@ -71,25 +62,25 @@ int thrd_func(void* arg) { } void make_threads_called_from_thrd_func(void) { - thrd_create(&g3[0], &thrd_func, NULL); // NON-COMPLIANT - pthread_create(&g4[0], NULL, &pthread_func, NULL); // NON-COMPLIANT + thrd_create(&g1, &thrd_func, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func, NULL); // NON-COMPLIANT } void func_called_from_pthread_thrd(void) { - make_threads_called_from_func_called_from_pthread_thrd(); + make_threads_called_from_func_called_from_pthread_thrd(); } void make_threads_called_from_func_called_from_pthread_thrd(void) { - thrd_create(&g3[0], &thrd_func, NULL); // NON-COMPLIANT - pthread_create(&g4[0], NULL, &pthread_func, NULL); // NON-COMPLIANT + thrd_create(&g1, &thrd_func, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func, NULL); // NON-COMPLIANT } void make_threads_called_from_main_pthread_thrd() { - thrd_create(&g3[0], &thrd_func, NULL); // NON-COMPLIANT - pthread_create(&g4[0], NULL, &pthread_func, NULL); // NON-COMPLIANT + thrd_create(&g1, &thrd_func, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func, NULL); // NON-COMPLIANT } void make_threads_not_called_by_anyone() { - thrd_create(&g3[0], &thrd_func, NULL); // COMPLIANT - pthread_create(&g4[0], NULL, &pthread_func, NULL); // COMPLIANT + thrd_create(&g1, &thrd_func, NULL); // COMPLIANT + pthread_create(&g2, NULL, &pthread_func, NULL); // COMPLIANT } From 14b7c61df9f5e4d18213b99a6a1f36c1fe1f0661 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 31 Oct 2024 21:50:31 -0700 Subject: [PATCH 078/628] Move 21-25 to Concurrency6 --- rules.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules.csv b/rules.csv index 7648052954..329d0d1bc5 100644 --- a/rules.csv +++ b/rules.csv @@ -790,7 +790,7 @@ c,MISRA-C-2012,RULE-21-21,Yes,Required,,,The Standard Library function system of c,MISRA-C-2012,RULE-21-22,Yes,Mandatory,,,All operand arguments to any type-generic macros in shall have an appropriate essential type,EXP37-C,EssentialTypes2,Hard, c,MISRA-C-2012,RULE-21-23,Yes,Required,,,All operand arguments to any multi-argument type-generic macros in shall have the same standard type,Rule-21-22,EssentialTypes2,Easy, c,MISRA-C-2012,RULE-21-24,Yes,Required,,,The random number generator functions of shall not be used,MSC30-C,Banned2,Easy, -c,MISRA-C-2012,RULE-21-25,Yes,Required,,,All memory synchronization operations shall be executed in sequentially consistent order,,Concurrency7,Medium, +c,MISRA-C-2012,RULE-21-25,Yes,Required,,,All memory synchronization operations shall be executed in sequentially consistent order,,Concurrency6,Medium, c,MISRA-C-2012,RULE-21-26,Yes,Required,,,The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type,,Concurrency7,Hard, c,MISRA-C-2012,RULE-22-1,Yes,Required,,,All resources obtained dynamically by means of Standard Library functions shall be explicitly released,,Memory2,Hard, c,MISRA-C-2012,RULE-22-2,Yes,Mandatory,,,A block of memory shall only be freed if it was allocated by means of a Standard Library function,,Memory2,Hard, From 3259d17e5d699628303d64f0d52345d0f62eaeca Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 31 Oct 2024 21:53:43 -0700 Subject: [PATCH 079/628] Fix query formatting --- .../DIR-5-2/NotNoDeadlocksBetweenThreads.ql | 3 ++- .../src/rules/DIR-5-3/ThreadCreatedByThread.ql | 2 +- .../RULE-21-25/InvalidMemoryOrderArgument.ql | 16 ++++++---------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/c/misra/src/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.ql b/c/misra/src/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.ql index ffe30a2b6a..5d949f56ed 100644 --- a/c/misra/src/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.ql +++ b/c/misra/src/rules/DIR-5-2/NotNoDeadlocksBetweenThreads.ql @@ -17,7 +17,8 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.rules.preventdeadlockbylockinginpredefinedorder.PreventDeadlockByLockingInPredefinedOrder -class NotNoDeadlocksBetweenThreadsQuery extends PreventDeadlockByLockingInPredefinedOrderSharedQuery { +class NotNoDeadlocksBetweenThreadsQuery extends PreventDeadlockByLockingInPredefinedOrderSharedQuery +{ NotNoDeadlocksBetweenThreadsQuery() { this = Concurrency6Package::notNoDeadlocksBetweenThreadsQuery() } diff --git a/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql b/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql index cf08a0c809..25b8b4cb9f 100644 --- a/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql +++ b/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql @@ -42,4 +42,4 @@ where enclosingFunction = tc.getEnclosingFunction() and threadRoot = enclosingFunction.getThreadRoot() select tc, "Thread creation call reachable from threaded function '$@'.", threadRoot, - threadRoot.toString() \ No newline at end of file + threadRoot.toString() diff --git a/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql b/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql index 4924c0df33..b0945db559 100644 --- a/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql +++ b/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql @@ -40,18 +40,13 @@ class MemoryOrderConstantExpr extends Expr { MemoryOrder ord; MemoryOrderConstantExpr() { - if - this instanceof MemoryOrderConstantAccess - then - ord = this.(MemoryOrderConstantAccess).getTarget() - else - ord.getIntValue() = getValue().toInt() + if this instanceof MemoryOrderConstantAccess + then ord = this.(MemoryOrderConstantAccess).getTarget() + else ord.getIntValue() = getValue().toInt() } /* Get the name of the `MemoryOrder` this expression is valued as. */ - string getMemoryOrderString() { - result = ord.toString() - } + string getMemoryOrderString() { result = ord.toString() } } /** @@ -75,7 +70,8 @@ class MemoryOrderedStdAtomicFunction extends Function { baseParamIdx = 1 and baseParams = 2 or - getName().regexpMatch(prefix + ["atomic_store", "atomic_fetch_.*", "atomic_exchange"] + suffix) and + getName() + .regexpMatch(prefix + ["atomic_store", "atomic_fetch_.*", "atomic_exchange"] + suffix) and baseParamIdx = 2 and baseParams = 3 or From 9ee2af69016c2bd07b39bfd48269674bd870243e Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 1 Nov 2024 02:35:55 -0700 Subject: [PATCH 080/628] Fix test issues --- .../ThreadWasPreviouslyJoinedOrDetached.qlref | 1 - .../AtomicVariableTwiceInExpression.expected | 8 ++++---- ...micAggregateObjectDirectlyAccessed.expected | 4 ++-- c/misra/test/rules/RULE-12-6/test.c | 18 ++++++++++-------- 4 files changed, 16 insertions(+), 15 deletions(-) delete mode 100644 c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.qlref diff --git a/c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.qlref b/c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.qlref deleted file mode 100644 index 5daa5a5046..0000000000 --- a/c/cert/test/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql \ No newline at end of file diff --git a/c/cert/test/rules/CON40-C/AtomicVariableTwiceInExpression.expected b/c/cert/test/rules/CON40-C/AtomicVariableTwiceInExpression.expected index ddff311b59..42d3ea924d 100644 --- a/c/cert/test/rules/CON40-C/AtomicVariableTwiceInExpression.expected +++ b/c/cert/test/rules/CON40-C/AtomicVariableTwiceInExpression.expected @@ -1,6 +1,6 @@ | test.c:7:18:7:39 | ATOMIC_VAR_INIT(value) | Atomic variable possibly referred to twice in an $@. | test.c:33:3:33:10 | ... += ... | expression | | test.c:7:18:7:39 | ATOMIC_VAR_INIT(value) | Atomic variable possibly referred to twice in an $@. | test.c:34:3:34:13 | ... = ... | expression | -| test.c:11:3:11:23 | atomic_store(a,b) | Atomic variable possibly referred to twice in an $@. | test.c:11:3:11:23 | atomic_store(a,b) | expression | -| test.c:12:3:12:35 | atomic_store_explicit(a,b,c) | Atomic variable possibly referred to twice in an $@. | test.c:12:3:12:35 | atomic_store_explicit(a,b,c) | expression | -| test.c:25:3:25:49 | atomic_compare_exchange_weak(a,b,c) | Atomic variable possibly referred to twice in an $@. | test.c:25:3:25:49 | atomic_compare_exchange_weak(a,b,c) | expression | -| test.c:26:3:27:42 | atomic_compare_exchange_weak_explicit(a,b,c,d,e) | Atomic variable possibly referred to twice in an $@. | test.c:26:3:27:42 | atomic_compare_exchange_weak_explicit(a,b,c,d,e) | expression | +| test.c:11:3:11:23 | atomic_store(object,desired) | Atomic variable possibly referred to twice in an $@. | test.c:11:3:11:23 | atomic_store(object,desired) | expression | +| test.c:12:3:12:23 | atomic_store_explicit | Atomic variable possibly referred to twice in an $@. | test.c:12:3:12:23 | atomic_store_explicit | expression | +| test.c:25:3:25:49 | atomic_compare_exchange_weak(object,expected,desired) | Atomic variable possibly referred to twice in an $@. | test.c:25:3:25:49 | atomic_compare_exchange_weak(object,expected,desired) | expression | +| test.c:26:3:26:39 | atomic_compare_exchange_weak_explicit | Atomic variable possibly referred to twice in an $@. | test.c:26:3:26:39 | atomic_compare_exchange_weak_explicit | expression | diff --git a/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected b/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected index 02159bef69..df7f149fcc 100644 --- a/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected +++ b/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected @@ -1,4 +1,4 @@ -| test.c:41:13:41:13 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | -| test.c:42:18:42:18 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | | test.c:43:13:43:13 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | | test.c:44:18:44:18 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:45:13:45:13 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:46:18:46:18 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | diff --git a/c/misra/test/rules/RULE-12-6/test.c b/c/misra/test/rules/RULE-12-6/test.c index 2b1eeb7568..ae6125da96 100644 --- a/c/misra/test/rules/RULE-12-6/test.c +++ b/c/misra/test/rules/RULE-12-6/test.c @@ -1,7 +1,7 @@ #include "stdatomic.h" #include "string.h" -typedef struct s2 { +typedef struct s1 { int x; } s1; @@ -16,14 +16,16 @@ _Atomic int g3; void takeCopy(s1 p1); void f1() { - s1 *l1; + s1 l1; + s1 *l2; l1 = atomic_load(&atomic_s1); // COMPLIANT l1 = atomic_load(ptr_atomic_s1); // COMPLIANT - l1 = atomic_load(&s1_atomic_ptr); // COMPLIANT - l1->x = 4; // COMPLIANT + l2 = atomic_load(&s1_atomic_ptr); // COMPLIANT + l1.x = 4; // COMPLIANT + l2->x = 4; // COMPLIANT atomic_store(&atomic_s1, l1); // COMPLIANT atomic_store(ptr_atomic_s1, l1); // COMPLIANT - atomic_store(&s1_atomic_ptr, l1); // COMPLIANT + atomic_store(&s1_atomic_ptr, l2); // COMPLIANT // Undefined behavior, but not banned by this rule. memset(&atomic_s1, sizeof(atomic_s1), 0); // COMPLIANT @@ -34,8 +36,8 @@ void f1() { takeCopy(*ptr_atomic_s1); // COMPLIANT atomic_s1 = (s1){0}; // COMPLIANT *ptr_atomic_s1 = (s1){0}; // COMPLIANT - atomic_s1 = *l1; // COMPLIANT - ptr_atomic_s1 = l1; // COMPLIANT + atomic_s1 = *l2; // COMPLIANT + ptr_atomic_s1 = l2; // COMPLIANT // Banned: circumvents data-race protection, results in UB. atomic_s1.x; // NON-COMPLIANT @@ -54,6 +56,6 @@ void f1() { memset(s1_atomic_ptr, sizeof(*s1_atomic_ptr), 0); // COMPLIANT takeCopy(*s1_atomic_ptr); // COMPLIANT *s1_atomic_ptr = (s1){0}; // COMPLIANT - s1_atomic_ptr = l1; // COMPLIANT + s1_atomic_ptr = l2; // COMPLIANT s1_atomic_ptr->x; // COMPLIANT } \ No newline at end of file From 1ed65cf5cd38ccb9add67211d6e8bd26401ba375 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sat, 2 Nov 2024 09:35:42 -0700 Subject: [PATCH 081/628] Fix another stdlib affected test --- .../WrapFunctionsThatCanFailSpuriouslyInLoop.expected | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/c/cert/test/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.expected b/c/cert/test/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.expected index 0c1e25cd00..b1c224173e 100644 --- a/c/cert/test/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.expected +++ b/c/cert/test/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.expected @@ -1,4 +1,4 @@ -| test.c:6:8:6:46 | atomic_compare_exchange_weak(a,b,c) | Function that can spuriously fail not wrapped in a loop. | -| test.c:10:3:10:41 | atomic_compare_exchange_weak(a,b,c) | Function that can spuriously fail not wrapped in a loop. | -| test.c:12:8:13:47 | atomic_compare_exchange_weak_explicit(a,b,c,d,e) | Function that can spuriously fail not wrapped in a loop. | -| test.c:17:3:17:56 | atomic_compare_exchange_weak_explicit(a,b,c,d,e) | Function that can spuriously fail not wrapped in a loop. | +| test.c:6:8:6:46 | atomic_compare_exchange_weak(object,expected,desired) | Function that can spuriously fail not wrapped in a loop. | +| test.c:10:3:10:41 | atomic_compare_exchange_weak(object,expected,desired) | Function that can spuriously fail not wrapped in a loop. | +| test.c:12:8:12:44 | atomic_compare_exchange_weak_explicit | Function that can spuriously fail not wrapped in a loop. | +| test.c:17:3:17:39 | atomic_compare_exchange_weak_explicit | Function that can spuriously fail not wrapped in a loop. | From de24d43f7c5590528e026a6ea21f76d7a971a8a3 Mon Sep 17 00:00:00 2001 From: "rakesh.pothengil" Date: Mon, 11 Nov 2024 13:17:25 +0900 Subject: [PATCH 082/628] Fix #789 --- change_notes/2024-11-11-fix-fp-789.md | 2 ++ .../rules/A7-1-2/VariableMissingConstexpr.ql | 6 +++++ .../A7-1-2/VariableMissingConstexpr.expected | 5 ++-- cpp/autosar/test/rules/A7-1-2/test.cpp | 25 +++++++++++++------ cpp/common/src/codingstandards/cpp/Expr.qll | 4 ++- 5 files changed, 31 insertions(+), 11 deletions(-) create mode 100644 change_notes/2024-11-11-fix-fp-789.md diff --git a/change_notes/2024-11-11-fix-fp-789.md b/change_notes/2024-11-11-fix-fp-789.md new file mode 100644 index 0000000000..6ba34dbd7c --- /dev/null +++ b/change_notes/2024-11-11-fix-fp-789.md @@ -0,0 +1,2 @@ +- `A7-1-2` - `VariableMissingConstexpr.ql`: + - Fixes #789. Doesn't alert on non-static member variables and compiler generated variables of range based for-loops. diff --git a/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql b/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql index f0adab07d4..b051965a56 100644 --- a/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql +++ b/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql @@ -42,6 +42,12 @@ where not v.isConstexpr() and not v instanceof Parameter and not v.isAffectedByMacro() and + // Don't consider non-static member variables. + ( + not v instanceof MemberVariable + or + v.isStatic() + ) and isLiteralType(v.getType()) and // Unfortunately, `isConstant` is not sufficient here because it doesn't include calls to // constexpr constructors, and does not take into account zero initialization diff --git a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected index f86faf1a7b..ee33044a2d 100644 --- a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected +++ b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected @@ -7,9 +7,8 @@ | test.cpp:41:14:41:15 | l2 | Variable 'l2' could be marked 'constexpr'. | | test.cpp:44:16:44:17 | lc | Variable 'lc' could be marked 'constexpr'. | | test.cpp:45:17:45:19 | lc2 | Variable 'lc2' could be marked 'constexpr'. | -| test.cpp:55:7:55:8 | m2 | Variable 'm2' could be marked 'constexpr'. | -| test.cpp:130:7:130:8 | m1 | Variable 'm1' could be marked 'constexpr'. | -| test.cpp:141:7:141:8 | m1 | Variable 'm1' could be marked 'constexpr'. | +| test.cpp:55:20:55:21 | m2 | Variable 'm2' could be marked 'constexpr'. | +| test.cpp:143:5:143:20 | m1 | Variable 'm1' could be marked 'constexpr'. | | test.cpp:221:7:221:8 | l1 | Variable 'l1' could be marked 'constexpr'. | | test.cpp:235:7:235:8 | l6 | Variable 'l6' could be marked 'constexpr'. | | test.cpp:237:7:237:8 | l8 | Variable 'l8' could be marked 'constexpr'. | diff --git a/cpp/autosar/test/rules/A7-1-2/test.cpp b/cpp/autosar/test/rules/A7-1-2/test.cpp index 8395f60ff3..3b45516bc3 100644 --- a/cpp/autosar/test/rules/A7-1-2/test.cpp +++ b/cpp/autosar/test/rules/A7-1-2/test.cpp @@ -51,9 +51,9 @@ class MemberConstExpr { MemberConstExpr(int p3) : m3(p3) {} private: - int m1; // COMPLIANT - is not always zero initialized - int m2 = 0; // NON_COMPLIANT - int m3 = 0; // COMPLIANT - can be set by constructor + int m1; // COMPLIANT - is not always zero initialized + static const int m2 = 0; // NON_COMPLIANT + int m3 = 0; // COMPLIANT - can be set by constructor }; int h1(int x, int y) { // NON_COMPLIANT @@ -127,7 +127,7 @@ class MissingConstexprClass { MissingConstexprClass(int i) = delete; // NON_COMPLIANT MissingConstexprClass(int i, LiteralClass lc) {} // NON_COMPLIANT private: - int m1 = 0; + int m1 = 0; // COMPLIANT - non-static member variable }; class VirtualBaseClass {}; @@ -138,9 +138,9 @@ class DerivedClass : public virtual VirtualBaseClass { DerivedClass(int i) = delete; // COMPLIANT DerivedClass(int i, LiteralClass lc) {} // COMPLIANT private: - int m1 = 0; + static int m1; // NON_COMPLAINT - static member variable can be constexpr }; - +int DerivedClass::m1 = 0; class NotAllMembersInitializedClass { public: NotAllMembersInitializedClass() = default; // COMPLIANT @@ -274,4 +274,15 @@ template T *init() { return t; } -void test_template_instantiation() { int *t = init(); } \ No newline at end of file +void test_template_instantiation() { int *t = init(); } + +#include +#include +void a_function() { + auto origin = std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9}; + auto values = std::vector>{}; + for (auto &value : + origin) { // Sometimes, CodeQL reports "value" should be constexpr + values.emplace_back(std::make_unique(value)); + } +} diff --git a/cpp/common/src/codingstandards/cpp/Expr.qll b/cpp/common/src/codingstandards/cpp/Expr.qll index fe2877f849..90730b9718 100644 --- a/cpp/common/src/codingstandards/cpp/Expr.qll +++ b/cpp/common/src/codingstandards/cpp/Expr.qll @@ -267,7 +267,9 @@ predicate isCompileTimeEvaluatedCall(Call call) { parameterUsingDefaultValue.getAnAssignedValue() = defaultValue | isDirectCompileTimeEvaluatedExpression(defaultValue) - ) + ) and + // 4. the call's qualifier is compile time evaluated. + (not call.hasQualifier() or isCompileTimeEvaluatedExpression(call.getQualifier())) } /* From 9aa4c38e4a54856234e9dc1d2c5297a0cbba1125 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 16:39:26 +0000 Subject: [PATCH 083/628] Bump actions/github-script from 3 to 7 Bumps [actions/github-script](https://github.com/actions/github-script) from 3 to 7. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v3...v7) --- updated-dependencies: - dependency-name: actions/github-script dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql_unit_tests.yml | 2 +- .github/workflows/dispatch-matrix-test-on-comment.yml | 2 +- .github/workflows/dispatch-release-performance-check.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/codeql_unit_tests.yml b/.github/workflows/codeql_unit_tests.yml index 2c771b4575..2fc28fc900 100644 --- a/.github/workflows/codeql_unit_tests.yml +++ b/.github/workflows/codeql_unit_tests.yml @@ -166,7 +166,7 @@ jobs: steps: - name: Check if run-test-suites job failed to complete, if so fail if: ${{ needs.run-test-suites.result == 'failure' }} - uses: actions/github-script@v3 + uses: actions/github-script@v7 with: script: | core.setFailed('Test run job failed') diff --git a/.github/workflows/dispatch-matrix-test-on-comment.yml b/.github/workflows/dispatch-matrix-test-on-comment.yml index 297b6fbc7e..964fb7e9f3 100644 --- a/.github/workflows/dispatch-matrix-test-on-comment.yml +++ b/.github/workflows/dispatch-matrix-test-on-comment.yml @@ -40,7 +40,7 @@ jobs: --json \ -R github/codeql-coding-standards-release-engineering - - uses: actions/github-script@v6 + - uses: actions/github-script@v7 if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/test-matrix') && steps.check-write-permission.outputs.has-permission }} with: script: | diff --git a/.github/workflows/dispatch-release-performance-check.yml b/.github/workflows/dispatch-release-performance-check.yml index 260846185a..a8df297f7d 100644 --- a/.github/workflows/dispatch-release-performance-check.yml +++ b/.github/workflows/dispatch-release-performance-check.yml @@ -40,7 +40,7 @@ jobs: --json \ -R github/codeql-coding-standards-release-engineering - - uses: actions/github-script@v6 + - uses: actions/github-script@v7 if: ${{ github.event.issue.pull_request && contains(github.event.comment.body, '/test-performance') && steps.check-write-permission.outputs.has-permission }} with: script: | From 73c075d2bc1b745a00efa5b1a4cbc5e8ede13b74 Mon Sep 17 00:00:00 2001 From: "rakesh.pothengil" Date: Wed, 13 Nov 2024 14:36:39 +0900 Subject: [PATCH 084/628] Fix #796 --- change_notes/2024-11-13-fix-fp-796.md | 2 ++ ...onThatContainsForwardingReferenceAsItsArgumentOverloaded.ql | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 change_notes/2024-11-13-fix-fp-796.md diff --git a/change_notes/2024-11-13-fix-fp-796.md b/change_notes/2024-11-13-fix-fp-796.md new file mode 100644 index 0000000000..5fa32f57e8 --- /dev/null +++ b/change_notes/2024-11-13-fix-fp-796.md @@ -0,0 +1,2 @@ + - `A13-3-1` - `FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql`: + - Reduce false positives by explicitly checking that the locations of overloaded functions are different. diff --git a/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql b/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql index 81ca7039c3..e3fb59bd8a 100644 --- a/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql +++ b/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql @@ -29,6 +29,9 @@ where OperatorsPackage::functionThatContainsForwardingReferenceAsItsArgumentOverloadedQuery()) and not f.isDeleted() and f = c.getAnOverload() and + // CodeQL sometimes fetches an overloaded function at the same location. + // Thus, a check is added explicitly (refer #796). + f.getLocation() != c.getLocation() and // allow for overloading with different number of parameters, because there is no // confusion on what function will be called. f.getNumberOfParameters() = c.getNumberOfParameters() and From b1c76190f42c28f51edceadb944b83c3daa7a28c Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 14 Nov 2024 20:56:51 -0800 Subject: [PATCH 085/628] Fix broken test --- .../RULE-1-5/UngetcCallOnStreamPositionZero.expected | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected index 98e7b34fbe..ff25a58e3c 100644 --- a/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected +++ b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected @@ -1,8 +1,8 @@ edges -| test.c:39:16:39:20 | call to fopen indirection | test.c:41:15:41:18 | file indirection | +| test.c:39:16:39:20 | *call to fopen | test.c:41:15:41:18 | *file | provenance | | nodes -| test.c:39:16:39:20 | call to fopen indirection | semmle.label | call to fopen indirection | -| test.c:41:15:41:18 | file indirection | semmle.label | file indirection | +| test.c:39:16:39:20 | *call to fopen | semmle.label | *call to fopen | +| test.c:41:15:41:18 | *file | semmle.label | *file | subpaths #select -| test.c:41:15:41:18 | file indirection | test.c:39:16:39:20 | call to fopen indirection | test.c:41:15:41:18 | file indirection | Obsolescent call to ungetc on file stream $@ at position zero. | test.c:39:16:39:20 | call to fopen indirection | call to fopen indirection | +| test.c:41:15:41:18 | *file | test.c:39:16:39:20 | *call to fopen | test.c:41:15:41:18 | *file | Obsolescent call to ungetc on file stream $@ at position zero. | test.c:39:16:39:20 | *call to fopen | *call to fopen | From bed2b88b76964c690aa327b73e08671e1d1bc0b4 Mon Sep 17 00:00:00 2001 From: Fernando Jose Date: Mon, 18 Nov 2024 08:30:26 +0900 Subject: [PATCH 086/628] review: add test cases. --- ...oopCounterModifiedWithinStatement.expected | 1 + cpp/autosar/test/rules/M6-5-3/test.cpp | 57 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/cpp/autosar/test/rules/M6-5-3/LoopCounterModifiedWithinStatement.expected b/cpp/autosar/test/rules/M6-5-3/LoopCounterModifiedWithinStatement.expected index a6988586f0..a8fc2afff6 100644 --- a/cpp/autosar/test/rules/M6-5-3/LoopCounterModifiedWithinStatement.expected +++ b/cpp/autosar/test/rules/M6-5-3/LoopCounterModifiedWithinStatement.expected @@ -2,3 +2,4 @@ | test.cpp:25:35:25:35 | x | Loop counters should not be modified within a statement in a for loop. | | test.cpp:36:5:36:5 | x | Loop counters should not be modified within a statement in a for loop. | | test.cpp:43:9:43:9 | i | Loop counters should not be modified within a statement in a for loop. | +| test.cpp:99:15:99:15 | i | Loop counters should not be modified within a statement in a for loop. | diff --git a/cpp/autosar/test/rules/M6-5-3/test.cpp b/cpp/autosar/test/rules/M6-5-3/test.cpp index a534e6ba8e..d60980588b 100644 --- a/cpp/autosar/test/rules/M6-5-3/test.cpp +++ b/cpp/autosar/test/rules/M6-5-3/test.cpp @@ -43,3 +43,60 @@ void test_loop_counter_mod_in_side_effect() { inc(i); // NON_COMPLIANT - modifies `i` } } + +void test_loop_counter_reference_mod_in_condition() { + auto loop = [](int& i){ + for (; (i++ < 10); i++) { // NON_COMPLIANT + } + }; + int i = 0; + loop(i); +} + +void test_loop_counter_reference_mod() { + auto loop = [](int& i){ + for (; i < 10; i++) { // COMPLIANT + } + }; + int i = 0; + loop(i); +} + +void test_loop_const_reference() { + auto loop = []([[maybe_unused]] int const& i){ + for (int i = 0; i < 10; i++) { // COMPLIANT + } + }; + int i = 0; + loop(i); +} + +void test_loop_counter_reference_mod_in_statement() { + auto loop = [](int& i){ + for (; (i < 10); i++) { + i++; // NON_COMPLIANT + } + }; + int i = 0; + loop(i); +} + +int const_reference(int const& i) { + return i; +} + +int reference(int& i) { + return i; +} + +int copy(int i) { + return i; +} + +void test_pass_argument_by() { + for (int i = 0; i < 10; i++) { + const_reference(i); // COMPLIANT + reference(i); // NON_COMPLIANT + copy(i); // COMPLIANT + } +} From dac5019b346f902eeef2a0889e7dbde3b523b647 Mon Sep 17 00:00:00 2001 From: Fernando Jose Date: Mon, 18 Nov 2024 08:48:15 +0900 Subject: [PATCH 087/628] Format test case. --- cpp/autosar/test/rules/M6-5-3/test.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/cpp/autosar/test/rules/M6-5-3/test.cpp b/cpp/autosar/test/rules/M6-5-3/test.cpp index d60980588b..a41ba8a22d 100644 --- a/cpp/autosar/test/rules/M6-5-3/test.cpp +++ b/cpp/autosar/test/rules/M6-5-3/test.cpp @@ -45,7 +45,7 @@ void test_loop_counter_mod_in_side_effect() { } void test_loop_counter_reference_mod_in_condition() { - auto loop = [](int& i){ + auto loop = [](int &i) { for (; (i++ < 10); i++) { // NON_COMPLIANT } }; @@ -54,7 +54,7 @@ void test_loop_counter_reference_mod_in_condition() { } void test_loop_counter_reference_mod() { - auto loop = [](int& i){ + auto loop = [](int &i) { for (; i < 10; i++) { // COMPLIANT } }; @@ -63,7 +63,7 @@ void test_loop_counter_reference_mod() { } void test_loop_const_reference() { - auto loop = []([[maybe_unused]] int const& i){ + auto loop = []([[maybe_unused]] int const &i) { for (int i = 0; i < 10; i++) { // COMPLIANT } }; @@ -72,7 +72,7 @@ void test_loop_const_reference() { } void test_loop_counter_reference_mod_in_statement() { - auto loop = [](int& i){ + auto loop = [](int &i) { for (; (i < 10); i++) { i++; // NON_COMPLIANT } @@ -81,17 +81,11 @@ void test_loop_counter_reference_mod_in_statement() { loop(i); } -int const_reference(int const& i) { - return i; -} +int const_reference(int const &i) { return i; } -int reference(int& i) { - return i; -} +int reference(int &i) { return i; } -int copy(int i) { - return i; -} +int copy(int i) { return i; } void test_pass_argument_by() { for (int i = 0; i < 10; i++) { From 916388130da293b0831348dcfe04d3fc6e52c18d Mon Sep 17 00:00:00 2001 From: Fernando Jose Date: Mon, 18 Nov 2024 10:46:53 +0900 Subject: [PATCH 088/628] Update test case expected's line number after previous format. --- .../rules/M6-5-3/LoopCounterModifiedWithinStatement.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/autosar/test/rules/M6-5-3/LoopCounterModifiedWithinStatement.expected b/cpp/autosar/test/rules/M6-5-3/LoopCounterModifiedWithinStatement.expected index a8fc2afff6..4643298e3a 100644 --- a/cpp/autosar/test/rules/M6-5-3/LoopCounterModifiedWithinStatement.expected +++ b/cpp/autosar/test/rules/M6-5-3/LoopCounterModifiedWithinStatement.expected @@ -2,4 +2,4 @@ | test.cpp:25:35:25:35 | x | Loop counters should not be modified within a statement in a for loop. | | test.cpp:36:5:36:5 | x | Loop counters should not be modified within a statement in a for loop. | | test.cpp:43:9:43:9 | i | Loop counters should not be modified within a statement in a for loop. | -| test.cpp:99:15:99:15 | i | Loop counters should not be modified within a statement in a for loop. | +| test.cpp:93:15:93:15 | i | Loop counters should not be modified within a statement in a for loop. | From 0683d4c67a47fd17732673bf6475ac406ed47b99 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 17 Nov 2024 19:12:24 -0800 Subject: [PATCH 089/628] Address feedback. --- ...RedeclarationOfObjectWithUnmatchedAlignment.ql | 15 ++------------- .../RedeclarationOfObjectWithoutAlignment.ql | 7 +++---- .../MoreThanOneAlignmentSpecifierOnDeclaration.ql | 5 ++++- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql index b17c1ef6c1..2969c0ea06 100644 --- a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql +++ b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql @@ -15,21 +15,10 @@ import cpp import codingstandards.c.misra - -predicate lexicallyEqualExpr(Expr a, Expr b) { - a.toString() = b.toString() and - a.getNumChild() = b.getNumChild() and - forall(Expr aChild, Expr bChild, int i | - aChild = a.getChild(i) and - bChild = b.getChild(i) and - i < a.getNumChild() - | - lexicallyEqualExpr(aChild, bChild) - ) -} +import semmle.code.cpp.valuenumbering.HashCons predicate lexicallyEqual(AttributeArgument a, AttributeArgument b) { - lexicallyEqualExpr(a.getValueConstant(), b.getValueConstant()) or + hashCons(a.getValueConstant()) = hashCons(b.getValueConstant()) or a.getValueType() = b.getValueType() } diff --git a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql index 986ab92f5a..3088708de0 100644 --- a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql +++ b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql @@ -46,10 +46,9 @@ newtype TAttributeDeclLocation = * This should give us a highly reliable means of finding which attributes are * associated with which `DeclarationEntry`s. * - * One note of caution: the associated `Variable` must be treated with caution, - * as there are multiple instances of that `Variable` if it is declared - * multiple times, they equal each other, and `getLocation()` on each variable - * returns every location result. This class must act on `DeclarationEntry`s to + * One note of caution: the location of the associated `Variable` must be + * treated with caution, as calls to `getLocation()` on a redeclared `Variable` + * can return multiple results. This class must act on `DeclarationEntry`s to * deliver reliable results. */ class DeclarationEntryAttribute extends Attribute { diff --git a/c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql b/c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql index 3c89a190ec..f4e0d93d92 100644 --- a/c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql +++ b/c/misra/src/rules/RULE-8-17/MoreThanOneAlignmentSpecifierOnDeclaration.ql @@ -20,9 +20,12 @@ where not isExcluded(v, AlignmentPackage::moreThanOneAlignmentSpecifierOnDeclarationQuery()) and first = v.getAnAttribute() and last = v.getAnAttribute() and - first != last and + not first = last and first.hasName("_Alignas") and last.hasName("_Alignas") and + // Handle double reporting: the first Attribute should really be first, and the last Attribute + // should really be last. This implies the first is before the last. This approach also ensures + // a single result for variables that have more than two alignment specifiers. not exists(Attribute beforeFirst | beforeFirst.getLocation().isBefore(first.getLocation(), _) and v.getAnAttribute() = beforeFirst From d584e309b212ad29e05e74a4a0760fb567ed92e7 Mon Sep 17 00:00:00 2001 From: "rakesh.pothengil" Date: Mon, 18 Nov 2024 13:12:44 +0900 Subject: [PATCH 090/628] Consider feedback on #789 --- .../rules/A7-1-2/VariableMissingConstexpr.ql | 17 ++++++++++---- .../A7-1-2/VariableMissingConstexpr.expected | 5 ++-- cpp/autosar/test/rules/A7-1-2/test.cpp | 23 +++++-------------- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql b/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql index b051965a56..a07dbd43f7 100644 --- a/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql +++ b/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql @@ -35,18 +35,24 @@ predicate isTypeZeroInitializable(Type t) { t.getUnderlyingType() instanceof ArrayType } -from Variable v +from Variable v, string msg where not isExcluded(v, ConstPackage::variableMissingConstexprQuery()) and v.hasDefinition() and not v.isConstexpr() and not v instanceof Parameter and not v.isAffectedByMacro() and - // Don't consider non-static member variables. ( not v instanceof MemberVariable or - v.isStatic() + // In case member functions are left un-instantiated, it is possible + // the member variable could be modified in them. + // Hence, don't raise an alert in case this member variable's class + // has a member function that doesn't have a definition. + not exists(MemberFunction mf | + mf.getDeclaringType() = v.getDeclaringType() and + mf.isFromUninstantiatedTemplate(_) + ) ) and isLiteralType(v.getType()) and // Unfortunately, `isConstant` is not sufficient here because it doesn't include calls to @@ -72,5 +78,6 @@ where // Exclude variables in uninstantiated templates, as they may be incomplete not v.isFromUninstantiatedTemplate(_) and // Exclude compiler generated variables, which are not user controllable - not v.isCompilerGenerated() -select v, "Variable '" + v.getName() + "' could be marked 'constexpr'." + not v.isCompilerGenerated() and + if v instanceof MemberVariable and not v.isStatic() then msg = " and static." else msg = "." +select v, "Variable '" + v.getName() + "' could be marked 'constexpr'" + msg diff --git a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected index ee33044a2d..31c26a11ff 100644 --- a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected +++ b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected @@ -7,8 +7,9 @@ | test.cpp:41:14:41:15 | l2 | Variable 'l2' could be marked 'constexpr'. | | test.cpp:44:16:44:17 | lc | Variable 'lc' could be marked 'constexpr'. | | test.cpp:45:17:45:19 | lc2 | Variable 'lc2' could be marked 'constexpr'. | -| test.cpp:55:20:55:21 | m2 | Variable 'm2' could be marked 'constexpr'. | -| test.cpp:143:5:143:20 | m1 | Variable 'm1' could be marked 'constexpr'. | +| test.cpp:55:7:55:8 | m2 | Variable 'm2' could be marked 'constexpr' and static. | +| test.cpp:130:7:130:8 | m1 | Variable 'm1' could be marked 'constexpr' and static. | +| test.cpp:141:7:141:8 | m1 | Variable 'm1' could be marked 'constexpr' and static. | | test.cpp:221:7:221:8 | l1 | Variable 'l1' could be marked 'constexpr'. | | test.cpp:235:7:235:8 | l6 | Variable 'l6' could be marked 'constexpr'. | | test.cpp:237:7:237:8 | l8 | Variable 'l8' could be marked 'constexpr'. | diff --git a/cpp/autosar/test/rules/A7-1-2/test.cpp b/cpp/autosar/test/rules/A7-1-2/test.cpp index 3b45516bc3..1bbe32a933 100644 --- a/cpp/autosar/test/rules/A7-1-2/test.cpp +++ b/cpp/autosar/test/rules/A7-1-2/test.cpp @@ -51,9 +51,9 @@ class MemberConstExpr { MemberConstExpr(int p3) : m3(p3) {} private: - int m1; // COMPLIANT - is not always zero initialized - static const int m2 = 0; // NON_COMPLIANT - int m3 = 0; // COMPLIANT - can be set by constructor + int m1; // COMPLIANT - is not always zero initialized + int m2 = 0; // NON_COMPLIANT + int m3 = 0; // COMPLIANT - can be set by constructor }; int h1(int x, int y) { // NON_COMPLIANT @@ -127,7 +127,7 @@ class MissingConstexprClass { MissingConstexprClass(int i) = delete; // NON_COMPLIANT MissingConstexprClass(int i, LiteralClass lc) {} // NON_COMPLIANT private: - int m1 = 0; // COMPLIANT - non-static member variable + int m1 = 0; }; class VirtualBaseClass {}; @@ -138,9 +138,9 @@ class DerivedClass : public virtual VirtualBaseClass { DerivedClass(int i) = delete; // COMPLIANT DerivedClass(int i, LiteralClass lc) {} // COMPLIANT private: - static int m1; // NON_COMPLAINT - static member variable can be constexpr + int m1 = 0; }; -int DerivedClass::m1 = 0; + class NotAllMembersInitializedClass { public: NotAllMembersInitializedClass() = default; // COMPLIANT @@ -275,14 +275,3 @@ template T *init() { } void test_template_instantiation() { int *t = init(); } - -#include -#include -void a_function() { - auto origin = std::vector{1, 2, 3, 4, 5, 6, 7, 8, 9}; - auto values = std::vector>{}; - for (auto &value : - origin) { // Sometimes, CodeQL reports "value" should be constexpr - values.emplace_back(std::make_unique(value)); - } -} From e736cb0dd3c50a7648b89c66f7a2b6f2ad52b468 Mon Sep 17 00:00:00 2001 From: "rakesh.pothengil" Date: Mon, 18 Nov 2024 13:18:14 +0900 Subject: [PATCH 091/628] Update change notes --- change_notes/2024-11-11-fix-fp-789.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/change_notes/2024-11-11-fix-fp-789.md b/change_notes/2024-11-11-fix-fp-789.md index 6ba34dbd7c..b06ebb9b11 100644 --- a/change_notes/2024-11-11-fix-fp-789.md +++ b/change_notes/2024-11-11-fix-fp-789.md @@ -1,2 +1,3 @@ - `A7-1-2` - `VariableMissingConstexpr.ql`: - - Fixes #789. Doesn't alert on non-static member variables and compiler generated variables of range based for-loops. + - Do not report on member variables if the class has un-instantiated member function(s). + - Check a call's qualifier as well whether it can be compile time evaluated or not. From 06ba26dca5afee4bd7a708ea2e0ab01e36f26007 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 17 Nov 2024 22:03:28 -0800 Subject: [PATCH 092/628] Address feedback --- ...ointersToVariablyModifiedArrayTypesUsed.ql | 79 +---------------- .../RULE-18-8/VariableLengthArrayTypesUsed.ql | 6 +- ...rayToPointerConversionOfTemporaryObject.ql | 28 ++---- .../cpp/VariablyModifiedTypes.qll | 85 +++++++++++++++++-- .../cpp/lifetimes/CLifetimes.qll | 2 +- 5 files changed, 92 insertions(+), 108 deletions(-) diff --git a/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql b/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql index fec8f5d2e1..6ca2289c67 100644 --- a/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql +++ b/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql @@ -18,84 +18,11 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.VariablyModifiedTypes -/** - * Check that the declaration entry, which may be a parameter or a variable - * etc., seems to subsume the location of `inner`, including the declaration - * type text. - * - * The location of the `DeclarationEntry` itself points to the _identifier_ - * that is declared. This range will not include the type of the declaration. - * - * For parameters, the `before` and `end` `Location` objects will be - * constrained to the closest earlier element (parameter or function body), - * these values can therefore be captured and inspected for debugging. - * - * For declarations which occur in statements, the `before` and `end` - * `Location` objects will be both constrained to be equal, and equal to, - * the `Location` of the containing `DeclStmt`. - */ -predicate declarationSubsumes( - DeclarationEntry entry, Location inner, Location before, Location after -) { - inner.getFile() = entry.getLocation().getFile() and - ( - exists(ParameterDeclarationEntry param, FunctionDeclarationEntry func, int i | - param = entry and - func = param.getFunctionDeclarationEntry() and - func.getParameterDeclarationEntry(i) = param and - before = entry.getLocation() and - ( - after = func.getParameterDeclarationEntry(i + 1).getLocation() - or - not exists(ParameterDeclarationEntry afterParam | - afterParam = func.getParameterDeclarationEntry(i + 1) - ) and - after = func.getBlock().getLocation() - ) - ) and - before.isBefore(inner, _) and - inner.isBefore(after, _) - or - exists(DeclStmt s | - s.getADeclaration() = entry.getDeclaration() and - before = s.getLocation() and - after = before and - before.subsumes(inner) - ) - ) -} - -/** - * A declaration involving a pointer to a variably-modified type. - */ -class InvalidDeclaration extends DeclarationEntry { - Expr sizeExpr; - CandidateVlaType vlaType; - // `before` and `after` are captured for debugging, see doc comment for - // `declarationSubsumes`. - Location before; - Location after; - - InvalidDeclaration() { - sizeExpr = any(VlaDimensionStmt vla).getDimensionExpr() and - declarationSubsumes(this, sizeExpr.getLocation(), before, after) and - ( - if this instanceof ParameterDeclarationEntry - then vlaType = this.getType().(VariablyModifiedTypeIfAdjusted).getInnerVlaType() - else vlaType = this.getType().(VariablyModifiedTypeIfUnadjusted).getInnerVlaType() - ) and - // Capture only pointers to VLA types, not raw VLA types. - not vlaType = this.getType() - } - - Expr getSizeExpr() { result = sizeExpr } - - CandidateVlaType getVlaType() { result = vlaType } -} - -from InvalidDeclaration v, string declstr, string adjuststr, string relationstr +from VmtDeclarationEntry v, string declstr, string adjuststr, string relationstr where not isExcluded(v, InvalidMemory3Package::pointersToVariablyModifiedArrayTypesUsedQuery()) and + // Capture only pointers to VLA types, not raw VLA types. + not v.getVlaType() = v.getType() and ( if v instanceof ParameterDeclarationEntry then declstr = "Parameter " diff --git a/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql b/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql index 96fbf697af..8e599f39f7 100644 --- a/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql +++ b/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql @@ -20,9 +20,11 @@ where not isExcluded(v, Declarations7Package::variableLengthArrayTypesUsedQuery()) and size = v.getVlaDimensionStmt(0).getDimensionExpr() and ( - arrayType = v.getVariable().getType() + // Holds is if v is a variable declaration: + arrayType = v.getVariable().getType().stripTopLevelSpecifiers() or - arrayType = v.getType().getUnspecifiedType() + // Holds is if v is a typedef declaration: + arrayType = v.getType().stripTopLevelSpecifiers() ) and typeStr = arrayType.getBaseType().toString() select v, "Variable length array of element type '" + typeStr + "' with non-constant size $@.", diff --git a/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql b/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql index 7df4e5371c..a64ccd44ff 100644 --- a/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql +++ b/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql @@ -18,32 +18,20 @@ import codingstandards.c.misra import codingstandards.cpp.lifetimes.CLifetimes /** - * Get the expression(s) whose value is "used" by this expression. + * Holds if the value of an expression is used or stored. * * For instance, `(x)` does not use any values, but `x + y` uses `x` and `y`. * * A pointer-to-array conversion does not need to be flagged if the result of * that conversion is not used or stored. */ -Expr usedValuesOf(Expr expr) { - result = expr.(BinaryOperation).getLeftOperand() +predicate isUsedOrStored(Expr e) { + e = any(Operation o).getAnOperand() or - result = expr.(BinaryOperation).getRightOperand() + e = any(ConditionalExpr c).getCondition() or - result = expr.(UnaryOperation).getOperand() + e = any(Call c).getAnArgument() or - result = expr.(ConditionalExpr).getCondition() - or - result = expr.(Call).getAnArgument() -} - -/** - * Get the expression(s) whose value is stored by this declaration. - * - * A pointer-to-array conversion does not need to be flagged if the result of - * that conversion is not used or stored. - */ -predicate isStored(Expr e) { e = any(VariableDeclarationEntry d).getDeclaration().getInitializer().getExpr() or e = any(ClassAggregateLiteral l).getAFieldExpr(_) @@ -77,10 +65,6 @@ where not isExcluded(conversion, InvalidMemory3Package::arrayToPointerConversionOfTemporaryObjectQuery()) and fa.getTemporary() = temporary and conversion.getExpr() = fa and - ( - temporaryObjectFlowStep*(conversion.getExpr()) = usedValuesOf(any(Expr e)) - or - isStored(temporaryObjectFlowStep*(conversion.getExpr())) - ) + isUsedOrStored(temporaryObjectFlowStep*(conversion.getExpr())) select conversion, "Array to pointer conversion of array $@ from temporary object $@", fa.getTarget(), fa.getTarget().getName(), temporary, temporary.toString() diff --git a/cpp/common/src/codingstandards/cpp/VariablyModifiedTypes.qll b/cpp/common/src/codingstandards/cpp/VariablyModifiedTypes.qll index 730a52d763..c0fb3a3db6 100644 --- a/cpp/common/src/codingstandards/cpp/VariablyModifiedTypes.qll +++ b/cpp/common/src/codingstandards/cpp/VariablyModifiedTypes.qll @@ -1,5 +1,82 @@ import cpp +/** + * A declaration involving a variably-modified type. + */ +class VmtDeclarationEntry extends DeclarationEntry { + Expr sizeExpr; + CandidateVlaType vlaType; + // `before` and `after` are captured for debugging, see doc comment for + // `declarationSubsumes`. + Location before; + Location after; + + VmtDeclarationEntry() { + // Most of this library looks for candidate VLA types, by looking for arrays + // without a size. These may or may not be VLA types. To confirm an a + // candidate type is really a VLA type, we check that the location of the + // declaration subsumes a `VlaDimensionStmt` which indicates a real VLA. + sizeExpr = any(VlaDimensionStmt vla).getDimensionExpr() and + declarationSubsumes(this, sizeExpr.getLocation(), before, after) and + ( + if this instanceof ParameterDeclarationEntry + then vlaType = this.getType().(VariablyModifiedTypeIfAdjusted).getInnerVlaType() + else vlaType = this.getType().(VariablyModifiedTypeIfUnadjusted).getInnerVlaType() + ) + } + + Expr getSizeExpr() { result = sizeExpr } + + CandidateVlaType getVlaType() { result = vlaType } +} + +/** + * Check that the declaration entry, which may be a parameter or a variable + * etc., seems to subsume the location of `inner`, including the declaration + * type text. + * + * The location of the `DeclarationEntry` itself points to the _identifier_ + * that is declared. This range will not include the type of the declaration. + * + * For parameters, the `before` and `end` `Location` objects will be + * constrained to the closest earlier element (parameter or function body), + * these values can therefore be captured and inspected for debugging. + * + * For declarations which occur in statements, the `before` and `end` + * `Location` objects will be both constrained to be equal, and equal to, + * the `Location` of the containing `DeclStmt`. + */ +private predicate declarationSubsumes( + DeclarationEntry entry, Location inner, Location before, Location after +) { + inner.getFile() = entry.getLocation().getFile() and + ( + exists(ParameterDeclarationEntry param, FunctionDeclarationEntry func, int i | + param = entry and + func = param.getFunctionDeclarationEntry() and + func.getParameterDeclarationEntry(i) = param and + before = entry.getLocation() and + ( + after = func.getParameterDeclarationEntry(i + 1).getLocation() + or + not exists(ParameterDeclarationEntry afterParam | + afterParam = func.getParameterDeclarationEntry(i + 1) + ) and + after = func.getBlock().getLocation() + ) + ) and + before.isBefore(inner, _) and + inner.isBefore(after, _) + or + exists(DeclStmt s | + s.getADeclaration() = entry.getDeclaration() and + before = s.getLocation() and + after = before and + before.subsumes(inner) + ) + ) +} + /** * A candidate to be a variably length array type (VLA). * @@ -90,19 +167,13 @@ class NoAdjustmentVariablyModifiedType extends Type { NoAdjustmentVariablyModifiedType() { exists(Type innerType | ( - innerType = this.(PointerType).getBaseType() - or - innerType = this.(ArrayType).getBaseType() + innerType = this.(DerivedType).getBaseType() or innerType = this.(RoutineType).getReturnType() or - innerType = this.(RoutineType).getAParameterType() - or innerType = this.(FunctionPointerType).getReturnType() or innerType = this.(TypedefType).getBaseType() - or - innerType = this.(SpecifiedType).getBaseType() ) and vlaType = innerType.(VariablyModifiedTypeIfUnadjusted).getInnerVlaType() ) diff --git a/cpp/common/src/codingstandards/cpp/lifetimes/CLifetimes.qll b/cpp/common/src/codingstandards/cpp/lifetimes/CLifetimes.qll index d27034f50d..9282260fb9 100644 --- a/cpp/common/src/codingstandards/cpp/lifetimes/CLifetimes.qll +++ b/cpp/common/src/codingstandards/cpp/lifetimes/CLifetimes.qll @@ -25,7 +25,7 @@ class TemporaryLifetimeExpr extends Expr { getUnconverted().getUnspecifiedType() instanceof StructOrUnionTypeWithArrayField and not isCLValue(this) or - this.(ArrayExpr).getArrayBase() instanceof TemporaryLifetimeArrayAccess + this.getUnconverted().(ArrayExpr).getArrayBase() instanceof TemporaryLifetimeArrayAccess } } From 0ec29359aaf921e5bc6c9af3b41327106f32542e Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 17 Nov 2024 22:05:43 -0800 Subject: [PATCH 093/628] fix format --- .../RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql index 2969c0ea06..878bfeeeaf 100644 --- a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql +++ b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql @@ -18,7 +18,7 @@ import codingstandards.c.misra import semmle.code.cpp.valuenumbering.HashCons predicate lexicallyEqual(AttributeArgument a, AttributeArgument b) { - hashCons(a.getValueConstant()) = hashCons(b.getValueConstant()) or + hashCons(a.getValueConstant()) = hashCons(b.getValueConstant()) or a.getValueType() = b.getValueType() } From 9ff699b63c073f5be42b6007864e605a01bc9dc1 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 17 Nov 2024 16:58:14 -0800 Subject: [PATCH 094/628] Implement Concurrency7 package --- .../includes/standard-library/stdatomic.h | 1 + .../TimedlockOnInappropriateMutexType.ql | 74 +++++++++++++++++++ .../RULE-9-7/UninitializedAtomicObject.ql | 73 ++++++++++++++++++ ...TimedlockOnInappropriateMutexType.expected | 45 +++++++++++ .../TimedlockOnInappropriateMutexType.qlref | 1 + c/misra/test/rules/RULE-21-26/test.c | 45 +++++++++++ .../UninitializedAtomicObject.expected | 3 + .../RULE-9-7/UninitializedAtomicObject.qlref | 1 + c/misra/test/rules/RULE-9-7/test.c | 34 +++++++++ .../cpp/exclusions/c/Concurrency7.qll | 44 +++++++++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + rule_packages/c/Concurrency7.json | 45 +++++++++++ rules.csv | 4 +- 13 files changed, 371 insertions(+), 2 deletions(-) create mode 100644 c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql create mode 100644 c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql create mode 100644 c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.expected create mode 100644 c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.qlref create mode 100644 c/misra/test/rules/RULE-21-26/test.c create mode 100644 c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.expected create mode 100644 c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.qlref create mode 100644 c/misra/test/rules/RULE-9-7/test.c create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency7.qll create mode 100644 rule_packages/c/Concurrency7.json diff --git a/c/common/test/includes/standard-library/stdatomic.h b/c/common/test/includes/standard-library/stdatomic.h index 66b74ae61a..229b8db906 100644 --- a/c/common/test/includes/standard-library/stdatomic.h +++ b/c/common/test/includes/standard-library/stdatomic.h @@ -5,5 +5,6 @@ #define atomic_store(a, b) 0 #define atomic_store_explicit(a, b, c) 0 #define ATOMIC_VAR_INIT(value) (value) +#define atomic_init __c11_atomic_init #define atomic_is_lock_free(obj) __c11_atomic_is_lock_free(sizeof(*(obj))) typedef _Atomic(int) atomic_int; \ No newline at end of file diff --git a/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql b/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql new file mode 100644 index 0000000000..d8d465045e --- /dev/null +++ b/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql @@ -0,0 +1,74 @@ +/** + * @id c/misra/timedlock-on-inappropriate-mutex-type + * @name RULE-21-26: The Standard Library function mtx_timedlock() shall only be invoked on mutexes of type mtx_timed + * @description The Standard Library function mtx_timedlock() shall only be invoked on mutex objects + * of appropriate mutex type + * @kind path-problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-21-26 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import semmle.code.cpp.dataflow.new.DataFlow + +class MutexTimed extends EnumConstant { + MutexTimed() { hasName("mtx_timed") } +} + +class MutexInitCall extends FunctionCall { + Expr mutexExpr; + Expr mutexTypeExpr; + + MutexInitCall() { + getTarget().hasName("mtx_init") and + mutexExpr = getArgument(0) and + mutexTypeExpr = getArgument(1) + } + + predicate isTimedMutexType() { + exists(EnumConstantAccess baseTypeAccess | + ( + baseTypeAccess = mutexTypeExpr + or + baseTypeAccess = mutexTypeExpr.(BinaryBitwiseOperation).getAnOperand() + ) and + baseTypeAccess.getTarget() instanceof MutexTimed + ) + or + mutexTypeExpr.getValue().toInt() = any(MutexTimed m).getValue().toInt() + } + + Expr getMutexExpr() { result = mutexExpr } +} + +module MutexTimedlockFlowConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { + exists(MutexInitCall init | + node.asDefiningArgument() = init.getMutexExpr() and not init.isTimedMutexType() + ) + } + + predicate isSink(DataFlow::Node node) { + exists(FunctionCall fc | + fc.getTarget().hasName("mtx_timedlock") and + node.asIndirectExpr() = fc.getArgument(0) + ) + } +} + +module Flow = DataFlow::Global; + +import Flow::PathGraph + +from Flow::PathNode source, Flow::PathNode sink +where + not isExcluded(sink.getNode().asExpr(), + Concurrency7Package::timedlockOnInappropriateMutexTypeQuery()) and + Flow::flowPath(source, sink) +select sink.getNode(), source, sink, "Call to mtx_timedlock with mutex not of type 'mtx_timed'." diff --git a/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql b/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql new file mode 100644 index 0000000000..40f833a740 --- /dev/null +++ b/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql @@ -0,0 +1,73 @@ +/** + * @id c/misra/uninitialized-atomic-object + * @name RULE-9-7: Atomic objects shall be appropriately initialized before being accessed + * @description Atomic objects that do not have static storage duration shall be initialized with a + * value or by using 'atomic_init()'. + * @kind problem + * @precision high + * @problem.severity warning + * @tags external/misra/id/rule-9-7 + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import semmle.code.cpp.controlflow.Dominance + +class ThreadSpawningFunction extends Function { + ThreadSpawningFunction() { + this.hasName("pthread_create") or + this.hasName("thrd_create") or + exists(FunctionCall fc | + fc.getTarget() instanceof ThreadSpawningFunction and + fc.getEnclosingFunction() = this) + } +} + +class AtomicInitAddressOfExpr extends FunctionCall { + Expr addressedExpr; + + AtomicInitAddressOfExpr() { + exists(AddressOfExpr addrOf | + getArgument(0) = addrOf and + addrOf.getOperand() = addressedExpr and + getTarget().getName() = "__c11_atomic_init" + ) + } + + Expr getAddressedExpr() { + result = addressedExpr + } +} + +ControlFlowNode getARequiredInitializationPoint(LocalScopeVariable v) { + result = v.getParentScope().(BlockStmt).getFollowingStmt() + or + exists(DeclStmt decl | + decl.getADeclaration() = v and + result = any(FunctionCall fc + | fc.getTarget() instanceof ThreadSpawningFunction and + fc.getEnclosingBlock().getEnclosingBlock*() = v.getParentScope() and + fc.getAPredecessor*() = decl + ) + ) +} + +from VariableDeclarationEntry decl, Variable v +where + not isExcluded(decl, Concurrency7Package::uninitializedAtomicObjectQuery()) and + v = decl.getVariable() and + v.getUnderlyingType().hasSpecifier("atomic") and + not v.isTopLevel() and + not exists(v.getInitializer()) and + exists(ControlFlowNode missingInitPoint | + missingInitPoint = getARequiredInitializationPoint(v) + and not exists(AtomicInitAddressOfExpr initialization | + initialization.getAddressedExpr().(VariableAccess).getTarget() = v and + dominates(initialization, missingInitPoint) + ) + ) +select decl, + "Atomic object '" + v.getName() + "' has no initializer or corresponding use of 'atomic_init()'." diff --git a/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.expected b/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.expected new file mode 100644 index 0000000000..442f20bf73 --- /dev/null +++ b/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.expected @@ -0,0 +1,45 @@ +edges +| test.c:10:24:10:24 | *m | test.c:10:43:10:43 | *m | provenance | | +| test.c:13:12:13:14 | mtx_init output argument | test.c:14:17:14:19 | *& ... | provenance | | +| test.c:13:12:13:14 | mtx_init output argument | test.c:15:14:15:16 | *& ... | provenance | | +| test.c:15:14:15:16 | *& ... | test.c:10:24:10:24 | *m | provenance | | +| test.c:17:12:17:14 | mtx_init output argument | test.c:18:17:18:19 | *& ... | provenance | | +| test.c:17:12:17:14 | mtx_init output argument | test.c:19:14:19:16 | *& ... | provenance | | +| test.c:19:14:19:16 | *& ... | test.c:10:24:10:24 | *m | provenance | | +| test.c:30:12:30:14 | mtx_init output argument | test.c:31:17:31:19 | *& ... | provenance | | +| test.c:30:12:30:14 | mtx_init output argument | test.c:32:14:32:16 | *& ... | provenance | | +| test.c:32:14:32:16 | *& ... | test.c:10:24:10:24 | *m | provenance | | +| test.c:42:12:42:16 | mtx_init output argument | test.c:42:13:42:14 | *l3 [post update] [m] | provenance | | +| test.c:42:13:42:14 | *l3 [post update] [m] | test.c:43:18:43:19 | *l3 [m] | provenance | | +| test.c:42:13:42:14 | *l3 [post update] [m] | test.c:44:15:44:16 | *l3 [m] | provenance | | +| test.c:43:18:43:19 | *l3 [m] | test.c:43:17:43:21 | *& ... | provenance | | +| test.c:44:14:44:18 | *& ... | test.c:10:24:10:24 | *m | provenance | | +| test.c:44:15:44:16 | *l3 [m] | test.c:44:14:44:18 | *& ... | provenance | | +nodes +| test.c:10:24:10:24 | *m | semmle.label | *m | +| test.c:10:43:10:43 | *m | semmle.label | *m | +| test.c:13:12:13:14 | mtx_init output argument | semmle.label | mtx_init output argument | +| test.c:14:17:14:19 | *& ... | semmle.label | *& ... | +| test.c:15:14:15:16 | *& ... | semmle.label | *& ... | +| test.c:17:12:17:14 | mtx_init output argument | semmle.label | mtx_init output argument | +| test.c:18:17:18:19 | *& ... | semmle.label | *& ... | +| test.c:19:14:19:16 | *& ... | semmle.label | *& ... | +| test.c:30:12:30:14 | mtx_init output argument | semmle.label | mtx_init output argument | +| test.c:31:17:31:19 | *& ... | semmle.label | *& ... | +| test.c:32:14:32:16 | *& ... | semmle.label | *& ... | +| test.c:42:12:42:16 | mtx_init output argument | semmle.label | mtx_init output argument | +| test.c:42:13:42:14 | *l3 [post update] [m] | semmle.label | *l3 [post update] [m] | +| test.c:43:17:43:21 | *& ... | semmle.label | *& ... | +| test.c:43:18:43:19 | *l3 [m] | semmle.label | *l3 [m] | +| test.c:44:14:44:18 | *& ... | semmle.label | *& ... | +| test.c:44:15:44:16 | *l3 [m] | semmle.label | *l3 [m] | +subpaths +#select +| test.c:10:43:10:43 | *m | test.c:13:12:13:14 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | +| test.c:10:43:10:43 | *m | test.c:17:12:17:14 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | +| test.c:10:43:10:43 | *m | test.c:30:12:30:14 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | +| test.c:10:43:10:43 | *m | test.c:42:12:42:16 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | +| test.c:14:17:14:19 | *& ... | test.c:13:12:13:14 | mtx_init output argument | test.c:14:17:14:19 | *& ... | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | +| test.c:18:17:18:19 | *& ... | test.c:17:12:17:14 | mtx_init output argument | test.c:18:17:18:19 | *& ... | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | +| test.c:31:17:31:19 | *& ... | test.c:30:12:30:14 | mtx_init output argument | test.c:31:17:31:19 | *& ... | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | +| test.c:43:17:43:21 | *& ... | test.c:42:12:42:16 | mtx_init output argument | test.c:43:17:43:21 | *& ... | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | diff --git a/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.qlref b/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.qlref new file mode 100644 index 0000000000..9ffe7e7494 --- /dev/null +++ b/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.qlref @@ -0,0 +1 @@ +rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-26/test.c b/c/misra/test/rules/RULE-21-26/test.c new file mode 100644 index 0000000000..d26f9c1f2f --- /dev/null +++ b/c/misra/test/rules/RULE-21-26/test.c @@ -0,0 +1,45 @@ +#include "threads.h" + +mtx_t g1; +mtx_t g2; +mtx_t g3; +mtx_t g4; + +struct timespec ts = {0, 0}; + +void doTimeLock(mtx_t *m) { mtx_timedlock(m, &ts); } + +void main(void) { + mtx_init(&g1, mtx_plain); + mtx_timedlock(&g1, &ts); // NON-COMPLIANT + doTimeLock(&g1); // NON-COMPLIANT + + mtx_init(&g2, mtx_plain | mtx_recursive); + mtx_timedlock(&g2, &ts); // NON-COMPLIANT + doTimeLock(&g2); // NON-COMPLIANT + + mtx_init(&g3, mtx_timed); + mtx_timedlock(&g3, &ts); // COMPLIANT + doTimeLock(&g3); // COMPLIANT + + mtx_init(&g4, mtx_timed | mtx_recursive); + mtx_timedlock(&g4, &ts); // COMPLIANT + doTimeLock(&g4); // COMPLIANT + + mtx_t l1; + mtx_init(&l1, mtx_plain); + mtx_timedlock(&l1, &ts); // NON-COMPLIANT + doTimeLock(&l1); // NON-COMPLIANT + + mtx_t l2; + mtx_init(&l2, mtx_timed); + mtx_timedlock(&l2, &ts); // COMPLIANT + doTimeLock(&l2); // COMPLIANT + + struct s { + mtx_t m; + } l3; + mtx_init(&l3.m, mtx_plain); + mtx_timedlock(&l3.m, &ts); // NON-COMPLIANT + doTimeLock(&l3.m); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.expected b/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.expected new file mode 100644 index 0000000000..89facda9bb --- /dev/null +++ b/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.expected @@ -0,0 +1,3 @@ +| test.c:22:15:22:16 | definition of l3 | Atomic object 'l3' has no initializer or corresponding use of 'atomic_init()'. | +| test.c:25:15:25:16 | definition of l4 | Atomic object 'l4' has no initializer or corresponding use of 'atomic_init()'. | +| test.c:29:15:29:16 | definition of l5 | Atomic object 'l5' has no initializer or corresponding use of 'atomic_init()'. | diff --git a/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.qlref b/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.qlref new file mode 100644 index 0000000000..11219b0741 --- /dev/null +++ b/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.qlref @@ -0,0 +1 @@ +rules/RULE-9-7/UninitializedAtomicObject.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-9-7/test.c b/c/misra/test/rules/RULE-9-7/test.c new file mode 100644 index 0000000000..5b3d8e36ec --- /dev/null +++ b/c/misra/test/rules/RULE-9-7/test.c @@ -0,0 +1,34 @@ +#include "stdatomic.h" +#include "threads.h" + +_Atomic int g1; // COMPLIANT +_Atomic int g2 = 0; // COMPLIANT + +void f_thread(void *x); + +void f_starts_thread() { + thrd_t t; + thrd_create(&t, f_thread, 0); +} + +void main() { + _Atomic int l1 = 1; // COMPLIANT + f_starts_thread(); + + _Atomic int l2; // COMPLIANT + atomic_init(&l2, 0); + f_starts_thread(); + + _Atomic int l3; // NON-COMPLIANT + f_starts_thread(); + + _Atomic int l4; // NON-COMPLIANT + f_starts_thread(); + atomic_init(&l4, 0); + + _Atomic int l5; // NON-COMPLIANT + if (g1 == 0) { + atomic_init(&l5, 0); + } + f_starts_thread(); +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency7.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency7.qll new file mode 100644 index 0000000000..ba492b2a6b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency7.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Concurrency7Query = + TUninitializedAtomicObjectQuery() or + TTimedlockOnInappropriateMutexTypeQuery() + +predicate isConcurrency7QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `uninitializedAtomicObject` query + Concurrency7Package::uninitializedAtomicObjectQuery() and + queryId = + // `@id` for the `uninitializedAtomicObject` query + "c/misra/uninitialized-atomic-object" and + ruleId = "RULE-9-7" and + category = "mandatory" + or + query = + // `Query` instance for the `timedlockOnInappropriateMutexType` query + Concurrency7Package::timedlockOnInappropriateMutexTypeQuery() and + queryId = + // `@id` for the `timedlockOnInappropriateMutexType` query + "c/misra/timedlock-on-inappropriate-mutex-type" and + ruleId = "RULE-21-26" and + category = "required" +} + +module Concurrency7Package { + Query uninitializedAtomicObjectQuery() { + //autogenerate `Query` type + result = + // `Query` type for `uninitializedAtomicObject` query + TQueryC(TConcurrency7PackageQuery(TUninitializedAtomicObjectQuery())) + } + + Query timedlockOnInappropriateMutexTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `timedlockOnInappropriateMutexType` query + TQueryC(TConcurrency7PackageQuery(TTimedlockOnInappropriateMutexTypeQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 3833533d50..b980584877 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -11,6 +11,7 @@ import Concurrency2 import Concurrency3 import Concurrency4 import Concurrency5 +import Concurrency7 import Contracts1 import Contracts2 import Contracts3 @@ -87,6 +88,7 @@ newtype TCQuery = TConcurrency3PackageQuery(Concurrency3Query q) or TConcurrency4PackageQuery(Concurrency4Query q) or TConcurrency5PackageQuery(Concurrency5Query q) or + TConcurrency7PackageQuery(Concurrency7Query q) or TContracts1PackageQuery(Contracts1Query q) or TContracts2PackageQuery(Contracts2Query q) or TContracts3PackageQuery(Contracts3Query q) or @@ -163,6 +165,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isConcurrency3QueryMetadata(query, queryId, ruleId, category) or isConcurrency4QueryMetadata(query, queryId, ruleId, category) or isConcurrency5QueryMetadata(query, queryId, ruleId, category) or + isConcurrency7QueryMetadata(query, queryId, ruleId, category) or isContracts1QueryMetadata(query, queryId, ruleId, category) or isContracts2QueryMetadata(query, queryId, ruleId, category) or isContracts3QueryMetadata(query, queryId, ruleId, category) or diff --git a/rule_packages/c/Concurrency7.json b/rule_packages/c/Concurrency7.json new file mode 100644 index 0000000000..c544cb88c7 --- /dev/null +++ b/rule_packages/c/Concurrency7.json @@ -0,0 +1,45 @@ +{ + "MISRA-C-2012": { + "RULE-9-7": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Atomic objects that do not have static storage duration shall be initialized with a value or by using 'atomic_init()'.", + "kind": "problem", + "name": "Atomic objects shall be appropriately initialized before being accessed", + "precision": "high", + "severity": "warning", + "short_name": "UninitializedAtomicObject", + "tags": [ + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "Atomic objects shall be appropriately initialized before being accessed" + }, + "RULE-21-26": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type", + "kind": "problem", + "name": "The Standard Library function mtx_timedlock() shall only be invoked on mutexes of type mtx_timed", + "precision": "high", + "severity": "error", + "short_name": "TimedlockOnInappropriateMutexType", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index 475ea1d66c..c07aeb58ed 100644 --- a/rules.csv +++ b/rules.csv @@ -678,7 +678,7 @@ c,MISRA-C-2012,RULE-9-3,Yes,Required,,,Arrays shall not be partially initialized c,MISRA-C-2012,RULE-9-4,Yes,Required,,,An element of an object shall not be initialized more than once,,Memory1,Medium, c,MISRA-C-2012,RULE-9-5,No,Required,,,Where designated initializers are used to initialize an array object the size of the array shall be specified explicitly,,,Medium, c,MISRA-C-2012,RULE-9-6,Yes,Required,,,An initializer using chained designators shall not contain initializers without designators,,Declarations9,Hard, -c,MISRA-C-2012,RULE-9-7,Yes,Mandatory,,,Atomic objects shall be appropriately initialized before being accessed,,Concurrency6,Hard, +c,MISRA-C-2012,RULE-9-7,Yes,Mandatory,,,Atomic objects shall be appropriately initialized before being accessed,,Concurrency7,Hard, c,MISRA-C-2012,RULE-10-1,Yes,Required,,,Operands shall not be of an inappropriate essential type,,EssentialTypes,Hard, c,MISRA-C-2012,RULE-10-2,Yes,Required,,,Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations,,EssentialTypes,Medium, c,MISRA-C-2012,RULE-10-3,Yes,Required,,,The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category,,EssentialTypes,Hard, @@ -791,7 +791,7 @@ c,MISRA-C-2012,RULE-21-22,Yes,Mandatory,,,All operand arguments to any type-gene c,MISRA-C-2012,RULE-21-23,Yes,Required,,,All operand arguments to any multi-argument type-generic macros in shall have the same standard type,Rule-21-22,EssentialTypes2,Easy, c,MISRA-C-2012,RULE-21-24,Yes,Required,,,The random number generator functions of shall not be used,MSC30-C,Banned2,Easy, c,MISRA-C-2012,RULE-21-25,Yes,Required,,,All memory synchronization operations shall be executed in sequentially consistent order,,Concurrency6,Medium, -c,MISRA-C-2012,RULE-21-26,Yes,Required,,,The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type,,Concurrency6,Hard, +c,MISRA-C-2012,RULE-21-26,Yes,Required,,,The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type,,Concurrency8,Hard, c,MISRA-C-2012,RULE-22-1,Yes,Required,,,All resources obtained dynamically by means of Standard Library functions shall be explicitly released,,Memory2,Hard, c,MISRA-C-2012,RULE-22-2,Yes,Mandatory,,,A block of memory shall only be freed if it was allocated by means of a Standard Library function,,Memory2,Hard, c,MISRA-C-2012,RULE-22-3,Yes,Required,,,The same file shall not be open for read and write access at the same time on different streams,,IO3,Hard, From 8a2076e5934d46a0ef70478ffd82b6bc146f884b Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 18 Nov 2024 00:03:04 -0800 Subject: [PATCH 095/628] Fix query metadata --- rule_packages/c/Concurrency7.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rule_packages/c/Concurrency7.json b/rule_packages/c/Concurrency7.json index c544cb88c7..f764468ae3 100644 --- a/rule_packages/c/Concurrency7.json +++ b/rule_packages/c/Concurrency7.json @@ -27,7 +27,7 @@ "queries": [ { "description": "The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type", - "kind": "problem", + "kind": "path-problem", "name": "The Standard Library function mtx_timedlock() shall only be invoked on mutexes of type mtx_timed", "precision": "high", "severity": "error", From 6f36b1c322d9c48599de3bc6829aeaa158c76704 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 18 Nov 2024 12:48:30 -0800 Subject: [PATCH 096/628] Fix query metadata, format --- .../TimedlockOnInappropriateMutexType.ql | 2 +- .../RULE-9-7/UninitializedAtomicObject.ql | 28 ++++++++++--------- rule_packages/c/Concurrency7.json | 2 +- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql b/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql index d8d465045e..e6dda61d79 100644 --- a/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql +++ b/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql @@ -2,7 +2,7 @@ * @id c/misra/timedlock-on-inappropriate-mutex-type * @name RULE-21-26: The Standard Library function mtx_timedlock() shall only be invoked on mutexes of type mtx_timed * @description The Standard Library function mtx_timedlock() shall only be invoked on mutex objects - * of appropriate mutex type + * of appropriate mutex type. * @kind path-problem * @precision high * @problem.severity error diff --git a/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql b/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql index 40f833a740..006e8e8178 100644 --- a/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql +++ b/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql @@ -18,11 +18,14 @@ import semmle.code.cpp.controlflow.Dominance class ThreadSpawningFunction extends Function { ThreadSpawningFunction() { - this.hasName("pthread_create") or - this.hasName("thrd_create") or + this.hasName("pthread_create") + or + this.hasName("thrd_create") + or exists(FunctionCall fc | fc.getTarget() instanceof ThreadSpawningFunction and - fc.getEnclosingFunction() = this) + fc.getEnclosingFunction() = this + ) } } @@ -37,9 +40,7 @@ class AtomicInitAddressOfExpr extends FunctionCall { ) } - Expr getAddressedExpr() { - result = addressedExpr - } + Expr getAddressedExpr() { result = addressedExpr } } ControlFlowNode getARequiredInitializationPoint(LocalScopeVariable v) { @@ -47,11 +48,12 @@ ControlFlowNode getARequiredInitializationPoint(LocalScopeVariable v) { or exists(DeclStmt decl | decl.getADeclaration() = v and - result = any(FunctionCall fc - | fc.getTarget() instanceof ThreadSpawningFunction and - fc.getEnclosingBlock().getEnclosingBlock*() = v.getParentScope() and - fc.getAPredecessor*() = decl - ) + result = + any(FunctionCall fc | + fc.getTarget() instanceof ThreadSpawningFunction and + fc.getEnclosingBlock().getEnclosingBlock*() = v.getParentScope() and + fc.getAPredecessor*() = decl + ) ) } @@ -63,8 +65,8 @@ where not v.isTopLevel() and not exists(v.getInitializer()) and exists(ControlFlowNode missingInitPoint | - missingInitPoint = getARequiredInitializationPoint(v) - and not exists(AtomicInitAddressOfExpr initialization | + missingInitPoint = getARequiredInitializationPoint(v) and + not exists(AtomicInitAddressOfExpr initialization | initialization.getAddressedExpr().(VariableAccess).getTarget() = v and dominates(initialization, missingInitPoint) ) diff --git a/rule_packages/c/Concurrency7.json b/rule_packages/c/Concurrency7.json index f764468ae3..6fdc49984b 100644 --- a/rule_packages/c/Concurrency7.json +++ b/rule_packages/c/Concurrency7.json @@ -26,7 +26,7 @@ }, "queries": [ { - "description": "The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type", + "description": "The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type.", "kind": "path-problem", "name": "The Standard Library function mtx_timedlock() shall only be invoked on mutexes of type mtx_timed", "precision": "high", From 9ac5159694585358fe6bf267d26b4062350b726f Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 18 Nov 2024 12:56:07 -0800 Subject: [PATCH 097/628] Fix rule 21-26 packages in rules.csv: Concurrency7 not 8. --- rules.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules.csv b/rules.csv index c07aeb58ed..b914f7cad5 100644 --- a/rules.csv +++ b/rules.csv @@ -791,7 +791,7 @@ c,MISRA-C-2012,RULE-21-22,Yes,Mandatory,,,All operand arguments to any type-gene c,MISRA-C-2012,RULE-21-23,Yes,Required,,,All operand arguments to any multi-argument type-generic macros in shall have the same standard type,Rule-21-22,EssentialTypes2,Easy, c,MISRA-C-2012,RULE-21-24,Yes,Required,,,The random number generator functions of shall not be used,MSC30-C,Banned2,Easy, c,MISRA-C-2012,RULE-21-25,Yes,Required,,,All memory synchronization operations shall be executed in sequentially consistent order,,Concurrency6,Medium, -c,MISRA-C-2012,RULE-21-26,Yes,Required,,,The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type,,Concurrency8,Hard, +c,MISRA-C-2012,RULE-21-26,Yes,Required,,,The Standard Library function mtx_timedlock() shall only be invoked on mutex objects of appropriate mutex type,,Concurrency7,Hard, c,MISRA-C-2012,RULE-22-1,Yes,Required,,,All resources obtained dynamically by means of Standard Library functions shall be explicitly released,,Memory2,Hard, c,MISRA-C-2012,RULE-22-2,Yes,Mandatory,,,A block of memory shall only be freed if it was allocated by means of a Standard Library function,,Memory2,Hard, c,MISRA-C-2012,RULE-22-3,Yes,Required,,,The same file shall not be open for read and write access at the same time on different streams,,IO3,Hard, From 492da67c1fa4f08075cbb6d8918abf966690da08 Mon Sep 17 00:00:00 2001 From: knewbury01 Date: Fri, 22 Nov 2024 18:24:29 +0000 Subject: [PATCH 098/628] Bump version to 2.39.0-dev --- c/cert/src/qlpack.yml | 2 +- c/cert/test/qlpack.yml | 2 +- c/common/src/qlpack.yml | 2 +- c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- c/misra/test/qlpack.yml | 2 +- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/qlpack.yml | 2 +- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- docs/user_manual.md | 12 ++++++------ 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index db08fb3ebe..00a8221f28 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.38.0-dev +version: 2.39.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index 0242ecdd10..a79ef5f692 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.38.0-dev +version: 2.39.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 9d05e536fd..41bf42d337 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.38.0-dev +version: 2.39.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index e19cb371e8..41737a34ec 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.38.0-dev +version: 2.39.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 0c78ad44b6..b160f27b6e 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.38.0-dev +version: 2.39.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index f27c03ca9e..3acb8455b1 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.38.0-dev +version: 2.39.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index 810af3bde4..cd37cef87e 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.38.0-dev +version: 2.39.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index 37dd488774..e7e8d3e2ce 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.38.0-dev +version: 2.39.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 2fb82cfe3f..464a5172fc 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.38.0-dev +version: 2.39.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index dfe027d387..ba7415c43e 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.38.0-dev +version: 2.39.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index eeee5f1fa9..3912f3531f 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards -version: 2.38.0-dev +version: 2.39.0-dev license: MIT dependencies: codeql/cpp-all: 0.12.9 diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index 8c37adba8d..3f061a2920 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.38.0-dev +version: 2.39.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 2ca5752f9c..c27400fc8e 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.38.0-dev +version: 2.39.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index b1601bcb74..e79e5934fa 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.38.0-dev +version: 2.39.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index 797c50b92b..6477e52747 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.38.0-dev +version: 2.39.0-dev license: MIT dependencies: codeql/cpp-all: 0.12.9 diff --git a/docs/user_manual.md b/docs/user_manual.md index 7f505673df..4c020dc73b 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -33,14 +33,14 @@ ## Release information -This user manual documents release `2.38.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.39.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: - `coding-standards-codeql-packs-2.37.0-dev.zip`: CodeQL packs that can be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `code-scanning-cpp-query-pack-2.38.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.38.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.38.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.38.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.39.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.39.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.39.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.39.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -573,7 +573,7 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.38.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.39.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | From a490400e4eacd36f0d36ed626c317e7609adad34 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 22 Nov 2024 20:40:25 -0800 Subject: [PATCH 099/628] Add full stops to report messages --- ...edeclarationOfObjectWithUnmatchedAlignment.ql | 2 +- .../RedeclarationOfObjectWithoutAlignment.ql | 2 +- ...rationOfObjectWithUnmatchedAlignment.expected | 16 ++++++++-------- ...edeclarationOfObjectWithoutAlignment.expected | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql index 878bfeeeaf..dc82f63d10 100644 --- a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql +++ b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.ql @@ -32,5 +32,5 @@ where ) and not lexicallyEqual(alignment.getArgument(0), mismatched.getArgument(0)) select alignment, - "Variable " + variable + " declared with lexically different _Alignof() values '$@' and '$@'", + "Variable " + variable + " declared with lexically different _Alignof() values '$@' and '$@'.", alignment, alignment.getArgument(0).toString(), mismatched, mismatched.getArgument(0).toString() diff --git a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql index 3088708de0..df9f3f2d1c 100644 --- a/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql +++ b/c/misra/src/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.ql @@ -92,5 +92,5 @@ where ) select unaligned, "Variable " + unaligned.getName() + - " declared without explicit alignment to match $@ with alignment $@", aligned, + " declared without explicit alignment to match $@ with alignment $@.", aligned, "other definition", attribute, attribute.toString() diff --git a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected index 83a27f9074..3479ef1e35 100644 --- a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected +++ b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected @@ -1,8 +1,8 @@ -| test.c:18:8:18:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@' | test.c:18:8:18:15 | alignas(...) | int | test.c:19:8:19:15 | alignas(...) | 4 | -| test.c:19:8:19:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@' | test.c:19:8:19:15 | alignas(...) | 4 | test.c:18:8:18:15 | alignas(...) | int | -| test.c:22:8:22:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@' | test.c:22:8:22:15 | alignas(...) | ... * ... | test.c:23:8:23:15 | alignas(...) | 32 | -| test.c:23:8:23:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@' | test.c:23:8:23:15 | alignas(...) | 32 | test.c:22:8:22:15 | alignas(...) | ... * ... | -| test.c:28:8:28:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@' | test.c:28:8:28:15 | alignas(...) | ... * ... | test.c:29:8:29:15 | alignas(...) | ... * ... | -| test.c:29:8:29:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@' | test.c:29:8:29:15 | alignas(...) | ... * ... | test.c:28:8:28:15 | alignas(...) | ... * ... | -| test.c:34:8:34:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@' | test.c:34:8:34:15 | alignas(...) | signed int | test.c:35:8:35:15 | alignas(...) | unsigned int | -| test.c:35:8:35:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@' | test.c:35:8:35:15 | alignas(...) | unsigned int | test.c:34:8:34:15 | alignas(...) | signed int | +| test.c:18:8:18:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:18:8:18:15 | alignas(...) | int | test.c:19:8:19:15 | alignas(...) | 4 | +| test.c:19:8:19:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:19:8:19:15 | alignas(...) | 4 | test.c:18:8:18:15 | alignas(...) | int | +| test.c:22:8:22:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:22:8:22:15 | alignas(...) | ... * ... | test.c:23:8:23:15 | alignas(...) | 32 | +| test.c:23:8:23:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:23:8:23:15 | alignas(...) | 32 | test.c:22:8:22:15 | alignas(...) | ... * ... | +| test.c:28:8:28:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:28:8:28:15 | alignas(...) | ... * ... | test.c:29:8:29:15 | alignas(...) | ... * ... | +| test.c:29:8:29:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:29:8:29:15 | alignas(...) | ... * ... | test.c:28:8:28:15 | alignas(...) | ... * ... | +| test.c:34:8:34:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:34:8:34:15 | alignas(...) | signed int | test.c:35:8:35:15 | alignas(...) | unsigned int | +| test.c:35:8:35:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:35:8:35:15 | alignas(...) | unsigned int | test.c:34:8:34:15 | alignas(...) | signed int | diff --git a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.expected b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.expected index e9b91d33a4..69d2c8bb2d 100644 --- a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.expected +++ b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithoutAlignment.expected @@ -1,2 +1,2 @@ -| test.c:5:12:5:13 | declaration of g2 | Variable g2 declared without explicit alignment to match $@ with alignment $@ | test.c:4:25:4:26 | declaration of g2 | other definition | test.c:4:8:4:15 | alignas(...) | alignas(...) | -| test.c:7:12:7:13 | declaration of g3 | Variable g3 declared without explicit alignment to match $@ with alignment $@ | test.c:8:25:8:26 | declaration of g3 | other definition | test.c:8:8:8:15 | alignas(...) | alignas(...) | +| test.c:5:12:5:13 | declaration of g2 | Variable g2 declared without explicit alignment to match $@ with alignment $@. | test.c:4:25:4:26 | declaration of g2 | other definition | test.c:4:8:4:15 | alignas(...) | alignas(...) | +| test.c:7:12:7:13 | declaration of g3 | Variable g3 declared without explicit alignment to match $@ with alignment $@. | test.c:8:25:8:26 | declaration of g3 | other definition | test.c:8:8:8:15 | alignas(...) | alignas(...) | From 791526e1583c7db9dd1175dff816a45697ce5cdb Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 22 Nov 2024 21:49:09 -0800 Subject: [PATCH 100/628] Address next round of feedback --- ...ointersToVariablyModifiedArrayTypesUsed.ql | 4 +- .../RULE-18-8/VariableLengthArrayTypesUsed.ql | 47 +++++++++++++++++-- ...rayToPointerConversionOfTemporaryObject.ql | 2 +- c/misra/test/rules/RULE-18-10/test.c | 12 ++++- c/misra/test/rules/RULE-18-8/test.c | 10 ++-- .../cpp/VariablyModifiedTypes.qll | 10 ++++ 6 files changed, 75 insertions(+), 10 deletions(-) diff --git a/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql b/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql index 6ca2289c67..3a99ebd842 100644 --- a/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql +++ b/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql @@ -42,7 +42,9 @@ where if v.getType().(PointerType).getBaseType() instanceof CandidateVlaType then relationstr = "pointer to" else relationstr = "with inner" - ) + ) and + // Remove results that appear to be unreliable, potentially from a macro. + not v.appearsDuplicated() select v, declstr + v.getName() + " is " + adjuststr + " variably-modified type, " + relationstr + " variable length array of non constant size $@ and element type '" + diff --git a/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql b/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql index 8e599f39f7..6e6f5c10c5 100644 --- a/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql +++ b/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql @@ -15,16 +15,55 @@ import cpp import codingstandards.c.misra -from VlaDeclStmt v, Expr size, ArrayType arrayType, string typeStr +/** + * Typedefs may be declared as VLAs, eg, `typedef int vla[x];`. This query finds types that refer to + * such typedef types, for instance `vla foo;` or adding a dimension via `vla bar[10];`. + * + * Consts and other specifiers may be added, but `vla *ptr;` is not a VLA any more, and is excluded. + */ +class VlaTypedefType extends Type { + VlaDeclStmt vlaDecl; + ArrayType arrayType; + + VlaTypedefType() { + // Holds for direct references to the typedef type: + this = vlaDecl.getType() and + vlaDecl.getType() instanceof TypedefType and + arrayType = vlaDecl.getType().stripTopLevelSpecifiers() + or + // Holds for adding a constant dimension to a VLA typedef type: + arrayType = this.stripTopLevelSpecifiers() and + vlaDecl = arrayType.getBaseType().(VlaTypedefType).getVlaDeclStmt() + or + // Carefully ignore specifiers, `stripTopLevelSpecifiers()` resolves past the typedef + exists(SpecifiedType st, VlaTypedefType inner | + st = this and + st.getBaseType() = inner and + arrayType = inner.getArrayType() and + vlaDecl = inner.getVlaDeclStmt() + ) + } + + VlaDeclStmt getVlaDeclStmt() { result = vlaDecl } + + ArrayType getArrayType() { result = arrayType } +} + +from Variable v, Expr size, ArrayType arrayType, VlaDeclStmt vlaDecl, string typeStr where not isExcluded(v, Declarations7Package::variableLengthArrayTypesUsedQuery()) and - size = v.getVlaDimensionStmt(0).getDimensionExpr() and + size = vlaDecl.getVlaDimensionStmt(0).getDimensionExpr() and ( // Holds is if v is a variable declaration: - arrayType = v.getVariable().getType().stripTopLevelSpecifiers() + v = vlaDecl.getVariable() and + arrayType = v.getType().stripTopLevelSpecifiers() or // Holds is if v is a typedef declaration: - arrayType = v.getType().stripTopLevelSpecifiers() + exists(VlaTypedefType typedef | + v.getType() = typedef and + arrayType = typedef.getArrayType() and + vlaDecl = typedef.getVlaDeclStmt() + ) ) and typeStr = arrayType.getBaseType().toString() select v, "Variable length array of element type '" + typeStr + "' with non-constant size $@.", diff --git a/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql b/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql index a64ccd44ff..5317966f3b 100644 --- a/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql +++ b/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql @@ -66,5 +66,5 @@ where fa.getTemporary() = temporary and conversion.getExpr() = fa and isUsedOrStored(temporaryObjectFlowStep*(conversion.getExpr())) -select conversion, "Array to pointer conversion of array $@ from temporary object $@", +select conversion, "Array to pointer conversion of array $@ from temporary object $@.", fa.getTarget(), fa.getTarget().getName(), temporary, temporary.toString() diff --git a/c/misra/test/rules/RULE-18-10/test.c b/c/misra/test/rules/RULE-18-10/test.c index dbddbecec8..3a44abd264 100644 --- a/c/misra/test/rules/RULE-18-10/test.c +++ b/c/misra/test/rules/RULE-18-10/test.c @@ -92,4 +92,14 @@ void f2(int (*p1)[3], // COMPLIANT int (*p3)[2][*], // NON-COMPLIANT[FALSE_NEGATIVE] int (*p4)[*][2], // NON-COMPLIANT[FALSE_NEGATIVE] int (*p5)[*][*] // NON-COMPLIANT[FALSE_NEGATIVE] -); \ No newline at end of file +); + +#define CONFUSING_MACRO() \ + int x; \ + int (*vla)[x]; \ + int (*not_vla)[]; + +void f3() { + // We cannot report `vla` in this macro without a false positive for `not_vla`. + CONFUSING_MACRO() // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-8/test.c b/c/misra/test/rules/RULE-18-8/test.c index c2f6027216..e6e038049c 100644 --- a/c/misra/test/rules/RULE-18-8/test.c +++ b/c/misra/test/rules/RULE-18-8/test.c @@ -14,9 +14,13 @@ void f(int n) { extern int e1[]; // COMPLIANT - // A typedef is not a VLA. However, `VlaDeclStmt`s match the typedef. - typedef int vlaTypedef[n]; // COMPLIANT[FALSE_POSITIVE] - vlaTypedef t1; // NON_COMPLIANT[FALSE_NEGATIVE] + // A typedef is not a VLA. + typedef int vlaTypedef[n]; // COMPLIANT + // The declarations using the typedef may or may not be VLAs. + vlaTypedef t1; // NON_COMPLIANT + vlaTypedef t2[1]; // NON_COMPLIANT + vlaTypedef t3[x]; // NON_COMPLIANT + vlaTypedef *t4; // COMPLIANT } void f1(int n, diff --git a/cpp/common/src/codingstandards/cpp/VariablyModifiedTypes.qll b/cpp/common/src/codingstandards/cpp/VariablyModifiedTypes.qll index c0fb3a3db6..9de533d050 100644 --- a/cpp/common/src/codingstandards/cpp/VariablyModifiedTypes.qll +++ b/cpp/common/src/codingstandards/cpp/VariablyModifiedTypes.qll @@ -2,6 +2,8 @@ import cpp /** * A declaration involving a variably-modified type. + * + * Note, this holds for both VLA variable and VLA typedefs. */ class VmtDeclarationEntry extends DeclarationEntry { Expr sizeExpr; @@ -28,6 +30,14 @@ class VmtDeclarationEntry extends DeclarationEntry { Expr getSizeExpr() { result = sizeExpr } CandidateVlaType getVlaType() { result = vlaType } + + /* VLAs may occur in macros, and result in duplication that messes up our analysis. */ + predicate appearsDuplicated() { + exists(VmtDeclarationEntry other | + other != this and + other.getSizeExpr() = getSizeExpr() + ) + } } /** From b477e34ef5ab008e6b5ce3e7586fa4308427dcbc Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 22 Nov 2024 21:51:29 -0800 Subject: [PATCH 101/628] Fix macro testcase formatting --- c/misra/test/rules/RULE-18-10/test.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/c/misra/test/rules/RULE-18-10/test.c b/c/misra/test/rules/RULE-18-10/test.c index 3a44abd264..645943733d 100644 --- a/c/misra/test/rules/RULE-18-10/test.c +++ b/c/misra/test/rules/RULE-18-10/test.c @@ -94,12 +94,13 @@ void f2(int (*p1)[3], // COMPLIANT int (*p5)[*][*] // NON-COMPLIANT[FALSE_NEGATIVE] ); -#define CONFUSING_MACRO() \ - int x; \ - int (*vla)[x]; \ - int (*not_vla)[]; +#define CONFUSING_MACRO() \ + int x; \ + int(*vla)[x]; \ + int(*not_vla)[]; void f3() { - // We cannot report `vla` in this macro without a false positive for `not_vla`. + // We cannot report `vla` in this macro without a false positive for + // `not_vla`. CONFUSING_MACRO() // COMPLIANT } \ No newline at end of file From 3873be762a39d123b9b3048a83881c2a992a6777 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sat, 23 Nov 2024 00:03:59 -0800 Subject: [PATCH 102/628] Commit changes to expected files, improve problem messages --- .../RULE-18-8/VariableLengthArrayTypesUsed.ql | 18 +++--- .../VariableLengthArrayTypesUsed.expected | 13 ++-- ...ointerConversionOfTemporaryObject.expected | 60 +++++++++---------- 3 files changed, 46 insertions(+), 45 deletions(-) diff --git a/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql b/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql index 6e6f5c10c5..cf19c02eca 100644 --- a/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql +++ b/c/misra/src/rules/RULE-18-8/VariableLengthArrayTypesUsed.ql @@ -31,16 +31,14 @@ class VlaTypedefType extends Type { vlaDecl.getType() instanceof TypedefType and arrayType = vlaDecl.getType().stripTopLevelSpecifiers() or - // Holds for adding a constant dimension to a VLA typedef type: - arrayType = this.stripTopLevelSpecifiers() and - vlaDecl = arrayType.getBaseType().(VlaTypedefType).getVlaDeclStmt() - or - // Carefully ignore specifiers, `stripTopLevelSpecifiers()` resolves past the typedef - exists(SpecifiedType st, VlaTypedefType inner | - st = this and - st.getBaseType() = inner and - arrayType = inner.getArrayType() and - vlaDecl = inner.getVlaDeclStmt() + // Handle arrays of VLA typedefs, and carefully handle specified VLA typedef types, as + // `stripTopLevelSpecifiers` resolves past the VLA typedef type. + exists(DerivedType dt, VlaTypedefType vlaType | + (dt instanceof ArrayType or dt instanceof SpecifiedType) and + this = dt and + vlaType = dt.getBaseType() and + vlaDecl = vlaType.getVlaDeclStmt() and + arrayType = vlaType.getArrayType() ) } diff --git a/c/misra/test/rules/RULE-18-8/VariableLengthArrayTypesUsed.expected b/c/misra/test/rules/RULE-18-8/VariableLengthArrayTypesUsed.expected index 24856619bf..af73daccfd 100644 --- a/c/misra/test/rules/RULE-18-8/VariableLengthArrayTypesUsed.expected +++ b/c/misra/test/rules/RULE-18-8/VariableLengthArrayTypesUsed.expected @@ -1,5 +1,8 @@ -| test.c:6:7:6:7 | VLA declaration | Variable length array of element type 'int' with non-constant size $@. | test.c:6:10:6:14 | ... + ... | ... + ... | -| test.c:7:7:7:7 | VLA declaration | Variable length array of element type 'int' with non-constant size $@. | test.c:7:10:7:10 | n | n | -| test.c:8:7:8:7 | VLA declaration | Variable length array of element type 'int[]' with non-constant size $@. | test.c:8:13:8:13 | n | n | -| test.c:12:7:12:7 | VLA declaration | Variable length array of element type 'int[1]' with non-constant size $@. | test.c:12:10:12:10 | n | n | -| test.c:18:15:18:15 | VLA declaration | Variable length array of element type 'int' with non-constant size $@. | test.c:18:26:18:26 | n | n | +| test.c:6:7:6:8 | a1 | Variable length array of element type 'int' with non-constant size $@. | test.c:6:10:6:14 | ... + ... | ... + ... | +| test.c:7:7:7:8 | a2 | Variable length array of element type 'int' with non-constant size $@. | test.c:7:10:7:10 | n | n | +| test.c:8:7:8:8 | a3 | Variable length array of element type 'int[]' with non-constant size $@. | test.c:8:13:8:13 | n | n | +| test.c:12:7:12:8 | a7 | Variable length array of element type 'int[1]' with non-constant size $@. | test.c:12:10:12:10 | n | n | +| test.c:20:14:20:15 | t1 | Variable length array of element type 'int' with non-constant size $@. | test.c:18:26:18:26 | n | n | +| test.c:21:14:21:15 | t2 | Variable length array of element type 'int' with non-constant size $@. | test.c:18:26:18:26 | n | n | +| test.c:22:14:22:15 | t3 | Variable length array of element type 'int' with non-constant size $@. | test.c:18:26:18:26 | n | n | +| test.c:22:14:22:15 | t3 | Variable length array of element type 'vlaTypedef' with non-constant size $@. | test.c:22:17:22:17 | x | x | diff --git a/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected b/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected index 7d760dc4a6..688dde4650 100644 --- a/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected +++ b/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected @@ -1,30 +1,30 @@ -| test.c:45:3:45:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:45:3:45:8 | call to get_s1 | call to get_s1 | -| test.c:46:3:46:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:46:3:46:8 | call to get_s1 | call to get_s1 | -| test.c:47:7:47:24 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:47:7:47:12 | call to get_s1 | call to get_s1 | -| test.c:48:4:48:21 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:48:4:48:9 | call to get_s1 | call to get_s1 | -| test.c:49:4:49:21 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:49:4:49:9 | call to get_s1 | call to get_s1 | -| test.c:50:3:50:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:50:3:50:8 | call to get_s1 | call to get_s1 | -| test.c:51:3:51:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:51:3:51:8 | call to get_s1 | call to get_s1 | -| test.c:52:3:52:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:52:3:52:8 | call to get_s1 | call to get_s1 | -| test.c:53:3:53:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:53:3:53:8 | call to get_s1 | call to get_s1 | -| test.c:54:3:54:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:54:3:54:8 | call to get_s1 | call to get_s1 | -| test.c:55:8:55:25 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:55:8:55:13 | call to get_s1 | call to get_s1 | -| test.c:56:3:56:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:56:3:56:8 | call to get_s1 | call to get_s1 | -| test.c:57:8:57:25 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:57:8:57:13 | call to get_s1 | call to get_s1 | -| test.c:58:3:58:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:58:3:58:8 | call to get_s1 | call to get_s1 | -| test.c:59:3:59:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:59:3:59:8 | call to get_s1 | call to get_s1 | -| test.c:60:15:60:32 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:60:15:60:20 | call to get_s1 | call to get_s1 | -| test.c:61:16:61:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:61:16:61:21 | call to get_s1 | call to get_s1 | -| test.c:62:23:62:40 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:62:23:62:28 | call to get_s1 | call to get_s1 | -| test.c:63:7:63:24 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:63:7:63:12 | call to get_s1 | call to get_s1 | -| test.c:64:16:64:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:64:16:64:21 | call to get_s1 | call to get_s1 | -| test.c:65:15:65:32 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:65:15:65:20 | call to get_s1 | call to get_s1 | -| test.c:66:16:66:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:66:16:66:21 | call to get_s1 | call to get_s1 | -| test.c:67:23:67:40 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:67:23:67:28 | call to get_s1 | call to get_s1 | -| test.c:89:3:89:30 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:89:12:89:20 | member_s1 | member_s1 | -| test.c:90:3:90:36 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:90:3:90:26 | access to array | access to array | -| test.c:91:15:91:42 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:91:24:91:32 | member_s1 | member_s1 | -| test.c:92:15:92:48 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:92:15:92:38 | access to array | access to array | -| test.c:111:15:111:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:111:16:111:22 | ... = ... | ... = ... | -| test.c:113:15:113:37 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:113:16:113:26 | ... ? ... : ... | ... ? ... : ... | -| test.c:114:15:114:31 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@ | test.c:3:13:3:21 | const_arr | const_arr | test.c:114:16:114:20 | ... , ... | ... , ... | +| test.c:45:3:45:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:45:3:45:8 | call to get_s1 | call to get_s1 | +| test.c:46:3:46:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:46:3:46:8 | call to get_s1 | call to get_s1 | +| test.c:47:7:47:24 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:47:7:47:12 | call to get_s1 | call to get_s1 | +| test.c:48:4:48:21 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:48:4:48:9 | call to get_s1 | call to get_s1 | +| test.c:49:4:49:21 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:49:4:49:9 | call to get_s1 | call to get_s1 | +| test.c:50:3:50:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:50:3:50:8 | call to get_s1 | call to get_s1 | +| test.c:51:3:51:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:51:3:51:8 | call to get_s1 | call to get_s1 | +| test.c:52:3:52:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:52:3:52:8 | call to get_s1 | call to get_s1 | +| test.c:53:3:53:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:53:3:53:8 | call to get_s1 | call to get_s1 | +| test.c:54:3:54:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:54:3:54:8 | call to get_s1 | call to get_s1 | +| test.c:55:8:55:25 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:55:8:55:13 | call to get_s1 | call to get_s1 | +| test.c:56:3:56:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:56:3:56:8 | call to get_s1 | call to get_s1 | +| test.c:57:8:57:25 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:57:8:57:13 | call to get_s1 | call to get_s1 | +| test.c:58:3:58:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:58:3:58:8 | call to get_s1 | call to get_s1 | +| test.c:59:3:59:20 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:59:3:59:8 | call to get_s1 | call to get_s1 | +| test.c:60:15:60:32 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:60:15:60:20 | call to get_s1 | call to get_s1 | +| test.c:61:16:61:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:61:16:61:21 | call to get_s1 | call to get_s1 | +| test.c:62:23:62:40 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:62:23:62:28 | call to get_s1 | call to get_s1 | +| test.c:63:7:63:24 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:63:7:63:12 | call to get_s1 | call to get_s1 | +| test.c:64:16:64:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:64:16:64:21 | call to get_s1 | call to get_s1 | +| test.c:65:15:65:32 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:65:15:65:20 | call to get_s1 | call to get_s1 | +| test.c:66:16:66:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:66:16:66:21 | call to get_s1 | call to get_s1 | +| test.c:67:23:67:40 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:67:23:67:28 | call to get_s1 | call to get_s1 | +| test.c:89:3:89:30 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:89:12:89:20 | member_s1 | member_s1 | +| test.c:90:3:90:36 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:90:3:90:26 | access to array | access to array | +| test.c:91:15:91:42 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:91:24:91:32 | member_s1 | member_s1 | +| test.c:92:15:92:48 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:92:15:92:38 | access to array | access to array | +| test.c:111:15:111:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:111:16:111:22 | ... = ... | ... = ... | +| test.c:113:15:113:37 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:113:16:113:26 | ... ? ... : ... | ... ? ... : ... | +| test.c:114:15:114:31 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:114:16:114:20 | ... , ... | ... , ... | From e9b3ebd1c9e4e92d83ac47a6a65f119709e0a5a5 Mon Sep 17 00:00:00 2001 From: "rakesh.pothengil" Date: Mon, 25 Nov 2024 10:15:29 +0900 Subject: [PATCH 103/628] Add markers for non-compliant cases --- cpp/autosar/test/rules/A7-1-2/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/autosar/test/rules/A7-1-2/test.cpp b/cpp/autosar/test/rules/A7-1-2/test.cpp index 1bbe32a933..664a9cb8e7 100644 --- a/cpp/autosar/test/rules/A7-1-2/test.cpp +++ b/cpp/autosar/test/rules/A7-1-2/test.cpp @@ -127,7 +127,7 @@ class MissingConstexprClass { MissingConstexprClass(int i) = delete; // NON_COMPLIANT MissingConstexprClass(int i, LiteralClass lc) {} // NON_COMPLIANT private: - int m1 = 0; + int m1 = 0; // NON_COMPLIANT }; class VirtualBaseClass {}; @@ -138,7 +138,7 @@ class DerivedClass : public virtual VirtualBaseClass { DerivedClass(int i) = delete; // COMPLIANT DerivedClass(int i, LiteralClass lc) {} // COMPLIANT private: - int m1 = 0; + int m1 = 0; // NON_COMPLIANT }; class NotAllMembersInitializedClass { From 56d886e8cd24d9ee2c9120e91881d9174f8a5b89 Mon Sep 17 00:00:00 2001 From: "rakesh.pothengil" Date: Tue, 26 Nov 2024 13:05:28 +0900 Subject: [PATCH 104/628] Fix as per review comments --- ...hatContainsForwardingReferenceAsItsArgumentOverloaded.ql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql b/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql index e3fb59bd8a..1ae2bc87ab 100644 --- a/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql +++ b/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql @@ -14,6 +14,7 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.FunctionEquivalence class Candidate extends TemplateFunction { Candidate() { @@ -29,9 +30,8 @@ where OperatorsPackage::functionThatContainsForwardingReferenceAsItsArgumentOverloadedQuery()) and not f.isDeleted() and f = c.getAnOverload() and - // CodeQL sometimes fetches an overloaded function at the same location. - // Thus, a check is added explicitly (refer #796). - f.getLocation() != c.getLocation() and + // Ensure the functions are not equivalent to each other (refer #796). + not f = getAnEquivalentFunction(c) and // allow for overloading with different number of parameters, because there is no // confusion on what function will be called. f.getNumberOfParameters() = c.getNumberOfParameters() and From b8d399e2a327c0d8d6c74e8b5863b95d5228d905 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 27 Nov 2024 23:49:55 +0000 Subject: [PATCH 105/628] M5-0-3: Consider static casts to be cvalues, as per spec --- ...essionConvertedToDifferentUnderlyingType.expected | 4 +++- cpp/autosar/test/rules/M5-0-3/test.cpp | 3 +++ cpp/common/src/codingstandards/cpp/Expr.qll | 12 ++---------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/cpp/autosar/test/rules/M5-0-3/CvalueExpressionConvertedToDifferentUnderlyingType.expected b/cpp/autosar/test/rules/M5-0-3/CvalueExpressionConvertedToDifferentUnderlyingType.expected index 773691efd1..8ce6a225dc 100644 --- a/cpp/autosar/test/rules/M5-0-3/CvalueExpressionConvertedToDifferentUnderlyingType.expected +++ b/cpp/autosar/test/rules/M5-0-3/CvalueExpressionConvertedToDifferentUnderlyingType.expected @@ -2,4 +2,6 @@ | test.cpp:12:8:12:14 | ... + ... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:12:8:12:14 | ... + ... | expression | | test.cpp:14:8:14:13 | ... + ... | Implicit conversion converts cvalue $@ from signed short to signed int. | test.cpp:14:8:14:13 | ... + ... | expression | | test.cpp:23:13:23:19 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:23:13:23:19 | ... + ... | expression | -| test.cpp:30:12:30:18 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:30:12:30:18 | ... + ... | expression | +| test.cpp:25:13:25:45 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:25:13:25:45 | static_cast... | expression | +| test.cpp:31:12:31:18 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:31:12:31:18 | ... + ... | expression | +| test.cpp:33:12:33:44 | (int16_t)... | Implicit conversion converts cvalue $@ from signed char to signed short. | test.cpp:33:12:33:44 | static_cast... | expression | diff --git a/cpp/autosar/test/rules/M5-0-3/test.cpp b/cpp/autosar/test/rules/M5-0-3/test.cpp index 9f368bae3f..7275204519 100644 --- a/cpp/autosar/test/rules/M5-0-3/test.cpp +++ b/cpp/autosar/test/rules/M5-0-3/test.cpp @@ -22,12 +22,15 @@ void test_func_call() { std::int8_t l1; int16_arg(l1 + l1); // NON_COMPLIANT int16_arg(static_cast(l1 + l1)); // COMPLIANT + int16_arg(static_cast(l1 + l1)); // NON_COMPLIANT } std::int16_t test_return(int test) { std::int8_t l1; if (test > 0) { return l1 + l1; // NON_COMPLIANT + } else if (test < 0) { + return static_cast(l1 + l1); // NON_COMPLIANT } else { return static_cast(l1 + l1); // COMPLIANT } diff --git a/cpp/common/src/codingstandards/cpp/Expr.qll b/cpp/common/src/codingstandards/cpp/Expr.qll index 51066cf4cb..c97c808f6f 100644 --- a/cpp/common/src/codingstandards/cpp/Expr.qll +++ b/cpp/common/src/codingstandards/cpp/Expr.qll @@ -148,17 +148,9 @@ module MisraExpr { private predicate isCValue(Expr e) { not e.isConstant() and ( - exists(ReturnStmt return | - e = return.getExpr() and - // Only return statements which are not explicitly casted are considered - not exists(Cast c | not c.isImplicit() and c.getExpr() = e) - ) + exists(ReturnStmt return | e = return.getExpr().getExplicitlyConverted()) or - exists(FunctionCall call | - e = call.getAnArgument() and - // // Only function arguments which are not explicitly casted are considered - not exists(Cast c | not c.isImplicit() and c.getExpr() = e) - ) + exists(FunctionCall call | e = call.getAnArgument().getExplicitlyConverted()) ) or isCValue(e.(ParenthesisExpr).getExpr()) From 503830ae350fd6979d120ceb992ca855e28680ce Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 22 Nov 2024 20:36:39 -0800 Subject: [PATCH 106/628] Implement Concurrency8 package --- ...AppropriateThreadObjectStorageDurations.ql | 43 +- ...propriateStorageDurationsFunctionReturn.ql | 11 +- ...DoNotModifyObjectsWithTemporaryLifetime.ql | 12 +- ...uctsWithAFlexibleArrayMemberDynamically.ql | 20 +- ...odifyObjectsWithTemporaryLifetime.expected | 8 +- .../codingstandards/c/IdentifierLinkage.qll | 47 +++ c/common/src/codingstandards/c/Objects.qll | 393 ++++++++++++++++++ .../src/codingstandards/c/StorageDuration.qll | 31 ++ .../codingstandards/c/UninitializedMutex.qll | 0 .../IdentifierLinkage.expected | 10 + .../identifierlinkage/IdentifierLinkage.ql | 5 + .../identifierlinkage/identifierlinkage.c | 30 ++ .../library/objects/ObjectIdentity.expected | 21 + .../test/library/objects/ObjectIdentity.ql | 5 + .../test/library/objects/objectidentity.c | 41 ++ ...rayToPointerConversionOfTemporaryObject.ql | 6 +- ...eLValueSubscriptedWithTemporaryLifetime.ql | 40 +- .../NonstandardUseOfThreadingObject.ql | 54 +++ ...readingObjectWithInvalidStorageDuration.ql | 31 ++ .../MutexInitWithInvalidMutexType.ql | 36 ++ .../MutexInitializedInsideThread.ql | 27 ++ .../MutexNotInitializedBeforeUse.ql | 130 ++++++ .../MutexObjectsNotAlwaysUnlocked.ql | 52 +++ ...ointerConversionOfTemporaryObject.expected | 8 +- ...eSubscriptedWithTemporaryLifetime.expected | 6 +- .../NonstandardUseOfThreadingObject.expected | 27 ++ .../NonstandardUseOfThreadingObject.qlref | 1 + c/misra/test/rules/RULE-22-12/test.c | 65 +++ ...gObjectWithInvalidStorageDuration.expected | 13 + ...dingObjectWithInvalidStorageDuration.qlref | 1 + c/misra/test/rules/RULE-22-13/test.c | 53 +++ .../MutexInitWithInvalidMutexType.expected | 5 + .../MutexInitWithInvalidMutexType.qlref | 1 + .../MutexInitializedInsideThread.expected | 1 + .../MutexInitializedInsideThread.qlref | 1 + .../MutexNotInitializedBeforeUse.expected | 14 + .../MutexNotInitializedBeforeUse.qlref | 1 + c/misra/test/rules/RULE-22-14/test.c | 146 +++++++ .../MutexObjectsNotAlwaysUnlocked.expected | 7 + .../MutexObjectsNotAlwaysUnlocked.qlref | 1 + c/misra/test/rules/RULE-22-16/test.c | 107 +++++ change_notes/2024-11-27-c-object-refactor.md | 21 + ...24-11-27-raii-concurrency-analysis-perf.md | 2 + ...4-11-27-resource-leak-analysis-refactor.md | 10 + .../src/codingstandards/cpp/Clvalues.qll | 3 + .../src/codingstandards/cpp/Concurrency.qll | 67 ++- cpp/common/src/codingstandards/cpp/Type.qll | 26 +- .../cpp/exclusions/c/Concurrency8.qll | 112 +++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + .../cpp/lifetimes/CLifetimes.qll | 48 --- .../cpp/resources/ResourceLeakAnalysis.qll | 101 +++++ .../cpp/resources/ResourceManagement.qll | 75 ++-- .../ExceptionSafetyValidState.qll | 63 +-- .../ExceptionSafetyValidState.expected | 8 +- rule_packages/c/Concurrency8.json | 115 +++++ rules.csv | 8 +- 56 files changed, 1964 insertions(+), 209 deletions(-) create mode 100644 c/common/src/codingstandards/c/IdentifierLinkage.qll create mode 100644 c/common/src/codingstandards/c/Objects.qll create mode 100644 c/common/src/codingstandards/c/StorageDuration.qll create mode 100644 c/common/src/codingstandards/c/UninitializedMutex.qll create mode 100644 c/common/test/library/identifierlinkage/IdentifierLinkage.expected create mode 100644 c/common/test/library/identifierlinkage/IdentifierLinkage.ql create mode 100644 c/common/test/library/identifierlinkage/identifierlinkage.c create mode 100644 c/common/test/library/objects/ObjectIdentity.expected create mode 100644 c/common/test/library/objects/ObjectIdentity.ql create mode 100644 c/common/test/library/objects/objectidentity.c create mode 100644 c/misra/src/rules/RULE-22-12/NonstandardUseOfThreadingObject.ql create mode 100644 c/misra/src/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.ql create mode 100644 c/misra/src/rules/RULE-22-14/MutexInitWithInvalidMutexType.ql create mode 100644 c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql create mode 100644 c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql create mode 100644 c/misra/src/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.ql create mode 100644 c/misra/test/rules/RULE-22-12/NonstandardUseOfThreadingObject.expected create mode 100644 c/misra/test/rules/RULE-22-12/NonstandardUseOfThreadingObject.qlref create mode 100644 c/misra/test/rules/RULE-22-12/test.c create mode 100644 c/misra/test/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.expected create mode 100644 c/misra/test/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.qlref create mode 100644 c/misra/test/rules/RULE-22-13/test.c create mode 100644 c/misra/test/rules/RULE-22-14/MutexInitWithInvalidMutexType.expected create mode 100644 c/misra/test/rules/RULE-22-14/MutexInitWithInvalidMutexType.qlref create mode 100644 c/misra/test/rules/RULE-22-14/MutexInitializedInsideThread.expected create mode 100644 c/misra/test/rules/RULE-22-14/MutexInitializedInsideThread.qlref create mode 100644 c/misra/test/rules/RULE-22-14/MutexNotInitializedBeforeUse.expected create mode 100644 c/misra/test/rules/RULE-22-14/MutexNotInitializedBeforeUse.qlref create mode 100644 c/misra/test/rules/RULE-22-14/test.c create mode 100644 c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected create mode 100644 c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.qlref create mode 100644 c/misra/test/rules/RULE-22-16/test.c create mode 100644 change_notes/2024-11-27-c-object-refactor.md create mode 100644 change_notes/2024-11-27-raii-concurrency-analysis-perf.md create mode 100644 change_notes/2024-11-27-resource-leak-analysis-refactor.md create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency8.qll delete mode 100644 cpp/common/src/codingstandards/cpp/lifetimes/CLifetimes.qll create mode 100644 cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll create mode 100644 rule_packages/c/Concurrency8.json diff --git a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql index e0617c266d..6d9caacc5c 100644 --- a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql +++ b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql @@ -14,30 +14,39 @@ import cpp import codingstandards.c.cert +import codingstandards.c.Objects import codingstandards.cpp.Concurrency import codingstandards.cpp.dataflow.TaintTracking import codingstandards.cpp.dataflow.DataFlow import semmle.code.cpp.commons.Alloc -from C11ThreadCreateCall tcc, StackVariable sv, Expr arg, Expr acc +from C11ThreadCreateCall tcc, Expr arg where not isExcluded(tcc, Concurrency4Package::appropriateThreadObjectStorageDurationsQuery()) and tcc.getArgument(2) = arg and - sv.getAnAccess() = acc and - // a stack variable that is given as an argument to a thread - TaintTracking::localTaint(DataFlow::exprNode(acc), DataFlow::exprNode(arg)) and - // or isn't one of the allowed usage patterns - not exists(Expr mfc | - isAllocationExpr(mfc) and - sv.getAnAssignedValue() = mfc and - acc.getAPredecessor*() = mfc - ) and - not exists(TSSGetFunctionCall tsg, TSSSetFunctionCall tss, DataFlow::Node src | - sv.getAnAssignedValue() = tsg and - acc.getAPredecessor*() = tsg and - // there should be dataflow from somewhere (the same somewhere) - // into each of the first arguments - DataFlow::localFlow(src, DataFlow::exprNode(tsg.getArgument(0))) and - DataFlow::localFlow(src, DataFlow::exprNode(tss.getArgument(0))) + ( + exists(ObjectIdentity obj, Expr acc | + obj.getASubobjectAccess() = acc and + obj.getStorageDuration().isAutomatic() and + exists(DataFlow::Node addrNode | + ( + addrNode = DataFlow::exprNode(any(AddressOfExpr e | e.getOperand() = acc)) + or + addrNode = DataFlow::exprNode(acc) and exists(ArrayToPointerConversion c | c.getExpr() = acc) + ) and + TaintTracking::localTaint(addrNode, DataFlow::exprNode(arg)) + ) + ) + or + // TODO: Remove/replace with tss_t type check, see #801. + exists(TSSGetFunctionCall tsg | + TaintTracking::localTaint(DataFlow::exprNode(tsg), DataFlow::exprNode(arg)) and + not exists(TSSSetFunctionCall tss, DataFlow::Node src | + // there should be dataflow from somewhere (the same somewhere) + // into each of the first arguments + DataFlow::localFlow(src, DataFlow::exprNode(tsg.getArgument(0))) and + DataFlow::localFlow(src, DataFlow::exprNode(tss.getArgument(0))) + ) + ) ) select tcc, "$@ not declared with appropriate storage duration", arg, "Shared object" diff --git a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql index 9097f14297..1e1e19c7c6 100644 --- a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql +++ b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql @@ -13,10 +13,15 @@ import cpp import codingstandards.c.cert +import codingstandards.c.Objects import codingstandards.cpp.dataflow.DataFlow -class Source extends StackVariable { - Source() { not this instanceof Parameter } +class Source extends Expr { + ObjectIdentity rootObject; + Source() { + rootObject.getStorageDuration().isAutomatic() + and this = rootObject.getASubobjectAddressExpr() + } } class Sink extends DataFlow::Node { @@ -40,7 +45,7 @@ from DataFlow::Node src, DataFlow::Node sink where not isExcluded(sink.asExpr(), Declarations8Package::appropriateStorageDurationsFunctionReturnQuery()) and - exists(Source s | src.asExpr() = s.getAnAccess()) and + exists(Source s | src.asExpr() = s) and sink instanceof Sink and DataFlow::localFlow(src, sink) select sink, "$@ with automatic storage may be accessible outside of its lifetime.", src, diff --git a/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql b/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql index 6a018ed8c4..3689aa4397 100644 --- a/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql +++ b/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql @@ -13,15 +13,13 @@ import cpp import codingstandards.c.cert -import codingstandards.cpp.lifetimes.CLifetimes +import codingstandards.c.Objects // Note: Undefined behavior is possible regardless of whether the accessed field from the returned // struct is an array or a scalar (i.e. arithmetic and pointer types) member, according to the standard. -from FieldAccess fa, FunctionCall fc +from FieldAccess fa, TemporaryObjectIdentity tempObject where not isExcluded(fa, InvalidMemory2Package::doNotModifyObjectsWithTemporaryLifetimeQuery()) and - not fa.getQualifier().isLValue() and - fa.getQualifier().getUnconverted() = fc and - fa.getQualifier().getUnconverted().getUnspecifiedType() instanceof StructOrUnionTypeWithArrayField -select fa, "Field access on $@ qualifier occurs after its temporary object lifetime.", fc, - "function call" + fa.getQualifier().getUnconverted() = tempObject +select fa, "Field access on $@ qualifier occurs after its temporary object lifetime.", tempObject, + "temporary object" diff --git a/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql b/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql index 620c4486a9..4e4ccc2171 100644 --- a/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql +++ b/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql @@ -14,6 +14,7 @@ import cpp import codingstandards.c.cert import codingstandards.c.Variable +import codingstandards.c.Objects import semmle.code.cpp.models.interfaces.Allocation import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis @@ -21,7 +22,7 @@ abstract class FlexibleArrayAlloc extends Element { /** * Returns the `Variable` being allocated. */ - abstract Variable getVariable(); + abstract Element getReportElement(); } /** @@ -53,18 +54,25 @@ class FlexibleArrayStructDynamicAlloc extends FlexibleArrayAlloc, FunctionCall { ) } - override Variable getVariable() { result = v } + override Element getReportElement() { result = v } } /** * A `Variable` of type `FlexibleArrayStructType` that is not allocated dynamically. */ -class FlexibleArrayNonDynamicAlloc extends FlexibleArrayAlloc, Variable { +class FlexibleArrayNonDynamicAlloc extends FlexibleArrayAlloc { + ObjectIdentity object; FlexibleArrayNonDynamicAlloc() { - this.getUnspecifiedType().getUnspecifiedType() instanceof FlexibleArrayStructType + this = object and + not object.getStorageDuration().isAllocated() and + // Exclude temporaries. Though they should violate this rule, in practice these results are + // often spurious and redundant, such as (*x = *x) which creates an unused temporary object. + not object.hasTemporaryLifetime() and + object.getType().getUnspecifiedType() instanceof FlexibleArrayStructType + and not exists(Variable v | v.getInitializer().getExpr() = this) } - override Variable getVariable() { result = this } + override Element getReportElement() { result = object } } from FlexibleArrayAlloc alloc, string message @@ -77,4 +85,4 @@ where alloc instanceof FlexibleArrayNonDynamicAlloc and message = "$@ contains a flexible array member but is not dynamically allocated." ) -select alloc, message, alloc.getVariable(), alloc.getVariable().getName() +select alloc, message, alloc.getReportElement(), alloc.getReportElement().toString() diff --git a/c/cert/test/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.expected b/c/cert/test/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.expected index f14ab4de4a..3fb10f3267 100644 --- a/c/cert/test/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.expected +++ b/c/cert/test/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.expected @@ -1,4 +1,4 @@ -| test.c:65:18:65:18 | a | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:65:9:65:14 | call to get_s1 | function call | -| test.c:67:18:67:19 | s1 | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:67:9:67:14 | call to get_s3 | function call | -| test.c:68:18:68:19 | i1 | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:68:9:68:14 | call to get_s3 | function call | -| test.c:69:18:69:21 | af12 | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:69:9:69:14 | call to get_s4 | function call | +| test.c:65:18:65:18 | a | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:65:9:65:14 | call to get_s1 | temporary object | +| test.c:67:18:67:19 | s1 | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:67:9:67:14 | call to get_s3 | temporary object | +| test.c:68:18:68:19 | i1 | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:68:9:68:14 | call to get_s3 | temporary object | +| test.c:69:18:69:21 | af12 | Field access on $@ qualifier occurs after its temporary object lifetime. | test.c:69:9:69:14 | call to get_s4 | temporary object | diff --git a/c/common/src/codingstandards/c/IdentifierLinkage.qll b/c/common/src/codingstandards/c/IdentifierLinkage.qll new file mode 100644 index 0000000000..085ebf5a7b --- /dev/null +++ b/c/common/src/codingstandards/c/IdentifierLinkage.qll @@ -0,0 +1,47 @@ +import cpp + +newtype TIdentifierLinkage = + TIdentifierLinkageExternal() or + TIdentifierLinkageInternal() or + TIdentifierLinkageNone() + +/** + * In C, identifiers have internal linkage, or external linkage, or no linkage (6.2.2.1). + * + * The linkage of an identifier is used to, among other things, determine the storage duration + * and/or lifetime of that identifier. Storage durations and lifetimes are often used to define + * rules in the various coding standards. + */ +class IdentifierLinkage extends TIdentifierLinkage { + predicate isExternal() { this = TIdentifierLinkageExternal() } + + predicate isInternal() { this = TIdentifierLinkageInternal() } + + predicate isNone() { this = TIdentifierLinkageNone() } + + string toString() { + this.isExternal() and result = "external linkage" + or + this.isInternal() and result = "internal linkage" + or + this.isNone() and result = "no linkage" + } +} + +/** + * Determine the linkage of a variable: external, or static, or none. + * + * The linkage of a variable is determined by its scope and storage class. Note that other types of + * identifiers (e.g. functions) may also have linkage, but that behavior is not covered in this + * predicate. + */ +IdentifierLinkage linkageOfVariable(Variable v) { + // 6.2.2.3, file scope identifiers marked static have internal linkage. + v.isTopLevel() and v.isStatic() and result.isInternal() + or + // 6.2.2.4 describes generally non-static file scope identifiers, which have external linkage. + v.isTopLevel() and not v.isStatic() and result.isExternal() + or + // Note: Not all identifiers have linkage, see 6.2.2.6 + not v.isTopLevel() and result.isNone() +} diff --git a/c/common/src/codingstandards/c/Objects.qll b/c/common/src/codingstandards/c/Objects.qll new file mode 100644 index 0000000000..105291c688 --- /dev/null +++ b/c/common/src/codingstandards/c/Objects.qll @@ -0,0 +1,393 @@ +import cpp +import codingstandards.c.StorageDuration +import codingstandards.c.IdentifierLinkage +import semmle.code.cpp.valuenumbering.HashCons +import codingstandards.cpp.Clvalues + +/** + * A libary for handling "Objects" in C. + * + * Objects may be stored in registers or memory, they have an address, a type, a storage duration, + * and a lifetime (which is different than storage duration). Objects which are structs or arrays + * have subobjects, which share the storage duration and lifetime of the parent object. + * + * Note: lifetime analysis is not performed in this library, but is available in + * the module `codingstandards.cpp.lifetimes.LifetimeProfile`. In the future, these libraries could + * be merged for more complete analysis. + * + * To get objects in a project, use the `ObjectIdentity` class which finds the following types of + * objects: + * - global variables + * - local variables + * - literals + * - malloc calls + * - certain temporary object expressions + * + * And direct references to these objects can be found via the member predicate `getAnAccess()`. + * However, much of a project's code will not refer to these objects directly, but rather, refer to + * their subobjects. The class `ObjectIdentity` exposes several member predicates for finding when + * these subobjects are used: + * - `getASubobjectType()` + * - `getASubobjectAccess()` + * - `getASubobjectAddressExpr()` + * + * These methods do not use flow analysis, and will not return a conclusive list of accesses. To + * get better results here, this library should be integrated with flow analysis or the library + * `LifetimeProfile.qll`. + * + * Additionally, subobjects are currently not tracked individually. In the future subobjects could + * be tracked as a root object and an access chain to refer to them. For now, however, finding *any* + * subobject access is sufficient for many analyses. + * + * To get the storage duration, `ObjectIdentity` exposes the member predicate + * `getStorageDuration()` with the following options: + * - `obj.getStorageDuration().isAutomatic()`: Stack objects + * - `obj.getStorageDuration().isStatic()`: Global objects + * - `obj.getStorageDuration().isThread()`: Threadlocal objects + * - `obj.getStorageDuration().isAllocated()`: Dynamic objects + * + * Note that lifetimes are not storage durations. The only lifetime tracking currently implemented + * is `hasTemporaryLifetime()`, which is a subset of automatic storage duration objects, and may + * be filtered out, or selected directly with `TemporaryObjectIdentity`. + */ +final class ObjectIdentity = ObjectIdentityBase; + +/** + * A base class for objects in C, along with the source location where the object can be identified + * in the project code (thus, this class extends `Element`), which may be variable, or may be an + * expression such as a literal or a malloc call. + * + * Extend this class to define a new type of object identity. To create a class which filters the + * set of object identities, users of this library should extend the final subclass + * `ObjectIdentity` instead. + */ +abstract class ObjectIdentityBase extends Element { + /** + * The type of this object. + * + * Note that for allocated objects, this is inferred from the sizeof() statement or the variable + * it is assigned to. + */ + abstract Type getType(); + + /* The storage duration of this object: static, thread, automatic, or allocated. */ + abstract StorageDuration getStorageDuration(); + + /** + * Get the nested objects within this object (members, array element types). + * + * Note that if a struct has a pointer member, the pointer itself is a subobject, but the value + * it points to is not. Therefore `struct { int* x; }` has a subobject of type `int*`, but not + * `int`. + */ + Type getASubObjectType() { result = getADirectSubobjectType*(getType()) } + + /** + * Get expressions which trivially access this object. Does not perform flow analysis. + * + * For dynamically allocated objects, this is a dereference of the malloc call. + */ + abstract Expr getAnAccess(); + + /** + * Get expressions which trivially access this object or a subobject of this object. Does not + * perform flow analysis. + * + * For dynamically allocated objects, this is a dereference of the malloc call or direct access + * of the result of dereferencing the malloc call. + */ + Expr getASubobjectAccess() { result = getASubobjectAccessOf(getAnAccess()) } + + /** + * Get expressions which trivially take the address of this object or a subobject of this object. + * Does not perform flow analysis. + */ + Expr getASubobjectAddressExpr() { + exists(Expr subobject | + subobject = getASubobjectAccess() and + ( + result = any(AddressOfExpr e | e.getOperand() = subobject) + or + exists(ArrayToPointerConversion c | c.getExpr() = subobject) and + not exists(ArrayExpr a | a.getArrayBase() = subobject) and + result = subobject + ) + ) + } + + /** + * Holds if the object has temporary lifetime. This is not a storage duration, but only objects + * with automatic storage duration have temporary lifetime. + */ + abstract predicate hasTemporaryLifetime(); +} + +/** + * Finds expressions `e.x` or `e[x]` for expression `e`, recursively. Does not resolve pointers. + * + * Note that this does not hold for `e->x` or `e[x]` where `e` is a pointer. + */ +private Expr getASubobjectAccessOf(Expr e) { + result = e + or + result.(DotFieldAccess).getQualifier() = getASubobjectAccessOf(e) + or + result.(ArrayExpr).getArrayBase() = getASubobjectAccessOf(e) and + not result.(ArrayExpr).getArrayBase().getUnspecifiedType() instanceof PointerType +} + +/** + * Find the object types that are embedded within the current type. + * + * For example, a block of memory with type `T[]` has subobjects of type `T`, and a struct with a + * member of `T member;` has a subobject of type `T`. + * + * Note that subobjects may be pointers, but the value they point to is not a subobject. For + * instance, `struct { int* x; }` has a subobject of type `int*`, but not `int`. + */ +Type getADirectSubobjectType(Type type) { + result = type.stripTopLevelSpecifiers().(Struct).getAMember().getADeclarationEntry().getType() + or + result = type.stripTopLevelSpecifiers().(ArrayType).getBaseType() +} + +/** + * An object in memory which may be identified by the variable that holds it. + * + * This may be a local variable, a global variable, or a parameter, etc. However, it cannot be a + * member of a struct or union, as these do not have storage duration. + */ +class VariableObjectIdentity extends Variable, ObjectIdentityBase { + VariableObjectIdentity() { + // Exclude members; member definitions does not allocate storage and thus do not have a storage + // duration. They are therefore not objects. To get the storage duration of members, use one of + // the predicates related to sub objects, e.g. `getASubObjectType()`. + not isMember() + } + + override StorageDuration getStorageDuration() { + // 6.2.4.4, objects declared _Thread_local have thread storage duration. + isThreadLocal() and result.isThread() + or + // 6.2.4.3, Non _ThreadLocal objects with internal or external linkage or declared static have + // static storage duration. + not isThreadLocal() and + (hasLinkage() or isStatic()) and + result.isStatic() + or + // 6.2.4.3, Non _ThreadLocal objects no linkage that are not static have automatic storage + // duration. + not isThreadLocal() and + not hasLinkage() and + not isStatic() and + result.isAutomatic() + } + + override Type getType() { + // Caution here: If we use `Variable.super.getType()` then override resolution is skipped, and + // it uses the base predicate defined as `none()`. By casting this to `Variable` and calling + // `getType()`, all overrides (harmlessly, *including this one*...) are considered, which means + // we defer to the subclasses such as `GlobalVariable` overrides of `getType()`, which is what + // we want. + result = this.(Variable).getType() + } + + /* The storage duration of a variable depends on its linkage. */ + IdentifierLinkage getLinkage() { result = linkageOfVariable(this) } + + predicate hasLinkage() { not getLinkage().isNone() } + + override VariableAccess getAnAccess() { result = Variable.super.getAnAccess() } + + override predicate hasTemporaryLifetime() { + none() // Objects identified by a variable do not have temporary lifetime. + } +} + +/** + * A string literal is an object with static storage duration. + * + * 6.4.5.6, multibyte character sequences initialize an array of static storage duration. + */ +class LiteralObjectIdentity extends Literal, ObjectIdentityBase { + override StorageDuration getStorageDuration() { result.isStatic() } + + override Type getType() { result = Literal.super.getType() } + + override Expr getAnAccess() { result = this } + + override predicate hasTemporaryLifetime() { + none() // String literal objects do not have temporary lifetime. + } +} + +/** + * An object identifiable as a struct or array literal, which is an lvalue that may have static or + * automatic storage duration depending on context. + * + * 6.5.2.5.5, compound literals outside of a function have static storage duration, while literals + * inside a function have automatic storage duration. + */ +class AggregateLiteralObjectIdentity extends AggregateLiteral, ObjectIdentityBase { + override StorageDuration getStorageDuration() { + if exists(getEnclosingFunction()) then result.isAutomatic() else result.isStatic() + } + + override Type getType() { result = AggregateLiteral.super.getType() } + + override Expr getAnAccess() { result = this } + + override predicate hasTemporaryLifetime() { + // Confusing; a struct literal is an lvalue, and therefore does not have temporary lifetime. + none() + } +} + +/** + * An object identified by a call to `malloc`. + * + * Note: the malloc expression returns an address to this object, not the object itself. Therefore, + * `getAnAccess()` returns cases where this malloc result is dereferenced, and not the malloc call + * itself. + * + * Note that the predicates for tracking accesses, subobject accesses, and address expresisons may + * be less reliable as dynamic memory is fundamentally more difficult to track. However, this class + * attempts to give reasonable results. In the future, this could be improved by integrating with + * LifetimeProfile.qll or by integrating flow analysis. + * + * Additionally, the type of this object is inferred based on its size and use. + */ +class AllocatedObjectIdentity extends AllocationExpr, ObjectIdentityBase { + AllocatedObjectIdentity() { + this.(FunctionCall).getTarget().(AllocationFunction).requiresDealloc() + } + + override StorageDuration getStorageDuration() { result.isAllocated() } + + /** Attempt to infer the type of the allocated memory */ + override Type getType() { result = this.getAllocatedElementType() } + + /** Find dereferences of direct aliases of this pointer result. */ + override Expr getAnAccess() { result.(PointerDereferenceExpr).getOperand() = getAnAlias() } + + /** + * Find the following subobject accesses, given a pointer alias `x`: + * - `(*x)` + * - `(*x).y` + * - `(*x)[i]` + * - `x->y` + * - `x[i]` + * - `x->y.z` + * - `x[i].y` + * - all direct accesses (`foo.x`, `foo[i]`) of the above + */ + override Expr getASubobjectAccess() { + result = getASubobjectAccessOf(getAnAccess()) + or + exists(PointerFieldAccess pfa | + pfa.getQualifier() = getASubobjectAddressExpr() and + result = getASubobjectAccessOf(pfa) + ) + or + exists(ArrayExpr arrayExpr | + arrayExpr.getArrayBase() = getASubobjectAddressExpr() and + result = getASubobjectAccessOf(arrayExpr) + ) + } + + /** + * Given a pointer alias `x`, finds `x` itself. Additionally, defers to the default class + * behavior, which finds address-of (`&`) and array-to-pointer conversions of all subobject + * accesses. (See `AllocatedObjectIdentity.getASubobjectAccess()`.) + */ + override Expr getASubobjectAddressExpr() { + result = getAnAlias() + or + result = super.getASubobjectAddressExpr() + } + + /** + * Find an obvious direct reference to the result of a `malloc()` function call. This includes + * the function call itself, but additionally: + * - For `T* x = malloc(...)`, accesses to variable `x` are likely aliases of the malloc result + * - For `(expr) = malloc(...)` future lexically identical uses of `expr` are likely aliases of + * the malloc result. + * + * This is used so that member predicates such as `getAnAccess()`, `getASubobjectAccess()` can + * find cases such as: + * + * ```c + * int *x = malloc(sizeof(int)); + * return *x; // accesses the malloc result + * ``` + */ + Expr getAnAlias() { + result = this + or + exists(AssignExpr assignExpr | + assignExpr.getRValue() = this and + hashCons(result) = hashCons(assignExpr.getLValue()) + ) + or + exists(Variable v | + v.getInitializer().getExpr() = this and + result = v.getAnAccess() + ) + } + + override predicate hasTemporaryLifetime() { + none() // Allocated objects do not have "temporary lifetime." + } +} + +/** + * A struct or union type that contains an array type, used to find objects with temporary + * lifetime. + */ +private class StructOrUnionTypeWithArrayField extends Struct { + StructOrUnionTypeWithArrayField() { + this.getAField().getUnspecifiedType() instanceof ArrayType + or + // nested struct or union containing an array type + this.getAField().getUnspecifiedType().(Struct) instanceof StructOrUnionTypeWithArrayField + } +} + +/** + * 6.2.4.7, A non-lvalue expression with struct or or union type that has a field member of array + * type, refers to an object with automatic storage duration (and has temporary lifetime). + * + * The spec uses the lanugage "refers to." This is likely intended to mean that the expression + * `foo().x` does not create a new temporary object, but rather "refers to" the temporary object + * storing the value of the expression `foo()`. + * + * Separate this predicate to avoid non-monotonic recursion (`C() { not exists(C c | ... ) }`). + */ +private class TemporaryObjectIdentityExpr extends Expr { + TemporaryObjectIdentityExpr() { + getType() instanceof StructOrUnionTypeWithArrayField and + not isCLValue(this) + } +} + +/** + * 6.2.4.7, A non-lvalue expression with struct or or union type that has a field member of array + * type, is an object with automatic storage duration (and has temporary lifetime). + */ +class TemporaryObjectIdentity extends ObjectIdentityBase instanceof TemporaryObjectIdentityExpr { + TemporaryObjectIdentity() { + // See comment in `TemporaryObjectIdentityExpr` for why we check `getASubobjectAccess()` here. + not exists(TemporaryObjectIdentityExpr parent | + this = getASubobjectAccessOf(parent) and + not this = parent + ) + } + + override StorageDuration getStorageDuration() { result.isAutomatic() } + + override Type getType() { result = this.(Expr).getType() } + + override Expr getAnAccess() { result = this } + + override predicate hasTemporaryLifetime() { any() } +} diff --git a/c/common/src/codingstandards/c/StorageDuration.qll b/c/common/src/codingstandards/c/StorageDuration.qll new file mode 100644 index 0000000000..4669d467bb --- /dev/null +++ b/c/common/src/codingstandards/c/StorageDuration.qll @@ -0,0 +1,31 @@ +import cpp + +class DeclarationWithStorageDuration extends Declaration { } + +newtype TStorageDuration = + StorageDurationStatic() or + StorageDurationAutomatic() or + StorageDurationThread() or + StorageDurationAllocated() + +class StorageDuration extends TStorageDuration { + predicate isStatic() { this = StorageDurationStatic() } + + predicate isAutomatic() { this = StorageDurationAutomatic() } + + predicate isThread() { this = StorageDurationThread() } + + predicate isAllocated() { this = StorageDurationAllocated() } + + string toString() { result = getStorageTypeName() + " storage duration" } + + string getStorageTypeName() { + isStatic() and result = "static" + or + isAutomatic() and result = "automatic" + or + isThread() and result = "thread" + or + isAllocated() and result = "allocated" + } +} diff --git a/c/common/src/codingstandards/c/UninitializedMutex.qll b/c/common/src/codingstandards/c/UninitializedMutex.qll new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/common/test/library/identifierlinkage/IdentifierLinkage.expected b/c/common/test/library/identifierlinkage/IdentifierLinkage.expected new file mode 100644 index 0000000000..c3f1bc39ef --- /dev/null +++ b/c/common/test/library/identifierlinkage/IdentifierLinkage.expected @@ -0,0 +1,10 @@ +| identifierlinkage.c:2:5:2:10 | g_ext1 | external linkage | +| identifierlinkage.c:3:12:3:17 | g_ext2 | external linkage | +| identifierlinkage.c:6:12:6:17 | g_int1 | internal linkage | +| identifierlinkage.c:9:5:9:10 | g_ext3 | external linkage | +| identifierlinkage.c:12:12:12:17 | g_int2 | internal linkage | +| identifierlinkage.c:15:12:15:12 | p | no linkage | +| identifierlinkage.c:16:7:16:13 | l_none1 | no linkage | +| identifierlinkage.c:17:14:17:20 | l_none2 | no linkage | +| identifierlinkage.c:18:14:18:19 | l_ext1 | external linkage | +| identifierlinkage.c:24:7:24:7 | m | no linkage | diff --git a/c/common/test/library/identifierlinkage/IdentifierLinkage.ql b/c/common/test/library/identifierlinkage/IdentifierLinkage.ql new file mode 100644 index 0000000000..37e5b4cd58 --- /dev/null +++ b/c/common/test/library/identifierlinkage/IdentifierLinkage.ql @@ -0,0 +1,5 @@ +import codingstandards.c.IdentifierLinkage + +from Variable v +where not v.getLocation().toString() = "file://:0:0:0:0" +select v, linkageOfVariable(v) diff --git a/c/common/test/library/identifierlinkage/identifierlinkage.c b/c/common/test/library/identifierlinkage/identifierlinkage.c new file mode 100644 index 0000000000..cf6b439797 --- /dev/null +++ b/c/common/test/library/identifierlinkage/identifierlinkage.c @@ -0,0 +1,30 @@ +// Simple external linkage +int g_ext1; +extern int g_ext2; + +// Simple internal linkage +static int g_int1; + +// Redefined maintaining linkage +int g_ext3; +extern int g_ext3; + +static int g_int2; +extern int g_int2; + +void f(int p) { + int l_none1; + static int l_none2; + extern int l_ext1; +} + +// Structs are not variables +struct s { + // Struct members are variables with no linkage. + int m; +}; + +// Enums and enum constants are not variables and have no linkage. +enum e { + E1 +}; \ No newline at end of file diff --git a/c/common/test/library/objects/ObjectIdentity.expected b/c/common/test/library/objects/ObjectIdentity.expected new file mode 100644 index 0000000000..34be1974f5 --- /dev/null +++ b/c/common/test/library/objects/ObjectIdentity.expected @@ -0,0 +1,21 @@ +| objectidentity.c:3:5:3:14 | g_statstg1 | static storage duration | file://:0:0:0:0 | int | +| objectidentity.c:4:12:4:21 | g_statstg2 | static storage duration | file://:0:0:0:0 | int | +| objectidentity.c:5:12:5:21 | g_statstg3 | static storage duration | file://:0:0:0:0 | int | +| objectidentity.c:8:13:8:22 | p_autostg1 | automatic storage duration | file://:0:0:0:0 | int | +| objectidentity.c:8:31:8:40 | l_autostg2 | automatic storage duration | file://:0:0:0:0 | int | +| objectidentity.c:12:14:12:23 | l_statstg1 | static storage duration | file://:0:0:0:0 | int | +| objectidentity.c:13:14:13:23 | l_statstg2 | static storage duration | file://:0:0:0:0 | int | +| objectidentity.c:17:15:17:24 | g_thrdstg1 | thread storage duration | file://:0:0:0:0 | int | +| objectidentity.c:18:22:18:31 | g_thrdstg2 | thread storage duration | file://:0:0:0:0 | int | +| objectidentity.c:19:22:19:31 | g_thrdstg3 | thread storage duration | file://:0:0:0:0 | int | +| objectidentity.c:21:24:21:33 | l_statstg3 | thread storage duration | file://:0:0:0:0 | int | +| objectidentity.c:22:24:22:33 | l_statstg4 | thread storage duration | file://:0:0:0:0 | int | +| objectidentity.c:35:11:35:20 | g_statstg4 | static storage duration | file://:0:0:0:0 | s * | +| objectidentity.c:35:35:35:37 | {...} | static storage duration | objectidentity.c:27:8:27:8 | s | +| objectidentity.c:35:36:35:36 | 0 | static storage duration | file://:0:0:0:0 | int | +| objectidentity.c:36:7:36:16 | g_statstg5 | static storage duration | file://:0:0:0:0 | char * | +| objectidentity.c:36:20:36:26 | hello | static storage duration | file://:0:0:0:0 | char[6] | +| objectidentity.c:38:3:38:3 | 1 | static storage duration | file://:0:0:0:0 | int | +| objectidentity.c:39:3:39:9 | hello | static storage duration | file://:0:0:0:0 | char[6] | +| objectidentity.c:40:3:40:15 | {...} | automatic storage duration | objectidentity.c:27:8:27:8 | s | +| objectidentity.c:40:14:40:14 | 1 | static storage duration | file://:0:0:0:0 | int | diff --git a/c/common/test/library/objects/ObjectIdentity.ql b/c/common/test/library/objects/ObjectIdentity.ql new file mode 100644 index 0000000000..28e6832bb2 --- /dev/null +++ b/c/common/test/library/objects/ObjectIdentity.ql @@ -0,0 +1,5 @@ +import codingstandards.c.Objects + +from ObjectIdentity obj +where obj.getFile().getBaseName() = "objectidentity.c" +select obj, obj.getStorageDuration(), obj.getType() \ No newline at end of file diff --git a/c/common/test/library/objects/objectidentity.c b/c/common/test/library/objects/objectidentity.c new file mode 100644 index 0000000000..066f68b1fd --- /dev/null +++ b/c/common/test/library/objects/objectidentity.c @@ -0,0 +1,41 @@ +#include "threads.h" +// Basic static storage duration +int g_statstg1; +extern int g_statstg2; +static int g_statstg3; + +// Basic automatic storage duration +void f1(int p_autostg1) { int l_autostg2; } + +// Block identifiers with static storage duration +void f2(void) { + extern int l_statstg1; + static int l_statstg2; +} + +// Thread storage duration +_Thread_local g_thrdstg1; +extern _Thread_local g_thrdstg2; +static _Thread_local g_thrdstg3; +void f3() { + extern _Thread_local l_statstg3; + static _Thread_local l_statstg4; +} + +// Struct declarations do not allocate storage, and do not have a storage +// duration. +struct s { + int m; +}; + +// Enums and enum constants are not variables and have no linkage. +enum e { E1 }; + +// Various literals: +struct s *g_statstg4 = &(struct s){0}; +char *g_statstg5 = "hello"; +void f4(void) { + 1; + "hello"; + (struct s){1}; +} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql b/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql index 5317966f3b..c65890f6bc 100644 --- a/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql +++ b/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.lifetimes.CLifetimes +import codingstandards.c.Objects /** * Holds if the value of an expression is used or stored. @@ -59,11 +59,11 @@ Expr temporaryObjectFlowStep(Expr e) { } from - TemporaryLifetimeArrayAccess fa, TemporaryLifetimeExpr temporary, + FieldAccess fa, TemporaryObjectIdentity temporary, ArrayToPointerConversion conversion where not isExcluded(conversion, InvalidMemory3Package::arrayToPointerConversionOfTemporaryObjectQuery()) and - fa.getTemporary() = temporary and + fa = temporary.getASubobjectAccess() and conversion.getExpr() = fa and isUsedOrStored(temporaryObjectFlowStep*(conversion.getExpr())) select conversion, "Array to pointer conversion of array $@ from temporary object $@.", diff --git a/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql b/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql index f8a341b9bd..e10b478ee7 100644 --- a/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql +++ b/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql @@ -15,45 +15,31 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.lifetimes.CLifetimes +import codingstandards.c.Objects +import codeql.util.Boolean -class TemporaryLifetimeArrayExpr extends ArrayExpr { - TemporaryLifetimeArrayAccess member; - Type elementType; - - TemporaryLifetimeArrayExpr() { - member = getArrayBase() and - elementType = member.getType().(ArrayType).getBaseType() - or - exists(TemporaryLifetimeArrayExpr inner | - inner = getArrayBase() and - member = inner.getMember() and - elementType = inner.getElementType().(ArrayType).getBaseType() - ) - } - - TemporaryLifetimeArrayAccess getMember() { result = member } - - Type getElementType() { result = elementType } -} - -predicate usedAsModifiableLvalue(Expr expr) { +predicate usedAsModifiableLvalue(Expr expr, Boolean allowArrayAccess) { exists(Assignment parent | parent.getLValue() = expr) or exists(CrementOperation parent | parent.getOperand() = expr) or exists(AddressOfExpr parent | parent.getOperand() = expr) or - exists(FieldAccess parent | parent.getQualifier() = expr and usedAsModifiableLvalue(parent)) + // Don't report `x.y[0].m[0]++` twice. Recurse with `allowArrayAccess` set to false. + exists(FieldAccess parent | parent.getQualifier() = expr and usedAsModifiableLvalue(parent, false)) + or + allowArrayAccess = true and + exists(ArrayExpr parent | parent.getArrayBase() = expr and usedAsModifiableLvalue(parent, true)) } -from TemporaryLifetimeArrayExpr expr, TemporaryLifetimeArrayAccess member +from ArrayExpr expr, FieldAccess fieldAccess, TemporaryObjectIdentity tempObject where not isExcluded(expr, InvalidMemory3Package::modifiableLValueSubscriptedWithTemporaryLifetimeQuery()) and - member = expr.getMember() and + expr = tempObject.getASubobjectAccess() and + fieldAccess = expr.getArrayBase() and not expr.isUnevaluated() and - usedAsModifiableLvalue(expr) + usedAsModifiableLvalue(expr, true) select expr, "Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ ", - member, member.getTarget().getName(), member.getTemporary(), member.getTemporary().toString() + fieldAccess, fieldAccess.getTarget().getName(), tempObject, tempObject.toString() diff --git a/c/misra/src/rules/RULE-22-12/NonstandardUseOfThreadingObject.ql b/c/misra/src/rules/RULE-22-12/NonstandardUseOfThreadingObject.ql new file mode 100644 index 0000000000..d92b4ccea6 --- /dev/null +++ b/c/misra/src/rules/RULE-22-12/NonstandardUseOfThreadingObject.ql @@ -0,0 +1,54 @@ +/** + * @id c/misra/nonstandard-use-of-threading-object + * @name RULE-22-12: Standard library threading objects (mutexes, threads, etc.) shall only be accessed by the appropriate Standard Library functions + * @description Thread objects, thread synchronization objects, and thread-specific storage pointers + * shall only be accessed by the appropriate Standard Library functions. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-22-12 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Concurrency +import codingstandards.cpp.Type + +predicate isThreadingObject(Type t) { t instanceof PossiblySpecified::Type } + +predicate validUseOfStdThreadObject(Expr e) { + e.getParent() instanceof AddressOfExpr + or + exists(Call c | + c.getTarget().hasName(["tss_get", "tss_set", "tss_delete"]) and + e = c.getArgument(0) + ) +} + +predicate isStdThreadObjectPtr(Type t) { isThreadingObject(t.(PointerType).getBaseType()) } + +predicate invalidStdThreadObjectUse(Expr e) { + // Invalid use of mtx_t, etc. + isThreadingObject(e.getType()) and + not validUseOfStdThreadObject(e) + or + // Invalid cast from mtx_t* to void*, etc. + isStdThreadObjectPtr(e.getType()) and + exists(Cast cast | + cast.getExpr() = e and + not isStdThreadObjectPtr(cast.getType()) + ) +} + +from Expr e +where + not isExcluded(e, Concurrency8Package::nonstandardUseOfThreadingObjectQuery()) and + invalidStdThreadObjectUse(e) and + // Deduplicate results: (mtx = mtx) is an expression of mtx type, but don't flag the equality + // check, only flag the two `mtx` references. + not invalidStdThreadObjectUse(e.getAChild+()) +select e, "Invalid usage of standard thread object type '" + e.getType().toString() + "'." diff --git a/c/misra/src/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.ql b/c/misra/src/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.ql new file mode 100644 index 0000000000..066cf3c295 --- /dev/null +++ b/c/misra/src/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.ql @@ -0,0 +1,31 @@ +/** + * @id c/misra/threading-object-with-invalid-storage-duration + * @name RULE-22-13: Threading objects (mutexes, threads, etc). shall have not have automatic or thread storage duration + * @description Thread objects, thread synchronization objects, and thread specific storage pointers + * shall have appropriate storage duration. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-22-13 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Objects +import codingstandards.cpp.Concurrency +import codingstandards.cpp.Type + +from ObjectIdentity obj, StorageDuration storageDuration, Type type +where + not isExcluded(obj, Concurrency8Package::threadingObjectWithInvalidStorageDurationQuery()) and + storageDuration = obj.getStorageDuration() and + not storageDuration.isStatic() and + type = obj.getASubObjectType() and + type instanceof PossiblySpecified::Type +select obj, + "Object of type '" + obj.getType().getName() + "' has invalid storage duration type '" + + storageDuration.getStorageTypeName() + "'." diff --git a/c/misra/src/rules/RULE-22-14/MutexInitWithInvalidMutexType.ql b/c/misra/src/rules/RULE-22-14/MutexInitWithInvalidMutexType.ql new file mode 100644 index 0000000000..a122a0bec4 --- /dev/null +++ b/c/misra/src/rules/RULE-22-14/MutexInitWithInvalidMutexType.ql @@ -0,0 +1,36 @@ +/** + * @id c/misra/mutex-init-with-invalid-mutex-type + * @name RULE-22-14: Mutexes shall be initialized with a valid mutex type + * @description Mutexes shall be initialized with a valid mutex type. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-14 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Concurrency + +predicate isBaseMutexType(EnumConstantAccess access) { + access.getTarget().hasName(["mtx_plain", "mtx_timed"]) +} + +predicate isValidMutexType(Expr expr) { + isBaseMutexType(expr) + or + exists(BinaryBitwiseOperation binOr | binOr = expr | + isBaseMutexType(binOr.getLeftOperand()) and + binOr.getRightOperand().(EnumConstantAccess).getTarget().hasName("mtx_recursive") + ) +} + +from C11MutexSource init +where + not isExcluded(init, Concurrency8Package::mutexInitWithInvalidMutexTypeQuery()) and + not isValidMutexType(init.getMutexTypeExpr()) +select init, "Mutex initialized with incorrect type expression." diff --git a/c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql b/c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql new file mode 100644 index 0000000000..649c941e66 --- /dev/null +++ b/c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql @@ -0,0 +1,27 @@ +/** + * @id c/misra/mutex-initialized-inside-thread + * @name RULE-22-14: Thread synchronization objects shall be initialized deterministically + * @description Mutex and condition objects initialized inside of threads may result in + * indeterministic state + * @kind problem + * @precision high + * @problem.severity recommendation + * @tags external/misra/id/rule-22-14 + * readability + * maintainability + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Concurrency + +from C11MutexSource mutexCreate, ThreadedFunction thread +where + not isExcluded(mutexCreate, Concurrency8Package::mutexInitializedInsideThreadQuery()) and + thread.calls*(mutexCreate.getEnclosingFunction()) +select +mutexCreate, "Mutex initialization reachable from threaded function '$@'.", +thread, thread.getName() diff --git a/c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql b/c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql new file mode 100644 index 0000000000..ed4226c207 --- /dev/null +++ b/c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql @@ -0,0 +1,130 @@ +/** + * @id c/misra/mutex-not-initialized-before-use + * @name RULE-22-14: Thread synchronization objects shall be initialized before being accessed + * @description Mutex and condition objects shall be initialized with the standard library functions + * before using them. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-14 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Objects +import codingstandards.cpp.Concurrency +import codingstandards.cpp.Type + +/** A function which is not called or started as a thread */ +class RootFunction extends Function { + RootFunction() { + not exists(Function f | f.calls(this)) and + not this instanceof ThreadedFunction + } +} + +/** A function call which initializes a mutex or a condition */ +class ThreadObjectInitialization extends FunctionCall { + ObjectIdentity owningObject; + + ThreadObjectInitialization() { + this.(C11MutexSource).getMutexExpr() = owningObject.getASubobjectAddressExpr() + or + exists(CConditionOperation condOp | + this = condOp and + condOp.isInit() and + condOp.getConditionExpr() = owningObject.getASubobjectAddressExpr() + ) + } + + ObjectIdentity getOwningObject() { result = owningObject } +} + +/** + * A function argument where that argument is used as a mutex or condition object. + */ +class ThreadObjectUse extends Expr { + ObjectIdentity owningObject; + string typeString; + ThreadObjectUse() { + owningObject.getASubobjectAddressExpr() = this and + ( + exists(CMutexFunctionCall mutexUse | this = mutexUse.getLockExpr()) and + typeString = "Mutex" + or + exists(CConditionOperation condOp | this = condOp.getMutexExpr()) and + typeString = "Mutex" + or + exists(CConditionOperation condOp | + condOp.isUse() and + this = condOp.getConditionExpr() and + typeString = "Condition" + ) + ) + } + + ObjectIdentity getOwningObject() { result = owningObject } + + string getDescription() { + if + getOwningObject().getType() instanceof PossiblySpecified::Type or + getOwningObject().getType() instanceof PossiblySpecified::Type + then result = typeString + else result = typeString + " in object" + } +} + + +predicate requiresInitializedMutexObject( + Function func, ThreadObjectUse mutexUse, ObjectIdentity owningObject +) { + mutexUse.getEnclosingFunction() = func and + owningObject = mutexUse.getOwningObject() and + not exists(ThreadObjectInitialization init | + init.getEnclosingFunction() = func and + init.getOwningObject() = owningObject and + mutexUse.getAPredecessor+() = init + ) + or + exists(FunctionCall call | + func = call.getEnclosingFunction() and + requiresInitializedMutexObject(call.getTarget(), mutexUse, owningObject) and + not exists(ThreadObjectInitialization init | + call.getAPredecessor*() = init and + init.getOwningObject() = owningObject + ) + ) + or + exists(C11ThreadCreateCall call | + func = call.getEnclosingFunction() and + not owningObject.getStorageDuration().isThread() and + requiresInitializedMutexObject(call.getFunction(), mutexUse, owningObject) and + not exists(ThreadObjectInitialization init | + call.getAPredecessor*() = init and + init.getOwningObject() = owningObject + ) + ) +} + +from ThreadObjectUse objUse, ObjectIdentity obj, Function callRoot +where + not isExcluded(objUse, Concurrency8Package::mutexNotInitializedBeforeUseQuery()) and + obj = objUse.getOwningObject() and + requiresInitializedMutexObject(callRoot, objUse, obj) and + ( + if obj.getStorageDuration().isAutomatic() + then obj.getEnclosingElement+() = callRoot + else ( + obj.getStorageDuration().isThread() and callRoot instanceof ThreadedFunction + or + callRoot instanceof RootFunction + ) + ) +select objUse, + objUse.getDescription() + + " '$@' possibly used before initialization, from entry point function '$@'.", obj, + obj.toString(), callRoot, callRoot.getName() diff --git a/c/misra/src/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.ql b/c/misra/src/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.ql new file mode 100644 index 0000000000..c86c9b9d9d --- /dev/null +++ b/c/misra/src/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.ql @@ -0,0 +1,52 @@ +/** + * @id c/misra/mutex-objects-not-always-unlocked + * @name RULE-22-16: All mutex objects locked by a thread shall be explicitly unlocked by the same thread + * @description Mutex not unlocked by thread on all execution paths in current thread after being + * locked. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-16 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Concurrency +import codingstandards.cpp.resources.ResourceLeakAnalysis + +module MutexLeakConfig implements ResourceLeakConfigSig { + predicate isAllocate(ControlFlowNode allocPoint, DataFlow::Node node) { + exists(MutexFunctionCall lock | + allocPoint = lock and + lock.isLock() and + node.asDefiningArgument() = lock.getLockExpr() + ) + } + + predicate isFree(ControlFlowNode node, DataFlow::Node resource) { + exists(MutexFunctionCall mfc | + node = mfc and + mfc.isUnlock() and + mfc.getLockExpr() = resource.asExpr() + ) + } +} + +string describeMutex(Expr mutexExpr) { + if mutexExpr instanceof AddressOfExpr + then result = mutexExpr.(AddressOfExpr).getOperand().toString() + else result = mutexExpr.toString() +} + +from MutexFunctionCall lockCall, string mutexDescription +where + not isExcluded(lockCall, Concurrency8Package::mutexObjectsNotAlwaysUnlockedQuery()) and + //lockCall.getLockExpr() = mutexNode.asDefiningArgument() and + exists(ResourceLeak::getALeak(lockCall)) and + mutexDescription = describeMutex(lockCall.getLockExpr()) +select lockCall, + "Mutex '" + mutexDescription + "' is locked here and may not always be subsequently unlocked." diff --git a/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected b/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected index 688dde4650..34bec03490 100644 --- a/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected +++ b/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected @@ -21,10 +21,10 @@ | test.c:65:15:65:32 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:65:15:65:20 | call to get_s1 | call to get_s1 | | test.c:66:16:66:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:66:16:66:21 | call to get_s1 | call to get_s1 | | test.c:67:23:67:40 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:67:23:67:28 | call to get_s1 | call to get_s1 | -| test.c:89:3:89:30 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:89:12:89:20 | member_s1 | member_s1 | -| test.c:90:3:90:36 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:90:3:90:26 | access to array | access to array | -| test.c:91:15:91:42 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:91:24:91:32 | member_s1 | member_s1 | -| test.c:92:15:92:48 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:92:15:92:38 | access to array | access to array | +| test.c:89:3:89:30 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:89:3:89:8 | call to get_s2 | call to get_s2 | +| test.c:90:3:90:36 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:90:3:90:8 | call to get_s2 | call to get_s2 | +| test.c:91:15:91:42 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:91:15:91:20 | call to get_s2 | call to get_s2 | +| test.c:92:15:92:48 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:92:15:92:20 | call to get_s2 | call to get_s2 | | test.c:111:15:111:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:111:16:111:22 | ... = ... | ... = ... | | test.c:113:15:113:37 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:113:16:113:26 | ... ? ... : ... | ... ? ... : ... | | test.c:114:15:114:31 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:114:16:114:20 | ... , ... | ... , ... | diff --git a/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected b/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected index ae140dcd59..19604e2092 100644 --- a/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected +++ b/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected @@ -3,13 +3,13 @@ | test.c:82:3:82:17 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:82:12:82:14 | arr | arr | test.c:82:3:82:8 | call to get_s1 | call to get_s1 | | test.c:83:3:83:17 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:83:12:83:14 | arr | arr | test.c:83:3:83:8 | call to get_s1 | call to get_s1 | | test.c:84:5:84:19 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:84:14:84:16 | arr | arr | test.c:84:5:84:10 | call to get_s1 | call to get_s1 | -| test.c:93:3:93:27 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:93:22:93:24 | arr | arr | test.c:93:12:93:20 | member_s1 | member_s1 | -| test.c:94:3:94:27 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:94:22:94:24 | arr | arr | test.c:94:3:94:20 | access to array | access to array | +| test.c:93:3:93:27 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:93:22:93:24 | arr | arr | test.c:93:3:93:8 | call to get_s2 | call to get_s2 | +| test.c:94:3:94:27 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:94:22:94:24 | arr | arr | test.c:94:3:94:8 | call to get_s2 | call to get_s2 | | test.c:137:3:137:23 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:137:12:137:20 | arr_union | arr_union | test.c:137:3:137:8 | call to get_s3 | call to get_s3 | | test.c:138:3:138:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:138:12:138:21 | arr_struct | arr_struct | test.c:138:3:138:8 | call to get_s3 | call to get_s3 | | test.c:139:3:139:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:139:12:139:21 | arr_struct | arr_struct | test.c:139:3:139:8 | call to get_s3 | call to get_s3 | | test.c:140:3:140:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:140:12:140:21 | arr_struct | arr_struct | test.c:140:3:140:8 | call to get_s3 | call to get_s3 | | test.c:141:3:141:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:141:12:141:21 | arr_struct | arr_struct | test.c:141:3:141:8 | call to get_s3 | call to get_s3 | | test.c:142:4:142:25 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:142:13:142:22 | arr_struct | arr_struct | test.c:142:4:142:9 | call to get_s3 | call to get_s3 | -| test.c:146:3:146:22 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:146:12:146:16 | arr2d | arr2d | test.c:146:3:146:8 | call to get_s3 | call to get_s3 | +| test.c:146:3:146:19 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:146:12:146:16 | arr2d | arr2d | test.c:146:3:146:8 | call to get_s3 | call to get_s3 | | test.c:147:4:147:20 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:147:13:147:17 | arr2d | arr2d | test.c:147:4:147:9 | call to get_s3 | call to get_s3 | diff --git a/c/misra/test/rules/RULE-22-12/NonstandardUseOfThreadingObject.expected b/c/misra/test/rules/RULE-22-12/NonstandardUseOfThreadingObject.expected new file mode 100644 index 0000000000..62a740f960 --- /dev/null +++ b/c/misra/test/rules/RULE-22-12/NonstandardUseOfThreadingObject.expected @@ -0,0 +1,27 @@ +| test.c:37:3:37:7 | mutex | Invalid usage of standard thread object type 'mtx_t'. | +| test.c:37:11:37:21 | * ... | Invalid usage of standard thread object type 'mtx_t'. | +| test.c:38:3:38:8 | thread | Invalid usage of standard thread object type 'thrd_t'. | +| test.c:38:12:38:23 | * ... | Invalid usage of standard thread object type 'thrd_t'. | +| test.c:39:3:39:13 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:39:17:39:27 | * ... | Invalid usage of standard thread object type 'tss_t'. | +| test.c:40:3:40:11 | condition | Invalid usage of standard thread object type 'cnd_t'. | +| test.c:40:15:40:25 | * ... | Invalid usage of standard thread object type 'cnd_t'. | +| test.c:43:10:43:15 | & ... | Invalid usage of standard thread object type 'mtx_t *'. | +| test.c:44:10:44:16 | & ... | Invalid usage of standard thread object type 'thrd_t *'. | +| test.c:45:10:45:21 | & ... | Invalid usage of standard thread object type 'tss_t *'. | +| test.c:46:10:46:19 | & ... | Invalid usage of standard thread object type 'cnd_t *'. | +| test.c:48:3:48:13 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:49:3:49:13 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:50:3:50:13 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:54:3:54:8 | thread | Invalid usage of standard thread object type 'thrd_t'. | +| test.c:54:13:54:18 | thread | Invalid usage of standard thread object type 'thrd_t'. | +| test.c:55:3:55:8 | thread | Invalid usage of standard thread object type 'thrd_t'. | +| test.c:55:13:55:18 | thread | Invalid usage of standard thread object type 'thrd_t'. | +| test.c:56:3:56:13 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:56:18:56:28 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:57:3:57:13 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:57:18:57:28 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:61:14:61:18 | mutex | Invalid usage of standard thread object type 'mtx_t'. | +| test.c:62:15:62:20 | thread | Invalid usage of standard thread object type 'thrd_t'. | +| test.c:63:20:63:30 | threadlocal | Invalid usage of standard thread object type 'tss_t'. | +| test.c:64:18:64:26 | condition | Invalid usage of standard thread object type 'cnd_t'. | diff --git a/c/misra/test/rules/RULE-22-12/NonstandardUseOfThreadingObject.qlref b/c/misra/test/rules/RULE-22-12/NonstandardUseOfThreadingObject.qlref new file mode 100644 index 0000000000..d1d345420d --- /dev/null +++ b/c/misra/test/rules/RULE-22-12/NonstandardUseOfThreadingObject.qlref @@ -0,0 +1 @@ +rules/RULE-22-12/NonstandardUseOfThreadingObject.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-12/test.c b/c/misra/test/rules/RULE-22-12/test.c new file mode 100644 index 0000000000..1c59c43d8c --- /dev/null +++ b/c/misra/test/rules/RULE-22-12/test.c @@ -0,0 +1,65 @@ +#include "string.h" +#include "threads.h" + +mtx_t mutex; +thrd_t thread; +tss_t threadlocal; +cnd_t condition; + +extern void use_mutex(mtx_t *m); +extern void use_thread(thrd_t *t); +extern void use_threadlocal(tss_t *t); +extern void use_condition(cnd_t *c); + +void valid_usages(void) { + mtx_init(&mutex, mtx_plain); // COMPLIANT + mtx_lock(&mutex); // COMPLIANT + mtx_unlock(&mutex); // COMPLIANT + thrd_create(&thread, NULL, NULL); // COMPLIANT + tss_create(&threadlocal, NULL); // COMPLIANT + tss_set(threadlocal, NULL); // COMPLIANT + cnd_init(&condition); // COMPLIANT + cnd_signal(&condition); // COMPLIANT + cnd_wait(&condition, &mutex); // COMPLIANT + + use_mutex(&mutex); // COMPLIANT + use_thread(&thread); // COMPLIANT + use_threadlocal(&threadlocal); // COMPLIANT + use_condition(&condition); // COMPLIANT +} + +extern void copy_mutex(mtx_t m); +extern void copy_thread(thrd_t t); +extern void copy_threadlocal(tss_t t); +extern void copy_condition(cnd_t t); + +void invalid_usages(void) { + mutex = *(mtx_t *)0; // NON-COMPLIANT + thread = *(thrd_t *)0; // NON-COMPLIANT + threadlocal = *(tss_t *)0; // NON-COMPLIANT + condition = *(cnd_t *)0; // NON-COMPLIANT + + int *buf; + memcpy(&mutex, buf, sizeof(mtx_t)); // NON-COMPLIANT + memcpy(&thread, buf, sizeof(thrd_t)); // NON-COMPLIANT + memcpy(&threadlocal, buf, sizeof(tss_t)); // NON-COMPLIANT + memcpy(&condition, buf, sizeof(cnd_t)); // NON-COMPLIANT + + threadlocal++; // NON-COMPLIANT + threadlocal += 1; // NON-COMPLIANT + threadlocal + 1; // NON-COMPLIANT + + // mutex == mutex; // NON-COMPLIANT + // mutex != mutex; // NON-COMPLIANT + thread == thread; // NON-COMPLIANT + thread != thread; // NON-COMPLIANT + threadlocal == threadlocal; // NON-COMPLIANT + threadlocal != threadlocal; // NON-COMPLIANT + // condition == condition; // NON-COMPLIANT + // condition != condition; // NON-COMPLIANT + + copy_mutex(mutex); // COMPLIANT + copy_thread(thread); // COMPLIANT + copy_threadlocal(threadlocal); // COMPLIANT + copy_condition(condition); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.expected b/c/misra/test/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.expected new file mode 100644 index 0000000000..0fe033366d --- /dev/null +++ b/c/misra/test/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.expected @@ -0,0 +1,13 @@ +| test.c:14:21:14:22 | g9 | Object of type 'mtx_t' has invalid storage duration type 'thread'. | +| test.c:15:22:15:24 | g10 | Object of type 'thrd_t' has invalid storage duration type 'thread'. | +| test.c:16:21:16:23 | g11 | Object of type 'tss_t' has invalid storage duration type 'thread'. | +| test.c:17:21:17:23 | g12 | Object of type 'cnd_t' has invalid storage duration type 'thread'. | +| test.c:34:9:34:10 | l1 | Object of type 'mtx_t' has invalid storage duration type 'automatic'. | +| test.c:35:10:35:11 | l2 | Object of type 'thrd_t' has invalid storage duration type 'automatic'. | +| test.c:36:9:36:10 | l3 | Object of type 'tss_t' has invalid storage duration type 'automatic'. | +| test.c:37:9:37:10 | l4 | Object of type 'cnd_t' has invalid storage duration type 'automatic'. | +| test.c:44:9:44:10 | l9 | Object of type 'mtx_t[10]' has invalid storage duration type 'automatic'. | +| test.c:46:13:46:15 | l11 | Object of type 'has_mtx_t' has invalid storage duration type 'automatic'. | +| test.c:48:13:48:15 | l13 | Object of type 'has_mtx_t[10]' has invalid storage duration type 'automatic'. | +| test.c:51:9:51:14 | call to malloc | Object of type 'mtx_t' has invalid storage duration type 'allocated'. | +| test.c:52:9:52:14 | call to malloc | Object of type 'mtx_t' has invalid storage duration type 'allocated'. | diff --git a/c/misra/test/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.qlref b/c/misra/test/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.qlref new file mode 100644 index 0000000000..9c054fc623 --- /dev/null +++ b/c/misra/test/rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.qlref @@ -0,0 +1 @@ +rules/RULE-22-13/ThreadingObjectWithInvalidStorageDuration.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-13/test.c b/c/misra/test/rules/RULE-22-13/test.c new file mode 100644 index 0000000000..0a5a84167d --- /dev/null +++ b/c/misra/test/rules/RULE-22-13/test.c @@ -0,0 +1,53 @@ +#include "stdlib.h" +#include "threads.h" + +mtx_t g1; // COMPLIANT +thrd_t g2; // COMPLIANT +tss_t g3; // COMPLIANT +cnd_t g4; // COMPLIANT + +static mtx_t g5; // COMPLIANT +static thrd_t g6; // COMPLIANT +static tss_t g7; // COMPLIANT +static cnd_t g8; // COMPLIANT + +_Thread_local mtx_t g9; // NON-COMPLIANT +_Thread_local thrd_t g10; // NON-COMPLIANT +_Thread_local tss_t g11; // NON-COMPLIANT +_Thread_local cnd_t g12; // NON-COMPLIANT + +typedef struct { + mtx_t m; +} has_mtx_t; + +typedef struct { + mtx_t *m; +} has_ptr_mtx_t; + +mtx_t g13[10]; // COMPLIANT +mtx_t *g14; // COMPLIANT +has_mtx_t g15; // COMPLIANT +has_ptr_mtx_t g16; // COMPLIANT +has_mtx_t g17[10]; // COMPLIANT + +void f1(void) { + mtx_t l1; // NON-COMPLIANT + thrd_t l2; // NON-COMPLIANT + tss_t l3; // NON-COMPLIANT + cnd_t l4; // NON-COMPLIANT + + static mtx_t l5; // COMPLIANT + static thrd_t l6; // COMPLIANT + static tss_t l7; // COMPLIANT + static cnd_t l8; // COMPLIANT + + mtx_t l9[10]; // NON-COMPLIANT + mtx_t *l10; // COMPLIANT + has_mtx_t l11; // NON-COMPLIANT + has_ptr_mtx_t l12; // COMPLIANT + has_mtx_t l13[10]; // NON-COMPLIANT + + l10 = &g1; // COMPLIANT + l10 = malloc(sizeof(mtx_t)); // NON-COMPLIANT + l10 = malloc(sizeof(mtx_t) * 4); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-14/MutexInitWithInvalidMutexType.expected b/c/misra/test/rules/RULE-22-14/MutexInitWithInvalidMutexType.expected new file mode 100644 index 0000000000..1ea39b6b1d --- /dev/null +++ b/c/misra/test/rules/RULE-22-14/MutexInitWithInvalidMutexType.expected @@ -0,0 +1,5 @@ +| test.c:140:3:140:10 | call to mtx_init | Mutex initialized with incorrect type expression. | +| test.c:141:3:141:10 | call to mtx_init | Mutex initialized with incorrect type expression. | +| test.c:142:3:142:10 | call to mtx_init | Mutex initialized with incorrect type expression. | +| test.c:144:3:144:10 | call to mtx_init | Mutex initialized with incorrect type expression. | +| test.c:145:3:145:10 | call to mtx_init | Mutex initialized with incorrect type expression. | diff --git a/c/misra/test/rules/RULE-22-14/MutexInitWithInvalidMutexType.qlref b/c/misra/test/rules/RULE-22-14/MutexInitWithInvalidMutexType.qlref new file mode 100644 index 0000000000..32b57cfd07 --- /dev/null +++ b/c/misra/test/rules/RULE-22-14/MutexInitWithInvalidMutexType.qlref @@ -0,0 +1 @@ +rules/RULE-22-14/MutexInitWithInvalidMutexType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-14/MutexInitializedInsideThread.expected b/c/misra/test/rules/RULE-22-14/MutexInitializedInsideThread.expected new file mode 100644 index 0000000000..360c02f622 --- /dev/null +++ b/c/misra/test/rules/RULE-22-14/MutexInitializedInsideThread.expected @@ -0,0 +1 @@ +| test.c:110:3:110:10 | call to mtx_init | Mutex initialization reachable from threaded function '$@'. | test.c:105:6:105:32 | from_root7_use_thread_local | from_root7_use_thread_local | diff --git a/c/misra/test/rules/RULE-22-14/MutexInitializedInsideThread.qlref b/c/misra/test/rules/RULE-22-14/MutexInitializedInsideThread.qlref new file mode 100644 index 0000000000..83ada06139 --- /dev/null +++ b/c/misra/test/rules/RULE-22-14/MutexInitializedInsideThread.qlref @@ -0,0 +1 @@ +rules/RULE-22-14/MutexInitializedInsideThread.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-14/MutexNotInitializedBeforeUse.expected b/c/misra/test/rules/RULE-22-14/MutexNotInitializedBeforeUse.expected new file mode 100644 index 0000000000..b9560165ce --- /dev/null +++ b/c/misra/test/rules/RULE-22-14/MutexNotInitializedBeforeUse.expected @@ -0,0 +1,14 @@ +| test.c:6:12:6:14 | & ... | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:5:9:5:10 | l1 | l1 | test.c:4:6:4:19 | use_local_mtxs | use_local_mtxs | +| test.c:13:12:13:16 | & ... | Mutex in object '$@' possibly used before initialization, from entry point function '$@'. | test.c:12:5:12:6 | l2 | l2 | test.c:4:6:4:19 | use_local_mtxs | use_local_mtxs | +| test.c:18:12:18:17 | & ... | Mutex in object '$@' possibly used before initialization, from entry point function '$@'. | test.c:17:9:17:10 | l3 | l3 | test.c:4:6:4:19 | use_local_mtxs | use_local_mtxs | +| test.c:23:12:23:13 | l4 | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:22:15:22:20 | call to malloc | call to malloc | test.c:28:6:28:31 | root1_calls_use_local_mtxs | root1_calls_use_local_mtxs | +| test.c:41:12:41:14 | & ... | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:34:7:34:8 | g1 | g1 | test.c:40:6:40:30 | root2_uses_global_mutexes | root2_uses_global_mutexes | +| test.c:42:12:42:17 | & ... | Mutex in object '$@' possibly used before initialization, from entry point function '$@'. | test.c:37:3:37:4 | g2 | g2 | test.c:40:6:40:30 | root2_uses_global_mutexes | root2_uses_global_mutexes | +| test.c:43:12:43:13 | g3 | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:56:8:56:13 | call to malloc | call to malloc | test.c:40:6:40:30 | root2_uses_global_mutexes | root2_uses_global_mutexes | +| test.c:64:12:64:14 | & ... | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:34:7:34:8 | g1 | g1 | test.c:67:6:67:45 | root4_call_thread_without_initialization | root4_call_thread_without_initialization | +| test.c:88:12:88:14 | & ... | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:87:9:87:10 | l1 | l1 | test.c:86:6:86:36 | island1_use_uninitialized_mutex | island1_use_uninitialized_mutex | +| test.c:100:12:100:14 | & ... | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:98:21:98:22 | g5 | g5 | test.c:99:6:99:27 | root6_use_thread_local | root6_use_thread_local | +| test.c:107:12:107:14 | & ... | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:98:21:98:22 | g5 | g5 | test.c:105:6:105:32 | from_root7_use_thread_local | from_root7_use_thread_local | +| test.c:124:12:124:13 | & ... | Condition '$@' possibly used before initialization, from entry point function '$@'. | test.c:122:9:122:9 | c | c | test.c:121:6:121:28 | root8_uninitialized_cnd | root8_uninitialized_cnd | +| test.c:124:16:124:17 | & ... | Mutex '$@' possibly used before initialization, from entry point function '$@'. | test.c:123:9:123:9 | m | m | test.c:121:6:121:28 | root8_uninitialized_cnd | root8_uninitialized_cnd | +| test.c:127:12:127:13 | & ... | Condition '$@' possibly used before initialization, from entry point function '$@'. | test.c:122:9:122:9 | c | c | test.c:121:6:121:28 | root8_uninitialized_cnd | root8_uninitialized_cnd | diff --git a/c/misra/test/rules/RULE-22-14/MutexNotInitializedBeforeUse.qlref b/c/misra/test/rules/RULE-22-14/MutexNotInitializedBeforeUse.qlref new file mode 100644 index 0000000000..2827a9c571 --- /dev/null +++ b/c/misra/test/rules/RULE-22-14/MutexNotInitializedBeforeUse.qlref @@ -0,0 +1 @@ +rules/RULE-22-14/MutexNotInitializedBeforeUse.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-14/test.c b/c/misra/test/rules/RULE-22-14/test.c new file mode 100644 index 0000000000..d8f1770ad8 --- /dev/null +++ b/c/misra/test/rules/RULE-22-14/test.c @@ -0,0 +1,146 @@ +#include "stdlib.h" +#include "threads.h" + +void use_local_mtxs(int x, int y) { + mtx_t l1; + mtx_lock(&l1); // NON-COMPLIANT + mtx_init(&l1, mtx_plain); + mtx_lock(&l1); // COMPLIANT + + struct { + mtx_t m; + } l2; + mtx_lock(&l2.m); // NON-COMPLIANT + mtx_init(&l2.m, mtx_plain); + mtx_lock(&l2.m); // COMPLIANT + + mtx_t l3[10]; + mtx_lock(&l3[y]); // NON-COMPLIANT + mtx_init(&l3[x], mtx_plain); + mtx_lock(&l3[y]); // COMPLIANT + + mtx_t *l4 = malloc(sizeof(mtx_t)); + mtx_lock(l4); // NON-COMPLIANT + mtx_init(l4, mtx_plain); + mtx_lock(l4); // COMPLIANT +} + +void root1_calls_use_local_mtxs() { + // Since a function exists which calls use_local_mtxs(), that function is not + // a root function. The query should still report unused locals in this case. + use_local_mtxs(1, 2); +} + +mtx_t g1; +struct { + mtx_t m1; +} g2; +mtx_t *g3; + +void root2_uses_global_mutexes() { + mtx_lock(&g1); // NON-COMPLIANT + mtx_lock(&g2.m1); // NON-COMPLIANT + mtx_lock(g3); // NON-COMPLIANT +} + +void from_root3_use_global_mutexes() { + mtx_lock(&g1); // COMPLIANT + mtx_lock(&g2.m1); // COMPLIANT + mtx_lock(g3); // COMPLIANT +} + +void root3_initializes_and_uses_global_mutexes() { + // Init global mutex with an allocated storage duration object. The existence + // of this malloc() is not checked by the query, but if its exists, the object + // and its uses should be trackable as a nice bonus. + g3 = malloc(sizeof(mtx_t)); + mtx_init(&g1, mtx_plain); + mtx_init(&g2.m1, mtx_plain); + mtx_init(g3, mtx_plain); + from_root3_use_global_mutexes(); +} + +void from_root4_use_global_mutex(void *arg) { + mtx_lock(&g1); // NON-COMPLIANT +} + +void root4_call_thread_without_initialization() { + thrd_t t; + thrd_create(&t, &from_root4_use_global_mutex, NULL); +} + +void from_root5_use_global_mutex(void *arg) { + mtx_lock(&g1); // COMPLIANT +} + +void root5_thread_with_initialization() { + mtx_init(&g1, mtx_plain); + thrd_t t; + thrd_create(&t, &from_root5_use_global_mutex, NULL); +} + +// Set up two functions such that a calls b and b calls a. This means there is +// no root function, but we should still report unused locals. +void island2_call_island1(); + +void island1_use_uninitialized_mutex() { + mtx_t l1; + mtx_lock(&l1); // NON-COMPLIANT + + // Globals are hard to detect + mtx_lock(&g1); // NON-COMPLIANT[False negative] + + island2_call_island1(); +} + +void island2_call_island1() { island1_use_uninitialized_mutex(); } + +_Thread_local mtx_t g5; +void root6_use_thread_local() { + mtx_lock(&g5); // NON-COMPLIANT + mtx_init(&g5, mtx_plain); + mtx_lock(&g5); // COMPLIANT +} + +void from_root7_use_thread_local() { + // Invalid, thread local g5 hasn't been initialized in this thread. + mtx_lock(&g5); // NON-COMPLIANT + + // Violates recommendation, mutexes initialized within a thread. + mtx_init(&g5, mtx_plain); // NON-COMPLIANT + + // Valid if we except the above initialization. + mtx_lock(&g5); // COMPLIANT +} + +void root7_spawn_thread_uninitialized_thread_local() { + thrd_t t; + thrd_create(&t, &from_root7_use_thread_local, NULL); +} + +void root8_uninitialized_cnd() { + cnd_t c; + mtx_t m; + cnd_wait(&c, &m); // NON-COMPLIANT + + mtx_init(&m, mtx_plain); + cnd_wait(&c, &m); // NON-COMPLIANT + + cnd_init(&c); + cnd_wait(&c, &m); // COMPLIANT +} + +void invalid_mtx_init_types() { + mtx_t m; + mtx_init(&m, mtx_plain); // COMPLIANT + mtx_init(&m, mtx_plain | mtx_recursive); // COMPLIANT + mtx_init(&m, mtx_timed); // COMPLIANT + mtx_init(&m, mtx_timed | mtx_recursive); // COMPLIANT + + mtx_init(&m, mtx_recursive); // NON-COMPLIANT + mtx_init(&m, mtx_plain | mtx_timed); // NON-COMPLIANT + mtx_init(&m, mtx_plain | mtx_plain); // NON-COMPLIANT + mtx_init(&m, mtx_plain & mtx_recursive); // NON-COMPLIANT + mtx_init(&m, mtx_plain * mtx_recursive); // NON-COMPLIANT + mtx_init(&m, -1); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected b/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected new file mode 100644 index 0000000000..126e75bca7 --- /dev/null +++ b/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected @@ -0,0 +1,7 @@ +| test.c:16:3:16:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | +| test.c:21:3:21:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | +| test.c:39:3:39:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | +| test.c:55:3:55:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | +| test.c:72:3:72:10 | call to mtx_lock | Mutex 'g1' is locked here and may not always be subsequently unlocked. | +| test.c:79:3:79:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | +| test.c:101:5:101:12 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | diff --git a/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.qlref b/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.qlref new file mode 100644 index 0000000000..a1877f944d --- /dev/null +++ b/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.qlref @@ -0,0 +1 @@ +rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-16/test.c b/c/misra/test/rules/RULE-22-16/test.c new file mode 100644 index 0000000000..b9a19165e8 --- /dev/null +++ b/c/misra/test/rules/RULE-22-16/test.c @@ -0,0 +1,107 @@ +#include "threads.h" + +void f1() { + mtx_t m; + mtx_lock(&m); // COMPLIANT + mtx_unlock(&m); +} + +void f2() { + mtx_t m; + mtx_unlock(&m); // COMPLIANT +} + +void f3() { + mtx_t m; + mtx_lock(&m); // NON-COMPLIANT +} + +void f4(int p) { + mtx_t m; + mtx_lock(&m); // NON-COMPLIANT + if (p) { + mtx_unlock(&m); + } +} + +void f5(int p) { + mtx_t m; + mtx_lock(&m); // COMPLIANT + if (p) { + mtx_unlock(&m); + } else { + mtx_unlock(&m); + } +} + +void f6(int p) { + mtx_t m; + mtx_lock(&m); // NON-COMPLIANT + if (p) { + goto skipped; + } + mtx_unlock(&m); + skipped: +} + +void f7(int p) { + mtx_t *m; + mtx_lock(m); // COMPLIANT + mtx_unlock(m); +} + +void f8(int p) { + mtx_t *m; + mtx_lock(m); // NON-COMPLIANT +} + +void f9(int p) { + mtx_t m; + mtx_lock(&m); // COMPLIANT + mtx_t *ptr_m = &m; + mtx_unlock(ptr_m); +} + +mtx_t g1; +void f10() { + mtx_lock(&g1); // COMPLIANT + mtx_unlock(&g1); +} + +void f11() { + mtx_lock(&g1); // NON-COMPLIANT +} + +void f12() { + struct { + mtx_t m; + } s; + mtx_lock(&s.m); // NON-COMPLIANT +} + +void f13() { + struct { + mtx_t m; + } s; + mtx_lock(&s.m); // COMPLIANT + mtx_unlock(&s.m); +} + +void f14() { + for(;;) { + mtx_t m; + mtx_lock(&m); // COMPLIANT + mtx_unlock(&m); + } +} + +void f15(int p) { + for(;;) { + mtx_t m; + mtx_lock(&m); // NON-COMPLIANT + if (p) { + break; + } + mtx_unlock(&m); + } +} \ No newline at end of file diff --git a/change_notes/2024-11-27-c-object-refactor.md b/change_notes/2024-11-27-c-object-refactor.md new file mode 100644 index 0000000000..511ce1b7ce --- /dev/null +++ b/change_notes/2024-11-27-c-object-refactor.md @@ -0,0 +1,21 @@ +- `CON34-C` - `AppropriateThreadObjectStorageDurations.ql`: + - Improved analysis for detecting objects with automatic storage duration + - New reports will include `a.x`, `a[x]` for object `a` with automatic storage duration +- `DCL30-C` - `AppropriateStorageDurationsFunctionReturn.ql`: + - Improved analysis for detecting objects with automatic storage duration + - New reports will include `a.x`, `a[x]` for object `a` with automatic storage duration + - False positives related to returning copying pointer values +- `EXP35-C` - `DoNotModifyObjectsWithTemporaryLifetime.ql`: + - Improved analysis for detecting objects with temporary lifetime + - More non-lvalue expressions that produce temporary objects detected, for instance `(x = y).x`, previously only `f().x` discovered +- `MEM33-C` - `AllocStructsWithAFlexibleArrayMemberDynamically.ql`: + - Improved analysis for detecting objects with automatic storage duration + - New reports will include struct literals with a flexible array member +- `RULE-18-9` - `ModifiableLValueSubscriptedWithTemporaryLifetime.ql`: + - Problems will be reported at more obviously non-lvalue locations + - Implementation refactored to be shared with other libraries + - No other changes expected +- `RULE-18-9` - `ArrayToPointerConversionOfTemporaryLifetime.ql`: + - Problems will be reported at more obviously non-lvalue locations + - Implementation refactored to be shared with other libraries + - No other changes expected \ No newline at end of file diff --git a/change_notes/2024-11-27-raii-concurrency-analysis-perf.md b/change_notes/2024-11-27-raii-concurrency-analysis-perf.md new file mode 100644 index 0000000000..3a08427808 --- /dev/null +++ b/change_notes/2024-11-27-raii-concurrency-analysis-perf.md @@ -0,0 +1,2 @@ + - `Concurrency` - for all queries related to RAII-style mutexes + - These types of locks have been refactored to improve performance in some queries. No change in query results expected. \ No newline at end of file diff --git a/change_notes/2024-11-27-resource-leak-analysis-refactor.md b/change_notes/2024-11-27-resource-leak-analysis-refactor.md new file mode 100644 index 0000000000..8f2799b543 --- /dev/null +++ b/change_notes/2024-11-27-resource-leak-analysis-refactor.md @@ -0,0 +1,10 @@ +- `ERR57-CPP` - `DoNotLeakResourcesWhenHandlingExceptions.ql`: + - Resource leak detection code refactored for sharing across queries + - Control flow no longer uses "cut nodes." This could impact performance positively or negatively, however measurements have been taken that indicate no significant change + - Some false positives have been suppressed due to slightly different control flow approach + - Leaked mutex locks and open files are reported at slightly different location, reported at call site (e.g. `f.open(...)`, `m.lock()`) rather than on the variable itself (`f` and `m`). +- `A15-1-4` - `ValidResourcesStateBeforeThrow.ql`: + - Resource leak detection code refactored for sharing across queries + - Control flow no longer uses "cut nodes." This could impact performance positively or negatively, however measurements have been taken that indicate no significant change + - Some false positives have been suppressed due to slightly different control flow approach + - Leaked mutex locks and open files are reported at slightly different location, reported at call site (e.g. `f.open(...)`, `m.lock()`) rather than on the variable itself (`f` and `m`). \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Clvalues.qll b/cpp/common/src/codingstandards/cpp/Clvalues.qll index 73fcd65eb1..157041f13b 100644 --- a/cpp/common/src/codingstandards/cpp/Clvalues.qll +++ b/cpp/common/src/codingstandards/cpp/Clvalues.qll @@ -14,4 +14,7 @@ predicate isCLValue(Expr expr) { not expr instanceof AssignExpr and not expr instanceof CommaExpr and not exists(Cast c | c = expr.getConversion*()) + or + // 6.5.2.5.4: Compound literals are always lvalues. + expr instanceof AggregateLiteral } diff --git a/cpp/common/src/codingstandards/cpp/Concurrency.qll b/cpp/common/src/codingstandards/cpp/Concurrency.qll index d856fa4515..f68553dfd9 100644 --- a/cpp/common/src/codingstandards/cpp/Concurrency.qll +++ b/cpp/common/src/codingstandards/cpp/Concurrency.qll @@ -69,6 +69,42 @@ class C11ThreadCreateCall extends ThreadCreationFunction { override ControlFlowNode getNext() { result = getFunction().getEntryPoint() } } +class C11MutexType extends TypedefType { + C11MutexType() { + this.hasName("mtx_t") + } +} + +class C11ThreadType extends TypedefType { + C11ThreadType() { + this.hasName("thrd_t") + } +} + +class C11ConditionType extends TypedefType { + C11ConditionType() { + this.hasName("cnd_t") + } +} + +class C11ThreadStorageType extends TypedefType { + C11ThreadStorageType() { + this.hasName("tss_t") + } +} + +class C11ThreadingObjectType extends TypedefType { + C11ThreadingObjectType() { + this instanceof C11MutexType + or + this instanceof C11ThreadType + or + this instanceof C11ConditionType + or + this instanceof C11ThreadStorageType + } +} + /** * Common base class providing an interface into function call * based mutex locks. @@ -317,14 +353,14 @@ abstract class LockingOperation extends FunctionCall { */ class RAIIStyleLock extends LockingOperation { VariableAccess lock; - Element e; RAIIStyleLock() { ( getTarget().getDeclaringType().hasQualifiedName("std", "lock_guard") or getTarget().getDeclaringType().hasQualifiedName("std", "unique_lock") or getTarget().getDeclaringType().hasQualifiedName("std", "scoped_lock") - ) + ) and + lock = getArgument(0).getAChild*() } /** @@ -333,7 +369,6 @@ class RAIIStyleLock extends LockingOperation { override predicate isLock() { not isLockingOperationWithinLockingOperation(this) and this instanceof ConstructorCall and - lock = getArgument(0).getAChild*() and // defer_locks don't cause a lock not exists(Expr exp | exp = getArgument(1) and @@ -463,6 +498,28 @@ class CConditionalWait extends ConditionalWait { CConditionalWait() { getTarget().getName() in ["cnd_wait"] } } +/** + * Models a function which uses a c condition variable. Not integrated into the thread aware CFG. + */ +class CConditionOperation extends FunctionCall { + CConditionOperation() { + getTarget().hasName(["cnd_broadcast", "cnd_signal", "cnd_timedwait", "cnd_wait", "cnd_init"]) + } + + predicate isInit() { + getTarget().hasName("cnd_init") + } + + predicate isUse() { + not isInit() + } + + Expr getConditionExpr() { result = getArgument(0) } + + /* Note: only holds for `cnd_wait()` and `cnd_timedwait()` */ + Expr getMutexExpr() { result = getArgument(1) } +} + /** * Models a call to a `std::thread` constructor that depends on a mutex. */ @@ -531,6 +588,10 @@ class CPPMutexSource extends MutexSource, ConstructorCall { */ class C11MutexSource extends MutexSource, FunctionCall { C11MutexSource() { getTarget().hasName("mtx_init") } + + Expr getMutexExpr() { result = getArgument(0) } + + Expr getMutexTypeExpr() { result = getArgument(1) } } /** diff --git a/cpp/common/src/codingstandards/cpp/Type.qll b/cpp/common/src/codingstandards/cpp/Type.qll index 4199b4a12d..4f72f5612e 100644 --- a/cpp/common/src/codingstandards/cpp/Type.qll +++ b/cpp/common/src/codingstandards/cpp/Type.qll @@ -60,6 +60,30 @@ Type stripSpecifiers(Type type) { else result = type } +signature class PossiblySpecifiedBaseType extends Type; + +/** + * This module defines a class `Type` which holds for types `T` and `const/volatile T` etc. + * + * Similar to `getUnspecifiedType()`, but does not resolve typedefs. Useful for matching + * potentially qualified versions of standard typedef types, such as `const mtx_t`. + * + * Example usage: `someType.(PossiblySpecified::Type).strip()` + */ +module PossiblySpecified { + import cpp as cpp + final class CppType = cpp::Type; + + class Type extends CppType { + BaseType baseType; + Type() { + baseType = stripSpecifiers(this) + } + + BaseType strip() { result = baseType } + } +} + /** * Get the precision of an integral type, where precision is defined as the number of bits * that can be used to represent the numeric value. @@ -69,4 +93,4 @@ int getPrecision(IntegralType type) { type.isExplicitlyUnsigned() and result = type.getSize() * 8 or type.isExplicitlySigned() and result = type.getSize() * 8 - 1 -} +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency8.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency8.qll new file mode 100644 index 0000000000..677b35d12b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency8.qll @@ -0,0 +1,112 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Concurrency8Query = + TNonstandardUseOfThreadingObjectQuery() or + TThreadingObjectWithInvalidStorageDurationQuery() or + TMutexNotInitializedBeforeUseQuery() or + TMutexInitializedInsideThreadQuery() or + TMutexInitWithInvalidMutexTypeQuery() or + TMutexObjectsNotAlwaysUnlockedQuery() + +predicate isConcurrency8QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `nonstandardUseOfThreadingObject` query + Concurrency8Package::nonstandardUseOfThreadingObjectQuery() and + queryId = + // `@id` for the `nonstandardUseOfThreadingObject` query + "c/misra/nonstandard-use-of-threading-object" and + ruleId = "RULE-22-12" and + category = "mandatory" + or + query = + // `Query` instance for the `threadingObjectWithInvalidStorageDuration` query + Concurrency8Package::threadingObjectWithInvalidStorageDurationQuery() and + queryId = + // `@id` for the `threadingObjectWithInvalidStorageDuration` query + "c/misra/threading-object-with-invalid-storage-duration" and + ruleId = "RULE-22-13" and + category = "required" + or + query = + // `Query` instance for the `mutexNotInitializedBeforeUse` query + Concurrency8Package::mutexNotInitializedBeforeUseQuery() and + queryId = + // `@id` for the `mutexNotInitializedBeforeUse` query + "c/misra/mutex-not-initialized-before-use" and + ruleId = "RULE-22-14" and + category = "mandatory" + or + query = + // `Query` instance for the `mutexInitializedInsideThread` query + Concurrency8Package::mutexInitializedInsideThreadQuery() and + queryId = + // `@id` for the `mutexInitializedInsideThread` query + "c/misra/mutex-initialized-inside-thread" and + ruleId = "RULE-22-14" and + category = "mandatory" + or + query = + // `Query` instance for the `mutexInitWithInvalidMutexType` query + Concurrency8Package::mutexInitWithInvalidMutexTypeQuery() and + queryId = + // `@id` for the `mutexInitWithInvalidMutexType` query + "c/misra/mutex-init-with-invalid-mutex-type" and + ruleId = "RULE-22-14" and + category = "mandatory" + or + query = + // `Query` instance for the `mutexObjectsNotAlwaysUnlocked` query + Concurrency8Package::mutexObjectsNotAlwaysUnlockedQuery() and + queryId = + // `@id` for the `mutexObjectsNotAlwaysUnlocked` query + "c/misra/mutex-objects-not-always-unlocked" and + ruleId = "RULE-22-16" and + category = "required" +} + +module Concurrency8Package { + Query nonstandardUseOfThreadingObjectQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonstandardUseOfThreadingObject` query + TQueryC(TConcurrency8PackageQuery(TNonstandardUseOfThreadingObjectQuery())) + } + + Query threadingObjectWithInvalidStorageDurationQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadingObjectWithInvalidStorageDuration` query + TQueryC(TConcurrency8PackageQuery(TThreadingObjectWithInvalidStorageDurationQuery())) + } + + Query mutexNotInitializedBeforeUseQuery() { + //autogenerate `Query` type + result = + // `Query` type for `mutexNotInitializedBeforeUse` query + TQueryC(TConcurrency8PackageQuery(TMutexNotInitializedBeforeUseQuery())) + } + + Query mutexInitializedInsideThreadQuery() { + //autogenerate `Query` type + result = + // `Query` type for `mutexInitializedInsideThread` query + TQueryC(TConcurrency8PackageQuery(TMutexInitializedInsideThreadQuery())) + } + + Query mutexInitWithInvalidMutexTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `mutexInitWithInvalidMutexType` query + TQueryC(TConcurrency8PackageQuery(TMutexInitWithInvalidMutexTypeQuery())) + } + + Query mutexObjectsNotAlwaysUnlockedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `mutexObjectsNotAlwaysUnlocked` query + TQueryC(TConcurrency8PackageQuery(TMutexObjectsNotAlwaysUnlockedQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 1562ba7894..f91f80f17a 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -12,6 +12,7 @@ import Concurrency2 import Concurrency3 import Concurrency4 import Concurrency5 +import Concurrency8 import Contracts1 import Contracts2 import Contracts3 @@ -91,6 +92,7 @@ newtype TCQuery = TConcurrency3PackageQuery(Concurrency3Query q) or TConcurrency4PackageQuery(Concurrency4Query q) or TConcurrency5PackageQuery(Concurrency5Query q) or + TConcurrency8PackageQuery(Concurrency8Query q) or TContracts1PackageQuery(Contracts1Query q) or TContracts2PackageQuery(Contracts2Query q) or TContracts3PackageQuery(Contracts3Query q) or @@ -170,6 +172,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isConcurrency3QueryMetadata(query, queryId, ruleId, category) or isConcurrency4QueryMetadata(query, queryId, ruleId, category) or isConcurrency5QueryMetadata(query, queryId, ruleId, category) or + isConcurrency8QueryMetadata(query, queryId, ruleId, category) or isContracts1QueryMetadata(query, queryId, ruleId, category) or isContracts2QueryMetadata(query, queryId, ruleId, category) or isContracts3QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/lifetimes/CLifetimes.qll b/cpp/common/src/codingstandards/cpp/lifetimes/CLifetimes.qll deleted file mode 100644 index 9282260fb9..0000000000 --- a/cpp/common/src/codingstandards/cpp/lifetimes/CLifetimes.qll +++ /dev/null @@ -1,48 +0,0 @@ -import cpp -import codingstandards.cpp.Clvalues - -/** - * A struct or union type that contains an array type. - */ -class StructOrUnionTypeWithArrayField extends Struct { - StructOrUnionTypeWithArrayField() { - this.getAField().getUnspecifiedType() instanceof ArrayType - or - // nested struct or union containing an array type - this.getAField().getUnspecifiedType().(Struct) instanceof StructOrUnionTypeWithArrayField - } -} - -/** - * A non-lvalue expression with struct or or union type that has a field member - * of array type, has a temporary lifetime. - * - * The array members are also part of that object, and thus also have temporary - * lifetime. - */ -class TemporaryLifetimeExpr extends Expr { - TemporaryLifetimeExpr() { - getUnconverted().getUnspecifiedType() instanceof StructOrUnionTypeWithArrayField and - not isCLValue(this) - or - this.getUnconverted().(ArrayExpr).getArrayBase() instanceof TemporaryLifetimeArrayAccess - } -} - -/** - * A field access on a temporary object that returns an array member. - */ -class TemporaryLifetimeArrayAccess extends FieldAccess { - // The temporary lifetime object which owns the array that is returned. - TemporaryLifetimeExpr temporary; - - TemporaryLifetimeArrayAccess() { - getQualifier().getUnconverted() = temporary and - getUnspecifiedType() instanceof ArrayType - } - - /** - * Get the temporary lifetime object which own the array that is returned. - */ - Expr getTemporary() { result = temporary } -} diff --git a/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll b/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll new file mode 100644 index 0000000000..4623b3e95e --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll @@ -0,0 +1,101 @@ +import cpp +import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.controlflow.Dominance +import codeql.util.Boolean + +/** + * A library for detecting leaked resources. + * + * To use this library, implement `ResourceLeakConfigSig`: + * + * ``` + * class UnjoinedThreadConfig implements ResourceLeakConfigSig { + * predicate isResource(DataFlow::Node node) { + * node.asExpr().isThreadCreate() + * } + * + * predicate isFree(ControlFlowNode node, DataFlow::Node resource) { + * node.asExpr().isThreadJoin(resource.asExpr()) + * } + * } + * ``` + * + * You can now check if a resource is leaked through the module predicate + * `ResourceLeak::isLeaked(resource)`. + * + * The leak analysis finds the exit point of the function in which the resource is is declared, and + * then reverses execution from there using `getAPredecessor()`. When this backwards walk discovers + * a control flow node that frees the resource, that exploration stops. If any exploration reaches + * a resource, that resource may be leaked via that path. + * + * Uses `DataFlow::Node` in order to track aliases of the resource to better detect when the + * resource is freed. + * + * This library by default assumes that resources are expression nodes. To use it with other kinds + * of nodes requires overriding `resourceInitPoint`. + */ +signature module ResourceLeakConfigSig { + predicate isAllocate(ControlFlowNode node, DataFlow::Node resource); + + predicate isFree(ControlFlowNode node, DataFlow::Node resource); + + default DataFlow::Node getAnAlias(DataFlow::Node node) { + DataFlow::localFlow(node, result) or + exists(Expr current, Expr after | + current in [node.asExpr(), node.asDefiningArgument()] and + after in [result.asExpr(), result.asDefiningArgument()] and + globalValueNumber(current) = globalValueNumber(after) and + strictlyDominates(current, after) + ) + } + + /* A point at which a resource is considered to have leaked if it has not been freed. */ + default ControlFlowNode outOfScope(ControlFlowNode allocPoint) { + result = allocPoint.(Expr).getEnclosingFunction().getBlock().getLastStmt() + } +} + +module ResourceLeak { + private newtype TResource = TJustResource(DataFlow::Node resource, ControlFlowNode cfgNode) { + Config::isAllocate(cfgNode, resource) + } + + /** + * Get an alias of a resource, and aliases of nodes that are aliased by a resource. + */ + private DataFlow::Node getAnAliasRecursive(DataFlow::Node node) { + result = Config::getAnAlias(node) and + Config::isAllocate(_, node) + or + exists(DataFlow::Node parent | + node = getAnAliasRecursive(parent) and + result = Config::getAnAlias(parent) + ) + } + + private predicate isLeakedAtControlPoint(TResource resource, ControlFlowNode cfgNode) { + // Holds if this control point is where the resource was allocated (and therefore not freed). + resource = TJustResource(_, cfgNode) + or + // Holds if this control point does not free the resource, and is reachable from a point that + // does not free the resource. + isLeakedAtControlPoint(resource, cfgNode.getAPredecessor()) and + not exists(DataFlow::Node freed, DataFlow::Node resourceNode | + Config::isFree(cfgNode, freed) and + freed = getAnAliasRecursive(resourceNode) and + resource = TJustResource(resourceNode, _) + ) + } + + /** + * Holds if `resource` is leaked. Use this module predicate to find leaked resources. + */ + ControlFlowNode getALeak(ControlFlowNode allocPoint) { + exists(TResource resourceWrapper, DataFlow::Node resource | + resourceWrapper = TJustResource(resource, allocPoint) and + result = Config::outOfScope(allocPoint) and + isLeakedAtControlPoint(resourceWrapper, result) + ) + } +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll b/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll index 0798575495..93c26e0a46 100644 --- a/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll +++ b/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll @@ -1,58 +1,45 @@ import cpp import codingstandards.cpp.dataflow.DataFlow +import codingstandards.cpp.resources.ResourceLeakAnalysis -/** - * The `ResourceAcquisitionExpr` abstract class models resource - * acquisition and release expressions - */ -abstract class ResourceAcquisitionExpr extends Expr { - abstract Expr getReleaseExpr(); -} - -// allocation - deallocation -class AllocExpr extends ResourceAcquisitionExpr { - AllocExpr() { this.(AllocationExpr).requiresDealloc() } - - override Expr getReleaseExpr() { - exists(DeallocationExpr d | result = d.getFreedExpr()) and - DataFlow::localFlow(DataFlow::exprNode(this), DataFlow::exprNode(result)) - } -} - -// file open-close -class FstreamAcquisitionExpr extends ResourceAcquisitionExpr { - FstreamAcquisitionExpr() { +module ResourceLeakConfig implements ResourceLeakConfigSig { + predicate isAllocate(ControlFlowNode allocPoint, DataFlow::Node node) { + exists(AllocationExpr alloc | + allocPoint = alloc and + alloc.requiresDealloc() and + node.asExpr() = alloc + ) + or exists(FunctionCall f | - f.getTarget().hasQualifiedName("std", "basic_fstream", "open") and this = f.getQualifier() + f.getTarget().hasQualifiedName("std", "basic_fstream", "open") + and allocPoint = f + and node.asDefiningArgument() = f.getQualifier() ) - } - - override Expr getReleaseExpr() { + or exists(FunctionCall f | - f.getTarget().hasQualifiedName("std", "basic_fstream", "close") and result = f.getQualifier() - ) and - exists(DataFlow::Node def | - def.asDefiningArgument() = this and - DataFlow::localFlow(def, DataFlow::exprNode(result)) + f.getTarget().hasQualifiedName("std", "mutex", "lock") and + allocPoint = f and + node.asDefiningArgument() = f.getQualifier() ) } -} -// mutex lock unlock -class MutexAcquisitionExpr extends ResourceAcquisitionExpr { - MutexAcquisitionExpr() { + predicate isFree(ControlFlowNode node, DataFlow::Node resource) { + exists(DeallocationExpr d, Expr freedExpr| + freedExpr = d.getFreedExpr() and + node = d and + resource.asExpr() = freedExpr + ) + or exists(FunctionCall f | - f.getTarget().hasQualifiedName("std", "mutex", "lock") and this = f.getQualifier() + f.getTarget().hasQualifiedName("std", "basic_fstream", "close") + and node = f and + resource.asExpr() = f.getQualifier() ) - } - - override Expr getReleaseExpr() { + or exists(FunctionCall f | - f.getTarget().hasQualifiedName("std", "mutex", "unlock") and result = f.getQualifier() - ) and - exists(DataFlow::Node def | - def.asDefiningArgument() = this and - DataFlow::localFlow(def, DataFlow::exprNode(result)) + f.getTarget().hasQualifiedName("std", "mutex", "unlock") + and node = f and + resource.asExpr() = f.getQualifier() ) } -} +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.qll b/cpp/common/src/codingstandards/cpp/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.qll index 16f86f78be..8ed5342def 100644 --- a/cpp/common/src/codingstandards/cpp/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.qll +++ b/cpp/common/src/codingstandards/cpp/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.qll @@ -4,42 +4,17 @@ */ import cpp -import semmle.code.cpp.controlflow.SubBasicBlocks import codingstandards.cpp.Exclusions import codingstandards.cpp.Customizations import codingstandards.cpp.exceptions.ExceptionFlow import codingstandards.cpp.ExceptionSafety import codingstandards.cpp.resources.ResourceManagement +import codingstandards.cpp.resources.ResourceLeakAnalysis abstract class ExceptionSafetyValidStateSharedQuery extends Query { } Query getQuery() { result instanceof ExceptionSafetyValidStateSharedQuery } -/** - * Ensures that `UncaughtThrowExpr` and `Expr` appear at the start of a `SubBasicBlock`. - */ -class SafetyValidStateSubBasicBlock extends SubBasicBlockCutNode { - SafetyValidStateSubBasicBlock() { - this instanceof ResourceAcquisitionExpr or - this = any(ResourceAcquisitionExpr rae).getReleaseExpr() or - this instanceof UncaughtThrowExpr - } -} - -/** - * Execution continues from an allocation expression - * without releasing the resource - */ -SubBasicBlock followsInitialized(ResourceAcquisitionExpr src) { - result = src - or - exists(SubBasicBlock mid | - mid = followsInitialized(src) and - result = mid.getASuccessor() and - //stop recursion on resource release - not result = src.getReleaseExpr() - ) -} /** * `UncaughtThrowExpr` models a `throw` expression that is not handled @@ -48,14 +23,40 @@ class UncaughtThrowExpr extends ThrowExpr { UncaughtThrowExpr() { getASuccessor() = getEnclosingFunction() } } +module ThrowLeakConfig implements ResourceLeakConfigSig { + + predicate isAllocate(ControlFlowNode node, DataFlow::Node resource) { + //exists(ResourceAcquisitionExpr rae | + // node = rae and resource.asExpr() = rae + //) + ResourceLeakConfig::isAllocate(node, resource) + } + + predicate isFree(ControlFlowNode node, DataFlow::Node resource) { + //exists(ResourceAcquisitionExpr rae | + // node = rae.getReleaseExpr() and resource.asExpr() = rae + //) + ResourceLeakConfig::isFree(node, resource) + } + + ControlFlowNode outOfScope(ControlFlowNode allocPoint) { + result.(UncaughtThrowExpr).getEnclosingFunction() = allocPoint.(Expr).getEnclosingFunction() + } + + DataFlow::Node getAnAlias(DataFlow::Node node) { + DataFlow::localFlow(node, result) + } +} + query predicate problems( - UncaughtThrowExpr te, string message, ResourceAcquisitionExpr e, string eDescription + UncaughtThrowExpr te, string message, Element e, string eDescription ) { not isExcluded(te, getQuery()) and - exists(SubBasicBlock sbb | - sbb.getANode() = e and - te = followsInitialized(sbb) - ) and + //exists(SubBasicBlock sbb | + // sbb.getANode() = e and + // te = followsInitialized(sbb) + //) and + te = ResourceLeak::getALeak(e) and message = "The $@ is not released explicitly before throwing an exception." and eDescription = "allocated resource" } diff --git a/cpp/common/test/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.expected b/cpp/common/test/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.expected index 18689c333b..b8a8c17435 100644 --- a/cpp/common/test/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.expected +++ b/cpp/common/test/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.expected @@ -6,7 +6,7 @@ | test.cpp:103:5:103:9 | re-throw exception | The $@ is not released explicitly before throwing an exception. | test.cpp:99:12:99:21 | new | allocated resource | | test.cpp:125:5:125:37 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:124:9:124:18 | new | allocated resource | | test.cpp:134:5:134:37 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:133:23:133:32 | new | allocated resource | -| test.cpp:142:3:142:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:141:3:141:4 | fs | allocated resource | -| test.cpp:154:3:154:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:152:3:152:4 | fs | allocated resource | -| test.cpp:160:3:160:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:159:3:159:5 | mtx | allocated resource | -| test.cpp:172:3:172:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:170:3:170:5 | mtx | allocated resource | +| test.cpp:142:3:142:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:141:6:141:9 | call to open | allocated resource | +| test.cpp:154:3:154:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:152:6:152:9 | call to open | allocated resource | +| test.cpp:160:3:160:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:159:7:159:10 | call to lock | allocated resource | +| test.cpp:172:3:172:35 | throw ... | The $@ is not released explicitly before throwing an exception. | test.cpp:170:7:170:10 | call to lock | allocated resource | diff --git a/rule_packages/c/Concurrency8.json b/rule_packages/c/Concurrency8.json new file mode 100644 index 0000000000..c27563f81e --- /dev/null +++ b/rule_packages/c/Concurrency8.json @@ -0,0 +1,115 @@ +{ + "MISRA-C-2012": { + "RULE-22-12": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Thread objects, thread synchronization objects, and thread-specific storage pointers shall only be accessed by the appropriate Standard Library functions.", + "kind": "problem", + "name": "Standard library threading objects (mutexes, threads, etc.) shall only be accessed by the appropriate Standard Library functions", + "precision": "very-high", + "severity": "error", + "short_name": "NonstandardUseOfThreadingObject", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "Thread objects, thread synchronization objects, and thread-specific storage pointers shall only be accessed by the appropriate Standard Library functions" + }, + "RULE-22-13": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Thread objects, thread synchronization objects, and thread specific storage pointers shall have appropriate storage duration.", + "kind": "problem", + "name": "Threading objects (mutexes, threads, etc). shall have not have automatic or thread storage duration", + "precision": "very-high", + "severity": "error", + "short_name": "ThreadingObjectWithInvalidStorageDuration", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "Thread objects, thread synchronization objects, and thread specific storage pointers shall have appropriate storage duration" + }, + "RULE-22-14": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Mutex and condition objects shall be initialized with the standard library functions before using them.", + "kind": "problem", + "name": "Thread synchronization objects shall be initialized before being accessed", + "precision": "high", + "severity": "error", + "short_name": "MutexNotInitializedBeforeUse", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + }, + { + "description": "Mutex and condition objects initialized inside of threads may result in indeterministic state", + "kind": "problem", + "name": "Thread synchronization objects shall be initialized deterministically", + "precision": "high", + "severity": "recommendation", + "short_name": "MutexInitializedInsideThread", + "tags": [ + "readability", + "maintainability", + "concurrency", + "external/misra/c/2012/amendment4" + ] + }, + { + "description": "Mutexes shall be initialized with a valid mutex type.", + "kind": "problem", + "name": "Mutexes shall be initialized with a valid mutex type", + "precision": "high", + "severity": "error", + "short_name": "MutexInitWithInvalidMutexType", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "Thread synchronization objects shall be initialized before being accessed" + }, + "RULE-22-16": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Mutex not unlocked by thread on all execution paths in current thread after being locked.", + "kind": "problem", + "name": "All mutex objects locked by a thread shall be explicitly unlocked by the same thread", + "precision": "high", + "severity": "error", + "short_name": "MutexObjectsNotAlwaysUnlocked", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "All mutex objects locked by a thread shall be explicitly unlocked by the same thread" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index 475ea1d66c..624de41885 100644 --- a/rules.csv +++ b/rules.csv @@ -803,11 +803,11 @@ c,MISRA-C-2012,RULE-22-8,Yes,Required,,,The value of errno shall be set to zero c,MISRA-C-2012,RULE-22-9,Yes,Required,,,The value of errno shall be tested against zero after calling an errno-setting-function,,Contracts3,Medium, c,MISRA-C-2012,RULE-22-10,Yes,Required,,,The value of errno shall only be tested when the last function to be called was an errno-setting-function,,Contracts3,Medium, c,MISRA-C-2012,RULE-22-11,Yes,Required,,,A thread that was previously either joined or detached shall not be subsequently joined nor detached,CON39-C,Concurrency6,Import, -c,MISRA-C-2012,RULE-22-12,Yes,Mandatory,,,"Thread objects, thread synchronization objects, and thread-specific storage pointers shall only be accessed by the appropriate Standard Library functions",,Concurrency6,Medium, -c,MISRA-C-2012,RULE-22-13,Yes,Required,,,"Thread objects, thread synchronization objects, and thread specific storage pointers shall have appropriate storage duration",EXP54-CPP and CON34-C,Concurrency6,Medium, -c,MISRA-C-2012,RULE-22-14,Yes,Mandatory,,,Thread synchronization objects shall be initialized before being accessed,EXP53-CPP,Concurrency6,Hard, +c,MISRA-C-2012,RULE-22-12,Yes,Mandatory,,,"Thread objects, thread synchronization objects, and thread-specific storage pointers shall only be accessed by the appropriate Standard Library functions",,Concurrency8,Medium, +c,MISRA-C-2012,RULE-22-13,Yes,Required,,,"Thread objects, thread synchronization objects, and thread specific storage pointers shall have appropriate storage duration",EXP54-CPP and CON34-C,Concurrency8,Medium, +c,MISRA-C-2012,RULE-22-14,Yes,Mandatory,,,Thread synchronization objects shall be initialized before being accessed,EXP53-CPP,Concurrency9,Hard, c,MISRA-C-2012,RULE-22-15,Yes,Required,,,Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated,,Concurrency6,Hard, -c,MISRA-C-2012,RULE-22-16,Yes,Required,,,All mutex objects locked by a thread shall be explicitly unlocked by the same thread,MEM51-CPP,Concurrency6,Hard, +c,MISRA-C-2012,RULE-22-16,Yes,Required,,,All mutex objects locked by a thread shall be explicitly unlocked by the same thread,MEM51-CPP,Concurrency9,Hard, c,MISRA-C-2012,RULE-22-17,Yes,Required,,,No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked before,Rule 22.2,Concurrency6,Medium, c,MISRA-C-2012,RULE-22-18,Yes,Required,,,Non-recursive mutexes shall not be recursively locked,CON56-CPP,Concurrency6,Medium, c,MISRA-C-2012,RULE-22-19,Yes,Required,,,A condition variable shall be associated with at most one mutex object,,Concurrency6,Medium, From 6a1fa993e30b666121ef65d6ed6ea42c51d22ce0 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 28 Nov 2024 05:12:32 -0800 Subject: [PATCH 107/628] Code format & package description fixes --- .../identifierlinkage/identifierlinkage.c | 4 +-- .../MutexInitializedInsideThread.ql | 2 +- c/misra/test/rules/RULE-22-13/test.c | 4 +-- c/misra/test/rules/RULE-22-16/test.c | 12 ++++----- .../src/codingstandards/cpp/Concurrency.qll | 26 +++++-------------- cpp/common/src/codingstandards/cpp/Type.qll | 12 ++++----- .../cpp/resources/ResourceLeakAnalysis.qll | 26 ++++++++++--------- .../cpp/resources/ResourceManagement.qll | 18 ++++++------- .../ExceptionSafetyValidState.qll | 20 ++------------ rule_packages/c/Concurrency8.json | 2 +- 10 files changed, 49 insertions(+), 77 deletions(-) diff --git a/c/common/test/library/identifierlinkage/identifierlinkage.c b/c/common/test/library/identifierlinkage/identifierlinkage.c index cf6b439797..25265aa144 100644 --- a/c/common/test/library/identifierlinkage/identifierlinkage.c +++ b/c/common/test/library/identifierlinkage/identifierlinkage.c @@ -25,6 +25,4 @@ struct s { }; // Enums and enum constants are not variables and have no linkage. -enum e { - E1 -}; \ No newline at end of file +enum e { E1 }; \ No newline at end of file diff --git a/c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql b/c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql index 649c941e66..a3a8f0b382 100644 --- a/c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql +++ b/c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql @@ -2,7 +2,7 @@ * @id c/misra/mutex-initialized-inside-thread * @name RULE-22-14: Thread synchronization objects shall be initialized deterministically * @description Mutex and condition objects initialized inside of threads may result in - * indeterministic state + * indeterministic state. * @kind problem * @precision high * @problem.severity recommendation diff --git a/c/misra/test/rules/RULE-22-13/test.c b/c/misra/test/rules/RULE-22-13/test.c index 0a5a84167d..193f4be471 100644 --- a/c/misra/test/rules/RULE-22-13/test.c +++ b/c/misra/test/rules/RULE-22-13/test.c @@ -47,7 +47,7 @@ void f1(void) { has_ptr_mtx_t l12; // COMPLIANT has_mtx_t l13[10]; // NON-COMPLIANT - l10 = &g1; // COMPLIANT - l10 = malloc(sizeof(mtx_t)); // NON-COMPLIANT + l10 = &g1; // COMPLIANT + l10 = malloc(sizeof(mtx_t)); // NON-COMPLIANT l10 = malloc(sizeof(mtx_t) * 4); // NON-COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-16/test.c b/c/misra/test/rules/RULE-22-16/test.c index b9a19165e8..00764645a4 100644 --- a/c/misra/test/rules/RULE-22-16/test.c +++ b/c/misra/test/rules/RULE-22-16/test.c @@ -41,7 +41,7 @@ void f6(int p) { goto skipped; } mtx_unlock(&m); - skipped: +skipped: } void f7(int p) { @@ -84,24 +84,24 @@ void f13() { mtx_t m; } s; mtx_lock(&s.m); // COMPLIANT - mtx_unlock(&s.m); + mtx_unlock(&s.m); } void f14() { - for(;;) { + for (;;) { mtx_t m; mtx_lock(&m); // COMPLIANT - mtx_unlock(&m); + mtx_unlock(&m); } } void f15(int p) { - for(;;) { + for (;;) { mtx_t m; mtx_lock(&m); // NON-COMPLIANT if (p) { break; } - mtx_unlock(&m); + mtx_unlock(&m); } } \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Concurrency.qll b/cpp/common/src/codingstandards/cpp/Concurrency.qll index f68553dfd9..ba4517a284 100644 --- a/cpp/common/src/codingstandards/cpp/Concurrency.qll +++ b/cpp/common/src/codingstandards/cpp/Concurrency.qll @@ -70,27 +70,19 @@ class C11ThreadCreateCall extends ThreadCreationFunction { } class C11MutexType extends TypedefType { - C11MutexType() { - this.hasName("mtx_t") - } + C11MutexType() { this.hasName("mtx_t") } } class C11ThreadType extends TypedefType { - C11ThreadType() { - this.hasName("thrd_t") - } + C11ThreadType() { this.hasName("thrd_t") } } class C11ConditionType extends TypedefType { - C11ConditionType() { - this.hasName("cnd_t") - } + C11ConditionType() { this.hasName("cnd_t") } } class C11ThreadStorageType extends TypedefType { - C11ThreadStorageType() { - this.hasName("tss_t") - } + C11ThreadStorageType() { this.hasName("tss_t") } } class C11ThreadingObjectType extends TypedefType { @@ -100,7 +92,7 @@ class C11ThreadingObjectType extends TypedefType { this instanceof C11ThreadType or this instanceof C11ConditionType - or + or this instanceof C11ThreadStorageType } } @@ -506,13 +498,9 @@ class CConditionOperation extends FunctionCall { getTarget().hasName(["cnd_broadcast", "cnd_signal", "cnd_timedwait", "cnd_wait", "cnd_init"]) } - predicate isInit() { - getTarget().hasName("cnd_init") - } + predicate isInit() { getTarget().hasName("cnd_init") } - predicate isUse() { - not isInit() - } + predicate isUse() { not isInit() } Expr getConditionExpr() { result = getArgument(0) } diff --git a/cpp/common/src/codingstandards/cpp/Type.qll b/cpp/common/src/codingstandards/cpp/Type.qll index 4f72f5612e..42d77b8055 100644 --- a/cpp/common/src/codingstandards/cpp/Type.qll +++ b/cpp/common/src/codingstandards/cpp/Type.qll @@ -64,21 +64,21 @@ signature class PossiblySpecifiedBaseType extends Type; /** * This module defines a class `Type` which holds for types `T` and `const/volatile T` etc. - * + * * Similar to `getUnspecifiedType()`, but does not resolve typedefs. Useful for matching * potentially qualified versions of standard typedef types, such as `const mtx_t`. - * + * * Example usage: `someType.(PossiblySpecified::Type).strip()` */ module PossiblySpecified { import cpp as cpp + final class CppType = cpp::Type; class Type extends CppType { BaseType baseType; - Type() { - baseType = stripSpecifiers(this) - } + + Type() { baseType = stripSpecifiers(this) } BaseType strip() { result = baseType } } @@ -93,4 +93,4 @@ int getPrecision(IntegralType type) { type.isExplicitlyUnsigned() and result = type.getSize() * 8 or type.isExplicitlySigned() and result = type.getSize() * 8 - 1 -} \ No newline at end of file +} diff --git a/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll b/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll index 4623b3e95e..2f932870b3 100644 --- a/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll +++ b/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll @@ -6,32 +6,32 @@ import codeql.util.Boolean /** * A library for detecting leaked resources. - * + * * To use this library, implement `ResourceLeakConfigSig`: - * + * * ``` * class UnjoinedThreadConfig implements ResourceLeakConfigSig { * predicate isResource(DataFlow::Node node) { * node.asExpr().isThreadCreate() * } - * + * * predicate isFree(ControlFlowNode node, DataFlow::Node resource) { * node.asExpr().isThreadJoin(resource.asExpr()) * } * } * ``` - * + * * You can now check if a resource is leaked through the module predicate * `ResourceLeak::isLeaked(resource)`. - * + * * The leak analysis finds the exit point of the function in which the resource is is declared, and * then reverses execution from there using `getAPredecessor()`. When this backwards walk discovers * a control flow node that frees the resource, that exploration stops. If any exploration reaches * a resource, that resource may be leaked via that path. - * + * * Uses `DataFlow::Node` in order to track aliases of the resource to better detect when the * resource is freed. - * + * * This library by default assumes that resources are expression nodes. To use it with other kinds * of nodes requires overriding `resourceInitPoint`. */ @@ -41,7 +41,8 @@ signature module ResourceLeakConfigSig { predicate isFree(ControlFlowNode node, DataFlow::Node resource); default DataFlow::Node getAnAlias(DataFlow::Node node) { - DataFlow::localFlow(node, result) or + DataFlow::localFlow(node, result) + or exists(Expr current, Expr after | current in [node.asExpr(), node.asDefiningArgument()] and after in [result.asExpr(), result.asDefiningArgument()] and @@ -57,9 +58,10 @@ signature module ResourceLeakConfigSig { } module ResourceLeak { - private newtype TResource = TJustResource(DataFlow::Node resource, ControlFlowNode cfgNode) { - Config::isAllocate(cfgNode, resource) - } + private newtype TResource = + TJustResource(DataFlow::Node resource, ControlFlowNode cfgNode) { + Config::isAllocate(cfgNode, resource) + } /** * Get an alias of a resource, and aliases of nodes that are aliased by a resource. @@ -98,4 +100,4 @@ module ResourceLeak { isLeakedAtControlPoint(resourceWrapper, result) ) } -} \ No newline at end of file +} diff --git a/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll b/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll index 93c26e0a46..58cf6fc8d2 100644 --- a/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll +++ b/cpp/common/src/codingstandards/cpp/resources/ResourceManagement.qll @@ -11,9 +11,9 @@ module ResourceLeakConfig implements ResourceLeakConfigSig { ) or exists(FunctionCall f | - f.getTarget().hasQualifiedName("std", "basic_fstream", "open") - and allocPoint = f - and node.asDefiningArgument() = f.getQualifier() + f.getTarget().hasQualifiedName("std", "basic_fstream", "open") and + allocPoint = f and + node.asDefiningArgument() = f.getQualifier() ) or exists(FunctionCall f | @@ -24,22 +24,22 @@ module ResourceLeakConfig implements ResourceLeakConfigSig { } predicate isFree(ControlFlowNode node, DataFlow::Node resource) { - exists(DeallocationExpr d, Expr freedExpr| + exists(DeallocationExpr d, Expr freedExpr | freedExpr = d.getFreedExpr() and node = d and resource.asExpr() = freedExpr ) or exists(FunctionCall f | - f.getTarget().hasQualifiedName("std", "basic_fstream", "close") - and node = f and + f.getTarget().hasQualifiedName("std", "basic_fstream", "close") and + node = f and resource.asExpr() = f.getQualifier() ) or exists(FunctionCall f | - f.getTarget().hasQualifiedName("std", "mutex", "unlock") - and node = f and + f.getTarget().hasQualifiedName("std", "mutex", "unlock") and + node = f and resource.asExpr() = f.getQualifier() ) } -} \ No newline at end of file +} diff --git a/cpp/common/src/codingstandards/cpp/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.qll b/cpp/common/src/codingstandards/cpp/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.qll index 8ed5342def..5a712dd522 100644 --- a/cpp/common/src/codingstandards/cpp/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.qll +++ b/cpp/common/src/codingstandards/cpp/rules/exceptionsafetyvalidstate/ExceptionSafetyValidState.qll @@ -15,7 +15,6 @@ abstract class ExceptionSafetyValidStateSharedQuery extends Query { } Query getQuery() { result instanceof ExceptionSafetyValidStateSharedQuery } - /** * `UncaughtThrowExpr` models a `throw` expression that is not handled */ @@ -24,18 +23,11 @@ class UncaughtThrowExpr extends ThrowExpr { } module ThrowLeakConfig implements ResourceLeakConfigSig { - predicate isAllocate(ControlFlowNode node, DataFlow::Node resource) { - //exists(ResourceAcquisitionExpr rae | - // node = rae and resource.asExpr() = rae - //) ResourceLeakConfig::isAllocate(node, resource) } predicate isFree(ControlFlowNode node, DataFlow::Node resource) { - //exists(ResourceAcquisitionExpr rae | - // node = rae.getReleaseExpr() and resource.asExpr() = rae - //) ResourceLeakConfig::isFree(node, resource) } @@ -43,19 +35,11 @@ module ThrowLeakConfig implements ResourceLeakConfigSig { result.(UncaughtThrowExpr).getEnclosingFunction() = allocPoint.(Expr).getEnclosingFunction() } - DataFlow::Node getAnAlias(DataFlow::Node node) { - DataFlow::localFlow(node, result) - } + DataFlow::Node getAnAlias(DataFlow::Node node) { DataFlow::localFlow(node, result) } } -query predicate problems( - UncaughtThrowExpr te, string message, Element e, string eDescription -) { +query predicate problems(UncaughtThrowExpr te, string message, Element e, string eDescription) { not isExcluded(te, getQuery()) and - //exists(SubBasicBlock sbb | - // sbb.getANode() = e and - // te = followsInitialized(sbb) - //) and te = ResourceLeak::getALeak(e) and message = "The $@ is not released explicitly before throwing an exception." and eDescription = "allocated resource" diff --git a/rule_packages/c/Concurrency8.json b/rule_packages/c/Concurrency8.json index c27563f81e..2dc5d48042 100644 --- a/rule_packages/c/Concurrency8.json +++ b/rule_packages/c/Concurrency8.json @@ -61,7 +61,7 @@ ] }, { - "description": "Mutex and condition objects initialized inside of threads may result in indeterministic state", + "description": "Mutex and condition objects initialized inside of threads may result in indeterministic state.", "kind": "problem", "name": "Thread synchronization objects shall be initialized deterministically", "precision": "high", From f73df15dab20ade19313fc45e0db062ae1026255 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 28 Nov 2024 05:14:49 -0800 Subject: [PATCH 108/628] fix rules.csv package changes --- rules.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rules.csv b/rules.csv index 624de41885..e58d5658af 100644 --- a/rules.csv +++ b/rules.csv @@ -805,9 +805,9 @@ c,MISRA-C-2012,RULE-22-10,Yes,Required,,,The value of errno shall only be tested c,MISRA-C-2012,RULE-22-11,Yes,Required,,,A thread that was previously either joined or detached shall not be subsequently joined nor detached,CON39-C,Concurrency6,Import, c,MISRA-C-2012,RULE-22-12,Yes,Mandatory,,,"Thread objects, thread synchronization objects, and thread-specific storage pointers shall only be accessed by the appropriate Standard Library functions",,Concurrency8,Medium, c,MISRA-C-2012,RULE-22-13,Yes,Required,,,"Thread objects, thread synchronization objects, and thread specific storage pointers shall have appropriate storage duration",EXP54-CPP and CON34-C,Concurrency8,Medium, -c,MISRA-C-2012,RULE-22-14,Yes,Mandatory,,,Thread synchronization objects shall be initialized before being accessed,EXP53-CPP,Concurrency9,Hard, +c,MISRA-C-2012,RULE-22-14,Yes,Mandatory,,,Thread synchronization objects shall be initialized before being accessed,EXP53-CPP,Concurrency8,Hard, c,MISRA-C-2012,RULE-22-15,Yes,Required,,,Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated,,Concurrency6,Hard, -c,MISRA-C-2012,RULE-22-16,Yes,Required,,,All mutex objects locked by a thread shall be explicitly unlocked by the same thread,MEM51-CPP,Concurrency9,Hard, +c,MISRA-C-2012,RULE-22-16,Yes,Required,,,All mutex objects locked by a thread shall be explicitly unlocked by the same thread,MEM51-CPP,Concurrency8,Hard, c,MISRA-C-2012,RULE-22-17,Yes,Required,,,No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked before,Rule 22.2,Concurrency6,Medium, c,MISRA-C-2012,RULE-22-18,Yes,Required,,,Non-recursive mutexes shall not be recursively locked,CON56-CPP,Concurrency6,Medium, c,MISRA-C-2012,RULE-22-19,Yes,Required,,,A condition variable shall be associated with at most one mutex object,,Concurrency6,Medium, From 616935254fd44bb1b3b96158e0169873fafeafc1 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 28 Nov 2024 05:21:53 -0800 Subject: [PATCH 109/628] Query formatting --- .../rules/CON34-C/AppropriateThreadObjectStorageDurations.ql | 3 ++- .../DCL30-C/AppropriateStorageDurationsFunctionReturn.ql | 5 +++-- .../AllocStructsWithAFlexibleArrayMemberDynamically.ql | 5 +++-- c/common/src/codingstandards/c/UninitializedMutex.qll | 0 c/common/test/library/objects/ObjectIdentity.ql | 2 +- .../RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql | 4 +--- .../ModifiableLValueSubscriptedWithTemporaryLifetime.ql | 4 +++- c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql | 5 ++--- c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql | 2 +- 9 files changed, 16 insertions(+), 14 deletions(-) delete mode 100644 c/common/src/codingstandards/c/UninitializedMutex.qll diff --git a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql index 6d9caacc5c..5a1dd3c461 100644 --- a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql +++ b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql @@ -32,7 +32,8 @@ where ( addrNode = DataFlow::exprNode(any(AddressOfExpr e | e.getOperand() = acc)) or - addrNode = DataFlow::exprNode(acc) and exists(ArrayToPointerConversion c | c.getExpr() = acc) + addrNode = DataFlow::exprNode(acc) and + exists(ArrayToPointerConversion c | c.getExpr() = acc) ) and TaintTracking::localTaint(addrNode, DataFlow::exprNode(arg)) ) diff --git a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql index 1e1e19c7c6..02f195e768 100644 --- a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql +++ b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql @@ -18,9 +18,10 @@ import codingstandards.cpp.dataflow.DataFlow class Source extends Expr { ObjectIdentity rootObject; + Source() { - rootObject.getStorageDuration().isAutomatic() - and this = rootObject.getASubobjectAddressExpr() + rootObject.getStorageDuration().isAutomatic() and + this = rootObject.getASubobjectAddressExpr() } } diff --git a/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql b/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql index 4e4ccc2171..f4483bd9fe 100644 --- a/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql +++ b/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql @@ -62,14 +62,15 @@ class FlexibleArrayStructDynamicAlloc extends FlexibleArrayAlloc, FunctionCall { */ class FlexibleArrayNonDynamicAlloc extends FlexibleArrayAlloc { ObjectIdentity object; + FlexibleArrayNonDynamicAlloc() { this = object and not object.getStorageDuration().isAllocated() and // Exclude temporaries. Though they should violate this rule, in practice these results are // often spurious and redundant, such as (*x = *x) which creates an unused temporary object. not object.hasTemporaryLifetime() and - object.getType().getUnspecifiedType() instanceof FlexibleArrayStructType - and not exists(Variable v | v.getInitializer().getExpr() = this) + object.getType().getUnspecifiedType() instanceof FlexibleArrayStructType and + not exists(Variable v | v.getInitializer().getExpr() = this) } override Element getReportElement() { result = object } diff --git a/c/common/src/codingstandards/c/UninitializedMutex.qll b/c/common/src/codingstandards/c/UninitializedMutex.qll deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/c/common/test/library/objects/ObjectIdentity.ql b/c/common/test/library/objects/ObjectIdentity.ql index 28e6832bb2..0e92e588ba 100644 --- a/c/common/test/library/objects/ObjectIdentity.ql +++ b/c/common/test/library/objects/ObjectIdentity.ql @@ -2,4 +2,4 @@ import codingstandards.c.Objects from ObjectIdentity obj where obj.getFile().getBaseName() = "objectidentity.c" -select obj, obj.getStorageDuration(), obj.getType() \ No newline at end of file +select obj, obj.getStorageDuration(), obj.getType() diff --git a/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql b/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql index c65890f6bc..da73214859 100644 --- a/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql +++ b/c/misra/src/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.ql @@ -58,9 +58,7 @@ Expr temporaryObjectFlowStep(Expr e) { e = result.(ConditionalExpr).getElse() } -from - FieldAccess fa, TemporaryObjectIdentity temporary, - ArrayToPointerConversion conversion +from FieldAccess fa, TemporaryObjectIdentity temporary, ArrayToPointerConversion conversion where not isExcluded(conversion, InvalidMemory3Package::arrayToPointerConversionOfTemporaryObjectQuery()) and fa = temporary.getASubobjectAccess() and diff --git a/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql b/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql index e10b478ee7..5ccc8316ec 100644 --- a/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql +++ b/c/misra/src/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.ql @@ -26,7 +26,9 @@ predicate usedAsModifiableLvalue(Expr expr, Boolean allowArrayAccess) { exists(AddressOfExpr parent | parent.getOperand() = expr) or // Don't report `x.y[0].m[0]++` twice. Recurse with `allowArrayAccess` set to false. - exists(FieldAccess parent | parent.getQualifier() = expr and usedAsModifiableLvalue(parent, false)) + exists(FieldAccess parent | + parent.getQualifier() = expr and usedAsModifiableLvalue(parent, false) + ) or allowArrayAccess = true and exists(ArrayExpr parent | parent.getArrayBase() = expr and usedAsModifiableLvalue(parent, true)) diff --git a/c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql b/c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql index a3a8f0b382..497fdaf14d 100644 --- a/c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql +++ b/c/misra/src/rules/RULE-22-14/MutexInitializedInsideThread.ql @@ -22,6 +22,5 @@ from C11MutexSource mutexCreate, ThreadedFunction thread where not isExcluded(mutexCreate, Concurrency8Package::mutexInitializedInsideThreadQuery()) and thread.calls*(mutexCreate.getEnclosingFunction()) -select -mutexCreate, "Mutex initialization reachable from threaded function '$@'.", -thread, thread.getName() +select mutexCreate, "Mutex initialization reachable from threaded function '$@'.", thread, + thread.getName() diff --git a/c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql b/c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql index ed4226c207..f02891d5d0 100644 --- a/c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql +++ b/c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql @@ -50,6 +50,7 @@ class ThreadObjectInitialization extends FunctionCall { class ThreadObjectUse extends Expr { ObjectIdentity owningObject; string typeString; + ThreadObjectUse() { owningObject.getASubobjectAddressExpr() = this and ( @@ -78,7 +79,6 @@ class ThreadObjectUse extends Expr { } } - predicate requiresInitializedMutexObject( Function func, ThreadObjectUse mutexUse, ObjectIdentity owningObject ) { From 6ad3660b0245b7c93509ed2389bc8a62ba139de7 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 28 Nov 2024 08:14:31 -0800 Subject: [PATCH 110/628] Fix RAII mutex test --- cpp/common/src/codingstandards/cpp/Concurrency.qll | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/Concurrency.qll b/cpp/common/src/codingstandards/cpp/Concurrency.qll index ba4517a284..8043352c5a 100644 --- a/cpp/common/src/codingstandards/cpp/Concurrency.qll +++ b/cpp/common/src/codingstandards/cpp/Concurrency.qll @@ -352,7 +352,15 @@ class RAIIStyleLock extends LockingOperation { getTarget().getDeclaringType().hasQualifiedName("std", "unique_lock") or getTarget().getDeclaringType().hasQualifiedName("std", "scoped_lock") ) and - lock = getArgument(0).getAChild*() + ( + lock = getArgument(0).getAChild*() + or + this instanceof DestructorCall and + exists(RAIIStyleLock constructor | + constructor = getQualifier().(VariableAccess).getTarget().getInitializer().getExpr() and + lock = constructor.getArgument(0).getAChild*() + ) + ) } /** @@ -361,6 +369,7 @@ class RAIIStyleLock extends LockingOperation { override predicate isLock() { not isLockingOperationWithinLockingOperation(this) and this instanceof ConstructorCall and + lock = getArgument(0).getAChild*() and // defer_locks don't cause a lock not exists(Expr exp | exp = getArgument(1) and From f3a6c3f4e53fbc80870d848da14c7f9b50d2a6c7 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 2 Dec 2024 14:33:04 +0000 Subject: [PATCH 111/628] Deviations: remove no longer required query lgtm-style suppressions are no longer supported by CodeQL and Code Scanning. --- .../deviations/DeviationsSuppression.qhelp | 12 -- .../cpp/deviations/DeviationsSuppression.ql | 120 ------------------ 2 files changed, 132 deletions(-) delete mode 100644 cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.qhelp delete mode 100644 cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql diff --git a/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.qhelp b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.qhelp deleted file mode 100644 index 0bf3a3a71b..0000000000 --- a/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.qhelp +++ /dev/null @@ -1,12 +0,0 @@ - - - -

This query generates suppression information for rules that have an associated deviation record.

-
- -
  • - MISRA Compliance 2020 document: - Chapter 4.2 (page 12) - Deviations. -
  • -
    -
    \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql deleted file mode 100644 index 9035b7d288..0000000000 --- a/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql +++ /dev/null @@ -1,120 +0,0 @@ -/** - * @name Deviation suppression - * @description Generates information about files and locations where certain alerts should be considered suppressed by deviations. - * @kind alert-suppression - * @id cpp/coding-standards/deviation-suppression - */ - -import cpp -import Deviations - -/** Holds if `lineNumber` is an indexed line number in file `f`. */ -private predicate isLineNumber(File f, int lineNumber) { - exists(Location l | l.getFile() = f | - l.getStartLine() = lineNumber - or - l.getEndLine() = lineNumber - ) -} - -/** Gets the last line number in `f`. */ -private int getLastLineNumber(File f) { result = max(int lineNumber | isLineNumber(f, lineNumber)) } - -/** Gets the last column number on the last line of `f`. */ -int getLastColumnNumber(File f) { - result = - max(Location l | - l.getFile() = f and - l.getEndLine() = getLastLineNumber(f) - | - l.getEndColumn() - ) -} - -newtype TDeviationScope = - TDeviationRecordFileScope(DeviationRecord dr, File file) { - exists(string deviationPath | - dr.isDeviated(_, deviationPath) and - file.getRelativePath().prefix(deviationPath.length()) = deviationPath - ) - } or - TDeviationRecordCommentScope(DeviationRecord dr, Comment c) { c = dr.getACodeIdentifierComment() } - -/** A deviation scope. */ -class DeviationScope extends TDeviationScope { - /** Gets the location at which this deviation was defined. */ - abstract Locatable getDeviationDefinitionLocation(); - - /** Gets the Query being deviated. */ - abstract Query getQuery(); - - abstract string toString(); - - abstract predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ); -} - -/** A deviation scope derived from a "path" entry in a `DeviationRecord`. */ -class DeviationRecordFileScope extends DeviationScope, TDeviationRecordFileScope { - private DeviationRecord getDeviationRecord() { this = TDeviationRecordFileScope(result, _) } - - override Locatable getDeviationDefinitionLocation() { result = getDeviationRecord() } - - private File getFile() { this = TDeviationRecordFileScope(_, result) } - - override Query getQuery() { result = getDeviationRecord().getQuery() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - // In an ideal world, we would produce a URL here that informed the AlertSuppression code that - // the whole file was suppressed. However, experimentation suggestions the alert suppression - // code only works with locations with lines and columns, so we generate a location that covers - // the whole "indexed" file, by finding the location indexed in the database with the latest - // line and column number. - exists(File f | f = getFile() | - f.getLocation().hasLocationInfo(filepath, _, _, _, _) and - startline = 1 and - startcolumn = 1 and - endline = getLastLineNumber(f) and - endcolumn = getLastColumnNumber(f) - ) - } - - override string toString() { - result = "Deviation of " + getDeviationRecord().getQuery() + " for " + getFile() + "." - } -} - -/** - * A deviation scope derived from a comment corresponding to a "code-identifier" entry for a - * `DeviationRecord`. - */ -class DeviationRecordCommentScope extends DeviationScope, TDeviationRecordCommentScope { - private DeviationRecord getDeviationRecord() { this = TDeviationRecordCommentScope(result, _) } - - private Comment getComment() { this = TDeviationRecordCommentScope(_, result) } - - override Locatable getDeviationDefinitionLocation() { result = getDeviationRecord() } - - override Query getQuery() { result = getDeviationRecord().getQuery() } - - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - getComment().getLocation().hasLocationInfo(filepath, startline, _, endline, endcolumn) and - startcolumn = 1 - } - - override string toString() { - result = - "Deviation of " + getDeviationRecord().getQuery() + " for comment " + getComment() + "." - } -} - -from DeviationScope deviationScope -select deviationScope.getDeviationDefinitionLocation(), // suppression comment - "// lgtm[" + deviationScope.getQuery().getQueryId() + "]", // text of suppression comment (excluding delimiters) - "lgtm[" + deviationScope.getQuery().getQueryId() + "]", // text of suppression annotation - deviationScope // scope of suppression From 7b2a2e0e183931cc12c2138f792ecfb045f74513 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Dec 2024 12:02:37 +0000 Subject: [PATCH 112/628] Add library for more complex code identifier deviations This new library supports deviating on the next line, or on ranges, in addition to deviating on the current line. --- .../deviations/CodeIdentifierDeviation.qll | 242 ++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll new file mode 100644 index 0000000000..e6220711a9 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -0,0 +1,242 @@ +/** + * A module for identifying comment markers in code that trigger deviations. + * + * Each comment marker consists of a `code-identifier` with some optional annotations. A deviation will be applied to + * some range of lines in the file containing the comment based on the annotation. The supported marker annotation + * formats are: + * - `` - the deviation applies to results on the current line. + * - `DEVIATION()` - same as above. + * - `DEVIATION_NEXT_LINE()` - this deviation applies to results on the next line. + * - `DEVIATION_BEGIN()` - marks the beginning of a range of lines where the deviation applies. + * - `DEVIATION_END()` - marks the end of a range of lines where the deviation applies. + * + * The valid `code-identifier`s are specified in deviation records, which also specify the query whose results are + * suppressed by the deviation. + * + * For begin/end, we maintain a stack of begin markers. When we encounter an end marker, we pop the stack to determine + * the range of that begin/end marker. If the stack is empty, the end marker is considered unmatched and invalid. If + * the stack is non-empty at the end of the file, all the begin markers are considered unmatched and invalid. + * + * Begin/end markers are not valid across include boundaries, as the stack is not maintained across files. + */ + +import cpp +import Deviations + +/** + * Holds if the given comment contains the code identifier. + */ +bindingset[codeIdentifier] +private predicate commentMatches(Comment comment, string codeIdentifier) { + exists(string text | + comment instanceof CppStyleComment and + // strip the beginning slashes + text = comment.getContents().suffix(2).trim() + or + comment instanceof CStyleComment and + // strip both the beginning /* and the end */ the comment + exists(string text0 | + text0 = comment.getContents().suffix(2) and + text = text0.prefix(text0.length() - 2).trim() + ) and + // The /* */ comment must be a single-line comment + not text.matches("%\n%") + | + // Code identifier appears at the start of the comment (modulo whitespace) + text.prefix(codeIdentifier.length()) = codeIdentifier + or + // Code identifier appears at the end of the comment (modulo whitespace) + text.suffix(text.length() - codeIdentifier.length()) = codeIdentifier + ) +} + +/** + * A deviation marker in the code. + */ +abstract class DeviationMarker extends Comment { + DeviationRecord record; + + /** + * Gets the deviation record associated with this deviation marker. + */ + DeviationRecord getRecord() { result = record } +} + +/** + * A deviation marker for a deviation that applies to the current line. + */ +class DeviationEndOfLineMarker extends DeviationMarker { + DeviationEndOfLineMarker() { + commentMatches(this, "DEVIATION(" + record.getCodeIdentifier() + ")") + } +} + +/** + * A deviation marker for a deviation that applies to the next line. + */ +class DeviationNextLineMarker extends DeviationMarker { + DeviationNextLineMarker() { + commentMatches(this, "DEVIATION_NEXT_LINE(" + record.getCodeIdentifier() + ")") + } +} + +/** + * A deviation marker for a deviation that applies to a range of lines + */ +abstract class DeviationRangeMarker extends DeviationMarker { } + +/** + * A deviation marker for a deviation that begins on this line. + */ +class DeviationBegin extends DeviationRangeMarker { + DeviationBegin() { commentMatches(this, "DEVIATION_BEGIN(" + record.getCodeIdentifier() + ")") } +} + +/** + * A deviation marker for a deviation that ends on this line. + */ +class DeviationEnd extends DeviationRangeMarker { + DeviationEnd() { commentMatches(this, "DEVIATION_END(" + record.getCodeIdentifier() + ")") } +} + +private predicate hasDeviationCommentFileOrdering( + DeviationRecord record, DeviationRangeMarker comment, File file, int index +) { + comment = + rank[index](DeviationRangeMarker c | + c.getRecord() = record and + file = c.getFile() + | + c order by c.getLocation().getStartLine(), c.getLocation().getStartColumn() + ) +} + +private predicate mkBeginStack(DeviationRecord record, File file, BeginStack stack, int index) { + // Stack is empty at the start + index = 0 and + stack = TEmptyBeginStack() and + exists(DeviationRangeMarker marker | + marker.getRecord() = record and marker.getLocation().getFile() = file + ) + or + // Next token is begin, so push it to the stack + exists(DeviationBegin begin, BeginStack prev | + record = begin.getRecord() and + hasDeviationCommentFileOrdering(record, begin, file, index) and + mkBeginStack(record, file, prev, index - 1) and + stack = TConsBeginStack(begin, prev) + ) + or + // Next token is end + exists(DeviationEnd end, BeginStack prevStack | + record = end.getRecord() and + hasDeviationCommentFileOrdering(record, end, file, index) and + mkBeginStack(record, file, prevStack, index - 1) + | + // There is, so pop the most recent begin off the stack + prevStack = TConsBeginStack(_, stack) + or + // Error, no begin on the stack, ignore and continue + prevStack = TEmptyBeginStack() and + stack = TEmptyBeginStack() + ) +} + +newtype TBeginStack = + TConsBeginStack(DeviationBegin begin, TBeginStack prev) { + exists(File file, int index | + hasDeviationCommentFileOrdering(begin.getRecord(), begin, file, index) and + mkBeginStack(begin.getRecord(), file, prev, index - 1) + ) + } or + TEmptyBeginStack() + +private class BeginStack extends TBeginStack { + string toString() { + exists(DeviationBegin begin, BeginStack prev | this = TConsBeginStack(begin, prev) | + result = "(" + begin + ", " + prev.toString() + ")" + ) + or + this = TEmptyBeginStack() and + result = "()" + } +} + +private predicate isDeviationRangePaired( + DeviationRecord record, DeviationBegin begin, DeviationEnd end +) { + exists(File file, int index | + record = end.getRecord() and + hasDeviationCommentFileOrdering(record, end, file, index) and + mkBeginStack(record, file, TConsBeginStack(begin, _), index - 1) + ) +} + +newtype TCodeIndentifierDeviation = + TSingleLineDeviation(DeviationRecord record, Comment comment, string filepath, int suppressedLine) { + ( + commentMatches(comment, record.getCodeIdentifier()) or + comment.(DeviationEndOfLineMarker).getRecord() = record + ) and + comment.getLocation().hasLocationInfo(filepath, suppressedLine, _, _, _) + or + comment.(DeviationNextLineMarker).getRecord() = record and + comment.getLocation().hasLocationInfo(filepath, suppressedLine - 1, _, _, _) + } or + TMultiLineDeviation( + DeviationRecord record, DeviationBegin beginComment, DeviationEnd endComment, string filepath, + int suppressedStartLine, int suppressedEndLine + ) { + isDeviationRangePaired(record, beginComment, endComment) and + beginComment.getLocation().hasLocationInfo(filepath, suppressedStartLine, _, _, _) and + endComment.getLocation().hasLocationInfo(filepath, suppressedEndLine, _, _, _) + } + +class CodeIdentifierDeviation extends TCodeIndentifierDeviation { + /** The deviation record associated with the deviation comment. */ + DeviationRecord getDeviationRecord() { + this = TSingleLineDeviation(result, _, _, _) + or + this = TMultiLineDeviation(result, _, _, _, _, _) + } + + /** + * Holds if the given element is matched by this code identifier deviation. + */ + bindingset[e] + pragma[inline_late] + predicate isElementMatching(Element e) { + exists(string filepath, int elementLocationStart | + e.getLocation().hasLocationInfo(filepath, elementLocationStart, _, _, _) + | + exists(int suppressedLine | + this = TSingleLineDeviation(_, _, filepath, suppressedLine) and + suppressedLine = elementLocationStart + ) + or + exists(int suppressedStartLine, int suppressedEndLine | + this = TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedEndLine) and + suppressedStartLine < elementLocationStart and + suppressedEndLine > elementLocationStart + ) + ) + } + + string toString() { + exists(string filepath | + exists(int suppressedLine | + this = TSingleLineDeviation(_, _, filepath, suppressedLine) and + result = + "Deviation record " + getDeviationRecord() + " applied to " + filepath + " Line " + + suppressedLine + ) + or + exists(int suppressedStartLine, int suppressedEndLine | + this = TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedEndLine) and + result = + "Deviation record " + getDeviationRecord() + " applied to " + filepath + " Line" + + suppressedStartLine + ":" + suppressedEndLine + ) + ) + } +} From f1730722ed98a0c7df7b27b755a43d27beb97302 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Dec 2024 12:04:31 +0000 Subject: [PATCH 113/628] Deviations: Integrate extended code-identifier deviations This ties in the code-identifier deviation support to the deviations and exclusions libraries. --- .../src/codingstandards/cpp/Exclusions.qll | 21 +++++--------- .../cpp/deviations/Deviations.qll | 29 ++----------------- 2 files changed, 11 insertions(+), 39 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Exclusions.qll b/cpp/common/src/codingstandards/cpp/Exclusions.qll index b718f6535d..e6a477b220 100644 --- a/cpp/common/src/codingstandards/cpp/Exclusions.qll +++ b/cpp/common/src/codingstandards/cpp/Exclusions.qll @@ -35,19 +35,14 @@ predicate isExcluded(Element e, Query query, string reason) { ) and reason = "Query has an associated deviation record for the element's file." or - // The element is on the same line as a suppression comment - exists(Comment c | - c = dr.getACodeIdentifierComment() and - query = dr.getQuery() - | - exists(string filepath, int endLine | - // Comment occurs on the same line as the end line of the element - e.getLocation().hasLocationInfo(filepath, _, _, endLine, _) and - c.getLocation().hasLocationInfo(filepath, endLine, _, _, _) - ) - ) and - reason = - "Query has an associated deviation record with a code identifier that is applied to the element." + // The element is annotated by a code identifier that deviates this rule + exists(CodeIdentifierDeviation deviationInCode | + dr.getQuery() = query and + deviationInCode = dr.getACodeIdentifierDeviation() and + deviationInCode.isElementMatching(e) and + reason = + "Query has an associated deviation record with a code identifier that is applied to the element." + ) ) or // The effective category of the query is 'Disapplied'. diff --git a/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll b/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll index 4dfadd12eb..2388f95a37 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll @@ -8,6 +8,7 @@ import cpp import semmle.code.cpp.XML import codingstandards.cpp.exclusions.RuleMetadata import codingstandards.cpp.Config +import CodeIdentifierDeviation predicate applyDeviationsAtQueryLevel() { not exists(CodingStandardsReportDeviatedAlerts reportDeviatedResults | @@ -219,32 +220,8 @@ class DeviationRecord extends XmlElement { else result = getADeviationPermit().getCodeIdentifier() } - /** Gets a comment which starts or ends with the code identifier comment. */ - Comment getACodeIdentifierComment() { - exists(string text | - ( - result instanceof CppStyleComment and - // strip the beginning slashes - text = result.getContents().suffix(2).trim() - or - result instanceof CStyleComment and - // strip both the beginning /* and the end */ the comment - exists(string text0 | - text0 = result.getContents().suffix(2) and - text = text0.prefix(text0.length() - 2).trim() - ) and - // The /* */ comment must be a single-line comment - not text.matches("%\n%") - ) and - ( - // Code identifier appears at the start of the comment (modulo whitespace) - text.prefix(getCodeIdentifier().length()) = getCodeIdentifier() - or - // Code identifier appears at the end of the comment (modulo whitespace) - text.suffix(text.length() - getCodeIdentifier().length()) = getCodeIdentifier() - ) - ) - } + /** Gets a code identifier deviation in code which starts or ends with the code identifier comment. */ + CodeIdentifierDeviation getACodeIdentifierDeviation() { this = result.getDeviationRecord() } /** Gets the `rule-id` specified for this record, if any. */ private string getRawRuleId() { result = getAChild("rule-id").getTextValue() } From e36828d9236f6c8c1fbfb631dc639aa6724f92cd Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Dec 2024 12:05:28 +0000 Subject: [PATCH 114/628] Deviations: Add test cases for new code-identifier deviations --- .../TypeLongDoubleUsed.expected | 4 +++ .../deviations/deviations_basic_test/main.cpp | 25 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected b/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected index 7b78d54892..a4e045edcf 100644 --- a/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected +++ b/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected @@ -1 +1,5 @@ | main.cpp:13:15:13:16 | d1 | Use of long double type. | +| main.cpp:18:15:18:16 | d4 | Use of long double type. | +| main.cpp:21:15:21:16 | d6 | Use of long double type. | +| main.cpp:30:15:30:17 | d10 | Use of long double type. | +| main.cpp:38:15:38:17 | d14 | Use of long double type. | diff --git a/cpp/common/test/deviations/deviations_basic_test/main.cpp b/cpp/common/test/deviations/deviations_basic_test/main.cpp index 0b302ea1f2..53258f00fd 100644 --- a/cpp/common/test/deviations/deviations_basic_test/main.cpp +++ b/cpp/common/test/deviations/deviations_basic_test/main.cpp @@ -12,5 +12,30 @@ int main(int argc, char **argv) { getX(); // NON_COMPLIANT long double d1; // NON_COMPLIANT (A0-4-2) long double d2; // a-0-4-2-deviation COMPLIANT[DEVIATED] + + long double d3; // DEVIATION(a-0-4-2-deviation) COMPLIANT[DEVIATED] + + long double d4; // NON_COMPLIANT (A0-4-2) + // DEVIATION_NEXT_LINE(a-0-4-2-deviation) + long double d5; // COMPLIANT[DEVIATED] + long double d6; // NON_COMPLIANT (A0-4-2) + + // DEVIATION_BEGIN(a-0-4-2-deviation) + long double d7; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d8; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d9; // COMPLIANT[DEVIATED] + // DEVIATION_END(a-0-4-2-deviation) + long double d10; // NON_COMPLIANT (A0-4-2) + // DEVIATION_BEGIN(a-0-4-2-deviation) + long double d11; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d12; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d13; // COMPLIANT[DEVIATED] + // DEVIATION_END(a-0-4-2-deviation) + long double d14; // NON_COMPLIANT (A0-4-2) + getX(); // NON_COMPLIANT (A0-1-2) return 0; } \ No newline at end of file From e0779350a71ca7cbcafaa483017ff686aba7724e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Dec 2024 12:06:53 +0000 Subject: [PATCH 115/628] Update user manual for new code identifier deviations --- docs/user_manual.md | 49 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/docs/user_manual.md b/docs/user_manual.md index 4c020dc73b..7ad4dc4208 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -29,7 +29,8 @@ | 0.21.0 | 2024-05-01 | Luke Cartey | Add MISRA C++ 2023 as under development, and clarify MISRA C 2012 coverage. | | 0.22.0 | 2024-10-02 | Luke Cartey | Add MISRA C 2023 as under development, and clarify MISRA C 2012 coverage. | | 0.23.0 | 2024-10-21 | Luke Cartey | Add assembly as a hazard. | -| 0.24.0 | 2024-10-22 | Luke Cartey | Add CodeQL packs as a usable output, update release artifacts list. | +| 0.24.0 | 2024-10-22 | Luke Cartey | Add CodeQL packs as a usable output, update release artifacts list. | +| 0.25.0 | 2024-12-03 | Luke Cartey | Discuss support for new deviation code identifier formats | ## Release information @@ -405,7 +406,7 @@ The example describes three ways of scoping a deviation: 1. The deviation for `A18-1-1` applies to any source file in the same or a child directory of the directory containing the example `coding-standards.yml`. 2. The deviation for `A18-5-1` applies to any source file in the directory `foo/bar` or a child directory of `foo/bar` relative to the directory containing the `coding-standards.yml`. -3. The deviation for `A0-4-2` applies to any source element that has a comment residing on **the same line** containing the identifier specified in `code-identifier`. +3. The deviation for `A0-4-2` applies to any source element that marked by a comment containing the identifier specified in `code-identifier`. The different acceptable formats are discussed in the next section. The activation of the deviation mechanism requires an extra step in the database creation process. This extra step is the invocation of the Python script `path/to/codeql-coding-standards/scripts/configuration/process_coding_standards_config.py` that is part of the coding standards code scanning pack. @@ -420,6 +421,50 @@ The `process_coding_standards_config.py` has a dependency on the package `pyyaml `pip3 install -r path/to/codeql-coding-standards/scripts/configuration/requirements.txt` +##### Deviation code identifiers + +A code identifier specified in a deviation record can be applied to certain results in the code by adding a comment marker consisting of a `code-identifier` with some optional annotations. The supported marker annotation formats are: + + - `` - the deviation applies to results on the current line. + - `DEVIATION()` - the deviation applies to results on the current line. + - `DEVIATION_NEXT_LINE()` - this deviation applies to results on the next line. + - `DEVIATION_BEGIN()` - marks the beginning of a range of lines where the deviation applies. + - `DEVIATION_END()` - marks the end of a range of lines where the deviation applies. + +Here are some examples, using the deviation record with the `a-0-4-2-deviation` code-identifier specified above: +```cpp + long double x1; // NON_COMPLIANT + + long double x2; // a-0-4-2-deviation - COMPLIANT + long double x3; // COMPLIANT - a-0-4-2-deviation + + long double x4; // DEVIATION(a-0-4-2-deviation) - COMPLIANT + long double x5; // COMPLIANT - DEVIATION(a-0-4-2-deviation) + + // DEVIATION_NEXT_LINE(a-0-4-2-deviation) + long double x6; // COMPLIANT + + // DEVIATION_BEGIN(a-0-4-2-deviation) + long double x7; // COMPLIANT + // DEVIATION_END(a-0-4-2-deviation) +``` + +`DEVIATION_END` markers will pair with the closest unmatched `DEVIATION_BEGIN` for the same `code-identifier`. Consider this example: +```cpp +1 | // DEVIATION_BEGIN(a-0-4-2-deviation) +2 | +3 | // DEVIATION_BEGIN(a-0-4-2-deviation) +4 | +5 | // DEVIATION_END(a-0-4-2-deviation) +6 | +7 | // DEVIATION_END(a-0-4-2-deviation) +``` +Here, Line 1 will pair with Line 7, and Line 3 will pair with Line 8. + +A `DEVIATION_END` without a matching `DEVIATION_BEGIN`, or `DEVIATION_BEGIN` without a matching `DEVIATION_END` is invalid and will be ignored. + +`DEVIATION_BEGIN` and `DEVIATION_END` markers only apply within a single file. Markers cannot be paired across files, and deviations do not apply to included files. + ##### Deviation permit The current implementation supports _deviation permits_ as described in the [MISRA Compliance:2020](https://www.misra.org.uk/app/uploads/2021/06/MISRA-Compliance-2020.pdf) section _4.3 Deviation permits_. From 9a1cbf3e1ddd88bbb6c8ca7b6eb61f5a9b9513aa Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Dec 2024 15:02:22 +0000 Subject: [PATCH 116/628] Cvalue widening change note --- change_notes/2024-10-23-cvalue-widening.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change_notes/2024-10-23-cvalue-widening.md diff --git a/change_notes/2024-10-23-cvalue-widening.md b/change_notes/2024-10-23-cvalue-widening.md new file mode 100644 index 0000000000..1d7a0f876a --- /dev/null +++ b/change_notes/2024-10-23-cvalue-widening.md @@ -0,0 +1,2 @@ + - `M5-0-3`, `M5-0-7`, `M5-0-8`, `M5-0-9` - `CvalueExpressionConvertedToDifferentUnderlyingType.ql`, `ExplicitFloatingIntegralConversionOfACValueExpr.ql`, `ExplicitWideningConversionOfACValueExpr.ql`, `ExplicitSignedness.ql`: + - Reduce false positives from misidentifying an explicitly casted expression used as a function argument or return value as a `cvalue`. From d77250ae1823f43e26875993df50d490525249d9 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 4 Dec 2024 16:40:28 +0000 Subject: [PATCH 117/628] C++: Change an 'extends' to an 'instanceof' to make the query compile even if IRGuard is a final class. --- .../rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql b/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql index ab121a5cc6..0e3bf26124 100644 --- a/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql +++ b/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql @@ -20,17 +20,17 @@ import semmle.code.cpp.controlflow.Guards * A check on `signal` call return value * `if (signal(SIGINT, handler) == SIG_ERR)` */ -class SignalCheckOperation extends EqualityOperation, GuardCondition { +class SignalCheckOperation extends EqualityOperation instanceof GuardCondition { BasicBlock errorSuccessor; SignalCheckOperation() { this.getAnOperand() = any(MacroInvocation m | m.getMacroName() = "SIG_ERR").getExpr() and ( this.getOperator() = "==" and - this.controls(errorSuccessor, true) + super.controls(errorSuccessor, true) or this.getOperator() = "!=" and - this.controls(errorSuccessor, false) + super.controls(errorSuccessor, false) ) } From 466f16ec87d17af43abcb67357f7c503a3a2512b Mon Sep 17 00:00:00 2001 From: lcartey <5377966+lcartey@users.noreply.github.com> Date: Wed, 4 Dec 2024 18:01:54 +0000 Subject: [PATCH 118/628] Upgrading `github/codeql` dependency to 2.18.4 --- c/cert/src/codeql-pack.lock.yml | 20 ++++++++++++------- c/cert/src/qlpack.yml | 2 +- c/cert/test/codeql-pack.lock.yml | 20 ++++++++++++------- c/common/src/codeql-pack.lock.yml | 20 ++++++++++++------- c/common/src/qlpack.yml | 2 +- c/common/test/codeql-pack.lock.yml | 20 ++++++++++++------- c/misra/src/codeql-pack.lock.yml | 20 ++++++++++++------- c/misra/src/qlpack.yml | 2 +- c/misra/test/codeql-pack.lock.yml | 20 ++++++++++++------- cpp/autosar/src/codeql-pack.lock.yml | 20 ++++++++++++------- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/codeql-pack.lock.yml | 20 ++++++++++++------- cpp/cert/src/codeql-pack.lock.yml | 20 ++++++++++++------- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/codeql-pack.lock.yml | 20 ++++++++++++------- cpp/common/src/codeql-pack.lock.yml | 20 ++++++++++++------- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/codeql-pack.lock.yml | 20 ++++++++++++------- cpp/misra/src/codeql-pack.lock.yml | 20 ++++++++++++------- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/codeql-pack.lock.yml | 20 ++++++++++++------- cpp/report/src/codeql-pack.lock.yml | 20 ++++++++++++------- cpp/report/src/qlpack.yml | 2 +- .../queries/codeql-pack.lock.yml | 20 ++++++++++++------- scripts/generate_modules/queries/qlpack.yml | 2 +- supported_codeql_configs.json | 6 +++--- 26 files changed, 220 insertions(+), 124 deletions(-) diff --git a/c/cert/src/codeql-pack.lock.yml b/c/cert/src/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/c/cert/src/codeql-pack.lock.yml +++ b/c/cert/src/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 00a8221f28..f7454d1ff0 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -5,4 +5,4 @@ suites: codeql-suites license: MIT dependencies: codeql/common-c-coding-standards: '*' - codeql/cpp-all: 0.12.9 + codeql/cpp-all: 1.4.2 diff --git a/c/cert/test/codeql-pack.lock.yml b/c/cert/test/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/c/cert/test/codeql-pack.lock.yml +++ b/c/cert/test/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/c/common/src/codeql-pack.lock.yml b/c/common/src/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/c/common/src/codeql-pack.lock.yml +++ b/c/common/src/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 41bf42d337..1930faeeb0 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -3,4 +3,4 @@ version: 2.39.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' - codeql/cpp-all: 0.12.9 + codeql/cpp-all: 1.4.2 diff --git a/c/common/test/codeql-pack.lock.yml b/c/common/test/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/c/common/test/codeql-pack.lock.yml +++ b/c/common/test/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/c/misra/src/codeql-pack.lock.yml b/c/misra/src/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/c/misra/src/codeql-pack.lock.yml +++ b/c/misra/src/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index b160f27b6e..656394ad1d 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -6,4 +6,4 @@ license: MIT default-suite-file: codeql-suites/misra-c-default.qls dependencies: codeql/common-c-coding-standards: '*' - codeql/cpp-all: 0.12.9 + codeql/cpp-all: 1.4.2 diff --git a/c/misra/test/codeql-pack.lock.yml b/c/misra/test/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/c/misra/test/codeql-pack.lock.yml +++ b/c/misra/test/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/cpp/autosar/src/codeql-pack.lock.yml b/cpp/autosar/src/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/cpp/autosar/src/codeql-pack.lock.yml +++ b/cpp/autosar/src/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index cd37cef87e..e1843eb2e7 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -5,4 +5,4 @@ suites: codeql-suites license: MIT dependencies: codeql/common-cpp-coding-standards: '*' - codeql/cpp-all: 0.12.9 + codeql/cpp-all: 1.4.2 diff --git a/cpp/autosar/test/codeql-pack.lock.yml b/cpp/autosar/test/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/cpp/autosar/test/codeql-pack.lock.yml +++ b/cpp/autosar/test/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/cpp/cert/src/codeql-pack.lock.yml b/cpp/cert/src/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/cpp/cert/src/codeql-pack.lock.yml +++ b/cpp/cert/src/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 464a5172fc..949087dfd5 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -4,5 +4,5 @@ description: CERT C++ 2016 suites: codeql-suites license: MIT dependencies: - codeql/cpp-all: 0.12.9 + codeql/cpp-all: 1.4.2 codeql/common-cpp-coding-standards: '*' diff --git a/cpp/cert/test/codeql-pack.lock.yml b/cpp/cert/test/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/cpp/cert/test/codeql-pack.lock.yml +++ b/cpp/cert/test/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/cpp/common/src/codeql-pack.lock.yml b/cpp/common/src/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/cpp/common/src/codeql-pack.lock.yml +++ b/cpp/common/src/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index 3912f3531f..1cfc63d8d9 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -2,6 +2,6 @@ name: codeql/common-cpp-coding-standards version: 2.39.0-dev license: MIT dependencies: - codeql/cpp-all: 0.12.9 + codeql/cpp-all: 1.4.2 dataExtensions: - ext/*.model.yml diff --git a/cpp/common/test/codeql-pack.lock.yml b/cpp/common/test/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/cpp/common/test/codeql-pack.lock.yml +++ b/cpp/common/test/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/cpp/misra/src/codeql-pack.lock.yml b/cpp/misra/src/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/cpp/misra/src/codeql-pack.lock.yml +++ b/cpp/misra/src/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index c27400fc8e..4f94ff4bec 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -5,4 +5,4 @@ default-suite: codeql-suites/misra-cpp-default.qls license: MIT dependencies: codeql/common-cpp-coding-standards: '*' - codeql/cpp-all: 0.12.9 + codeql/cpp-all: 1.4.2 diff --git a/cpp/misra/test/codeql-pack.lock.yml b/cpp/misra/test/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/cpp/misra/test/codeql-pack.lock.yml +++ b/cpp/misra/test/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/cpp/report/src/codeql-pack.lock.yml b/cpp/report/src/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/cpp/report/src/codeql-pack.lock.yml +++ b/cpp/report/src/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index 6477e52747..73f4cf3276 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -2,4 +2,4 @@ name: codeql/report-cpp-coding-standards version: 2.39.0-dev license: MIT dependencies: - codeql/cpp-all: 0.12.9 + codeql/cpp-all: 1.4.2 diff --git a/scripts/generate_modules/queries/codeql-pack.lock.yml b/scripts/generate_modules/queries/codeql-pack.lock.yml index 2cbbccee53..910a6e060e 100644 --- a/scripts/generate_modules/queries/codeql-pack.lock.yml +++ b/scripts/generate_modules/queries/codeql-pack.lock.yml @@ -2,17 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 0.12.9 + version: 1.4.2 codeql/dataflow: - version: 0.2.3 + version: 1.1.1 + codeql/mad: + version: 1.0.7 codeql/rangeanalysis: - version: 0.0.11 + version: 1.0.7 codeql/ssa: - version: 0.2.12 + version: 1.0.7 codeql/tutorial: - version: 0.2.12 + version: 1.0.7 + codeql/typeflow: + version: 1.0.7 codeql/typetracking: - version: 0.2.12 + version: 1.0.7 codeql/util: - version: 0.2.12 + version: 1.0.7 + codeql/xml: + version: 1.0.7 compiled: false diff --git a/scripts/generate_modules/queries/qlpack.yml b/scripts/generate_modules/queries/qlpack.yml index fea871b973..88a48269e7 100644 --- a/scripts/generate_modules/queries/qlpack.yml +++ b/scripts/generate_modules/queries/qlpack.yml @@ -2,4 +2,4 @@ name: codeql/standard-library-extraction-cpp-coding-standards version: 0.0.0 license: MIT dependencies: - codeql/cpp-all: 0.12.9 + codeql/cpp-all: 1.4.2 diff --git a/supported_codeql_configs.json b/supported_codeql_configs.json index e8b2597100..b143f67fe9 100644 --- a/supported_codeql_configs.json +++ b/supported_codeql_configs.json @@ -1,9 +1,9 @@ { "supported_environment": [ { - "codeql_cli": "2.16.6", - "codeql_standard_library": "codeql-cli/v2.16.6", - "codeql_cli_bundle": "codeql-bundle-v2.16.6" + "codeql_cli": "2.18.4", + "codeql_standard_library": "codeql-cli/v2.18.4", + "codeql_cli_bundle": "codeql-bundle-v2.18.4" } ], "supported_language": [ From 585b864eccb3b836659b41941f1d87c8eaabe374 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 4 Dec 2024 23:02:33 +0000 Subject: [PATCH 119/628] ValidContainerElementAccess: Address new FPs We had some new false positives because in 2.18.4 string taint is tracked into the qualifier of a string operation, such as insert. This caused us to erroneously identify the container itself as a reference to an element of the container. This has been addressed by excluding uses of the owning container from pointer or reference access. --- cpp/common/src/codingstandards/cpp/Iterators.qll | 4 +++- .../ValidContainerElementAccess.expected | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Iterators.qll b/cpp/common/src/codingstandards/cpp/Iterators.qll index 8add8598fc..76751aa87b 100644 --- a/cpp/common/src/codingstandards/cpp/Iterators.qll +++ b/cpp/common/src/codingstandards/cpp/Iterators.qll @@ -37,7 +37,9 @@ class ContainerPointerOrReferenceAccess extends ContainerAccess { ) and localTaint(DataFlow::exprNode(fc), DataFlow::exprNode(this)) and (getUnderlyingType() instanceof ReferenceType or getUnderlyingType() instanceof PointerType) and - fc.getQualifier().(VariableAccess).getTarget() = owningContainer + fc.getQualifier().(VariableAccess).getTarget() = owningContainer and + // Exclude cases where we see taint into the owning container + not this = owningContainer.getAnAccess() ) } diff --git a/cpp/common/test/rules/validcontainerelementaccess/ValidContainerElementAccess.expected b/cpp/common/test/rules/validcontainerelementaccess/ValidContainerElementAccess.expected index 1738cbe330..988846beef 100644 --- a/cpp/common/test/rules/validcontainerelementaccess/ValidContainerElementAccess.expected +++ b/cpp/common/test/rules/validcontainerelementaccess/ValidContainerElementAccess.expected @@ -7,6 +7,4 @@ | test.cpp:89:15:89:16 | it | Elements of $@ not accessed with valid reference, pointer, or iterator because of a prior $@. | test.cpp:86:20:86:20 | d | container | test.cpp:92:7:92:12 | call to insert | invalidation | | test.cpp:91:9:91:10 | it | Elements of $@ not accessed with valid reference, pointer, or iterator because of a prior $@. | test.cpp:86:20:86:20 | d | container | test.cpp:92:7:92:12 | call to insert | invalidation | | test.cpp:98:56:98:58 | loc | Elements of $@ not accessed with valid reference, pointer, or iterator because of a prior $@. | test.cpp:96:44:96:46 | str | container | test.cpp:99:9:99:14 | call to insert | invalidation | -| test.cpp:99:5:99:7 | str | Elements of $@ not accessed with valid reference, pointer, or iterator because of a prior $@. | test.cpp:96:44:96:46 | str | container | test.cpp:99:9:99:14 | call to insert | invalidation | | test.cpp:99:16:99:18 | loc | Elements of $@ not accessed with valid reference, pointer, or iterator because of a prior $@. | test.cpp:96:44:96:46 | str | container | test.cpp:99:9:99:14 | call to insert | invalidation | -| test.cpp:106:11:106:13 | str | Elements of $@ not accessed with valid reference, pointer, or iterator because of a prior $@. | test.cpp:103:45:103:47 | str | container | test.cpp:106:15:106:20 | call to insert | invalidation | From 365c090bc85532c53605b43b1f47aa8c7a765ed9 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 5 Dec 2024 10:18:40 +0000 Subject: [PATCH 120/628] Update expected results files after upgrade - Rule 1.5 has an extra data flow node that is harmless. - The other rules had changes to the .ql which affected the location of the deprecated data flow library warnings. --- .../UngetcCallOnStreamPositionZero.expected | 2 ++ ...rrayFunctionArgumentNumberOfElements.expected | 12 ++++++------ ...mpUsedToCompareNullTerminatedStrings.expected | 8 ++++---- ...penForReadAndWriteOnDifferentStreams.expected | 2 +- .../AttemptToWriteToAReadOnlyStream.expected | 12 ++++++------ ...BeComparedWithUnmodifiedReturnValues.expected | 16 ++++++++-------- 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected index ff25a58e3c..fb8d44ea19 100644 --- a/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected +++ b/c/misra/test/rules/RULE-1-5/UngetcCallOnStreamPositionZero.expected @@ -1,7 +1,9 @@ edges +| test.c:39:16:39:20 | *call to fopen | test.c:39:16:39:20 | *call to fopen | provenance | | | test.c:39:16:39:20 | *call to fopen | test.c:41:15:41:18 | *file | provenance | | nodes | test.c:39:16:39:20 | *call to fopen | semmle.label | *call to fopen | +| test.c:39:16:39:20 | *call to fopen | semmle.label | *call to fopen | | test.c:41:15:41:18 | *file | semmle.label | *file | subpaths #select diff --git a/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected b/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected index cb4422f5f1..174c6aa40f 100644 --- a/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected +++ b/c/misra/test/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.expected @@ -1,9 +1,9 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:47,36-44) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:48,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:50,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:55,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:71,28-36) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:71,51-59) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:48,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:49,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:51,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:56,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:72,28-36) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ArrayFunctionArgumentNumberOfElements.ql:72,51-59) | test.c:18:6:18:6 | 0 | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | | test.c:19:6:19:7 | ar | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | | test.c:21:6:21:9 | ar2p | The function argument does not have a sufficient number or elements declared in the $@. | test.c:1:13:1:14 | ar | parameter | diff --git a/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected b/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected index cf45b21eb4..5ae49919a9 100644 --- a/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected +++ b/c/misra/test/rules/RULE-21-14/MemcmpUsedToCompareNullTerminatedStrings.expected @@ -1,7 +1,7 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:22,54-62) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:23,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:49,20-28) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:57,43-56) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:23,54-62) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:24,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:50,20-28) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (MemcmpUsedToCompareNullTerminatedStrings.ql:58,43-56) edges | test.c:12:13:12:15 | a | test.c:14:10:14:10 | a | provenance | | | test.c:12:13:12:15 | a | test.c:23:13:23:13 | a | provenance | | diff --git a/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected b/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected index 6360b21973..0365f4980d 100644 --- a/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected +++ b/c/misra/test/rules/RULE-22-3/FileOpenForReadAndWriteOnDifferentStreams.expected @@ -1,4 +1,4 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (FileOpenForReadAndWriteOnDifferentStreams.ql:38,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (FileOpenForReadAndWriteOnDifferentStreams.ql:39,9-17) | test.c:6:14:6:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:5:14:5:18 | call to fopen | here | | test.c:17:14:17:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:16:14:16:18 | call to fopen | here | | test.c:33:14:33:18 | call to fopen | The same file was already opened $@. Files should not be read and written at the same time using different streams. | test.c:32:14:32:18 | call to fopen | here | diff --git a/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected b/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected index 88dca316a2..dbf08e3d3d 100644 --- a/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected +++ b/c/misra/test/rules/RULE-22-4/AttemptToWriteToAReadOnlyStream.expected @@ -1,8 +1,8 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:18,32-40) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:19,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:24,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:30,21-29) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:32,6-14) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:35,28-36) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:19,32-40) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:20,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:25,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:31,21-29) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:33,6-14) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AttemptToWriteToAReadOnlyStream.ql:36,28-36) | test.c:10:3:10:9 | call to fprintf | Attempt to write to a $@ opened as read-only. | test.c:9:14:9:18 | call to fopen | stream | | test.c:15:3:15:9 | call to fprintf | Attempt to write to a $@ opened as read-only. | test.c:18:14:18:18 | call to fopen | stream | diff --git a/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected index a7ee20c0b0..83a10a46fb 100644 --- a/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected +++ b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected @@ -1,10 +1,10 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:22,28-36) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:23,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:27,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:36,23-31) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:41,17-25) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:50,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:58,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:58,46-54) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:23,28-36) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:24,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:28,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:37,23-31) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:42,17-25) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:51,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:59,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:59,46-54) | test.c:6:7:6:20 | ... != ... | The check is not reliable as the type of the return value of $@ is converted. | test.c:5:14:5:20 | call to getchar | call to getchar | | test.c:13:7:13:15 | ... != ... | The check is not reliable as the type of the return value of $@ is converted. | test.c:12:14:12:20 | call to getchar | call to getchar | From 7595aa41a7e0bfff32776d5a679e5f9366b30528 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 5 Dec 2024 10:54:28 +0000 Subject: [PATCH 121/628] Add FALSE_NEGATIVE markers for #811 https://github.com/github/codeql-coding-standards/issues/811 --- cpp/autosar/test/rules/A12-8-6/test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/autosar/test/rules/A12-8-6/test.cpp b/cpp/autosar/test/rules/A12-8-6/test.cpp index 6a31ca60ae..d197fc18fb 100644 --- a/cpp/autosar/test/rules/A12-8-6/test.cpp +++ b/cpp/autosar/test/rules/A12-8-6/test.cpp @@ -12,8 +12,8 @@ class DerivedClass1 // COMPLIANT - not a base class itself // Base class with compiler generated move/copy is not compliant, because they // are public by default -class BaseClass2 {}; // NON_COMPLIANT - compiler generated move and assignment - // are in contravention +class BaseClass2 {}; // NON_COMPLIANT[FALSE_NEGATIVE] - compiler generated move + // and assignment are in contravention class DerivedClass2 // COMPLIANT - not a base class itself : public BaseClass2 {}; @@ -87,7 +87,7 @@ template class BaseClass7 { BaseClass7 &operator=(BaseClass7 const &) = default; // NON_COMPLIANT BaseClass7 &operator=(BaseClass7 &&) = default; // NON_COMPLIANT int operator=(int i); // COMPLIANT - not an assignment operator -}; // COMPLIANT +}; template class DerivedClass7 // COMPLIANT - not a base class itself @@ -121,7 +121,7 @@ class DerivedClass9 // COMPLIANT - not a base class itself T t; }; -template class BaseClass9 { // NON_COMPLIANT +template class BaseClass9 { // NON_COMPLIANT[FALSE_NEGATIVE] public: BaseClass9() {} From d7be5cca7f47055a1de40a2e51b308680147c852 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 5 Dec 2024 10:55:05 +0000 Subject: [PATCH 122/628] Add change note for upgrade --- change_notes/2024-12-05-upgrade-to-2.18.4.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 change_notes/2024-12-05-upgrade-to-2.18.4.md diff --git a/change_notes/2024-12-05-upgrade-to-2.18.4.md b/change_notes/2024-12-05-upgrade-to-2.18.4.md new file mode 100644 index 0000000000..6f3d4ba404 --- /dev/null +++ b/change_notes/2024-12-05-upgrade-to-2.18.4.md @@ -0,0 +1,3 @@ +- Updated the CodeQL version to `2.18.4`. +- `A12-8-6` - `CopyAndMoveNotDeclaredProtected.ql`: + - Implicitly created copy and move constructors will no longer be flagged in tenplate instantiations when they are unused, or trivial (tracked at https://github.com/github/codeql-coding-standards/issues/811). \ No newline at end of file From 0aa1f5f6965b7835fdcabab09fa60f1b8eea7208 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 5 Dec 2024 22:45:24 +0000 Subject: [PATCH 123/628] Remove no longer needed false positive markers --- cpp/common/test/rules/validcontainerelementaccess/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/common/test/rules/validcontainerelementaccess/test.cpp b/cpp/common/test/rules/validcontainerelementaccess/test.cpp index d9e2c2d89a..55c94cf8f1 100644 --- a/cpp/common/test/rules/validcontainerelementaccess/test.cpp +++ b/cpp/common/test/rules/validcontainerelementaccess/test.cpp @@ -96,14 +96,14 @@ void f8(const int *ar) { void f9(const std::string &s, std::string &str) { std::string::iterator loc = str.begin(); for (auto i = s.begin(), e = s.end(); i != e; ++i, ++loc) { // NON_COMPLIANT - str.insert(loc, 'c'); // NON_COMPLIANT[FALSE POSITIVE for str] + str.insert(loc, 'c'); // NON_COMPLIANT } } void f10(const std::string &s, std::string &str) { std::string::iterator loc = str.begin(); for (auto i = s.begin(), e = s.end(); i != e; ++i, ++loc) { // COMPLIANT - loc = str.insert(loc, 'c'); // COMPLIANT[FALSE POSITIVE] + loc = str.insert(loc, 'c'); // COMPLIANT } } From 27efc319d67e44524f3eeeae10b61b85f71671c0 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Dec 2024 22:53:18 +0000 Subject: [PATCH 124/628] Remove unused Scope import --- cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.ql | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.ql b/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.ql index 3f91530c84..368c0a05e4 100644 --- a/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.ql +++ b/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.ql @@ -13,7 +13,6 @@ import cpp import codingstandards.cpp.cert -import codingstandards.cpp.Scope class LocalUserFunctionDeclarationEntry extends FunctionDeclarationEntry { DeclStmt ds; From 0c92f2efa9b6305fae4e3e188c5eab2939f71886 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Dec 2024 23:54:56 +0000 Subject: [PATCH 125/628] DCL53-CPP: Migrate to hidesStrict Any conflicting variable will be, by definition, in a different scope. --- .../LocalConstructorInitializedObjectHidesIdentifier.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.ql b/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.ql index 237ebbe985..f6fe18a3db 100644 --- a/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.ql +++ b/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.ql @@ -20,6 +20,6 @@ from UserVariable v, UserVariable hidden where not isExcluded(v, ScopePackage::localConstructorInitializedObjectHidesIdentifierQuery()) and v.getInitializer().getExpr() instanceof ConstructorCall and - hides(hidden, v) + hidesStrict(hidden, v) select v, "The declaration declares variable " + v.getName() + " that hides $@", hidden, hidden.getName() From 90d4127a7bc8c8f3a9a09541f39aebb50f25a98d Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sat, 7 Dec 2024 00:04:46 +0000 Subject: [PATCH 126/628] Scope: Remove hides(..) and related predicates There are no more consumers of hides(..). In addition, it doesn't make sense conceptually to look for variables in the same scope with the same name, as scopes will prohibit using the same name in the same scope. Reviewing real world cases where this occurs, they all seem to be extractor oddities (multiple copies of parameters for the same function etc.) which provides further evidence that this mode is not required. --- cpp/common/src/codingstandards/cpp/Scope.qll | 28 -------------------- 1 file changed, 28 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Scope.qll b/cpp/common/src/codingstandards/cpp/Scope.qll index d9a81b98e3..b05c5dc9c4 100644 --- a/cpp/common/src/codingstandards/cpp/Scope.qll +++ b/cpp/common/src/codingstandards/cpp/Scope.qll @@ -160,15 +160,6 @@ predicate inSameTranslationUnit(File f1, File f2) { ) } -/** - * Gets a user variable which occurs in the "potential scope" of variable `v`. - */ -cached -UserVariable getPotentialScopeOfVariable(UserVariable v) { - result = getPotentialScopeOfVariable_candidate(v) and - inSameTranslationUnit(v.getFile(), result.getFile()) -} - /** * Gets a user variable which occurs in the "outer scope" of variable `v`. */ @@ -203,15 +194,6 @@ class TranslationUnit extends SourceFile { } } -/** Holds if `v2` may hide `v1`. */ -private predicate hides_candidate(UserVariable v1, UserVariable v2) { - not v1 = v2 and - v2 = getPotentialScopeOfVariable(v1) and - v1.getName() = v2.getName() and - // Member variables cannot hide other variables nor be hidden because the can be referenced through their qualified name. - not (v1.isMember() or v2.isMember()) -} - /** Holds if `v2` may hide `v1`. */ private predicate hides_candidateStrict(UserVariable v1, UserVariable v2) { not v1 = v2 and @@ -256,16 +238,6 @@ private Stmt getEnclosingStmt(LocalScopeVariable v) { ) } -/** Holds if `v2` hides `v1`. */ -predicate hides(UserVariable v1, UserVariable v2) { - hides_candidate(v1, v2) and - // Confirm that there's no closer candidate variable which `v2` hides - not exists(UserVariable mid | - hides_candidate(v1, mid) and - hides_candidate(mid, v2) - ) -} - /** Holds if `v2` strictly (`v2` is in an inner scope compared to `v1`) hides `v1`. */ predicate hidesStrict(UserVariable v1, UserVariable v2) { hides_candidateStrict(v1, v2) and From 6b5021a923702d9b85bca2e923ff279b8e5fd69f Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 8 Dec 2024 17:23:28 +0000 Subject: [PATCH 127/628] Scope: Add getParentScope testing - Expose the internal getParentScope for testing. - Add test cases --- cpp/common/src/codingstandards/cpp/Scope.qll | 107 ++++++++++-------- .../cpp/scope/ParentScope.expected | 96 ++++++++++++++++ .../codingstandards/cpp/scope/ParentScope.ql | 5 + .../codingstandards/cpp/scope/test.cpp | 37 ++++++ 4 files changed, 195 insertions(+), 50 deletions(-) create mode 100644 cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected create mode 100644 cpp/common/test/library/codingstandards/cpp/scope/ParentScope.ql create mode 100644 cpp/common/test/library/codingstandards/cpp/scope/test.cpp diff --git a/cpp/common/src/codingstandards/cpp/Scope.qll b/cpp/common/src/codingstandards/cpp/Scope.qll index b05c5dc9c4..9af5c8e21c 100644 --- a/cpp/common/src/codingstandards/cpp/Scope.qll +++ b/cpp/common/src/codingstandards/cpp/Scope.qll @@ -5,54 +5,59 @@ import cpp /** - * Gets the parent scope of this `Element`, if any. - * A scope is a `Type` (`Class` / `Enum`), a `Namespace`, a `Block`, a `Function`, - * or certain kinds of `Statement`. - * Differs from `Element::getParentScope` when `e` is a `LoopControlVariable` + * Internal module, exposed for testing. */ -private Element getParentScope(Element e) { - /* - * A `Block` cannot have a `ForStmt` as its parent scope so we have to special case - * for loop bodies to ensure that identifiers inside the loop bodies have the for stmt as a parent scope. - * If this is not the case then `i2` in the following example cannot be in `i1`'s potential scope, because - * the parent scope of `i1` is the `ForStmt` while the transitive closure of the parent scope for `i2` doesn't include - * outer scope. Blocks can only have blocks as parent scopes. - * void f() { - * for( int i1; ... ) { - * for (int i2; ...) { - * } - * } - * } +module Internal { + /** + * Gets the parent scope of this `Element`, if any. + * A scope is a `Type` (`Class` / `Enum`), a `Namespace`, a `Block`, a `Function`, + * or certain kinds of `Statement`. + * Differs from `Element::getParentScope` when `e` is a `LoopControlVariable` */ - - exists(Loop loop | loop.getStmt() = e and result = loop) - or - exists(IfStmt ifStmt | - (ifStmt.getThen() = e or ifStmt.getElse() = e) and - result = ifStmt - ) - or - exists(SwitchStmt switchStmt | switchStmt.getStmt() = e and result = switchStmt) - or - not result.(Loop).getStmt() = e and - not result.(IfStmt).getThen() = e and - not result.(IfStmt).getElse() = e and - not result.(SwitchStmt).getStmt() = e and - if exists(e.getParentScope()) - then result = e.getParentScope() - else ( - // Statements do no have a parent scope, so return the enclosing block. - result = e.(Stmt).getEnclosingBlock() + Element getParentScope(Element e) { + /* + * A `Block` cannot have a `ForStmt` as its parent scope so we have to special case + * for loop bodies to ensure that identifiers inside the loop bodies have the for stmt as a parent scope. + * If this is not the case then `i2` in the following example cannot be in `i1`'s potential scope, because + * the parent scope of `i1` is the `ForStmt` while the transitive closure of the parent scope for `i2` doesn't include + * outer scope. Blocks can only have blocks as parent scopes. + * void f() { + * for( int i1; ... ) { + * for (int i2; ...) { + * } + * } + * } + */ + + exists(Loop loop | loop.getStmt() = e and result = loop) + or + exists(IfStmt ifStmt | + (ifStmt.getThen() = e or ifStmt.getElse() = e) and + result = ifStmt + ) or - result = e.(Expr).getEnclosingBlock() + exists(SwitchStmt switchStmt | switchStmt.getStmt() = e and result = switchStmt) or - // Catch block parameters don't have an enclosing scope, so attach them to the - // the block itself - exists(CatchBlock cb | - e = cb.getParameter() and - result = cb + not result.(Loop).getStmt() = e and + not result.(IfStmt).getThen() = e and + not result.(IfStmt).getElse() = e and + not result.(SwitchStmt).getStmt() = e and + if exists(e.getParentScope()) + then result = e.getParentScope() + else ( + // Statements do no have a parent scope, so return the enclosing block. + result = e.(Stmt).getEnclosingBlock() + or + result = e.(Expr).getEnclosingBlock() + or + // Catch block parameters don't have an enclosing scope, so attach them to the + // the block itself + exists(CatchBlock cb | + e = cb.getParameter() and + result = cb + ) ) - ) + } } /** A variable which is defined by the user, rather than being from a third party or compiler generated. */ @@ -68,19 +73,19 @@ class UserVariable extends Variable { /** An element which is the parent scope of at least one other element in the program. */ class Scope extends Element { - Scope() { this = getParentScope(_) } + Scope() { this = Internal::getParentScope(_) } - UserVariable getAVariable() { getParentScope(result) = this } + UserVariable getAVariable() { Internal::getParentScope(result) = this } int getNumberOfVariables() { result = count(getAVariable()) } Scope getAnAncestor() { result = this.getStrictParent+() } - Scope getStrictParent() { result = getParentScope(this) } + Scope getStrictParent() { result = Internal::getParentScope(this) } - Declaration getADeclaration() { getParentScope(result) = this } + Declaration getADeclaration() { Internal::getParentScope(result) = this } - Expr getAnExpr() { this = getParentScope(result) } + Expr getAnExpr() { this = Internal::getParentScope(result) } private predicate getLocationInfo( PreprocessorBranchDirective pbd, string file1, string file2, int startline1, int startline2 @@ -112,9 +117,11 @@ class Scope extends Element { predicate isGenerated() { this instanceof GeneratedBlockStmt } int getDepth() { - exists(Scope parent | parent = getParentScope(this) and result = 1 + parent.getDepth()) + exists(Scope parent | + parent = Internal::getParentScope(this) and result = 1 + parent.getDepth() + ) or - not exists(getParentScope(this)) and result = 0 + not exists(Internal::getParentScope(this)) and result = 0 } } diff --git a/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected new file mode 100644 index 0000000000..0d36cc980d --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected @@ -0,0 +1,96 @@ +| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | operator= | +| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | operator= | +| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:8:7:8:7 | operator= | +| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:8:7:8:7 | operator= | +| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:27:28:27:28 | (unnamed constructor) | +| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:27:28:27:28 | (unnamed constructor) | +| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:27:28:27:28 | operator= | +| file://:0:0:0:0 | __va_list_tag | file://:0:0:0:0 | (global namespace) | +| file://:0:0:0:0 | fp_offset | file://:0:0:0:0 | __va_list_tag | +| file://:0:0:0:0 | gp_offset | file://:0:0:0:0 | __va_list_tag | +| file://:0:0:0:0 | operator= | file://:0:0:0:0 | __va_list_tag | +| file://:0:0:0:0 | operator= | file://:0:0:0:0 | __va_list_tag | +| file://:0:0:0:0 | overflow_arg_area | file://:0:0:0:0 | __va_list_tag | +| file://:0:0:0:0 | reg_save_area | file://:0:0:0:0 | __va_list_tag | +| test.cpp:1:5:1:7 | id1 | file://:0:0:0:0 | (global namespace) | +| test.cpp:3:11:3:13 | ns1 | file://:0:0:0:0 | (global namespace) | +| test.cpp:4:5:4:7 | id1 | test.cpp:3:11:3:13 | ns1 | +| test.cpp:6:11:6:13 | ns1::ns2 | test.cpp:3:11:3:13 | ns1 | +| test.cpp:7:5:7:7 | id1 | test.cpp:6:11:6:13 | ns1::ns2 | +| test.cpp:8:7:8:7 | C1 | test.cpp:8:7:8:8 | C1 | +| test.cpp:8:7:8:7 | operator= | test.cpp:8:7:8:8 | C1 | +| test.cpp:8:7:8:7 | operator= | test.cpp:8:7:8:8 | C1 | +| test.cpp:8:7:8:8 | C1 | test.cpp:6:11:6:13 | ns1::ns2 | +| test.cpp:9:7:9:9 | id1 | test.cpp:8:7:8:8 | C1 | +| test.cpp:10:8:10:17 | test_scope | test.cpp:8:7:8:8 | C1 | +| test.cpp:10:23:10:25 | id1 | test.cpp:10:8:10:17 | test_scope | +| test.cpp:10:28:34:3 | { ... } | test.cpp:10:8:10:17 | test_scope | +| test.cpp:11:5:33:5 | for(...;...;...) ... | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:10:11:17 | declaration | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:14:11:16 | id1 | test.cpp:11:5:33:5 | for(...;...;...) ... | +| test.cpp:11:19:11:21 | id1 | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:19:11:25 | ... < ... | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:25:11:25 | 1 | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:28:11:30 | id1 | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:28:11:32 | ... ++ | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:35:33:5 | { ... } | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:35:33:5 | { ... } | test.cpp:11:5:33:5 | for(...;...;...) ... | +| test.cpp:12:7:32:7 | for(...;...;...) ... | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:12:12:19 | declaration | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:16:12:18 | id1 | test.cpp:12:7:32:7 | for(...;...;...) ... | +| test.cpp:12:21:12:23 | id1 | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:21:12:27 | ... < ... | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:27:12:27 | 1 | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:30:12:32 | id1 | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:30:12:34 | ... ++ | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:37:32:7 | { ... } | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:37:32:7 | { ... } | test.cpp:12:7:32:7 | for(...;...;...) ... | +| test.cpp:13:9:31:9 | { ... } | test.cpp:12:37:32:7 | { ... } | +| test.cpp:14:11:14:18 | declaration | test.cpp:13:9:31:9 | { ... } | +| test.cpp:14:15:14:17 | id1 | test.cpp:13:9:31:9 | { ... } | +| test.cpp:16:11:20:11 | if (...) ... | test.cpp:13:9:31:9 | { ... } | +| test.cpp:16:15:16:17 | id1 | test.cpp:13:9:31:9 | { ... } | +| test.cpp:16:15:16:22 | ... == ... | test.cpp:13:9:31:9 | { ... } | +| test.cpp:16:22:16:22 | 0 | test.cpp:13:9:31:9 | { ... } | +| test.cpp:16:25:18:11 | { ... } | test.cpp:13:9:31:9 | { ... } | +| test.cpp:16:25:18:11 | { ... } | test.cpp:16:11:20:11 | if (...) ... | +| test.cpp:17:13:17:20 | declaration | test.cpp:16:25:18:11 | { ... } | +| test.cpp:17:17:17:19 | id1 | test.cpp:16:25:18:11 | { ... } | +| test.cpp:18:18:20:11 | { ... } | test.cpp:13:9:31:9 | { ... } | +| test.cpp:18:18:20:11 | { ... } | test.cpp:16:11:20:11 | if (...) ... | +| test.cpp:19:13:19:20 | declaration | test.cpp:18:18:20:11 | { ... } | +| test.cpp:19:17:19:19 | id1 | test.cpp:18:18:20:11 | { ... } | +| test.cpp:21:11:25:11 | switch (...) ... | test.cpp:13:9:31:9 | { ... } | +| test.cpp:21:19:21:21 | id1 | test.cpp:13:9:31:9 | { ... } | +| test.cpp:21:24:25:11 | { ... } | test.cpp:13:9:31:9 | { ... } | +| test.cpp:21:24:25:11 | { ... } | test.cpp:21:11:25:11 | switch (...) ... | +| test.cpp:22:11:22:17 | case ...: | test.cpp:21:24:25:11 | { ... } | +| test.cpp:22:16:22:16 | 0 | test.cpp:21:24:25:11 | { ... } | +| test.cpp:23:13:23:20 | declaration | test.cpp:21:24:25:11 | { ... } | +| test.cpp:23:17:23:19 | id1 | test.cpp:21:24:25:11 | { ... } | +| test.cpp:24:13:24:18 | break; | test.cpp:21:24:25:11 | { ... } | +| test.cpp:25:11:25:11 | label ...: | test.cpp:13:9:31:9 | { ... } | +| test.cpp:26:11:28:11 | try { ... } | test.cpp:13:9:31:9 | { ... } | +| test.cpp:26:15:28:11 | { ... } | test.cpp:13:9:31:9 | { ... } | +| test.cpp:27:13:27:53 | declaration | test.cpp:26:15:28:11 | { ... } | +| test.cpp:27:18:27:24 | lambda1 | test.cpp:26:15:28:11 | { ... } | +| test.cpp:27:27:27:52 | [...](...){...} | test.cpp:26:15:28:11 | { ... } | +| test.cpp:27:27:27:52 | {...} | test.cpp:26:15:28:11 | { ... } | +| test.cpp:27:28:27:28 | (unnamed constructor) | file://:0:0:0:0 | decltype([...](...){...}) | +| test.cpp:27:28:27:28 | (unnamed constructor) | file://:0:0:0:0 | decltype([...](...){...}) | +| test.cpp:27:28:27:28 | (unnamed constructor) | file://:0:0:0:0 | decltype([...](...){...}) | +| test.cpp:27:28:27:28 | operator= | file://:0:0:0:0 | decltype([...](...){...}) | +| test.cpp:27:29:27:29 | id1 | file://:0:0:0:0 | decltype([...](...){...}) | +| test.cpp:27:29:27:31 | id1 | test.cpp:26:15:28:11 | { ... } | +| test.cpp:27:33:27:33 | operator() | file://:0:0:0:0 | decltype([...](...){...}) | +| test.cpp:27:36:27:52 | { ... } | test.cpp:27:33:27:33 | operator() | +| test.cpp:27:38:27:50 | declaration | test.cpp:27:36:27:52 | { ... } | +| test.cpp:27:42:27:44 | id1 | test.cpp:27:36:27:52 | { ... } | +| test.cpp:27:47:27:49 | 10 | test.cpp:27:36:27:52 | { ... } | +| test.cpp:27:52:27:52 | return ... | test.cpp:27:36:27:52 | { ... } | +| test.cpp:28:24:28:26 | id1 | test.cpp:28:29:30:11 | { ... } | +| test.cpp:28:29:30:11 | | test.cpp:13:9:31:9 | { ... } | +| test.cpp:28:29:30:11 | { ... } | test.cpp:13:9:31:9 | { ... } | +| test.cpp:29:13:29:20 | declaration | test.cpp:28:29:30:11 | { ... } | +| test.cpp:29:17:29:19 | id1 | test.cpp:28:29:30:11 | { ... } | +| test.cpp:34:3:34:3 | return ... | test.cpp:10:28:34:3 | { ... } | diff --git a/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.ql b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.ql new file mode 100644 index 0000000000..47d27fb0f0 --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.ql @@ -0,0 +1,5 @@ +import codingstandards.cpp.Scope + +from Element e, Element parent +where Internal::getParentScope(e) = parent +select e, parent diff --git a/cpp/common/test/library/codingstandards/cpp/scope/test.cpp b/cpp/common/test/library/codingstandards/cpp/scope/test.cpp new file mode 100644 index 0000000000..a0b617916d --- /dev/null +++ b/cpp/common/test/library/codingstandards/cpp/scope/test.cpp @@ -0,0 +1,37 @@ +int id1; + +namespace ns1 { +int id1; // COMPLIANT + +namespace ns2 { +int id1; // COMPLIANT +class C1 { + int id1; + void test_scope(int id1) { + for (int id1; id1 < 1; id1++) { + for (int id1; id1 < 1; id1++) { + { + int id1; + + if (id1 == 0) { + int id1; + } else { + int id1; + } + switch (id1) { + case 0: + int id1; + break; + } + try { + auto lambda1 = [id1]() { int id1 = 10; }; + } catch (int id1) { + int id1; + } + } + } + } + } +}; +} // namespace ns2 +} // namespace ns1 From b8b41312c24fa6d9ce511a5d0543ddef08c7f6ee Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 8 Dec 2024 17:26:09 +0000 Subject: [PATCH 128/628] Scope: Address logic flaw creating multiple parents We adjust the parent scope explicitly for loops, if statements and switch statements, but, due to a logic bug, we previously retained the existing results provided by Element.getParentScope(). --- cpp/common/src/codingstandards/cpp/Scope.qll | 7 +++---- .../library/codingstandards/cpp/scope/ParentScope.expected | 5 ----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Scope.qll b/cpp/common/src/codingstandards/cpp/Scope.qll index 9af5c8e21c..ce8c5be113 100644 --- a/cpp/common/src/codingstandards/cpp/Scope.qll +++ b/cpp/common/src/codingstandards/cpp/Scope.qll @@ -38,10 +38,9 @@ module Internal { or exists(SwitchStmt switchStmt | switchStmt.getStmt() = e and result = switchStmt) or - not result.(Loop).getStmt() = e and - not result.(IfStmt).getThen() = e and - not result.(IfStmt).getElse() = e and - not result.(SwitchStmt).getStmt() = e and + not exists(Loop loop | loop.getStmt() = e) and + not exists(IfStmt ifStmt | ifStmt.getThen() = e or ifStmt.getElse() = e) and + not exists(SwitchStmt switchStmt | switchStmt.getStmt() = e) and if exists(e.getParentScope()) then result = e.getParentScope() else ( diff --git a/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected index 0d36cc980d..6335394970 100644 --- a/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected +++ b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected @@ -33,7 +33,6 @@ | test.cpp:11:25:11:25 | 1 | test.cpp:10:28:34:3 | { ... } | | test.cpp:11:28:11:30 | id1 | test.cpp:10:28:34:3 | { ... } | | test.cpp:11:28:11:32 | ... ++ | test.cpp:10:28:34:3 | { ... } | -| test.cpp:11:35:33:5 | { ... } | test.cpp:10:28:34:3 | { ... } | | test.cpp:11:35:33:5 | { ... } | test.cpp:11:5:33:5 | for(...;...;...) ... | | test.cpp:12:7:32:7 | for(...;...;...) ... | test.cpp:11:35:33:5 | { ... } | | test.cpp:12:12:12:19 | declaration | test.cpp:11:35:33:5 | { ... } | @@ -43,7 +42,6 @@ | test.cpp:12:27:12:27 | 1 | test.cpp:11:35:33:5 | { ... } | | test.cpp:12:30:12:32 | id1 | test.cpp:11:35:33:5 | { ... } | | test.cpp:12:30:12:34 | ... ++ | test.cpp:11:35:33:5 | { ... } | -| test.cpp:12:37:32:7 | { ... } | test.cpp:11:35:33:5 | { ... } | | test.cpp:12:37:32:7 | { ... } | test.cpp:12:7:32:7 | for(...;...;...) ... | | test.cpp:13:9:31:9 | { ... } | test.cpp:12:37:32:7 | { ... } | | test.cpp:14:11:14:18 | declaration | test.cpp:13:9:31:9 | { ... } | @@ -52,17 +50,14 @@ | test.cpp:16:15:16:17 | id1 | test.cpp:13:9:31:9 | { ... } | | test.cpp:16:15:16:22 | ... == ... | test.cpp:13:9:31:9 | { ... } | | test.cpp:16:22:16:22 | 0 | test.cpp:13:9:31:9 | { ... } | -| test.cpp:16:25:18:11 | { ... } | test.cpp:13:9:31:9 | { ... } | | test.cpp:16:25:18:11 | { ... } | test.cpp:16:11:20:11 | if (...) ... | | test.cpp:17:13:17:20 | declaration | test.cpp:16:25:18:11 | { ... } | | test.cpp:17:17:17:19 | id1 | test.cpp:16:25:18:11 | { ... } | -| test.cpp:18:18:20:11 | { ... } | test.cpp:13:9:31:9 | { ... } | | test.cpp:18:18:20:11 | { ... } | test.cpp:16:11:20:11 | if (...) ... | | test.cpp:19:13:19:20 | declaration | test.cpp:18:18:20:11 | { ... } | | test.cpp:19:17:19:19 | id1 | test.cpp:18:18:20:11 | { ... } | | test.cpp:21:11:25:11 | switch (...) ... | test.cpp:13:9:31:9 | { ... } | | test.cpp:21:19:21:21 | id1 | test.cpp:13:9:31:9 | { ... } | -| test.cpp:21:24:25:11 | { ... } | test.cpp:13:9:31:9 | { ... } | | test.cpp:21:24:25:11 | { ... } | test.cpp:21:11:25:11 | switch (...) ... | | test.cpp:22:11:22:17 | case ...: | test.cpp:21:24:25:11 | { ... } | | test.cpp:22:16:22:16 | 0 | test.cpp:21:24:25:11 | { ... } | From 1f8e2baedb543b5a4318fc87d63b797865902f18 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 8 Dec 2024 17:31:41 +0000 Subject: [PATCH 129/628] Scope: Ensure loop entries have correct parent scope All direct children of a for loop should have the for loop itself as the scope. --- cpp/common/src/codingstandards/cpp/Scope.qll | 4 ++-- .../codingstandards/cpp/scope/ParentScope.expected | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Scope.qll b/cpp/common/src/codingstandards/cpp/Scope.qll index ce8c5be113..ad99ab8bd4 100644 --- a/cpp/common/src/codingstandards/cpp/Scope.qll +++ b/cpp/common/src/codingstandards/cpp/Scope.qll @@ -29,7 +29,7 @@ module Internal { * } */ - exists(Loop loop | loop.getStmt() = e and result = loop) + exists(Loop loop | loop.getAChild() = e and result = loop) or exists(IfStmt ifStmt | (ifStmt.getThen() = e or ifStmt.getElse() = e) and @@ -38,7 +38,7 @@ module Internal { or exists(SwitchStmt switchStmt | switchStmt.getStmt() = e and result = switchStmt) or - not exists(Loop loop | loop.getStmt() = e) and + not exists(Loop loop | loop.getAChild() = e) and not exists(IfStmt ifStmt | ifStmt.getThen() = e or ifStmt.getElse() = e) and not exists(SwitchStmt switchStmt | switchStmt.getStmt() = e) and if exists(e.getParentScope()) diff --git a/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected index 6335394970..34a48c8065 100644 --- a/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected +++ b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected @@ -26,22 +26,22 @@ | test.cpp:10:23:10:25 | id1 | test.cpp:10:8:10:17 | test_scope | | test.cpp:10:28:34:3 | { ... } | test.cpp:10:8:10:17 | test_scope | | test.cpp:11:5:33:5 | for(...;...;...) ... | test.cpp:10:28:34:3 | { ... } | -| test.cpp:11:10:11:17 | declaration | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:10:11:17 | declaration | test.cpp:11:5:33:5 | for(...;...;...) ... | | test.cpp:11:14:11:16 | id1 | test.cpp:11:5:33:5 | for(...;...;...) ... | | test.cpp:11:19:11:21 | id1 | test.cpp:10:28:34:3 | { ... } | -| test.cpp:11:19:11:25 | ... < ... | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:19:11:25 | ... < ... | test.cpp:11:5:33:5 | for(...;...;...) ... | | test.cpp:11:25:11:25 | 1 | test.cpp:10:28:34:3 | { ... } | | test.cpp:11:28:11:30 | id1 | test.cpp:10:28:34:3 | { ... } | -| test.cpp:11:28:11:32 | ... ++ | test.cpp:10:28:34:3 | { ... } | +| test.cpp:11:28:11:32 | ... ++ | test.cpp:11:5:33:5 | for(...;...;...) ... | | test.cpp:11:35:33:5 | { ... } | test.cpp:11:5:33:5 | for(...;...;...) ... | | test.cpp:12:7:32:7 | for(...;...;...) ... | test.cpp:11:35:33:5 | { ... } | -| test.cpp:12:12:12:19 | declaration | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:12:12:19 | declaration | test.cpp:12:7:32:7 | for(...;...;...) ... | | test.cpp:12:16:12:18 | id1 | test.cpp:12:7:32:7 | for(...;...;...) ... | | test.cpp:12:21:12:23 | id1 | test.cpp:11:35:33:5 | { ... } | -| test.cpp:12:21:12:27 | ... < ... | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:21:12:27 | ... < ... | test.cpp:12:7:32:7 | for(...;...;...) ... | | test.cpp:12:27:12:27 | 1 | test.cpp:11:35:33:5 | { ... } | | test.cpp:12:30:12:32 | id1 | test.cpp:11:35:33:5 | { ... } | -| test.cpp:12:30:12:34 | ... ++ | test.cpp:11:35:33:5 | { ... } | +| test.cpp:12:30:12:34 | ... ++ | test.cpp:12:7:32:7 | for(...;...;...) ... | | test.cpp:12:37:32:7 | { ... } | test.cpp:12:7:32:7 | for(...;...;...) ... | | test.cpp:13:9:31:9 | { ... } | test.cpp:12:37:32:7 | { ... } | | test.cpp:14:11:14:18 | declaration | test.cpp:13:9:31:9 | { ... } | From 63a60b1855f00c96a63e16242055ab2f660782f8 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 8 Dec 2024 18:19:26 +0000 Subject: [PATCH 130/628] Scope: Address performance issues with excludedViaNestedNamespace Add pragma_inline to ensure we consider this as a post-filtering step. --- cpp/common/src/codingstandards/cpp/Scope.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpp/common/src/codingstandards/cpp/Scope.qll b/cpp/common/src/codingstandards/cpp/Scope.qll index ad99ab8bd4..3e1bb6c803 100644 --- a/cpp/common/src/codingstandards/cpp/Scope.qll +++ b/cpp/common/src/codingstandards/cpp/Scope.qll @@ -269,6 +269,8 @@ predicate hasBlockScope(Declaration decl) { exists(BlockStmt b | b.getADeclarati /** * identifiers in nested (named/nonglobal) namespaces are exceptions to hiding due to being able access via fully qualified ids */ +bindingset[outerDecl, innerDecl] +pragma[inline_late] predicate excludedViaNestedNamespaces(UserVariable outerDecl, UserVariable innerDecl) { exists(Namespace inner, Namespace outer | outer.getAChildNamespace+() = inner and From 1bd839c34c39e3546484d666ebe8b15d0e9e0451 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sat, 7 Dec 2024 00:43:37 +0000 Subject: [PATCH 131/628] Scope: Improve performance of hidesStrict Improves performance by: - Capturing for each scope the list of names defined by nested scopes - Use that to determine hidden identifiers for a scope. - Separately determine the hiding identifiers for a scope. This addresses performance issues in the now deleted predicate getOuterScopesOfVariable_candidate(). --- cpp/common/src/codingstandards/cpp/Scope.qll | 119 +++++++++++++------ 1 file changed, 82 insertions(+), 37 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Scope.qll b/cpp/common/src/codingstandards/cpp/Scope.qll index 3e1bb6c803..8e618cb21e 100644 --- a/cpp/common/src/codingstandards/cpp/Scope.qll +++ b/cpp/common/src/codingstandards/cpp/Scope.qll @@ -122,39 +122,77 @@ class Scope extends Element { or not exists(Internal::getParentScope(this)) and result = 0 } -} -class GeneratedBlockStmt extends BlockStmt { - GeneratedBlockStmt() { this.getLocation() instanceof UnknownLocation } -} + /** + * Holds if `name` is declared in this scope, or in a nested scope. + */ + private predicate isNameDeclaredInThisOrNestedScope(string name) { + name = getAVariable().getName() + or + isNameDeclaredInNestedScope(name) + } + + /** + * Holds if `name` is declared in a nested scope. + */ + private predicate isNameDeclaredInNestedScope(string name) { + exists(Scope child | + child.getStrictParent() = this and + child.isNameDeclaredInThisOrNestedScope(name) + ) + } + + /** + * Holds if `name` is declared in this scope and is hidden in a child scope. + */ + private predicate isDeclaredNameHiddenByChild(string name) { + isNameDeclaredInNestedScope(name) and + name = getAVariable().getName() + } + + /** + * Gets a variable with `name` which is hidden in at least one nested scope. + */ + UserVariable getAHiddenVariable(string name) { + result = getAVariable() and + result.getName() = name and + isDeclaredNameHiddenByChild(name) + } -/** Gets a variable that is in the potential scope of variable `v`. */ -private UserVariable getPotentialScopeOfVariable_candidate(UserVariable v) { - exists(Scope s | - result = s.getAVariable() and + /** + * Holds if `name` is declared above this scope and hidden by this or a nested scope. + */ + private predicate isNameDeclaredAboveHiddenByThisOrNested(string name) { ( - // Variable in an ancestor scope, but only if there are less than 100 variables in this scope - v = s.getAnAncestor().getAVariable() and - s.getNumberOfVariables() < 100 + this.getStrictParent().isDeclaredNameHiddenByChild(name) or + this.getStrictParent().isNameDeclaredAboveHiddenByThisOrNested(name) + ) and + isNameDeclaredInThisOrNestedScope(name) + } + + /** + * Gets a variable with `name` which is declared above and hidden by a variable in this or a nested scope. + */ + UserVariable getAHidingVariable(string name) { + isNameDeclaredAboveHiddenByThisOrNested(name) and + ( + // Declared in this scope + getAVariable().getName() = name and + result = getAVariable() and + result.getName() = name or - // In the same scope, but not the same variable, and choose just one to report - v = s.getAVariable() and - not result = v and - v.getName() <= result.getName() + // Declared in a child scope + exists(Scope child | + child.getStrictParent() = this and + child.isNameDeclaredInThisOrNestedScope(name) and + result = child.getAHidingVariable(name) + ) ) - ) + } } -/** Gets a variable that is in the potential scope of variable `v`. */ -private UserVariable getOuterScopesOfVariable_candidate(UserVariable v) { - exists(Scope s | - result = s.getAVariable() and - ( - // Variable in an ancestor scope, but only if there are less than 100 variables in this scope - v = s.getAnAncestor().getAVariable() and - s.getNumberOfVariables() < 100 - ) - ) +class GeneratedBlockStmt extends BlockStmt { + GeneratedBlockStmt() { this.getLocation() instanceof UnknownLocation } } /** Holds if there exists a translation unit that includes both `f1` and `f2`. */ @@ -167,12 +205,17 @@ predicate inSameTranslationUnit(File f1, File f2) { } /** - * Gets a user variable which occurs in the "outer scope" of variable `v`. + * Holds if there exists a translation unit that includes both `f1` and `f2`. + * + * This version is late bound. */ -cached -UserVariable getPotentialScopeOfVariableStrict(UserVariable v) { - result = getOuterScopesOfVariable_candidate(v) and - inSameTranslationUnit(v.getFile(), result.getFile()) +bindingset[f1, f2] +pragma[inline_late] +predicate inSameTranslationUnitLate(File f1, File f2) { + exists(TranslationUnit c | + c.getAUserFile() = f1 and + c.getAUserFile() = f2 + ) } /** A file that is a C/C++ source file */ @@ -200,12 +243,14 @@ class TranslationUnit extends SourceFile { } } -/** Holds if `v2` may hide `v1`. */ -private predicate hides_candidateStrict(UserVariable v1, UserVariable v2) { - not v1 = v2 and - v2 = getPotentialScopeOfVariableStrict(v1) and - v1.getName() = v2.getName() and - // Member variables cannot hide other variables nor be hidden because the can be referenced through their qualified name. +/** Holds if `v2` strictly (`v2` is in an inner scope compared to `v1`) hides `v1`. */ +predicate hides_candidateStrict(UserVariable v1, UserVariable v2) { + exists(Scope s, string name | + v1 = s.getStrictParent().getAHiddenVariable(name) and + v2 = s.getAHidingVariable(name) and + not v1 = v2 + ) and + inSameTranslationUnitLate(v1.getFile(), v2.getFile()) and not (v1.isMember() or v2.isMember()) and ( // If v1 is a local variable, ensure that v1 is declared before v2 From f25507e821aeae14df6e2b676599b57768016387 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 8 Dec 2024 19:20:03 +0000 Subject: [PATCH 132/628] Scope: Add a child scope accessor --- cpp/common/src/codingstandards/cpp/Scope.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpp/common/src/codingstandards/cpp/Scope.qll b/cpp/common/src/codingstandards/cpp/Scope.qll index 8e618cb21e..1c9a621b39 100644 --- a/cpp/common/src/codingstandards/cpp/Scope.qll +++ b/cpp/common/src/codingstandards/cpp/Scope.qll @@ -80,6 +80,8 @@ class Scope extends Element { Scope getAnAncestor() { result = this.getStrictParent+() } + Scope getAChildScope() { result.getStrictParent() = this } + Scope getStrictParent() { result = Internal::getParentScope(this) } Declaration getADeclaration() { Internal::getParentScope(result) = this } From b5ff407e07197d229664b462503916f1da268104 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 8 Dec 2024 19:20:40 +0000 Subject: [PATCH 133/628] Scope: Adopt use of getAChildScope() --- cpp/common/src/codingstandards/cpp/Scope.qll | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Scope.qll b/cpp/common/src/codingstandards/cpp/Scope.qll index 1c9a621b39..d0f5995537 100644 --- a/cpp/common/src/codingstandards/cpp/Scope.qll +++ b/cpp/common/src/codingstandards/cpp/Scope.qll @@ -138,10 +138,7 @@ class Scope extends Element { * Holds if `name` is declared in a nested scope. */ private predicate isNameDeclaredInNestedScope(string name) { - exists(Scope child | - child.getStrictParent() = this and - child.isNameDeclaredInThisOrNestedScope(name) - ) + this.getAChildScope().isNameDeclaredInThisOrNestedScope(name) } /** @@ -173,7 +170,8 @@ class Scope extends Element { } /** - * Gets a variable with `name` which is declared above and hidden by a variable in this or a nested scope. + * Gets a variable with `name` which is declared in a scope above this one, and hidden by a variable in this or a + * nested scope. */ UserVariable getAHidingVariable(string name) { isNameDeclaredAboveHiddenByThisOrNested(name) and @@ -185,7 +183,7 @@ class Scope extends Element { or // Declared in a child scope exists(Scope child | - child.getStrictParent() = this and + getAChildScope() = child and child.isNameDeclaredInThisOrNestedScope(name) and result = child.getAHidingVariable(name) ) @@ -248,8 +246,8 @@ class TranslationUnit extends SourceFile { /** Holds if `v2` strictly (`v2` is in an inner scope compared to `v1`) hides `v1`. */ predicate hides_candidateStrict(UserVariable v1, UserVariable v2) { exists(Scope s, string name | - v1 = s.getStrictParent().getAHiddenVariable(name) and - v2 = s.getAHidingVariable(name) and + v1 = s.getAHiddenVariable(name) and + v2 = s.getAChildScope().getAHidingVariable(name) and not v1 = v2 ) and inSameTranslationUnitLate(v1.getFile(), v2.getFile()) and From dbd3fe6eeb10a1db03b2599765632a80539557e7 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 8 Dec 2024 22:27:35 +0000 Subject: [PATCH 134/628] Scope: Fix the parent scope of catch blocks We now tie the Handler into the TryStmt, and catch-block parameters into the Handler for a consistent AST hierarchy. --- cpp/common/src/codingstandards/cpp/Scope.qll | 18 ++++++++++-------- .../cpp/scope/ParentScope.expected | 4 ++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Scope.qll b/cpp/common/src/codingstandards/cpp/Scope.qll index d0f5995537..1027e251f2 100644 --- a/cpp/common/src/codingstandards/cpp/Scope.qll +++ b/cpp/common/src/codingstandards/cpp/Scope.qll @@ -38,23 +38,25 @@ module Internal { or exists(SwitchStmt switchStmt | switchStmt.getStmt() = e and result = switchStmt) or + // A catch-block parameter, whose parent is the `Handler` + exists(CatchBlock c | c.getParameter() = e and result = c.getParent()) + or + // A catch-block `Handler`, whose parent is the `TryStmt` + e.(Handler).getParent() = result + or not exists(Loop loop | loop.getAChild() = e) and not exists(IfStmt ifStmt | ifStmt.getThen() = e or ifStmt.getElse() = e) and not exists(SwitchStmt switchStmt | switchStmt.getStmt() = e) and + not exists(CatchBlock c | c.getParameter() = e) and + not e instanceof Handler and if exists(e.getParentScope()) then result = e.getParentScope() else ( - // Statements do no have a parent scope, so return the enclosing block. + // Statements do not have a parent scope, so return the enclosing block. result = e.(Stmt).getEnclosingBlock() or + // Expressions do not have a parent scope, so return the enclosing block. result = e.(Expr).getEnclosingBlock() - or - // Catch block parameters don't have an enclosing scope, so attach them to the - // the block itself - exists(CatchBlock cb | - e = cb.getParameter() and - result = cb - ) ) } } diff --git a/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected index 34a48c8065..e2152773af 100644 --- a/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected +++ b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected @@ -83,8 +83,8 @@ | test.cpp:27:42:27:44 | id1 | test.cpp:27:36:27:52 | { ... } | | test.cpp:27:47:27:49 | 10 | test.cpp:27:36:27:52 | { ... } | | test.cpp:27:52:27:52 | return ... | test.cpp:27:36:27:52 | { ... } | -| test.cpp:28:24:28:26 | id1 | test.cpp:28:29:30:11 | { ... } | -| test.cpp:28:29:30:11 | | test.cpp:13:9:31:9 | { ... } | +| test.cpp:28:24:28:26 | id1 | test.cpp:28:29:30:11 | | +| test.cpp:28:29:30:11 | | test.cpp:26:11:28:11 | try { ... } | | test.cpp:28:29:30:11 | { ... } | test.cpp:13:9:31:9 | { ... } | | test.cpp:29:13:29:20 | declaration | test.cpp:28:29:30:11 | { ... } | | test.cpp:29:17:29:19 | id1 | test.cpp:28:29:30:11 | { ... } | From 61521e0144707fe65c611988f2412d86af94e07c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 8 Dec 2024 23:20:37 +0000 Subject: [PATCH 135/628] Scope: Simplify mechanism for identifying declaration order --- cpp/common/src/codingstandards/cpp/Scope.qll | 50 +++++++------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Scope.qll b/cpp/common/src/codingstandards/cpp/Scope.qll index 1027e251f2..c716896356 100644 --- a/cpp/common/src/codingstandards/cpp/Scope.qll +++ b/cpp/common/src/codingstandards/cpp/Scope.qll @@ -247,48 +247,30 @@ class TranslationUnit extends SourceFile { /** Holds if `v2` strictly (`v2` is in an inner scope compared to `v1`) hides `v1`. */ predicate hides_candidateStrict(UserVariable v1, UserVariable v2) { - exists(Scope s, string name | - v1 = s.getAHiddenVariable(name) and - v2 = s.getAChildScope().getAHidingVariable(name) and + exists(Scope parentScope, Scope childScope, string name | + v1 = parentScope.getAHiddenVariable(name) and + childScope = parentScope.getAChildScope() and + v2 = childScope.getAHidingVariable(name) and not v1 = v2 - ) and - inSameTranslationUnitLate(v1.getFile(), v2.getFile()) and - not (v1.isMember() or v2.isMember()) and - ( - // If v1 is a local variable, ensure that v1 is declared before v2 + | + // If v1 is a local variable defined in a `DeclStmt` ensure that it is declared before `v2`, + // otherwise it would not be hidden ( - v1 instanceof LocalVariable and - // Ignore variables declared in conditional expressions, as they apply to - // the nested scope - not v1 = any(ConditionDeclExpr cde).getVariable() and - // Ignore variables declared in loops - not exists(Loop l | l.getADeclaration() = v1) + parentScope instanceof BlockStmt and + exists(DeclStmt ds | ds.getADeclaration() = v1) and + exists(parentScope.(BlockStmt).getIndexOfStmt(childScope)) ) implies exists(BlockStmt bs, DeclStmt v1Stmt, Stmt v2Stmt | - v1 = v1Stmt.getADeclaration() and - getEnclosingStmt(v2).getParentStmt*() = v2Stmt + bs = parentScope and + v2Stmt = childScope and + v1Stmt.getADeclaration() = v1 | bs.getIndexOfStmt(v1Stmt) <= bs.getIndexOfStmt(v2Stmt) ) - ) -} - -/** - * Gets the enclosing statement of the given variable, if any. - */ -private Stmt getEnclosingStmt(LocalScopeVariable v) { - result.(DeclStmt).getADeclaration() = v - or - exists(ConditionDeclExpr cde | - cde.getVariable() = v and - result = cde.getEnclosingStmt() - ) - or - exists(CatchBlock cb | - cb.getParameter() = v and - result = cb.getEnclosingStmt() - ) + ) and + inSameTranslationUnitLate(v1.getFile(), v2.getFile()) and + not (v1.isMember() or v2.isMember()) } /** Holds if `v2` strictly (`v2` is in an inner scope compared to `v1`) hides `v1`. */ From 47b3fb272f27f2fd7f06ab09d0c1195a7d06a16d Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 9 Dec 2024 12:15:50 +0000 Subject: [PATCH 136/628] Scope: refactor hides calculation to expose pairs of variables Behaviour preserving refactor to allow future filtering of invalid pairs of variables during the traversal algorithm. For example, whether a variable declared within a lambda variable hides an outer scope variable depends on the type and nature of the variable. By exposing pairs of candidate variables, we can more easily filter on these conditions. --- cpp/common/src/codingstandards/cpp/Scope.qll | 54 ++++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Scope.qll b/cpp/common/src/codingstandards/cpp/Scope.qll index c716896356..6ca3fc8657 100644 --- a/cpp/common/src/codingstandards/cpp/Scope.qll +++ b/cpp/common/src/codingstandards/cpp/Scope.qll @@ -78,6 +78,14 @@ class Scope extends Element { UserVariable getAVariable() { Internal::getParentScope(result) = this } + /** + * Gets the `Variable` with the given `name` that is declared in this scope. + */ + UserVariable getVariable(string name) { + result = getAVariable() and + result.getName() = name + } + int getNumberOfVariables() { result = count(getAVariable()) } Scope getAnAncestor() { result = this.getStrictParent+() } @@ -152,9 +160,9 @@ class Scope extends Element { } /** - * Gets a variable with `name` which is hidden in at least one nested scope. + * Gets a variable with `name` which is potentially hidden in at least one nested scope. */ - UserVariable getAHiddenVariable(string name) { + private UserVariable getAPotentiallyHiddenVariable(string name) { result = getAVariable() and result.getName() = name and isDeclaredNameHiddenByChild(name) @@ -163,34 +171,43 @@ class Scope extends Element { /** * Holds if `name` is declared above this scope and hidden by this or a nested scope. */ - private predicate isNameDeclaredAboveHiddenByThisOrNested(string name) { - ( - this.getStrictParent().isDeclaredNameHiddenByChild(name) or - this.getStrictParent().isNameDeclaredAboveHiddenByThisOrNested(name) + UserVariable getAVariableHiddenByThisOrNestedScope(string name) { + exists(Scope parent | parent = this.getStrictParent() | + result = parent.getAPotentiallyHiddenVariable(name) or + result = parent.getAVariableHiddenByThisOrNestedScope(name) ) and isNameDeclaredInThisOrNestedScope(name) } /** - * Gets a variable with `name` which is declared in a scope above this one, and hidden by a variable in this or a - * nested scope. + * Holds if `hiddenVariable` and `hidingVariable` are a candidate hiding pair at this scope. */ - UserVariable getAHidingVariable(string name) { - isNameDeclaredAboveHiddenByThisOrNested(name) and + private predicate hidesCandidate( + UserVariable hiddenVariable, UserVariable hidingVariable, string name + ) { ( // Declared in this scope - getAVariable().getName() = name and - result = getAVariable() and - result.getName() = name + hidingVariable = getVariable(name) and + hiddenVariable = getAVariableHiddenByThisOrNestedScope(name) or // Declared in a child scope exists(Scope child | getAChildScope() = child and - child.isNameDeclaredInThisOrNestedScope(name) and - result = child.getAHidingVariable(name) + child.hidesCandidate(hiddenVariable, hidingVariable, name) ) ) } + + /** + * Holds if `hiddenVariable` is declared in this scope and hidden by `hidingVariable`. + */ + predicate hides(UserVariable hiddenVariable, UserVariable hidingVariable, Scope childScope) { + exists(string name | + hiddenVariable = getAPotentiallyHiddenVariable(name) and + childScope = getAChildScope() and + childScope.hidesCandidate(hiddenVariable, hidingVariable, name) + ) + } } class GeneratedBlockStmt extends BlockStmt { @@ -247,12 +264,7 @@ class TranslationUnit extends SourceFile { /** Holds if `v2` strictly (`v2` is in an inner scope compared to `v1`) hides `v1`. */ predicate hides_candidateStrict(UserVariable v1, UserVariable v2) { - exists(Scope parentScope, Scope childScope, string name | - v1 = parentScope.getAHiddenVariable(name) and - childScope = parentScope.getAChildScope() and - v2 = childScope.getAHidingVariable(name) and - not v1 = v2 - | + exists(Scope parentScope, Scope childScope | parentScope.hides(v1, v2, childScope) | // If v1 is a local variable defined in a `DeclStmt` ensure that it is declared before `v2`, // otherwise it would not be hidden ( From 9b7e1299fc91d9845f5e9250d33102b6fb627755 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 9 Dec 2024 12:27:50 +0000 Subject: [PATCH 137/628] Scope: Special case lambda expressions Lambda expressions have special visibility rules that affect identifier hiding, which we incorporate into the Scope hiding calculations. Note: Lambda expressions are not currently tied into the parent scope hierarchy, so this change doesn't affect calculations until getParentScope(Element e) is extended to support them. --- cpp/common/src/codingstandards/cpp/Scope.qll | 59 ++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/cpp/common/src/codingstandards/cpp/Scope.qll b/cpp/common/src/codingstandards/cpp/Scope.qll index 6ca3fc8657..c705137d8c 100644 --- a/cpp/common/src/codingstandards/cpp/Scope.qll +++ b/cpp/common/src/codingstandards/cpp/Scope.qll @@ -3,6 +3,19 @@ */ import cpp +import codingstandards.cpp.ConstHelpers + +/** + * a `Variable` that is nonvolatile and const + * and of type `IntegralOrEnumType` + */ +class NonVolatileConstIntegralOrEnumVariable extends Variable { + NonVolatileConstIntegralOrEnumVariable() { + not this.isVolatile() and + this.isConst() and + this.getUnspecifiedType() instanceof IntegralOrEnumType + } +} /** * Internal module, exposed for testing. @@ -210,6 +223,52 @@ class Scope extends Element { } } +/** + * A scope representing the generated `operator()` of a lambda function. + */ +class LambdaScope extends Scope { + Closure closure; + + LambdaScope() { this = closure.getLambdaFunction() } + + override UserVariable getAVariableHiddenByThisOrNestedScope(string name) { + // Handle special cases for lambdas + exists(UserVariable hiddenVariable, LambdaExpression lambdaExpr | + // Find the variable that is potentially hidden inside the lambda + hiddenVariable = super.getAVariableHiddenByThisOrNestedScope(name) and + result = hiddenVariable and + lambdaExpr = closure.getLambdaExpression() + | + // A definition can be hidden if it is in scope and it is captured by the lambda, + exists(LambdaCapture cap | + lambdaExpr.getACapture() = cap and + // The outer declaration is captured by the lambda + hiddenVariable.getAnAccess() = cap.getInitializer() + ) + or + // it is is non-local, + hiddenVariable instanceof GlobalVariable + or + // it has static or thread local storage duration, + (hiddenVariable.isThreadLocal() or hiddenVariable.isStatic()) + or + //it is a reference that has been initialized with a constant expression. + hiddenVariable.getType().stripTopLevelSpecifiers() instanceof ReferenceType and + hiddenVariable.getInitializer().getExpr() instanceof Literal + or + // //it const non-volatile integral or enumeration type and has been initialized with a constant expression + hiddenVariable instanceof NonVolatileConstIntegralOrEnumVariable and + hiddenVariable.getInitializer().getExpr() instanceof Literal + or + //it is constexpr and has no mutable members + hiddenVariable.isConstexpr() and + not exists(Class c | + c = hiddenVariable.getType() and not c.getAMember() instanceof MutableVariable + ) + ) + } +} + class GeneratedBlockStmt extends BlockStmt { GeneratedBlockStmt() { this.getLocation() instanceof UnknownLocation } } From 117d0fba033e58ac03d7903ada230e2a09114972 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 9 Dec 2024 12:30:30 +0000 Subject: [PATCH 138/628] Scope: Extend getParentScope for lambda expressions Lambda functions are tied into the parent statement of their declaring lambda expression, which enables Scope's hiding predicates to calculate hiding behaviour for lambda expressions. --- cpp/common/src/codingstandards/cpp/Scope.qll | 11 +++++++++++ .../codingstandards/cpp/scope/ParentScope.expected | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/Scope.qll b/cpp/common/src/codingstandards/cpp/Scope.qll index c705137d8c..5438c17133 100644 --- a/cpp/common/src/codingstandards/cpp/Scope.qll +++ b/cpp/common/src/codingstandards/cpp/Scope.qll @@ -57,11 +57,22 @@ module Internal { // A catch-block `Handler`, whose parent is the `TryStmt` e.(Handler).getParent() = result or + // The parent scope of a lambda is the scope in which the lambda expression is defined. + // + // Lambda functions are defined in a generated `Closure` class, as the `operator()` function. We choose the + // enclosing statement of the lambda expression as the parent scope of the lambda function. This is so we can + // determine the order of definition if a variable is defined in the same scope as the lambda expression. + exists(Closure lambdaClosure | + lambdaClosure.getLambdaFunction() = e and + lambdaClosure.getLambdaExpression().getEnclosingStmt() = result + ) + or not exists(Loop loop | loop.getAChild() = e) and not exists(IfStmt ifStmt | ifStmt.getThen() = e or ifStmt.getElse() = e) and not exists(SwitchStmt switchStmt | switchStmt.getStmt() = e) and not exists(CatchBlock c | c.getParameter() = e) and not e instanceof Handler and + not exists(Closure lambdaClosure | lambdaClosure.getLambdaFunction() = e) and if exists(e.getParentScope()) then result = e.getParentScope() else ( diff --git a/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected index e2152773af..90aa3b30c8 100644 --- a/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected +++ b/cpp/common/test/library/codingstandards/cpp/scope/ParentScope.expected @@ -77,7 +77,7 @@ | test.cpp:27:28:27:28 | operator= | file://:0:0:0:0 | decltype([...](...){...}) | | test.cpp:27:29:27:29 | id1 | file://:0:0:0:0 | decltype([...](...){...}) | | test.cpp:27:29:27:31 | id1 | test.cpp:26:15:28:11 | { ... } | -| test.cpp:27:33:27:33 | operator() | file://:0:0:0:0 | decltype([...](...){...}) | +| test.cpp:27:33:27:33 | operator() | test.cpp:27:13:27:53 | declaration | | test.cpp:27:36:27:52 | { ... } | test.cpp:27:33:27:33 | operator() | | test.cpp:27:38:27:50 | declaration | test.cpp:27:36:27:52 | { ... } | | test.cpp:27:42:27:44 | id1 | test.cpp:27:36:27:52 | { ... } | From 411ecde2794bb92bb6981ee6107044d66d5de4ac Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 9 Dec 2024 12:32:08 +0000 Subject: [PATCH 139/628] IdentifierHidden: remove lambda special casing This removes the special handling of lambda expressions, which was causing performance issues. Instead, we rely on the new behviour of the Scope library, which calculates identifier hiding for lambda expressions as part of the main calculation. This has one semantic change - the new code applies `isInSameTranslationUnit`, which reduces false positives where the identifier "hiding" in a lambda occurred with an outer variable in a different translation unit. --- .../identifierhidden/IdentifierHidden.qll | 66 +------------------ 1 file changed, 1 insertion(+), 65 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/identifierhidden/IdentifierHidden.qll b/cpp/common/src/codingstandards/cpp/rules/identifierhidden/IdentifierHidden.qll index 9534c2f78a..39d24299b8 100644 --- a/cpp/common/src/codingstandards/cpp/rules/identifierhidden/IdentifierHidden.qll +++ b/cpp/common/src/codingstandards/cpp/rules/identifierhidden/IdentifierHidden.qll @@ -9,75 +9,11 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.Scope -import codingstandards.cpp.ConstHelpers abstract class IdentifierHiddenSharedQuery extends Query { } Query getQuery() { result instanceof IdentifierHiddenSharedQuery } -/** - * a `Variable` that is nonvolatile and const - * and of type `IntegralOrEnumType` - */ -class NonVolatileConstIntegralOrEnumVariable extends Variable { - NonVolatileConstIntegralOrEnumVariable() { - not this.isVolatile() and - this.isConst() and - this.getUnspecifiedType() instanceof IntegralOrEnumType - } -} - -/** - * Holds if declaration `innerDecl`, declared in a lambda, hides a declaration `outerDecl` by the lambda. - */ -predicate hiddenInLambda(UserVariable outerDecl, UserVariable innerDecl) { - exists( - Scope innerScope, LambdaExpression lambdaExpr, Scope lambdaExprScope, Scope outerScope, - Closure lambdaClosure - | - // The variable `innerDecl` is declared inside of the lambda. - innerScope.getADeclaration() = innerDecl and - // Because a lambda is compiled down to a closure, we need to use the closure to determine if the declaration - // is part of the lambda. - innerScope.getAnAncestor() = lambdaClosure and - // Next we determine the scope of the lambda expression to determine if `outerDecl` is visible in the scope of the lambda. - lambdaClosure.getLambdaExpression() = lambdaExpr and - lambdaExprScope.getAnExpr() = lambdaExpr and - outerScope.getADeclaration() = outerDecl and - lambdaExprScope.getStrictParent*() = outerScope and - ( - // A definition can be hidden if it is in scope and it is captured by the lambda, - exists(LambdaCapture cap | - lambdaExpr.getACapture() = cap and - // The outer declaration is captured by the lambda - outerDecl.getAnAccess() = cap.getInitializer() - ) - or - // it is is non-local, - outerDecl instanceof GlobalVariable - or - // it has static or thread local storage duration, - (outerDecl.isThreadLocal() or outerDecl.isStatic()) - or - //it is a reference that has been initialized with a constant expression. - outerDecl.getType().stripTopLevelSpecifiers() instanceof ReferenceType and - outerDecl.getInitializer().getExpr() instanceof Literal - or - // //it const non-volatile integral or enumeration type and has been initialized with a constant expression - outerDecl instanceof NonVolatileConstIntegralOrEnumVariable and - outerDecl.getInitializer().getExpr() instanceof Literal - or - //it is constexpr and has no mutable members - outerDecl.isConstexpr() and - not exists(Class c | - c = outerDecl.getType() and not c.getAMember() instanceof MutableVariable - ) - ) and - // Finally, the variables must have the same names. - innerDecl.getName() = outerDecl.getName() - ) -} - query predicate problems( UserVariable innerDecl, string message, UserVariable outerDecl, string varName ) { @@ -86,7 +22,7 @@ query predicate problems( //ignore template variables for this rule not outerDecl instanceof TemplateVariable and not innerDecl instanceof TemplateVariable and - (hidesStrict(outerDecl, innerDecl) or hiddenInLambda(outerDecl, innerDecl)) and + hidesStrict(outerDecl, innerDecl) and not excludedViaNestedNamespaces(outerDecl, innerDecl) and varName = outerDecl.getName() and message = "Variable is hiding variable $@." From 52e1bc142013d35d1ebb6050111b7939dc1f25cb Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 9 Dec 2024 12:54:54 +0000 Subject: [PATCH 140/628] IdentifierHiding - Add change note --- change_notes/2024-12-08-identifier-hiding.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 change_notes/2024-12-08-identifier-hiding.md diff --git a/change_notes/2024-12-08-identifier-hiding.md b/change_notes/2024-12-08-identifier-hiding.md new file mode 100644 index 0000000000..0600c9e6ee --- /dev/null +++ b/change_notes/2024-12-08-identifier-hiding.md @@ -0,0 +1,4 @@ + - `A2-10-1` - `IdentifierHiding.ql`: + - Improved evaluation performance. + - Addressed false negatives where nested loops used the same variable name. + - Exclude cases where a variable declared in a lambda expression shadowed a globa or namespace variable that did not appear in the same translation unit. From cf315bad52bb20208ab84809f90310e3875bb7b3 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 9 Dec 2024 12:57:12 +0000 Subject: [PATCH 141/628] Add extra change note entry --- change_notes/2024-12-08-identifier-hiding.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/change_notes/2024-12-08-identifier-hiding.md b/change_notes/2024-12-08-identifier-hiding.md index 0600c9e6ee..c983f5390a 100644 --- a/change_notes/2024-12-08-identifier-hiding.md +++ b/change_notes/2024-12-08-identifier-hiding.md @@ -2,3 +2,6 @@ - Improved evaluation performance. - Addressed false negatives where nested loops used the same variable name. - Exclude cases where a variable declared in a lambda expression shadowed a globa or namespace variable that did not appear in the same translation unit. + - `RULE-5-3` - `IdentifierHidingC.ql`: + - Improved evaluation performance. + - Addressed false negatives where nested loops used the same variable name. \ No newline at end of file From c56e1ce54401c05d5f27c9c86a843625f6f6b37c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 9 Dec 2024 23:34:03 +0000 Subject: [PATCH 142/628] TypographicallyDifferent: Update after changes to Scope Scope no longer provides a suitable predicate for determining variables in nested scopes. Instead, first determine the set of conflicting names, then identify a set of variables which are conflicting, and are hidden within a nested scope. --- ...entifiersNotTypographicallyUnambiguous.qll | 47 ++++++++++++++++--- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.qll b/cpp/common/src/codingstandards/cpp/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.qll index 87a4580ab3..5c7475883e 100644 --- a/cpp/common/src/codingstandards/cpp/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.qll +++ b/cpp/common/src/codingstandards/cpp/rules/differentidentifiersnottypographicallyunambiguous/DifferentIdentifiersNotTypographicallyUnambiguous.qll @@ -46,16 +46,32 @@ string step1(string s) { string step2(string s) { s = "m_" and result = "rn" } -predicate violation(UserVariable v1, UserVariable v2) { - v2 = getPotentialScopeOfVariable(v1) and +class VariableName extends string { + VariableName() { exists(UserVariable uv | uv.getName() = this) } + + string getCanon() { + result = + this.toLowerCase() + .replaceAll("_", "") + .regexpReplaceAll("[il]", "1") + .replaceAll("s", "5") + .replaceAll("z", "2") + .replaceAll("b", "8") + .replaceAll("h", "n") + .replaceAll("m", "rn") + .replaceAll("o", "0") + } +} + +predicate isConflictingName(VariableName name1, VariableName name2) { exists(string s1, string s2 | // over-approximate a match, because it is cheaper to compute - getCanon(v1) = getCanon(v2) and - v1 != v2 and - not v1.getName() = v2.getName() and + name1.getCanon() = name2.getCanon() and + // Exclude identical names + not name1 = name2 and // expand 'm' to 'm_' to match either 'm_' or 'rn' - s1 = v1.getName().replaceAll("_", "").replaceAll("m", "m_") and - s2 = v2.getName().replaceAll("_", "").replaceAll("m", "m_") and + s1 = name1.replaceAll("_", "").replaceAll("m", "m_") and + s2 = name2.replaceAll("_", "").replaceAll("m", "m_") and // at this point the strings must have equal length, the substitutions do not expand nor contract the string s1.length() = s2.length() and forall(int i | i in [0 .. s1.length() - 1] | @@ -87,6 +103,23 @@ predicate violation(UserVariable v1, UserVariable v2) { ) } +predicate violation(UserVariable v1, UserVariable v2) { + exists(string name1, string name2 | + isConflictingName(name1, name2) and + exists(Scope parentScope, Scope childScope | + parentScope.getVariable(name1) = v1 and + childScope.getVariable(name2) = v2 + | + childScope.getStrictParent+() = parentScope + or + // Disambiguate names in the same scope by name order + childScope = parentScope and + name1 < name2 + ) and + inSameTranslationUnitLate(v1.getFile(), v2.getFile()) + ) +} + query predicate problems( UserVariable v, string message, UserVariable v1, string v1Description, UserVariable v2, string v2Description From 125650c582ec38fb4785940444fdf6fe927c4efd Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 9 Dec 2024 16:37:57 -0800 Subject: [PATCH 143/628] Address review feedback --- c/misra/src/codeql-suites/misra-c-default.qls | 1 + c/misra/src/codeql-suites/misra-c-strict.qls | 8 ++++ .../RULE-2-8/UnusedObjectDefinition.expected | 2 + c/misra/test/rules/RULE-2-8/test.c | 18 +++++++++ .../cpp/deadcode/UnusedObjects.qll | 10 +++-- .../cpp/deadcode/UnusedVariables.qll | 39 ++++++++++++++----- docs/development_handbook.md | 2 + docs/user_manual.md | 13 ++++++- rule_packages/c/DeadCode2.json | 5 ++- 9 files changed, 82 insertions(+), 16 deletions(-) create mode 100644 c/misra/src/codeql-suites/misra-c-strict.qls diff --git a/c/misra/src/codeql-suites/misra-c-default.qls b/c/misra/src/codeql-suites/misra-c-default.qls index 343379a2b3..f72a63ba49 100644 --- a/c/misra/src/codeql-suites/misra-c-default.qls +++ b/c/misra/src/codeql-suites/misra-c-default.qls @@ -7,4 +7,5 @@ - exclude: tags contain: - external/misra/audit + - external/misra/strict - external/misra/default-disabled diff --git a/c/misra/src/codeql-suites/misra-c-strict.qls b/c/misra/src/codeql-suites/misra-c-strict.qls new file mode 100644 index 0000000000..6fb642424c --- /dev/null +++ b/c/misra/src/codeql-suites/misra-c-strict.qls @@ -0,0 +1,8 @@ +- description: MISRA C 2012 (Strict) +- qlpack: codeql/misra-c-coding-standards +- include: + kind: + - problem + - path-problem + tags contain: + - external/misra/strict diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected index fc6f320539..ce7e198122 100644 --- a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected @@ -6,3 +6,5 @@ | test.c:45:9:45:10 | definition of g6 | Unused object definition 'g6'. | test.c:45:9:45:10 | test.c:45:9:45:10 | | | test.c:51:5:51:6 | definition of g7 | Unused object definition 'g7'. | test.c:51:5:51:6 | test.c:51:5:51:6 | | | test.c:64:3:64:18 | ONLY_DEF_VAR(x) | Unused object definition 'l2' from macro '$@'. | test.c:60:1:60:34 | test.c:60:1:60:34 | ONLY_DEF_VAR | +| test.c:117:11:117:13 | definition of g10 | Unused object definition 'g10'. | test.c:117:11:117:13 | test.c:117:11:117:13 | | +| test.c:122:13:122:14 | definition of l2 | Unused object definition 'l2'. | test.c:122:13:122:14 | test.c:122:13:122:14 | | diff --git a/c/misra/test/rules/RULE-2-8/test.c b/c/misra/test/rules/RULE-2-8/test.c index 21a2479163..cffb4f2e33 100644 --- a/c/misra/test/rules/RULE-2-8/test.c +++ b/c/misra/test/rules/RULE-2-8/test.c @@ -111,3 +111,21 @@ void f8() { void f9() { DEF_ATTR_UNUSED_INNER_VAR(); // COMPLIANT } + +// Const variable tests: +const int g9 = 1; // COMPLIANT +const int g10 = 1; // NON-COMPLIANT + +void f10() { + g9; + const int l1 = 1; // COMPLIANT + const int l2 = 1; // NON-COMPLIANT + l1; +} + +// Side effects should not disable this rule: +void f11() { + int l1 = 1; // COMPLIANT + int l2 = l1++; // COMPLIANT + l2; +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll b/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll index 70944dfad4..96dcc8d315 100644 --- a/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll +++ b/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll @@ -1,4 +1,5 @@ import cpp +import codingstandards.cpp.deadcode.UnusedVariables import codingstandards.cpp.alertreporting.HoldsForAllCopies import codingstandards.cpp.alertreporting.DeduplicateMacroResults @@ -15,10 +16,13 @@ import codingstandards.cpp.alertreporting.DeduplicateMacroResults */ class UnusedObjectDefinition extends VariableDeclarationEntry { UnusedObjectDefinition() { + ( + getVariable() instanceof BasePotentiallyUnusedLocalVariable + or + getVariable() instanceof BasePotentiallyUnusedGlobalOrNamespaceVariable + ) and not exists(VariableAccess access | access.getTarget() = getVariable()) and - getVariable().getDefinition() = this and - not this instanceof ParameterDeclarationEntry and - not getVariable() instanceof MemberVariable + getVariable().getDefinition() = this } /* Dead objects with these attributes are reported in the "strict" queries. */ diff --git a/cpp/common/src/codingstandards/cpp/deadcode/UnusedVariables.qll b/cpp/common/src/codingstandards/cpp/deadcode/UnusedVariables.qll index 912d2babcd..b896fb6f9e 100644 --- a/cpp/common/src/codingstandards/cpp/deadcode/UnusedVariables.qll +++ b/cpp/common/src/codingstandards/cpp/deadcode/UnusedVariables.qll @@ -36,11 +36,11 @@ predicate declarationHasSideEffects(Variable v) { v.getType() instanceof TemplateDependentType } -/** A `LocalVariable` which is a candidate for being unused. */ -class PotentiallyUnusedLocalVariable extends LocalVariable { - PotentiallyUnusedLocalVariable() { - // Ignore variables declared in macro expansions - not exists(DeclStmt ds | ds.getADeclaration() = this and ds.isInMacroExpansion()) and +/** + * A `LocalVariable` which is a candidate for being unused, and may or may not be defined in a macro. + */ +class BasePotentiallyUnusedLocalVariable extends LocalVariable { + BasePotentiallyUnusedLocalVariable() { // Ignore variables where initializing the variable has side effects not declarationHasSideEffects(this) and // TODO non POD types with initializers? Also, do something different with templates? exists(Function f | f = getFunction() | @@ -56,6 +56,16 @@ class PotentiallyUnusedLocalVariable extends LocalVariable { } } +/** + * A `LocalVariable` which is a candidate for being unused, and not defined in a macro. + */ +class PotentiallyUnusedLocalVariable extends BasePotentiallyUnusedLocalVariable { + PotentiallyUnusedLocalVariable() { + // Ignore variables declared in macro expansions + not exists(DeclStmt ds | ds.getADeclaration() = this and ds.isInMacroExpansion()) + } +} + /** Holds if `mf` is "defined" in this database. */ predicate isDefined(MemberFunction mf) { exists(MemberFunction definedMemberFunction | @@ -105,13 +115,11 @@ class PotentiallyUnusedMemberVariable extends MemberVariable { } } -/** A `GlobalOrNamespaceVariable` which is potentially unused. */ -class PotentiallyUnusedGlobalOrNamespaceVariable extends GlobalOrNamespaceVariable { - PotentiallyUnusedGlobalOrNamespaceVariable() { +/** A `GlobalOrNamespaceVariable` which is potentially unused and may or may not be defined in a macro */ +class BasePotentiallyUnusedGlobalOrNamespaceVariable extends GlobalOrNamespaceVariable { + BasePotentiallyUnusedGlobalOrNamespaceVariable() { // A non-defined variable may never be used hasDefinition() and - // Not declared in a macro expansion - not isInMacroExpansion() and // No side-effects from declaration not declarationHasSideEffects(this) and // exclude uninstantiated template members @@ -121,6 +129,17 @@ class PotentiallyUnusedGlobalOrNamespaceVariable extends GlobalOrNamespaceVariab } } +/** + * A `GlobalOrNamespaceVariable` which is potentially unused, and is not defined in a macro. +*/ +class PotentiallyUnusedGlobalOrNamespaceVariable extends BasePotentiallyUnusedGlobalOrNamespaceVariable +{ + PotentiallyUnusedGlobalOrNamespaceVariable() { + // Not declared in a macro expansion + not isInMacroExpansion() + } +} + predicate isUnused(Variable variable) { not exists(variable.getAnAccess()) and variable.getInitializer().fromSource() diff --git a/docs/development_handbook.md b/docs/development_handbook.md index dc50bf59ff..97c615ba2e 100644 --- a/docs/development_handbook.md +++ b/docs/development_handbook.md @@ -51,6 +51,8 @@ Each coding standard consists of a list of "guidelines", however not all the gui For some of the rules which are not amenable to static analysis, we may opt to provide a query which aids with "auditing" the rules. For example, AUTOSAR includes a rule (A10-0-1) "Public inheritance shall be used to implement 'is-a' relationship.". This is not directly amenable to static analysis, because it requires external context around the concept being modeled. However, we can provide an "audit" rule which reports all the public and private inheritance relationships in the program, so they can be manually verified. +For other rules, there may be means of indicating that a contravention is intentional, and where requiring a _devation report_ may be extra burdensome on developers and require double-entry. These results should be reported under a "strict" query. For instance, `RULE-2-8` "A project should not contain unused object definitions," where adding `__attribute__((unused))` may be preferable in order to suppress compiler warnings (which _deviation reports_ do not do) and are highly indicative of an intentional contravention by a developer. + For each rule which will be implemented with a query we have assigned a "rule package". Rule packages represent sets of rules, possibly across standards, that will be implemented together. Examples of rule packages include "Exceptions", "Naming", "Pointers" and so forth. By implementing queries for related rules together, we intend to maximize the amount of code shared between queries, and to ensure query developers can gain a deep understanding of that specific topic. The canonical list of rules, with implementation categorization and assigned rule packages, are stored in this repository in the `rules.csv` file. diff --git a/docs/user_manual.md b/docs/user_manual.md index db0f836339..1ddf68870e 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -71,6 +71,7 @@ For each rule we therefore identify whether it is supportable or not. Furthermor - **Automated** - the queries for the rule find contraventions directly. - **Audit only** - the queries for the rule does not find contraventions directly, but instead report a list of _candidates_ that can be used as input into a manual audit. For example, `A10-0-1` (_Public inheritance shall be used to implement 'is-a' relationship_) is not directly amenable to static analysis, but CodeQL can be used to produce a list of all the locations that use public inheritance so they can be manually reviewed. +- **Strict only** - the queries for the rule find contraventions directly, but find results which are strongly indicated to be intentional, and where adding a _deviation report_ may be extra burden on developers. For example, in `RULE-2-8` (_A project should not contain unused object definitions_), declaring objects with `__attribute__((unused))` may be preferable to a _deviation report_, which will not suppress relevant compiler warnings, and therefore would otherwise require developer double-entry. Each supported rule is implemented as one or more CodeQL queries, with each query covering an aspect of the rule. In many coding standards, the rules cover non-trivial semantic properties of the codebase under analysis. @@ -214,14 +215,22 @@ The following flags may be passed to the `database analyze` command to adjust th The output of this command will be a [SARIF file](https://sarifweb.azurewebsites.net/) called `.sarif`. -#### Running the analysis for audit level queries +#### Running the analysis for strict and/or audit level queries -Optionally, you may want to run the "audit" level queries. These queries produce lists of results that do not directly highlight contraventions of the rule. Instead, they identify locations in the code that can be manually audited to verify the absence of problems for that particular rule. +Optionally, you may want to run the "strict" or "audit" level queries. + +Audit queries produce lists of results that do not directly highlight contraventions of the rule. Instead, they identify locations in the code that can be manually audited to verify the absence of problems for that particular rule. ```bash codeql database analyze --format=sarifv2.1.0 --output=.sarif path/to/ path/to/codeql-coding-standards/cpp//src/codeql-suites/-audit.qls... ``` +Strict queries identify contraventions in the code that strongly suggest they are deliberate, and where adding an explicit _deviation report_ may be extra burden on developers. + +```bash +codeql database analyze --format=sarifv2.1.0 --output=.sarif path/to/ path/to/codeql-coding-standards/cpp//src/codeql-suites/-strict.qls... +``` + For each Coding Standard you want to run, add a trailing entry in the following format: `path/to/codeql-coding-standards/cpp//src/codeql-suites/-default.qls`. #### Producing an analysis report diff --git a/rule_packages/c/DeadCode2.json b/rule_packages/c/DeadCode2.json index da114a2349..b897f595e6 100644 --- a/rule_packages/c/DeadCode2.json +++ b/rule_packages/c/DeadCode2.json @@ -60,7 +60,10 @@ ] } ], - "title": "A project should not contain unused object definitions" + "title": "A project should not contain unused object definitions", + "implementation_scope": { + "description": "Unused object definitions marked with `__attribute__((unused))` (and `used`, `maybe_used`, `cleanup`) are separately reported under the 'strict' query suite. This is because these attributes strongly indicate the contravention is intentional, and a deviation report alone will not suppress compiler warnings." + } } } } \ No newline at end of file From 003feefeafe2d02809060551c07aa1aa5d5a25ca Mon Sep 17 00:00:00 2001 From: Fernando Jose Date: Tue, 10 Dec 2024 11:50:33 +0900 Subject: [PATCH 144/628] Exclude rvalue references from const in AUTOSAR rule 7-1-1. --- .../A7-1-1/DeclarationUnmodifiedObjectMissingConstSpecifier.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedObjectMissingConstSpecifier.ql b/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedObjectMissingConstSpecifier.ql index ff07bcbdb2..b961acce64 100644 --- a/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedObjectMissingConstSpecifier.ql +++ b/cpp/autosar/src/rules/A7-1-1/DeclarationUnmodifiedObjectMissingConstSpecifier.ql @@ -38,6 +38,7 @@ where not exists(LambdaExpression lc | lc.getACapture().getField() = v) and not v.isFromUninstantiatedTemplate(_) and not v.isCompilerGenerated() and + not v.getType() instanceof RValueReferenceType and //if the instantiation is not constexpr but the template is, still exclude it as a candidate not exists(TemplateVariable b | b.getAnInstantiation() = v and b.isConstexpr()) select v, "Non-constant variable " + v.getName() + cond + " and is not modified." From 18b92ec47d9121d990a12c7b59b8f956b3a59fdc Mon Sep 17 00:00:00 2001 From: Fernando Jose Date: Tue, 10 Dec 2024 12:42:56 +0900 Subject: [PATCH 145/628] Add change note. --- change_notes/2024-12-10-udpate-a7-1-1.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change_notes/2024-12-10-udpate-a7-1-1.md diff --git a/change_notes/2024-12-10-udpate-a7-1-1.md b/change_notes/2024-12-10-udpate-a7-1-1.md new file mode 100644 index 0000000000..6efa1ae01f --- /dev/null +++ b/change_notes/2024-12-10-udpate-a7-1-1.md @@ -0,0 +1,2 @@ +- `A7-1-1` - `DeclarationUnmodifiedObjectMissingConstSpecifier.ql`: + - Exclude rvalue references. From 4d31f5f11cd33031a87d1c1ff070c791f0049529 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Tue, 10 Dec 2024 01:16:51 -0500 Subject: [PATCH 146/628] Update change_notes/2024-12-08-identifier-hiding.md Co-authored-by: Fernando Jose --- change_notes/2024-12-08-identifier-hiding.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change_notes/2024-12-08-identifier-hiding.md b/change_notes/2024-12-08-identifier-hiding.md index c983f5390a..b769b16e57 100644 --- a/change_notes/2024-12-08-identifier-hiding.md +++ b/change_notes/2024-12-08-identifier-hiding.md @@ -1,7 +1,7 @@ - `A2-10-1` - `IdentifierHiding.ql`: - Improved evaluation performance. - Addressed false negatives where nested loops used the same variable name. - - Exclude cases where a variable declared in a lambda expression shadowed a globa or namespace variable that did not appear in the same translation unit. + - Exclude cases where a variable declared in a lambda expression shadowed a global or namespace variable that did not appear in the same translation unit. - `RULE-5-3` - `IdentifierHidingC.ql`: - Improved evaluation performance. - Addressed false negatives where nested loops used the same variable name. \ No newline at end of file From 0673c778943ceda34d7156bf5108f6b9d3a87960 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 29 Nov 2024 15:20:54 +0000 Subject: [PATCH 147/628] A15-4-4: Support deviation on the function declaration --- cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql | 2 +- cpp/autosar/test/rules/A15-4-4/test.cpp | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql b/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql index 7701a8a1ea..bbdb8d93f3 100644 --- a/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql +++ b/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql @@ -21,7 +21,7 @@ import codingstandards.cpp.exceptions.ExceptionFlow from Function f where - not isExcluded(f, Exceptions1Package::missingNoExceptQuery()) and + not isExcluded(f.getADeclarationEntry(), Exceptions1Package::missingNoExceptQuery()) and // No thrown exceptions not exists(getAFunctionThrownType(f, _)) and // But not marked noexcept(true) diff --git a/cpp/autosar/test/rules/A15-4-4/test.cpp b/cpp/autosar/test/rules/A15-4-4/test.cpp index 1f9d0d5a85..faae76ca8e 100644 --- a/cpp/autosar/test/rules/A15-4-4/test.cpp +++ b/cpp/autosar/test/rules/A15-4-4/test.cpp @@ -56,4 +56,12 @@ std::string test_fp_reported_in_424( s3.append(s1.c_str(), s1.size()); s3.append(s2.c_str(), s2.size()); return s3; -} \ No newline at end of file +} + +void test_no_except_deviated_decl(); // a-15-4-4-deviation + +void test_no_except_deviated_decl() {} + +void test_no_except_deviated_defn(); + +void test_no_except_deviated_defn() {} // a-15-4-4-deviation \ No newline at end of file From 5e753af5dc4e815a3de2046dc94b1f08a42a5824 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 10 Dec 2024 13:44:36 +0000 Subject: [PATCH 148/628] Add change note --- change_notes/2024-12-10-a15-4-4-deviations.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change_notes/2024-12-10-a15-4-4-deviations.md diff --git a/change_notes/2024-12-10-a15-4-4-deviations.md b/change_notes/2024-12-10-a15-4-4-deviations.md new file mode 100644 index 0000000000..4a595e3e00 --- /dev/null +++ b/change_notes/2024-12-10-a15-4-4-deviations.md @@ -0,0 +1,2 @@ + - `A15-4-4` - `MissingNoExcept.ql`: + - Enable deviations on either declarations or definitions. \ No newline at end of file From 9492933c0ac32ac1a98b2bcb51e8f985f5ce5d3b Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 10 Dec 2024 08:25:01 -0800 Subject: [PATCH 149/628] Format --- cpp/common/src/codingstandards/cpp/deadcode/UnusedVariables.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/deadcode/UnusedVariables.qll b/cpp/common/src/codingstandards/cpp/deadcode/UnusedVariables.qll index b896fb6f9e..a7accd5252 100644 --- a/cpp/common/src/codingstandards/cpp/deadcode/UnusedVariables.qll +++ b/cpp/common/src/codingstandards/cpp/deadcode/UnusedVariables.qll @@ -131,7 +131,7 @@ class BasePotentiallyUnusedGlobalOrNamespaceVariable extends GlobalOrNamespaceVa /** * A `GlobalOrNamespaceVariable` which is potentially unused, and is not defined in a macro. -*/ + */ class PotentiallyUnusedGlobalOrNamespaceVariable extends BasePotentiallyUnusedGlobalOrNamespaceVariable { PotentiallyUnusedGlobalOrNamespaceVariable() { From 8c31c8c296b5992b931fe1cbc8b338b89e8dc048 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 10 Dec 2024 08:26:37 -0800 Subject: [PATCH 150/628] format c --- c/misra/test/rules/RULE-2-8/test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/c/misra/test/rules/RULE-2-8/test.c b/c/misra/test/rules/RULE-2-8/test.c index cffb4f2e33..ef40dfb2a4 100644 --- a/c/misra/test/rules/RULE-2-8/test.c +++ b/c/misra/test/rules/RULE-2-8/test.c @@ -113,7 +113,7 @@ void f9() { } // Const variable tests: -const int g9 = 1; // COMPLIANT +const int g9 = 1; // COMPLIANT const int g10 = 1; // NON-COMPLIANT void f10() { @@ -125,7 +125,7 @@ void f10() { // Side effects should not disable this rule: void f11() { - int l1 = 1; // COMPLIANT + int l1 = 1; // COMPLIANT int l2 = l1++; // COMPLIANT l2; } \ No newline at end of file From 7631a61cdd55ec9b46804941bdd04d65d3a40f38 Mon Sep 17 00:00:00 2001 From: knewbury01 Date: Tue, 10 Dec 2024 21:27:28 +0000 Subject: [PATCH 151/628] Bump version to 2.40.0-dev --- c/cert/src/qlpack.yml | 2 +- c/cert/test/qlpack.yml | 2 +- c/common/src/qlpack.yml | 2 +- c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- c/misra/test/qlpack.yml | 2 +- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/qlpack.yml | 2 +- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- docs/user_manual.md | 12 ++++++------ 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index f7454d1ff0..2778e44435 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.39.0-dev +version: 2.40.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index a79ef5f692..461ebe9677 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.39.0-dev +version: 2.40.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 1930faeeb0..f39f3cb1c4 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.39.0-dev +version: 2.40.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index 41737a34ec..d417a17df2 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.39.0-dev +version: 2.40.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 656394ad1d..9aceed1a49 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.39.0-dev +version: 2.40.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index 3acb8455b1..d53bc95f28 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.39.0-dev +version: 2.40.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index e1843eb2e7..f44ad54c74 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.39.0-dev +version: 2.40.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index e7e8d3e2ce..178d8cc314 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.39.0-dev +version: 2.40.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 949087dfd5..735dd9f5b4 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.39.0-dev +version: 2.40.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index ba7415c43e..3a6d02e7d4 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.39.0-dev +version: 2.40.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index 1cfc63d8d9..1ae6dfd997 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards -version: 2.39.0-dev +version: 2.40.0-dev license: MIT dependencies: codeql/cpp-all: 1.4.2 diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index 3f061a2920..90236b203e 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.39.0-dev +version: 2.40.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 4f94ff4bec..96fc96ce24 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.39.0-dev +version: 2.40.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index e79e5934fa..207facda4e 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.39.0-dev +version: 2.40.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index 73f4cf3276..e569153ae8 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.39.0-dev +version: 2.40.0-dev license: MIT dependencies: codeql/cpp-all: 1.4.2 diff --git a/docs/user_manual.md b/docs/user_manual.md index 4c020dc73b..952a9a3c99 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -33,14 +33,14 @@ ## Release information -This user manual documents release `2.39.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.40.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: - `coding-standards-codeql-packs-2.37.0-dev.zip`: CodeQL packs that can be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `code-scanning-cpp-query-pack-2.39.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.39.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.39.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.39.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.40.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.40.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.40.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.40.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -573,7 +573,7 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.39.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.40.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | From 78ae4ce64cc8b7188234e618aa3ae33fd57d3f30 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 10 Dec 2024 18:03:04 -0800 Subject: [PATCH 152/628] Implement MISRA-C clarifications from amendments3, 4, at TC2. Some amendments were improperly categorized, fixed. Rule 10.1 also had an additional amendment (amdt4 and tc2). --- amendments.csv | 53 ++++++++++++++++--------------- rule_packages/c/Banned.json | 2 +- rule_packages/c/Contracts6.json | 2 +- rule_packages/c/Pointers1.json | 2 +- rule_packages/c/SideEffects1.json | 2 +- 5 files changed, 31 insertions(+), 30 deletions(-) diff --git a/amendments.csv b/amendments.csv index ce285a29ba..2d7254efec 100644 --- a/amendments.csv +++ b/amendments.csv @@ -9,41 +9,42 @@ c,MISRA-C-2012,Amendment3,RULE-10-4,Yes,Refine,No,Import c,MISRA-C-2012,Amendment3,RULE-10-5,Yes,Expand,No,Easy c,MISRA-C-2012,Amendment3,RULE-10-7,Yes,Refine,No,Import c,MISRA-C-2012,Amendment3,RULE-10-8,Yes,Refine,No,Import -c,MISRA-C-2012,Amendment3,RULE-21-11,Yes,Clarification,No,Import +c,MISRA-C-2012,Amendment3,RULE-21-11,Yes,Clarification,Yes,Import c,MISRA-C-2012,Amendment3,RULE-21-12,Yes,Replace,No,Easy c,MISRA-C-2012,Amendment4,RULE-11-3,Yes,Expand,No,Easy c,MISRA-C-2012,Amendment4,RULE-11-8,Yes,Expand,No,Easy c,MISRA-C-2012,Amendment4,RULE-13-2,Yes,Expand,No,Very Hard c,MISRA-C-2012,Amendment4,RULE-18-6,Yes,Expand,No,Medium c,MISRA-C-2012,Amendment4,RULE-18-8,Yes,Split,Yes,Easy -c,MISRA-C-2012,Corrigendum2,RULE-2-2,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-2-7,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-3-1,Yes,Refine,No,Easy -c,MISRA-C-2012,Corrigendum2,RULE-8-6,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-8-9,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-9-4,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-10-1,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-18-3,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-1-4,Yes,Replace,No,Easy -c,MISRA-C-2012,Corrigendum2,RULE-9-1,Yes,Refine,No,Easy -c,MISRA-C-2012,Corrigendum2,RULE-9-2,Yes,Refine,No,Import -c,MISRA-C-2012,Corrigendum2,DIR-4-10,Yes,Clarification,No,Import +c,MISRA-C-2012,Amendment4,RULE-2-2,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment4,RULE-2-7,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment4,RULE-3-1,Yes,Refine,No,Easy +c,MISRA-C-2012,Amendment4,RULE-8-6,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment4,RULE-8-9,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment4,RULE-9-4,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment4,RULE-10-1,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment4,RULE-18-3,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Amendment4,RULE-1-4,Yes,Replace,No,Easy +c,MISRA-C-2012,Amendment4,RULE-9-1,Yes,Refine,No,Easy +c,MISRA-C-2012,Amendment4,RULE-9-2,Yes,Refine,No,Import +c,MISRA-C-2012,Corrigendum2,DIR-4-10,Yes,Clarification,Yes,Import c,MISRA-C-2012,Corrigendum2,RULE-7-4,Yes,Refine,No,Easy -c,MISRA-C-2012,Corrigendum2,RULE-8-2,Yes,Clarification,No,Import +c,MISRA-C-2012,Corrigendum2,RULE-8-2,Yes,Clarification,Yes,Import c,MISRA-C-2012,Corrigendum2,RULE-8-3,Yes,Refine,No,Easy -c,MISRA-C-2012,Corrigendum2,RULE-8-7,Yes,Clarification,No,Import +c,MISRA-C-2012,Corrigendum2,RULE-8-7,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-10-1,Yes,Clarification,Yes,Import c,MISRA-C-2012,Corrigendum2,RULE-10-2,Yes,Refine,No,Easy -c,MISRA-C-2012,Corrigendum2,RULE-10-3,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-11-3,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-11-6,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-13-2,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-13-6,Yes,Clarification,No,Import +c,MISRA-C-2012,Corrigendum2,RULE-10-3,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-11-3,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-11-6,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-13-2,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-13-6,Yes,Clarification,Yes,Import c,MISRA-C-2012,Corrigendum2,RULE-14-3,Yes,Refine,No,Easy -c,MISRA-C-2012,Corrigendum2,RULE-15-7,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-17-4,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-17-5,Yes,Clarification,No,Import +c,MISRA-C-2012,Corrigendum2,RULE-15-7,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-17-4,Yes,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-17-5,Yes,Clarification,Yes,Import c,MISRA-C-2012,Corrigendum2,RULE-18-1,Yes,Refine,No,Easy -c,MISRA-C-2012,Corrigendum2,RULE-20-14,No,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-21-19,Yes,Clarification,No,Import +c,MISRA-C-2012,Corrigendum2,RULE-20-14,No,Clarification,Yes,Import +c,MISRA-C-2012,Corrigendum2,RULE-21-19,Yes,Clarification,Yes,Import c,MISRA-C-2012,Corrigendum2,RULE-21-20,Yes,Refine,No,Easy -c,MISRA-C-2012,Corrigendum2,RULE-22-9,Yes,Clarification,No,Import \ No newline at end of file +c,MISRA-C-2012,Corrigendum2,RULE-22-9,Yes,Clarification,Yes,Import \ No newline at end of file diff --git a/rule_packages/c/Banned.json b/rule_packages/c/Banned.json index d3825f8f30..4decbae6f2 100644 --- a/rule_packages/c/Banned.json +++ b/rule_packages/c/Banned.json @@ -104,7 +104,7 @@ }, "RULE-21-11": { "properties": { - "obligation": "required" + "obligation": "advisory" }, "queries": [ { diff --git a/rule_packages/c/Contracts6.json b/rule_packages/c/Contracts6.json index 4dbae7e121..c46ef2f710 100644 --- a/rule_packages/c/Contracts6.json +++ b/rule_packages/c/Contracts6.json @@ -26,7 +26,7 @@ "MISRA-C-2012": { "RULE-17-5": { "properties": { - "obligation": "advisory" + "obligation": "required" }, "queries": [ { diff --git a/rule_packages/c/Pointers1.json b/rule_packages/c/Pointers1.json index 29b658d823..5f53d15702 100644 --- a/rule_packages/c/Pointers1.json +++ b/rule_packages/c/Pointers1.json @@ -244,7 +244,7 @@ ] } ], - "title": "The relational operators >, >=, < and <= shall not be applied to objects of pointer type except where they point into the same object" + "title": "The relational operators >, >=, < and <= shall not be applied to expressions of pointer type except where they point into the same object" }, "RULE-18-4": { "properties": { diff --git a/rule_packages/c/SideEffects1.json b/rule_packages/c/SideEffects1.json index 9ecb79447d..9d91fce671 100644 --- a/rule_packages/c/SideEffects1.json +++ b/rule_packages/c/SideEffects1.json @@ -166,7 +166,7 @@ }, "RULE-13-6": { "properties": { - "obligation": "mandatory" + "obligation": "required" }, "queries": [ { From 08fdda904d09921412d6ee1d3e85d2c5484cc07d Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 10 Dec 2024 18:10:39 -0800 Subject: [PATCH 153/628] Regenerate query files --- c/misra/src/rules/RULE-13-6/SizeofOperandWithSideEffect.ql | 2 +- .../rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql | 2 +- c/misra/src/rules/RULE-21-11/StandardHeaderFileTgmathhUsed.ql | 2 +- cpp/common/src/codingstandards/cpp/exclusions/c/Banned.qll | 2 +- cpp/common/src/codingstandards/cpp/exclusions/c/Contracts6.qll | 2 +- .../src/codingstandards/cpp/exclusions/c/SideEffects1.qll | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/c/misra/src/rules/RULE-13-6/SizeofOperandWithSideEffect.ql b/c/misra/src/rules/RULE-13-6/SizeofOperandWithSideEffect.ql index ec1551c2a6..759ad9b06a 100644 --- a/c/misra/src/rules/RULE-13-6/SizeofOperandWithSideEffect.ql +++ b/c/misra/src/rules/RULE-13-6/SizeofOperandWithSideEffect.ql @@ -9,7 +9,7 @@ * @tags external/misra/id/rule-13-6 * correctness * external/misra/c/2012/third-edition-first-revision - * external/misra/obligation/mandatory + * external/misra/obligation/required */ import cpp diff --git a/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql b/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql index 9673b39eb2..1a142ddb22 100644 --- a/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql +++ b/c/misra/src/rules/RULE-17-5/ArrayFunctionArgumentNumberOfElements.ql @@ -9,7 +9,7 @@ * @tags external/misra/id/rule-17-5 * correctness * external/misra/c/2012/third-edition-first-revision - * external/misra/obligation/advisory + * external/misra/obligation/required */ import cpp diff --git a/c/misra/src/rules/RULE-21-11/StandardHeaderFileTgmathhUsed.ql b/c/misra/src/rules/RULE-21-11/StandardHeaderFileTgmathhUsed.ql index 1c6b1bcd3d..50c4d48cb6 100644 --- a/c/misra/src/rules/RULE-21-11/StandardHeaderFileTgmathhUsed.ql +++ b/c/misra/src/rules/RULE-21-11/StandardHeaderFileTgmathhUsed.ql @@ -8,7 +8,7 @@ * @tags external/misra/id/rule-21-11 * correctness * external/misra/c/2012/third-edition-first-revision - * external/misra/obligation/required + * external/misra/obligation/advisory */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Banned.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Banned.qll index 888e0863a3..f8a4e027bb 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Banned.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Banned.qll @@ -77,7 +77,7 @@ predicate isBannedQueryMetadata(Query query, string queryId, string ruleId, stri // `@id` for the `standardHeaderFileTgmathhUsed` query "c/misra/standard-header-file-tgmathh-used" and ruleId = "RULE-21-11" and - category = "required" + category = "advisory" or query = // `Query` instance for the `exceptionHandlingFeaturesOfFenvhUsed` query diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts6.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts6.qll index bd897bd79f..eed78ae507 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts6.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts6.qll @@ -25,7 +25,7 @@ predicate isContracts6QueryMetadata(Query query, string queryId, string ruleId, // `@id` for the `arrayFunctionArgumentNumberOfElements` query "c/misra/array-function-argument-number-of-elements" and ruleId = "RULE-17-5" and - category = "advisory" + category = "required" or query = // `Query` instance for the `valueReturnedByAFunctionNotUsed` query diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects1.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects1.qll index 24175cdfb7..ec8ab3eae8 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects1.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects1.qll @@ -104,7 +104,7 @@ predicate isSideEffects1QueryMetadata(Query query, string queryId, string ruleId // `@id` for the `sizeofOperandWithSideEffect` query "c/misra/sizeof-operand-with-side-effect" and ruleId = "RULE-13-6" and - category = "mandatory" + category = "required" } module SideEffects1Package { From dbb452317756c635407229676c5d19fc31e3b817 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 12 Dec 2024 17:15:17 -0800 Subject: [PATCH 154/628] Address most MISRA C 2012 rule amendments in Amendment3. Does not address amendments that are covered in other PRs (clarifications) or Generics behavior. Most updates related to complex floating types. One update related to emergent language features. --- amendments.csv | 18 +- .../c/misra/EssentialTypes.qll | 28 +- ...ainNumericalTypeUsedOverExplicitTypedef.ql | 58 ++- .../OperandsOfAnInappropriateEssentialType.ql | 68 ++- .../AssignmentOfIncompatibleEssentialType.ql | 6 + ...andsWithMismatchedEssentialTypeCategory.ql | 5 + .../InappropriateEssentialTypeCast.ql | 6 +- ...ImplicitConversionOfCompositeExpression.ql | 6 +- .../InappropriateCastOfCompositeExpression.ql | 21 +- .../RULE-14-1/LoopOverEssentiallyFloatType.ql | 2 +- ...ericalTypeUsedOverExplicitTypedef.expected | 40 +- c/misra/test/rules/DIR-4-6/test.c | 11 +- .../EmergentLanguageFeaturesUsed.expected | 14 - c/misra/test/rules/RULE-1-4/test.c | 32 +- ...ndsOfAnInappropriateEssentialType.expected | 392 +++++++++--------- .../PointerTypeOnLogicalOperator.expected | 10 +- c/misra/test/rules/RULE-10-1/test.c | 169 ++++++-- ...gnmentOfIncompatibleEssentialType.expected | 321 ++++++++------ c/misra/test/rules/RULE-10-3/test.c | 283 +++++++++---- ...thMismatchedEssentialTypeCategory.expected | 23 +- c/misra/test/rules/RULE-10-4/test.c | 9 + .../InappropriateEssentialTypeCast.expected | 45 +- c/misra/test/rules/RULE-10-5/test.c | 90 ++-- ...itConversionOfCompositeExpression.expected | 4 + c/misra/test/rules/RULE-10-7/test.c | 14 + ...ropriateCastOfCompositeExpression.expected | 10 +- c/misra/test/rules/RULE-10-8/test.c | 25 ++ .../src/codingstandards/cpp/Emergent.qll | 34 -- 28 files changed, 1104 insertions(+), 640 deletions(-) diff --git a/amendments.csv b/amendments.csv index ce285a29ba..0f588b0e05 100644 --- a/amendments.csv +++ b/amendments.csv @@ -1,14 +1,14 @@ language,standard,amendment,rule_id,supportable,implementation_category,implemented,difficulty -c,MISRA-C-2012,Amendment3,DIR-4-6,Yes,Expand,No,Easy +c,MISRA-C-2012,Amendment3,DIR-4-6,Yes,Expand,Yes,Easy c,MISRA-C-2012,Amendment3,DIR-4-9,Yes,Refine,No,Easy c,MISRA-C-2012,Amendment3,DIR-4-11,Yes,Refine,No,Import -c,MISRA-C-2012,Amendment3,RULE-1-4,Yes,Replace,No,Easy -c,MISRA-C-2012,Amendment3,RULE-10-1,Yes,Replace,No,Easy -c,MISRA-C-2012,Amendment3,RULE-10-3,Yes,Refine,No,Easy -c,MISRA-C-2012,Amendment3,RULE-10-4,Yes,Refine,No,Import -c,MISRA-C-2012,Amendment3,RULE-10-5,Yes,Expand,No,Easy -c,MISRA-C-2012,Amendment3,RULE-10-7,Yes,Refine,No,Import -c,MISRA-C-2012,Amendment3,RULE-10-8,Yes,Refine,No,Import +c,MISRA-C-2012,Amendment3,RULE-1-4,Yes,Replace,Yes,Easy +c,MISRA-C-2012,Amendment3,RULE-10-1,Yes,Replace,Yes,Easy +c,MISRA-C-2012,Amendment3,RULE-10-3,Yes,Refine,Yes,Easy +c,MISRA-C-2012,Amendment3,RULE-10-4,Yes,Refine,Yes,Import +c,MISRA-C-2012,Amendment3,RULE-10-5,Yes,Expand,Yes,Easy +c,MISRA-C-2012,Amendment3,RULE-10-7,Yes,Refine,Yes,Import +c,MISRA-C-2012,Amendment3,RULE-10-8,Yes,Refine,Yes,Import c,MISRA-C-2012,Amendment3,RULE-21-11,Yes,Clarification,No,Import c,MISRA-C-2012,Amendment3,RULE-21-12,Yes,Replace,No,Easy c,MISRA-C-2012,Amendment4,RULE-11-3,Yes,Expand,No,Easy @@ -24,7 +24,7 @@ c,MISRA-C-2012,Corrigendum2,RULE-8-9,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-9-4,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-10-1,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-18-3,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-1-4,Yes,Replace,No,Easy +c,MISRA-C-2012,Corrigendum2,RULE-1-4,Yes,Replace,Yes,Easy c,MISRA-C-2012,Corrigendum2,RULE-9-1,Yes,Refine,No,Easy c,MISRA-C-2012,Corrigendum2,RULE-9-2,Yes,Refine,No,Import c,MISRA-C-2012,Corrigendum2,DIR-4-10,Yes,Clarification,No,Import diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 4783547ed2..98c110f979 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -6,13 +6,17 @@ import codingstandards.c.misra import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils import MisraExpressions +newtype TEssentialFloatCategory = + Real() or + Complex() + newtype TEssentialTypeCategory = EssentiallyBooleanType() or EssentiallyCharacterType() or EssentiallyEnumType() or EssentiallySignedType() or EssentiallyUnsignedType() or - EssentiallyFloatingType() + EssentiallyFloatingType(TEssentialFloatCategory c) /** An essential type category, as specified by Appendix D.1. */ class EssentialTypeCategory extends TEssentialTypeCategory { @@ -27,7 +31,9 @@ class EssentialTypeCategory extends TEssentialTypeCategory { or this = EssentiallyUnsignedType() and result = "essentially Unsigned type" or - this = EssentiallyFloatingType() and result = "essentially Floating type" + this = EssentiallyFloatingType(Real()) and result = "essentially Floating type" + or + this = EssentiallyFloatingType(Complex()) and result = "essentially Complex Floating type" } } @@ -143,8 +149,11 @@ EssentialTypeCategory getEssentialTypeCategory(Type type) { essentialType instanceof NamedEnumType and not essentialType instanceof MisraBoolType or - result = EssentiallyFloatingType() and - essentialType instanceof FloatingPointType + result = EssentiallyFloatingType(Real()) and + essentialType instanceof RealNumberType + or + result = EssentiallyFloatingType(Complex()) and + essentialType instanceof ComplexNumberType ) } @@ -166,6 +175,17 @@ Type getEssentialType(Expr e) { Type getEssentialTypeBeforeConversions(Expr e) { result = e.(EssentialExpr).getEssentialType() } +/** + * For most essential types, `Type.getSize()` is correct, except for complex floating types. + * + * For complex floating types, the size is the size of the real part, so we divide by 2. + */ +int getEssentialSize(Type essentialType) { + if getEssentialTypeCategory(essentialType) = EssentiallyFloatingType(Complex()) + then result = essentialType.getSize() / 2 + else result = essentialType.getSize() +} + class EssentialExpr extends Expr { Type getEssentialType() { result = this.getType() } diff --git a/c/misra/src/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.ql b/c/misra/src/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.ql index 3891d8c99f..0e6c902441 100644 --- a/c/misra/src/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.ql +++ b/c/misra/src/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.ql @@ -29,6 +29,8 @@ class BuiltInNumericType extends BuiltInType { this instanceof DoubleType or this instanceof LongDoubleType + or + this instanceof ComplexNumberType } } @@ -38,22 +40,64 @@ predicate forbiddenBuiltinNumericUsedInDecl(Variable var, string message) { message = "The type " + var.getType() + " is not a fixed-width numeric type." } +class SizedTypeString extends string { + string pattern; + int size; + + bindingset[this] + pragma[inline] + SizedTypeString() { + pattern = "(u?int|c?float)(4|8|16|32|64|128)_t" and + this.regexpMatch(pattern) and + size = this.regexpCapture(pattern, 2).toInt() + } + + bindingset[this] + pragma[inline] + int getSize() { result = size } + + bindingset[this] + pragma[inline] + predicate isComplex() { this.charAt(0) = "c" } +} + +predicate forbiddenComplexType(CTypedefType typedef, string message) { + typedef.getName().(SizedTypeString).isComplex() and + ( + if typedef.getBaseType().stripTopLevelSpecifiers() instanceof ComplexNumberType + then + typedef.getSize() * 8 != typedef.getName().(SizedTypeString).getSize() * 2 and + message = "The typedef type " + typedef.getName() + " does not have its indicated real size." + else message = "The typedef type " + typedef.getName() + " is not a complex type." + ) +} + +predicate forbiddenRealType(CTypedefType typedef, string message) { + not typedef.getName().(SizedTypeString).isComplex() and + ( + if typedef.getBaseType().stripTopLevelSpecifiers() instanceof ComplexNumberType + then message = "The typedef name " + typedef.getName() + " does not indicate a complex type." + else ( + typedef.getSize() * 8 != typedef.getName().(SizedTypeString).getSize() and + message = "The typedef type " + typedef.getName() + " does not have its indicated size." + ) + ) +} + predicate forbiddenTypedef(CTypedefType typedef, string message) { /* If the typedef's name contains an explicit size */ ( - if typedef.getName().regexpMatch("u?(int|float)(4|8|16|32|64|128)_t") + if typedef.getName() instanceof SizedTypeString then ( - /* Then the actual type size should match. */ - not typedef.getSize() * 8 = - // times 8 because getSize() gets the size in bytes - typedef.getName().regexpCapture("u?(int|float)(4|8|16|32|64|128)_t", 2).toInt() and - message = "The typedef type " + typedef.getName() + " does not have its indicated size." + forbiddenRealType(typedef, message) + or + forbiddenComplexType(typedef, message) ) else ( ( // type def is to a built in numeric type typedef.getBaseType() instanceof BuiltInNumericType and // but does not include the size in the name - not typedef.getName().regexpMatch("u?(int|float)(4|8|16|32|64|128)_t") + not typedef.getName() instanceof SizedTypeString or // this is a typedef to a forbidden type def forbiddenTypedef(typedef.getBaseType(), _) diff --git a/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql b/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql index 10b24b8c8a..d06ba09f3d 100644 --- a/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql +++ b/c/misra/src/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.ql @@ -16,6 +16,15 @@ import cpp import codingstandards.c.misra import codingstandards.c.misra.EssentialTypes +predicate hasComparableFloatValue(Expr e) { + exists(float value | + value = e.getValue().toFloat() or + value = -e.(UnaryMinusExpr).getOperand().getValue().toFloat() + | + value in [0.0, "Infinity".toFloat(), -"Infinity".toFloat()] + ) +} + /** * Holds if the operator `operator` has an operand `child` that is of an inappropriate essential type * according to MISRA C 2012 Rule 10.1. @@ -33,8 +42,11 @@ predicate isInappropriateEssentialType( etc = EssentiallyCharacterType() and rationaleId = 4 or - etc = EssentiallyFloatingType() and + etc = EssentiallyFloatingType(Real()) and rationaleId = 1 + or + etc = EssentiallyFloatingType(Complex()) and + rationaleId = 9 ) or child = operator.(UnaryPlusExpr).getOperand() and @@ -64,8 +76,6 @@ predicate isInappropriateEssentialType( rationaleId = 8 ) or - // The table only talks about + and -, but below it clarifies ++ and -- are also considered to - // be equivalent. child = [ operator.(AddExpr).getAnOperand(), operator.(SubExpr).getAnOperand(), @@ -80,6 +90,13 @@ predicate isInappropriateEssentialType( rationaleId = 5 ) or + child = + [operator.(IncrementOperation).getAnOperand(), operator.(DecrementOperation).getAnOperand()] and + ( + etc = EssentiallyFloatingType(Complex()) and + rationaleId = 9 + ) + or child = [ operator.(DivExpr).getAnOperand(), operator.(MulExpr).getAnOperand(), @@ -107,13 +124,26 @@ predicate isInappropriateEssentialType( etc = EssentiallyEnumType() and rationaleId = 5 or - etc = EssentiallyFloatingType() and + etc = EssentiallyFloatingType(Real()) and rationaleId = 1 + or + etc = EssentiallyFloatingType(Complex()) and + rationaleId = 9 ) or child = operator.(RelationalOperation).getAnOperand() and - etc = EssentiallyBooleanType() and - rationaleId = 3 + ( + etc = EssentiallyBooleanType() and + rationaleId = 3 + or + etc = EssentiallyFloatingType(Complex()) and + rationaleId = 9 + ) + or + child = operator.(EqualityOperation).getAnOperand() and + rationaleId = 10 and + not hasComparableFloatValue(operator.(EqualityOperation).getAnOperand()) and + etc = EssentiallyFloatingType(_) or child = [operator.(NotExpr).getAnOperand(), operator.(BinaryLogicalOperation).getAnOperand()] and rationaleId = 2 and @@ -126,7 +156,7 @@ predicate isInappropriateEssentialType( or etc = EssentiallyUnsignedType() or - etc = EssentiallyFloatingType() + etc = EssentiallyFloatingType(_) ) or child = @@ -147,8 +177,11 @@ predicate isInappropriateEssentialType( etc = EssentiallySignedType() and rationaleId = 6 or - etc = EssentiallyFloatingType() and + etc = EssentiallyFloatingType(Real()) and rationaleId = 1 + or + etc = EssentiallyFloatingType(Complex()) and + rationaleId = 9 ) or child = @@ -171,8 +204,11 @@ predicate isInappropriateEssentialType( etc = EssentiallySignedType() and rationaleId = 7 or - etc = EssentiallyFloatingType() and + etc = EssentiallyFloatingType(Real()) and rationaleId = 1 + or + etc = EssentiallyFloatingType(Complex()) and + rationaleId = 9 ) or child = @@ -197,8 +233,11 @@ predicate isInappropriateEssentialType( etc = EssentiallySignedType() and rationaleId = 6 or - etc = EssentiallyFloatingType() and + etc = EssentiallyFloatingType(Real()) and rationaleId = 1 + or + etc = EssentiallyFloatingType(Complex()) and + rationaleId = 9 ) or child = operator.(ConditionalExpr).getCondition() and @@ -215,7 +254,7 @@ predicate isInappropriateEssentialType( etc = EssentiallyUnsignedType() and rationaleId = 2 or - etc = EssentiallyFloatingType() and + etc = EssentiallyFloatingType(_) and rationaleId = 2 ) ) @@ -245,6 +284,13 @@ string getRationaleMessage(int rationaleId, EssentialTypeCategory etc) { rationaleId = 8 and result = "Operand of essentially Unsigned type will be converted to a signed type with the signedness dependent on the implemented size of int." + or + rationaleId = 9 and + result = "Use of essentially Complex type in this way is a constraint violation." + or + rationaleId = 10 and + result = + "Floating point numbers have inherent error such that comparisons should consider precision and not exact equality." } from Expr operator, Expr child, int rationaleId, EssentialTypeCategory etc diff --git a/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql b/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql index af120fb13d..7574531332 100644 --- a/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql +++ b/c/misra/src/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.ql @@ -48,5 +48,11 @@ where lValueTypeCategory = EssentiallyUnsignedType() and const >= 0 and const <= 2.pow(lValueEssentialType.getSize() * 8) + ) and + // Exception 4: Real floating point values may be assignable to complex floating point values + not ( + lValueTypeCategory = EssentiallyFloatingType(Complex()) and + rValueTypeCategory = EssentiallyFloatingType(Real()) and + lValueEssentialType.getSize() >= rValueEssentialType.getSize() * 2 ) select rValue, message diff --git a/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql b/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql index d1fed06319..71681ad3bc 100644 --- a/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql +++ b/c/misra/src/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.ql @@ -30,6 +30,11 @@ where rightOpTypeCategory = getEssentialTypeCategory(rightOpEssentialType) and ( not leftOpTypeCategory = rightOpTypeCategory and + not ( + // Exception 3: Operands where both are real or complex floating types are allowed. + leftOpTypeCategory = EssentiallyFloatingType(_) and + rightOpTypeCategory = EssentiallyFloatingType(_) + ) and message = "The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: " + leftOpTypeCategory + ", right operand: " + rightOpTypeCategory + ")." diff --git a/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql b/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql index f782a16597..7cadb104ad 100644 --- a/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql +++ b/c/misra/src/rules/RULE-10-5/InappropriateEssentialTypeCast.ql @@ -23,14 +23,14 @@ predicate isIncompatibleEssentialTypeCast(EssentialTypeCategory fromCat, Essenti toCat = [ EssentiallyCharacterType(), EssentiallyEnumType(), EssentiallySignedType(), - EssentiallyUnsignedType(), EssentiallyFloatingType().(TEssentialTypeCategory) + EssentiallyUnsignedType(), EssentiallyFloatingType(_).(TEssentialTypeCategory) ] or fromCat = EssentiallyCharacterType() and toCat = [ EssentiallyBooleanType(), EssentiallyEnumType(), - EssentiallyFloatingType().(TEssentialTypeCategory) + EssentiallyFloatingType(_).(TEssentialTypeCategory) ] or fromCat = EssentiallyEnumType() and @@ -42,7 +42,7 @@ predicate isIncompatibleEssentialTypeCast(EssentialTypeCategory fromCat, Essenti fromCat = EssentiallyUnsignedType() and toCat = [EssentiallyBooleanType(), EssentiallyEnumType().(TEssentialTypeCategory)] or - fromCat = EssentiallyFloatingType() and + fromCat = EssentiallyFloatingType(_) and toCat = [ EssentiallyBooleanType(), EssentiallyCharacterType(), diff --git a/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql b/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql index 911aa5e00e..d674f78dc3 100644 --- a/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql +++ b/c/misra/src/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.ql @@ -23,6 +23,10 @@ bindingset[essentialTypeLeft, essentialTypeRight] pragma[inline_late] predicate isSameEssentialTypeCategory(Type essentialTypeLeft, Type essentialTypeRight) { getEssentialTypeCategory(essentialTypeLeft) = getEssentialTypeCategory(essentialTypeRight) + or + // Complex and real floating types are considered interchangeable + getEssentialTypeCategory(essentialTypeLeft) = EssentiallyFloatingType(_) and + getEssentialTypeCategory(essentialTypeRight) = EssentiallyFloatingType(_) } from @@ -35,7 +39,7 @@ where not otherOp = compositeOp and compositeEssentialType = getEssentialType(compositeOp) and otherOpEssentialType = getEssentialType(otherOp) and - compositeEssentialType.getSize() < otherOpEssentialType.getSize() and + getEssentialSize(compositeEssentialType) < getEssentialSize(otherOpEssentialType) and // Operands of a different type category in an operation with the usual arithmetic conversions is // prohibited by Rule 10.4, so we only report cases here where the essential type categories are // the same diff --git a/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql b/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql index 162ba4439c..b4d54bf2e8 100644 --- a/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql +++ b/c/misra/src/rules/RULE-10-8/InappropriateCastOfCompositeExpression.ql @@ -30,12 +30,19 @@ where castTypeCategory = getEssentialTypeCategory(castEssentialType) and compositeTypeCategory = getEssentialTypeCategory(compositeExprEssentialType) and ( - not castTypeCategory = compositeTypeCategory and - message = - "Cast from " + compositeTypeCategory + " to " + castTypeCategory + " changes type category." - or - castTypeCategory = compositeTypeCategory and - castEssentialType.getSize() > compositeExprEssentialType.getSize() and - message = "Cast from " + compositeTypeCategory + " to " + castTypeCategory + " widens type." + if + not castTypeCategory = compositeTypeCategory and + not ( + // Exception 2: Casts between real or complex floating types are allowed + castTypeCategory = EssentiallyFloatingType(_) and + compositeTypeCategory = EssentiallyFloatingType(_) + ) + then + message = + "Cast from " + compositeTypeCategory + " to " + castTypeCategory + " changes type category." + else ( + getEssentialSize(castEssentialType) > getEssentialSize(compositeExprEssentialType) and + message = "Cast from " + compositeTypeCategory + " to " + castTypeCategory + " widens type." + ) ) select ce, message diff --git a/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql b/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql index 83d91dac63..3d351c898e 100644 --- a/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql +++ b/c/misra/src/rules/RULE-14-1/LoopOverEssentiallyFloatType.ql @@ -21,6 +21,6 @@ from ForStmt forLoop, Variable loopIterationVariable where not isExcluded(loopIterationVariable, EssentialTypesPackage::loopOverEssentiallyFloatTypeQuery()) and getAnIterationVariable(forLoop) = loopIterationVariable and - getEssentialTypeCategory(loopIterationVariable.getType()) = EssentiallyFloatingType() + getEssentialTypeCategory(loopIterationVariable.getType()) = EssentiallyFloatingType(_) select loopIterationVariable, "Loop iteration variable " + loopIterationVariable.getName() + " is essentially Floating type." diff --git a/c/misra/test/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.expected b/c/misra/test/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.expected index c7f1cba77a..49e0b1c34c 100644 --- a/c/misra/test/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.expected +++ b/c/misra/test/rules/DIR-4-6/PlainNumericalTypeUsedOverExplicitTypedef.expected @@ -1,20 +1,24 @@ | test.c:14:5:14:10 | int4_t | The typedef type int4_t does not have its indicated size. | | test.c:16:5:16:11 | uint4_t | The typedef type uint4_t does not have its indicated size. | -| test.c:27:5:27:26 | _astronomical_number_t | The type _astronomical_number_t is not an alias to a fixed-width numeric type. | -| test.c:34:15:34:16 | c2 | The type signed char is not a fixed-width numeric type. | -| test.c:35:17:35:18 | c3 | The type unsigned char is not a fixed-width numeric type. | -| test.c:38:9:38:10 | s1 | The type short is not a fixed-width numeric type. | -| test.c:39:16:39:17 | s2 | The type signed short is not a fixed-width numeric type. | -| test.c:40:18:40:19 | s3 | The type unsigned short is not a fixed-width numeric type. | -| test.c:43:7:43:8 | i1 | The type int is not a fixed-width numeric type. | -| test.c:44:14:44:15 | i2 | The type signed int is not a fixed-width numeric type. | -| test.c:45:16:45:17 | i3 | The type unsigned int is not a fixed-width numeric type. | -| test.c:48:8:48:9 | l1 | The type long is not a fixed-width numeric type. | -| test.c:49:15:49:16 | l2 | The type signed long is not a fixed-width numeric type. | -| test.c:50:17:50:18 | l3 | The type unsigned long is not a fixed-width numeric type. | -| test.c:53:13:53:15 | ll1 | The type long long is not a fixed-width numeric type. | -| test.c:54:20:54:22 | ll2 | The type signed long long is not a fixed-width numeric type. | -| test.c:55:22:55:24 | ll3 | The type unsigned long long is not a fixed-width numeric type. | -| test.c:58:9:58:10 | f1 | The type float is not a fixed-width numeric type. | -| test.c:61:10:61:11 | d1 | The type double is not a fixed-width numeric type. | -| test.c:64:15:64:17 | ld1 | The type long double is not a fixed-width numeric type. | +| test.c:19:25:19:33 | float64_t | The typedef name float64_t does not indicate a complex type. | +| test.c:22:15:22:24 | cfloat32_t | The typedef type cfloat32_t is not a complex type. | +| test.c:24:25:24:35 | cfloat128_t | The typedef type cfloat128_t does not have its indicated real size. | +| test.c:31:5:31:26 | _astronomical_number_t | The type _astronomical_number_t is not an alias to a fixed-width numeric type. | +| test.c:38:15:38:16 | c2 | The type signed char is not a fixed-width numeric type. | +| test.c:39:17:39:18 | c3 | The type unsigned char is not a fixed-width numeric type. | +| test.c:42:9:42:10 | s1 | The type short is not a fixed-width numeric type. | +| test.c:43:16:43:17 | s2 | The type signed short is not a fixed-width numeric type. | +| test.c:44:18:44:19 | s3 | The type unsigned short is not a fixed-width numeric type. | +| test.c:47:7:47:8 | i1 | The type int is not a fixed-width numeric type. | +| test.c:48:14:48:15 | i2 | The type signed int is not a fixed-width numeric type. | +| test.c:49:16:49:17 | i3 | The type unsigned int is not a fixed-width numeric type. | +| test.c:52:8:52:9 | l1 | The type long is not a fixed-width numeric type. | +| test.c:53:15:53:16 | l2 | The type signed long is not a fixed-width numeric type. | +| test.c:54:17:54:18 | l3 | The type unsigned long is not a fixed-width numeric type. | +| test.c:57:13:57:15 | ll1 | The type long long is not a fixed-width numeric type. | +| test.c:58:20:58:22 | ll2 | The type signed long long is not a fixed-width numeric type. | +| test.c:59:22:59:24 | ll3 | The type unsigned long long is not a fixed-width numeric type. | +| test.c:62:9:62:10 | f1 | The type float is not a fixed-width numeric type. | +| test.c:65:10:65:11 | d1 | The type double is not a fixed-width numeric type. | +| test.c:68:15:68:17 | ld1 | The type long double is not a fixed-width numeric type. | +| test.c:71:18:71:20 | cf1 | The type _Complex float is not a fixed-width numeric type. | diff --git a/c/misra/test/rules/DIR-4-6/test.c b/c/misra/test/rules/DIR-4-6/test.c index db0842c4f6..0fc79faa2e 100644 --- a/c/misra/test/rules/DIR-4-6/test.c +++ b/c/misra/test/rules/DIR-4-6/test.c @@ -15,10 +15,14 @@ typedef signed long long typedef unsigned long long uint4_t; // NON_COMPLIANT: typedef does not have its indicated size -typedef float float32_t; // COMPLIANT: exception, typedefs are permitted -typedef double float64_t; // COMPLIANT: exception, typedefs are permitted +typedef float float32_t; // COMPLIANT: exception, typedefs are permitted +typedef double _Complex float64_t; // NON-COMPLIANT: not complex floating type typedef long double float128_t; // COMPLIANT: exception, typedefs are permitted +typedef float cfloat32_t; // NON-COMPLIANT: not a complex floating type +typedef double _Complex cfloat64_t; // COMPLIANT: correct complex floating type +typedef double _Complex cfloat128_t; // NON-COMPLIANT: incorrect complex size + typedef int8_t astronomical_number_t; // COMPLIANT: aliasing a fixed-width numeric typedef typedef uint8_t u_astronomical_number_t; // COMPLIANT: aliasing a fixed-width @@ -63,4 +67,7 @@ main(int argc, // COMPLIANT: exception, argc's type can be plain int long double ld1 = 1; // NON_COMPLIANT: int is a basic numeric type float128_t ld2 = 1; // COMPLIANT: typedef used instead + + float _Complex cf1 = 1; // NON_COMPLIANT: complex basic numeric type + cfloat64_t cf2 = 1; // COMPLIANT: typedef used instead } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected b/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected index 2745223358..3f63a6c26c 100644 --- a/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected +++ b/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected @@ -1,15 +1 @@ -| test.c:1:1:1:21 | #include | Usage of emergent language feature. | -| test.c:2:1:2:22 | #include | Usage of emergent language feature. | -| test.c:3:1:3:24 | #include | Usage of emergent language feature. | -| test.c:4:1:4:20 | #include | Usage of emergent language feature. | -| test.c:6:1:6:49 | #define MACRO(x) _Generic((x), int : 0, long : 1) | Usage of emergent language feature. | | test.c:7:1:7:32 | #define __STDC_WANT_LIB_EXT1__ 1 | Usage of emergent language feature. | -| test.c:9:16:9:17 | f0 | Usage of emergent language feature. | -| test.c:12:26:12:40 | atomic_new_type | Usage of emergent language feature. | -| test.c:17:15:17:15 | i | Usage of emergent language feature. | -| test.c:19:3:19:10 | alignas(...) | Usage of emergent language feature. | -| test.c:20:3:20:9 | alignas(...) | Usage of emergent language feature. | -| test.c:21:11:21:23 | alignof(int) | Usage of emergent language feature. | -| test.c:22:12:22:23 | alignof(int) | Usage of emergent language feature. | -| test.c:24:27:24:28 | i3 | Usage of emergent language feature. | -| test.c:25:28:25:29 | i4 | Usage of emergent language feature. | diff --git a/c/misra/test/rules/RULE-1-4/test.c b/c/misra/test/rules/RULE-1-4/test.c index 153c722c94..8c1e44e6bd 100644 --- a/c/misra/test/rules/RULE-1-4/test.c +++ b/c/misra/test/rules/RULE-1-4/test.c @@ -1,26 +1,26 @@ -#include //NON_COMPLIANT -#include //NON_COMPLIANT -#include //NON_COMPLIANT -#include //NON_COMPLIANT +#include //COMPLIANT +#include //COMPLIANT +#include //COMPLIANT +#include //COMPLIANT -#define MACRO(x) _Generic((x), int : 0, long : 1) // NON_COMPLIANT -#define __STDC_WANT_LIB_EXT1__ 1 // NON_COMPLIANT +#define MACRO(x) _Generic((x), int : 0, long : 1) // COMPLIANT +#define __STDC_WANT_LIB_EXT1__ 1 // NON-COMPLIANT -_Noreturn void f0(); // NON_COMPLIANT +_Noreturn void f0(); // COMPLIANT typedef int new_type; // COMPLIANT -typedef _Atomic new_type atomic_new_type; // NON_COMPLIANT +typedef _Atomic new_type atomic_new_type; // COMPLIANT void f(int p) { - int i0 = _Generic(p, int : 0, long : 1); // NON_COMPLIANT[FALSE_NEGATIVE] + int i0 = _Generic(p, int : 0, long : 1); // COMPLIANT - _Atomic int i; // NON_COMPLIANT + _Atomic int i; // COMPLIANT - _Alignas(4) int i1; // NON_COMPLIANT - alignas(4) int i2; // NON_COMPLIANT - int a = _Alignof(int); // NON_COMPLIANT - int a1 = alignof(int); // NON_COMPLIANT + _Alignas(4) int i1; // COMPLIANT + alignas(4) int i2; // COMPLIANT + int a = _Alignof(int); // COMPLIANT + int a1 = alignof(int); // COMPLIANT - static thread_local int i3; // NON_COMPLIANT - static _Thread_local int i4; // NON_COMPLIANT + static thread_local int i3; // COMPLIANT + static _Thread_local int i4; // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected b/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected index 8d1b1d8d1b..aad8dadf99 100644 --- a/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected +++ b/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected @@ -1,191 +1,209 @@ -| test.c:13:5:13:5 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:14:5:14:5 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:20:4:20:4 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:21:4:21:4 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:22:4:22:5 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:27:4:27:4 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:28:4:28:4 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:29:4:29:5 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:31:4:31:4 | u | Operand of essentially Unsigned type will be converted to a signed type with the signedness dependent on the implemented size of int. | -| test.c:34:7:34:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:36:7:36:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:41:7:41:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:43:7:43:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:48:3:48:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:50:3:50:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:15:5:15:5 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:16:5:16:5 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:23:4:23:4 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:24:4:24:4 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:25:4:25:5 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:31:4:31:4 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:32:4:32:4 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:33:4:33:5 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:35:4:35:4 | u | Operand of essentially Unsigned type will be converted to a signed type with the signedness dependent on the implemented size of int. | +| test.c:39:7:39:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:41:7:41:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:47:7:47:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:49:7:49:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | | test.c:55:3:55:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | | test.c:57:3:57:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:62:3:62:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:64:3:64:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:69:3:69:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:71:3:71:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:76:5:76:5 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:78:5:78:6 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:83:5:83:5 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:85:5:85:6 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:90:7:90:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:91:7:91:7 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:92:7:92:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:97:7:97:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:98:7:98:7 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:99:7:99:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:104:3:104:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:105:3:105:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:106:3:106:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:111:3:111:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:112:3:112:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:113:3:113:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:118:3:118:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:119:3:119:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:120:3:120:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:125:7:125:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:126:7:126:7 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:127:7:127:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:132:7:132:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:139:7:139:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:146:8:146:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:153:8:153:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:160:3:160:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:167:3:167:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:174:3:174:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:181:3:181:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:217:4:217:4 | c | Operand of essentially Character type type interpreted as a Boolean value. | -| test.c:218:4:218:5 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | -| test.c:219:4:219:4 | s | Operand of essentially Signed type type interpreted as a Boolean value. | -| test.c:220:4:220:4 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | -| test.c:221:4:221:4 | f | Operand of essentially Floating type type interpreted as a Boolean value. | -| test.c:224:3:224:3 | c | Operand of essentially Character type type interpreted as a Boolean value. | -| test.c:225:3:225:4 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | -| test.c:226:3:226:3 | s | Operand of essentially Signed type type interpreted as a Boolean value. | -| test.c:227:3:227:3 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | -| test.c:228:3:228:3 | f | Operand of essentially Floating type type interpreted as a Boolean value. | -| test.c:231:3:231:3 | c | Operand of essentially Character type type interpreted as a Boolean value. | -| test.c:232:3:232:4 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | -| test.c:233:3:233:3 | s | Operand of essentially Signed type type interpreted as a Boolean value. | -| test.c:234:3:234:3 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | -| test.c:235:3:235:3 | f | Operand of essentially Floating type type interpreted as a Boolean value. | -| test.c:238:11:238:11 | c | Operand of essentially Character type type interpreted as a Boolean value. | -| test.c:239:11:239:12 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | -| test.c:240:11:240:11 | s | Operand of essentially Signed type type interpreted as a Boolean value. | -| test.c:241:11:241:11 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | -| test.c:242:11:242:11 | f | Operand of essentially Floating type type interpreted as a Boolean value. | -| test.c:245:12:245:12 | c | Operand of essentially Character type type interpreted as a Boolean value. | -| test.c:246:12:246:13 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | -| test.c:247:12:247:12 | s | Operand of essentially Signed type type interpreted as a Boolean value. | -| test.c:248:12:248:12 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | -| test.c:249:12:249:12 | f | Operand of essentially Floating type type interpreted as a Boolean value. | -| test.c:251:3:251:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:252:3:252:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:253:3:253:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:254:3:254:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:258:3:258:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:259:3:259:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:260:3:260:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:261:3:261:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:265:8:265:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:266:8:266:8 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:267:8:267:9 | e1 | Right hand operand of shift operator is essentially Enum Type and not not essentially unsigned. | -| test.c:268:8:268:8 | s | Right hand operand of shift operator is essentially Signed type and not not essentially unsigned. | -| test.c:272:8:272:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:273:8:273:8 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:274:8:274:9 | e1 | Right hand operand of shift operator is essentially Enum Type and not not essentially unsigned. | -| test.c:275:8:275:8 | s | Right hand operand of shift operator is essentially Signed type and not not essentially unsigned. | -| test.c:279:3:279:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:280:3:280:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:281:3:281:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:282:3:282:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:286:3:286:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:287:3:287:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:288:3:288:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:289:3:289:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:293:3:293:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:294:3:294:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:295:3:295:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:296:3:296:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:300:6:300:6 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:301:6:301:6 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:302:6:302:7 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:303:6:303:6 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:307:7:307:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:308:7:308:7 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:309:7:309:8 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:310:7:310:7 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:314:7:314:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:315:7:315:7 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:316:7:316:8 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:317:7:317:7 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:321:4:321:4 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:322:4:322:4 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:323:4:323:5 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:324:4:324:4 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:329:3:329:3 | c | Operand of essentially Character type type interpreted as a Boolean value. | -| test.c:330:3:330:4 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | -| test.c:331:3:331:3 | s | Operand of essentially Signed type type interpreted as a Boolean value. | -| test.c:332:3:332:3 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | -| test.c:333:3:333:3 | f | Operand of essentially Floating type type interpreted as a Boolean value. | -| test.c:342:3:342:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:344:3:344:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:349:3:349:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:351:3:351:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:356:8:356:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:358:8:358:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:363:8:363:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:365:8:365:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:370:3:370:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:371:3:371:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:372:3:372:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:377:3:377:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:378:3:378:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:379:3:379:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:384:8:384:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:385:8:385:8 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:386:8:386:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:391:8:391:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:392:8:392:8 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:393:8:393:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:398:3:398:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:399:3:399:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:400:3:400:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:405:8:405:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:406:8:406:8 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:407:8:407:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | -| test.c:412:3:412:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:413:3:413:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:414:3:414:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:415:3:415:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:419:3:419:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:420:3:420:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:421:3:421:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:422:3:422:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:426:9:426:9 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:427:9:427:9 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:428:9:428:10 | e1 | Right hand operand of shift operator is essentially Enum Type and not not essentially unsigned. | -| test.c:429:9:429:9 | s | Right hand operand of shift operator is essentially Signed type and not not essentially unsigned. | -| test.c:433:9:433:9 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:434:9:434:9 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:435:9:435:10 | e1 | Right hand operand of shift operator is essentially Enum Type and not not essentially unsigned. | -| test.c:436:9:436:9 | s | Right hand operand of shift operator is essentially Signed type and not not essentially unsigned. | -| test.c:440:3:440:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:441:3:441:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:442:3:442:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:443:3:443:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:63:3:63:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:65:3:65:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:71:3:71:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:73:3:73:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:77:3:77:4 | cf | Use of essentially Complex type in this way is a constraint violation. | +| test.c:79:3:79:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:81:3:81:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:85:3:85:4 | cf | Use of essentially Complex type in this way is a constraint violation. | +| test.c:87:5:87:5 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:89:5:89:6 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:93:5:93:6 | cf | Use of essentially Complex type in this way is a constraint violation. | +| test.c:95:5:95:5 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:97:5:97:6 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:101:5:101:6 | cf | Use of essentially Complex type in this way is a constraint violation. | +| test.c:103:7:103:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:104:7:104:7 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:105:7:105:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:111:7:111:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:112:7:112:7 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:113:7:113:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:119:3:119:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:120:3:120:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:121:3:121:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:127:3:127:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:128:3:128:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:129:3:129:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:135:3:135:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:136:3:136:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:137:3:137:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:143:7:143:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:144:7:144:7 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:145:7:145:8 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:151:7:151:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:159:7:159:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:167:8:167:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:175:8:175:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:183:3:183:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:191:3:191:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:199:3:199:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:207:3:207:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:220:3:220:3 | f | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:221:3:221:4 | cf | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:234:3:234:3 | f | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:235:3:235:4 | cf | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:248:8:248:8 | f | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:249:8:249:9 | cf | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:262:8:262:8 | f | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:263:8:263:9 | cf | Floating point numbers have inherent error such that comparisons should consider precision and not exact equality. | +| test.c:272:4:272:4 | c | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:273:4:273:5 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:274:4:274:4 | s | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:275:4:275:4 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:276:4:276:4 | f | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:277:4:277:5 | cf | Operand of essentially Complex Floating type type interpreted as a Boolean value. | +| test.c:280:3:280:3 | c | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:281:3:281:4 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:282:3:282:3 | s | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:283:3:283:3 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:284:3:284:3 | f | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:285:3:285:4 | cf | Operand of essentially Complex Floating type type interpreted as a Boolean value. | +| test.c:288:3:288:3 | c | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:289:3:289:4 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:290:3:290:3 | s | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:291:3:291:3 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:292:3:292:3 | f | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:293:3:293:4 | cf | Operand of essentially Complex Floating type type interpreted as a Boolean value. | +| test.c:296:11:296:11 | c | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:297:11:297:12 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:298:11:298:11 | s | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:299:11:299:11 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:300:11:300:11 | f | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:301:11:301:12 | cf | Operand of essentially Complex Floating type type interpreted as a Boolean value. | +| test.c:304:12:304:12 | c | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:305:12:305:13 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:306:12:306:12 | s | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:307:12:307:12 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:308:12:308:12 | f | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:309:12:309:13 | cf | Operand of essentially Complex Floating type type interpreted as a Boolean value. | +| test.c:311:3:311:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:312:3:312:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:313:3:313:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:314:3:314:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:319:3:319:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:320:3:320:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:321:3:321:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:322:3:322:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:327:8:327:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:328:8:328:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:329:8:329:9 | e1 | Right hand operand of shift operator is essentially Enum Type and not not essentially unsigned. | +| test.c:330:8:330:8 | s | Right hand operand of shift operator is essentially Signed type and not not essentially unsigned. | +| test.c:335:8:335:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:336:8:336:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:337:8:337:9 | e1 | Right hand operand of shift operator is essentially Enum Type and not not essentially unsigned. | +| test.c:338:8:338:8 | s | Right hand operand of shift operator is essentially Signed type and not not essentially unsigned. | +| test.c:343:3:343:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:344:3:344:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:345:3:345:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:346:3:346:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:351:3:351:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:352:3:352:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:353:3:353:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:354:3:354:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:359:3:359:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:360:3:360:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:361:3:361:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:362:3:362:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:367:7:367:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:368:7:368:7 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:369:7:369:8 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:370:7:370:7 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:375:7:375:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:376:7:376:7 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:377:7:377:8 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:378:7:378:7 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:383:7:383:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:384:7:384:7 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:385:7:385:8 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:386:7:386:7 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:391:4:391:4 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:392:4:392:4 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:393:4:393:5 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:394:4:394:4 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:400:3:400:3 | c | Operand of essentially Character type type interpreted as a Boolean value. | +| test.c:401:3:401:4 | e1 | Operand of essentially Enum Type type interpreted as a Boolean value. | +| test.c:402:3:402:3 | s | Operand of essentially Signed type type interpreted as a Boolean value. | +| test.c:403:3:403:3 | u | Operand of essentially Unsigned type type interpreted as a Boolean value. | +| test.c:404:3:404:3 | f | Operand of essentially Floating type type interpreted as a Boolean value. | +| test.c:405:3:405:4 | cf | Operand of essentially Complex Floating type type interpreted as a Boolean value. | +| test.c:415:3:415:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:417:3:417:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:423:3:423:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:425:3:425:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:431:8:431:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:433:8:433:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:439:8:439:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:441:8:441:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | | test.c:447:3:447:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | | test.c:448:3:448:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:449:3:449:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:450:3:450:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:454:3:454:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:455:3:455:3 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:456:3:456:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:457:3:457:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:461:8:461:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:462:8:462:8 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:463:8:463:9 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:464:8:464:8 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:468:8:468:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:469:8:469:8 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:470:8:470:9 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:471:8:471:8 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:475:8:475:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:476:8:476:8 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:477:8:477:9 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:478:8:478:8 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:449:3:449:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:455:3:455:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:456:3:456:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:457:3:457:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:463:8:463:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:464:8:464:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:465:8:465:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:471:8:471:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:472:8:472:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:473:8:473:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:479:3:479:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:480:3:480:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:481:3:481:4 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:487:8:487:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:488:8:488:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:489:8:489:9 | e1 | Operand of essentially Enum type used in arithmetic operation, but has an implementation defined integer type. | +| test.c:495:3:495:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:496:3:496:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:497:3:497:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:498:3:498:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:503:3:503:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:504:3:504:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:505:3:505:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:506:3:506:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:511:9:511:9 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:512:9:512:9 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:513:9:513:10 | e1 | Right hand operand of shift operator is essentially Enum Type and not not essentially unsigned. | +| test.c:514:9:514:9 | s | Right hand operand of shift operator is essentially Signed type and not not essentially unsigned. | +| test.c:519:9:519:9 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:520:9:520:9 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:521:9:521:10 | e1 | Right hand operand of shift operator is essentially Enum Type and not not essentially unsigned. | +| test.c:522:9:522:9 | s | Right hand operand of shift operator is essentially Signed type and not not essentially unsigned. | +| test.c:527:3:527:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:528:3:528:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:529:3:529:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:530:3:530:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:535:3:535:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:536:3:536:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:537:3:537:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:538:3:538:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:543:3:543:3 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:544:3:544:3 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:545:3:545:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:546:3:546:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:551:8:551:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:552:8:552:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:553:8:553:9 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:554:8:554:8 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:559:8:559:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:560:8:560:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:561:8:561:9 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:562:8:562:8 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:567:8:567:8 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:568:8:568:8 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:569:8:569:9 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:570:8:570:8 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | diff --git a/c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.expected b/c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.expected index 35a55919fd..34d2993389 100644 --- a/c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.expected +++ b/c/misra/test/rules/RULE-10-1/PointerTypeOnLogicalOperator.expected @@ -1,5 +1,5 @@ -| test.c:488:4:488:4 | p | Logical operators should not be used with pointer types. | -| test.c:490:3:490:3 | p | Logical operators should not be used with pointer types. | -| test.c:491:7:491:7 | p | Logical operators should not be used with pointer types. | -| test.c:493:3:493:3 | p | Logical operators should not be used with pointer types. | -| test.c:494:8:494:8 | p | Logical operators should not be used with pointer types. | +| test.c:581:4:581:4 | p | Logical operators should not be used with pointer types. | +| test.c:583:3:583:3 | p | Logical operators should not be used with pointer types. | +| test.c:584:7:584:7 | p | Logical operators should not be used with pointer types. | +| test.c:586:3:586:3 | p | Logical operators should not be used with pointer types. | +| test.c:587:8:587:8 | p | Logical operators should not be used with pointer types. | diff --git a/c/misra/test/rules/RULE-10-1/test.c b/c/misra/test/rules/RULE-10-1/test.c index 19b7d2e3e8..f8d1a4fca5 100644 --- a/c/misra/test/rules/RULE-10-1/test.c +++ b/c/misra/test/rules/RULE-10-1/test.c @@ -1,3 +1,4 @@ +#include "math.h" #include "stdbool.h" void testInappropriateOperands() { @@ -7,6 +8,7 @@ void testInappropriateOperands() { signed int s = 100; unsigned int u = 1; float f = 1.0; + float _Complex cf = 1.0 + 1.0i; int a[20]; @@ -16,6 +18,7 @@ void testInappropriateOperands() { a[s]; // COMPLIANT a[u]; // COMPLIANT // a[f]; // NON_COMPILABLE + // a[cf]; // NON_COMPILABLE +b; // NON_COMPLIANT +c; // NON_COMPLIANT @@ -23,6 +26,7 @@ void testInappropriateOperands() { +s; // COMPLIANT +u; // COMPLIANT +f; // COMPLIANT + +cf; // COMPLIANT -b; // NON_COMPLIANT -c; // NON_COMPLIANT @@ -30,6 +34,7 @@ void testInappropriateOperands() { -s; // COMPLIANT -u; // NON_COMPLIANT -f; // COMPLIANT + -cf; // COMPLIANT 1 + b; // NON_COMPLIANT 1 + c; // COMPLIANT @@ -37,6 +42,7 @@ void testInappropriateOperands() { 1 + s; // COMPLIANT 1 + u; // COMPLIANT 1 + f; // COMPLIANT + 1 + cf; // COMPLIANT 1 - b; // NON_COMPLIANT 1 - c; // COMPLIANT @@ -44,6 +50,7 @@ void testInappropriateOperands() { 1 - s; // COMPLIANT 1 - u; // COMPLIANT 1 - f; // COMPLIANT + 1 - cf; // COMPLIANT b + 1; // NON_COMPLIANT c + 1; // COMPLIANT @@ -51,6 +58,7 @@ void testInappropriateOperands() { s + 1; // COMPLIANT u + 1; // COMPLIANT f + 1; // COMPLIANT + cf + 1; // COMPLIANT b - 1; // NON_COMPLIANT c - 1; // COMPLIANT @@ -58,6 +66,7 @@ void testInappropriateOperands() { s - 1; // COMPLIANT u - 1; // COMPLIANT f - 1; // COMPLIANT + cf - 1; // COMPLIANT b++; // NON_COMPLIANT c++; // COMPLIANT @@ -65,6 +74,7 @@ void testInappropriateOperands() { s++; // COMPLIANT u++; // COMPLIANT f++; // COMPLIANT + cf++; // NON_COMPLIANT b--; // NON_COMPLIANT c--; // COMPLIANT @@ -72,6 +82,7 @@ void testInappropriateOperands() { s--; // COMPLIANT u--; // COMPLIANT f--; // COMPLIANT + cf--; // NON_COMPLIANT ++b; // NON_COMPLIANT ++c; // COMPLIANT @@ -79,6 +90,7 @@ void testInappropriateOperands() { ++s; // COMPLIANT ++u; // COMPLIANT ++f; // COMPLIANT + ++cf; // NON_COMPLIANT --b; // NON_COMPLIANT --c; // COMPLIANT @@ -86,6 +98,7 @@ void testInappropriateOperands() { --s; // COMPLIANT --u; // COMPLIANT --f; // COMPLIANT + --cf; // NON_COMPLIANT 1 * b; // NON_COMPLIANT 1 * c; // NON_COMPLIANT @@ -93,6 +106,7 @@ void testInappropriateOperands() { 1 * s; // COMPLIANT 1 * u; // COMPLIANT 1 * f; // COMPLIANT + 1 * cf; // COMPLIANT 1 / b; // NON_COMPLIANT 1 / c; // NON_COMPLIANT @@ -100,6 +114,7 @@ void testInappropriateOperands() { 1 / s; // COMPLIANT 1 / u; // COMPLIANT 1 / f; // COMPLIANT + 1 / cf; // COMPLIANT b * 1; // NON_COMPLIANT c * 1; // NON_COMPLIANT @@ -107,6 +122,7 @@ void testInappropriateOperands() { s * 1; // COMPLIANT u * 1; // COMPLIANT f * 1; // COMPLIANT + cf * 1; // COMPLIANT b / 1; // NON_COMPLIANT c / 1; // NON_COMPLIANT @@ -114,6 +130,7 @@ void testInappropriateOperands() { s / 1; // COMPLIANT u / 1; // COMPLIANT f / 1; // COMPLIANT + cf / 1; // COMPLIANT b % 1; // NON_COMPLIANT c % 1; // NON_COMPLIANT @@ -121,6 +138,7 @@ void testInappropriateOperands() { s % 1; // COMPLIANT u % 1; // COMPLIANT // f % 1; // NON_COMPILABLE + // cf % 1; // NON_COMPILABLE 1 % b; // NON_COMPLIANT 1 % c; // NON_COMPLIANT @@ -128,6 +146,7 @@ void testInappropriateOperands() { 1 % s; // COMPLIANT 1 % u; // COMPLIANT // 1 % f; // NON_COMPILABLE + // 1 % cf; // NON_COMPILABLE 1 < b; // NON_COMPLIANT 1 < c; // COMPLIANT @@ -135,6 +154,7 @@ void testInappropriateOperands() { 1 < s; // COMPLIANT 1 < u; // COMPLIANT 1 < f; // COMPLIANT + // 1 < cf; // NON_COMPILABLE 1 > b; // NON_COMPLIANT 1 > c; // COMPLIANT @@ -142,6 +162,7 @@ void testInappropriateOperands() { 1 > s; // COMPLIANT 1 > u; // COMPLIANT 1 > f; // COMPLIANT + // 1 > cf; // NON_COMPILABLE 1 <= b; // NON_COMPLIANT 1 <= c; // COMPLIANT @@ -149,6 +170,7 @@ void testInappropriateOperands() { 1 <= s; // COMPLIANT 1 <= u; // COMPLIANT 1 <= f; // COMPLIANT + // 1 <= cf; // NON_COMPILABLE 1 >= b; // NON_COMPLIANT 1 >= c; // COMPLIANT @@ -156,6 +178,7 @@ void testInappropriateOperands() { 1 >= s; // COMPLIANT 1 >= u; // COMPLIANT 1 >= f; // COMPLIANT + // 1 >= cf; // NON_COMPILABLE b < 1; // NON_COMPLIANT c < 1; // COMPLIANT @@ -163,6 +186,7 @@ void testInappropriateOperands() { s < 1; // COMPLIANT u < 1; // COMPLIANT f < 1; // COMPLIANT + // cf < 1; // NON_COMPILABLE b > 1; // NON_COMPLIANT c > 1; // COMPLIANT @@ -170,6 +194,7 @@ void testInappropriateOperands() { s > 1; // COMPLIANT u > 1; // COMPLIANT f > 1; // COMPLIANT + // cf > 1; // NON_COMPILABLE b <= 1; // NON_COMPLIANT c <= 1; // COMPLIANT @@ -177,6 +202,7 @@ void testInappropriateOperands() { s <= 1; // COMPLIANT u <= 1; // COMPLIANT f <= 1; // COMPLIANT + // cf <= 1; // NON_COMPILABLE b >= 1; // NON_COMPLIANT c >= 1; // COMPLIANT @@ -184,34 +210,63 @@ void testInappropriateOperands() { s >= 1; // COMPLIANT u >= 1; // COMPLIANT f >= 1; // COMPLIANT - - b == 1; // COMPLIANT - c == 1; // COMPLIANT - e1 == 1; // COMPLIANT - s == 1; // COMPLIANT - u == 1; // COMPLIANT - f == 1; // COMPLIANT - - b != 1; // COMPLIANT - c != 1; // COMPLIANT - e1 != 1; // COMPLIANT - s != 1; // COMPLIANT - u != 1; // COMPLIANT - f != 1; // COMPLIANT - - 1 == b; // COMPLIANT - 1 == c; // COMPLIANT - 1 == e1; // COMPLIANT - 1 == s; // COMPLIANT - 1 == u; // COMPLIANT - 1 == f; // COMPLIANT - - 1 != b; // COMPLIANT - 1 != c; // COMPLIANT - 1 != e1; // COMPLIANT - 1 != s; // COMPLIANT - 1 != u; // COMPLIANT - 1 != f; // COMPLIANT + // cf >= 1; // NON_COMPILABLE + + b == 1; // COMPLIANT + c == 1; // COMPLIANT + e1 == 1; // COMPLIANT + s == 1; // COMPLIANT + u == 1; // COMPLIANT + f == 1; // NON_COMPLIANT + cf == 1; // NON_COMPLIANT + f == 0; // COMPLIANT + f == INFINITY; // COMPLIANT + f == -INFINITY; // COMPLIANT + cf == 0; // COMPLIANT + cf == INFINITY; // COMPLIANT + cf == -INFINITY; // COMPLIANT + + b != 1; // COMPLIANT + c != 1; // COMPLIANT + e1 != 1; // COMPLIANT + s != 1; // COMPLIANT + u != 1; // COMPLIANT + f != 1; // NON_COMPLIANT + cf != 1; // NON_COMPLIANT + f != 0; // COMPLIANT + f != INFINITY; // COMPLIANT + f != -INFINITY; // COMPLIANT + cf != 0; // COMPLIANT + cf != INFINITY; // COMPLIANT + cf != -INFINITY; // COMPLIANT + + 1 == b; // COMPLIANT + 1 == c; // COMPLIANT + 1 == e1; // COMPLIANT + 1 == s; // COMPLIANT + 1 == u; // COMPLIANT + 1 == f; // NON_COMPLIANT + 1 == cf; // NON_COMPLIANT + 0 == f; // COMPLIANT + INFINITY == f; // COMPLIANT + -INFINITY == f; // COMPLIANT + 0 == cf; // COMPLIANT + INFINITY == cf; // COMPLIANT + -INFINITY == cf; // COMPLIANT + + 1 != b; // COMPLIANT + 1 != c; // COMPLIANT + 1 != e1; // COMPLIANT + 1 != s; // COMPLIANT + 1 != u; // COMPLIANT + 1 != f; // NON_COMPLIANT + 1 != cf; // NON_COMPLIANT + 0 != f; // COMPLIANT + INFINITY != f; // COMPLIANT + -INFINITY != f; // COMPLIANT + 0 != cf; // COMPLIANT + INFINITY != cf; // COMPLIANT + -INFINITY != cf; // COMPLIANT !b; // COMPLIANT !c; // NON_COMPLIANT @@ -219,6 +274,7 @@ void testInappropriateOperands() { !s; // NON_COMPLIANT !u; // NON_COMPLIANT !f; // NON_COMPLIANT + !cf; // NON_COMPLIANT b && true; // COMPLIANT c && true; // NON_COMPLIANT @@ -226,6 +282,7 @@ void testInappropriateOperands() { s && true; // NON_COMPLIANT u && true; // NON_COMPLIANT f && true; // NON_COMPLIANT + cf && true; // NON_COMPLIANT b || false; // COMPLIANT c || false; // NON_COMPLIANT @@ -233,6 +290,7 @@ void testInappropriateOperands() { s || false; // NON_COMPLIANT u || false; // NON_COMPLIANT f || false; // NON_COMPLIANT + cf || false; // NON_COMPLIANT true && b; // COMPLIANT true && c; // NON_COMPLIANT @@ -240,6 +298,7 @@ void testInappropriateOperands() { true && s; // NON_COMPLIANT true && u; // NON_COMPLIANT true && f; // NON_COMPLIANT + true && cf; // NON_COMPLIANT false || b; // COMPLIANT false || c; // NON_COMPLIANT @@ -247,6 +306,7 @@ void testInappropriateOperands() { false || s; // NON_COMPLIANT false || u; // NON_COMPLIANT false || f; // NON_COMPLIANT + false || cf; // NON_COMPLIANT b << u; // NON_COMPLIANT c << u; // NON_COMPLIANT @@ -254,6 +314,7 @@ void testInappropriateOperands() { s << u; // NON_COMPLIANT u << u; // COMPLIANT // f << u; // NON_COMPILABLE + // cf << u; // NON_COMPILABLE b >> u; // NON_COMPLIANT c >> u; // NON_COMPLIANT @@ -261,6 +322,7 @@ void testInappropriateOperands() { s >> u; // NON_COMPLIANT u >> u; // COMPLIANT // f >> u; // NON_COMPILABLE + // cf >> u; // NON_COMPILABLE u << b; // NON_COMPLIANT u << c; // NON_COMPLIANT @@ -268,6 +330,7 @@ void testInappropriateOperands() { u << s; // NON_COMPLIANT u << u; // COMPLIANT // u << f; // NON_COMPILABLE + // u << cf; // NON_COMPILABLE u >> b; // NON_COMPLIANT u >> c; // NON_COMPLIANT @@ -275,13 +338,15 @@ void testInappropriateOperands() { u >> s; // NON_COMPLIANT u >> u; // COMPLIANT // u >> f; // NON_COMPILABLE + // u >> cf; // NON_COMPILABLE - b &u; // NON_COMPLIANT - c &u; // NON_COMPLIANT - e1 &u; // NON_COMPLIANT - s &u; // NON_COMPLIANT - u &u; // COMPLIANT + b & u; // NON_COMPLIANT + c & u; // NON_COMPLIANT + e1 & u; // NON_COMPLIANT + s & u; // NON_COMPLIANT + u & u; // COMPLIANT // f &u; // NON_COMPILABLE + // cf &u; // NON_COMPILABLE b | u; // NON_COMPLIANT c | u; // NON_COMPLIANT @@ -289,6 +354,7 @@ void testInappropriateOperands() { s | u; // NON_COMPLIANT u | u; // COMPLIANT // f | u; // NON_COMPILABLE + // cf | u; // NON_COMPILABLE b ^ u; // NON_COMPLIANT c ^ u; // NON_COMPLIANT @@ -296,13 +362,15 @@ void testInappropriateOperands() { s ^ u; // NON_COMPLIANT u ^ u; // COMPLIANT // f ^ u; // NON_COMPILABLE + // cf ^ u; // NON_COMPILABLE - u &b; // NON_COMPLIANT - u &c; // NON_COMPLIANT - u &e1; // NON_COMPLIANT - u &s; // NON_COMPLIANT - u &u; // COMPLIANT + u & b; // NON_COMPLIANT + u & c; // NON_COMPLIANT + u & e1; // NON_COMPLIANT + u & s; // NON_COMPLIANT + u & u; // COMPLIANT // u &f; // NON_COMPILABLE + // u &cf; // NON_COMPILABLE u | b; // NON_COMPLIANT u | c; // NON_COMPLIANT @@ -310,6 +378,7 @@ void testInappropriateOperands() { u | s; // NON_COMPLIANT u | u; // COMPLIANT // u | f; // NON_COMPILABLE + // u | cf; // NON_COMPILABLE u ^ b; // NON_COMPLIANT u ^ c; // NON_COMPLIANT @@ -317,6 +386,7 @@ void testInappropriateOperands() { u ^ s; // NON_COMPLIANT u ^ u; // COMPLIANT // u ^ f; // NON_COMPILABLE + // u ^ cf; // NON_COMPILABLE ~b; // NON_COMPLIANT ~c; // NON_COMPLIANT @@ -324,6 +394,7 @@ void testInappropriateOperands() { ~s; // NON_COMPLIANT ~u; // COMPLIANT //~f; // NON_COMPILABLE + ~cf; // NON_COMPLIANT b ? 1 : 2; // COMPLIANT c ? 1 : 2; // NON_COMPLIANT @@ -331,6 +402,7 @@ void testInappropriateOperands() { s ? 1 : 2; // NON_COMPLIANT u ? 1 : 2; // NON_COMPLIANT f ? 1 : 2; // NON_COMPLIANT + cf ? 1 : 2; // NON_COMPLIANT b ? b : b; // COMPLIANT b ? c : c; // COMPLIANT @@ -338,6 +410,7 @@ void testInappropriateOperands() { b ? s : s; // COMPLIANT b ? u : u; // COMPLIANT b ? f : f; // COMPLIANT + b ? cf : cf; // COMPLIANT b += 1; // NON_COMPLIANT c += 1; // COMPLIANT @@ -345,6 +418,7 @@ void testInappropriateOperands() { s += 1; // COMPLIANT u += 1; // COMPLIANT f += 1; // COMPLIANT + cf += 1; // COMPLIANT b -= 1; // NON_COMPLIANT c -= 1; // COMPLIANT @@ -352,6 +426,7 @@ void testInappropriateOperands() { s -= 1; // COMPLIANT u -= 1; // COMPLIANT f -= 1; // COMPLIANT + cf -= 1; // COMPLIANT u += b; // NON_COMPLIANT u += c; // COMPLIANT @@ -359,6 +434,7 @@ void testInappropriateOperands() { u += s; // COMPLIANT u += u; // COMPLIANT u += f; // COMPLIANT + u += cf; // COMPLIANT u -= b; // NON_COMPLIANT u -= c; // COMPLIANT @@ -366,6 +442,7 @@ void testInappropriateOperands() { u -= s; // COMPLIANT u -= u; // COMPLIANT u -= f; // COMPLIANT + u -= cf; // COMPLIANT b *= 1; // NON_COMPLIANT c *= 1; // NON_COMPLIANT @@ -373,6 +450,7 @@ void testInappropriateOperands() { s *= 1; // COMPLIANT u *= 1; // COMPLIANT f *= 1; // COMPLIANT + cf *= 1; // COMPLIANT b /= 1; // NON_COMPLIANT c /= 1; // NON_COMPLIANT @@ -380,6 +458,7 @@ void testInappropriateOperands() { s /= 1; // COMPLIANT u /= 1; // COMPLIANT f /= 1; // COMPLIANT + cf /= 1; // COMPLIANT u *= b; // NON_COMPLIANT u *= c; // NON_COMPLIANT @@ -387,6 +466,7 @@ void testInappropriateOperands() { u *= s; // COMPLIANT u *= u; // COMPLIANT u *= f; // COMPLIANT + u *= cf; // COMPLIANT u /= b; // NON_COMPLIANT u /= c; // NON_COMPLIANT @@ -394,6 +474,7 @@ void testInappropriateOperands() { u /= s; // COMPLIANT u /= u; // COMPLIANT u /= f; // COMPLIANT + u /= cf; // COMPLIANT b %= 1; // NON_COMPLIANT c %= 1; // NON_COMPLIANT @@ -401,6 +482,7 @@ void testInappropriateOperands() { s %= 1; // COMPLIANT u %= 1; // COMPLIANT // f %= 1; // NON_COMPILABLE + // cf %= 1; // NON_COMPILABLE u %= b; // NON_COMPLIANT u %= c; // NON_COMPLIANT @@ -408,6 +490,7 @@ void testInappropriateOperands() { u %= s; // COMPLIANT u %= u; // COMPLIANT // u %= f; // NON_COMPILABLE + // u %= cf; // NON_COMPILABLE b <<= u; // NON_COMPLIANT c <<= u; // NON_COMPLIANT @@ -415,6 +498,7 @@ void testInappropriateOperands() { s <<= u; // NON_COMPLIANT u <<= u; // COMPLIANT // f <<= u; // NON_COMPILABLE + // cf <<= u; // NON_COMPILABLE b >>= u; // NON_COMPLIANT c >>= u; // NON_COMPLIANT @@ -422,6 +506,7 @@ void testInappropriateOperands() { s >>= u; // NON_COMPLIANT u >>= u; // COMPLIANT // f >>= u; // NON_COMPILABLE + // cf >>= u; // NON_COMPILABLE u <<= b; // NON_COMPLIANT u <<= c; // NON_COMPLIANT @@ -429,6 +514,7 @@ void testInappropriateOperands() { u <<= s; // NON_COMPLIANT u <<= u; // COMPLIANT // u <<= f; // NON_COMPILABLE + // u <<= cf; // NON_COMPILABLE u >>= b; // NON_COMPLIANT u >>= c; // NON_COMPLIANT @@ -436,6 +522,7 @@ void testInappropriateOperands() { u >>= s; // NON_COMPLIANT u >>= u; // COMPLIANT // u >>= f; // NON_COMPILABLE + // u >>= cf; // NON_COMPILABLE b &= u; // NON_COMPLIANT c &= u; // NON_COMPLIANT @@ -443,6 +530,7 @@ void testInappropriateOperands() { s &= u; // NON_COMPLIANT u &= u; // COMPLIANT // f &= u; // NON_COMPILABLE + // cf &= u; // NON_COMPILABLE b ^= u; // NON_COMPLIANT c ^= u; // NON_COMPLIANT @@ -450,6 +538,7 @@ void testInappropriateOperands() { s ^= u; // NON_COMPLIANT u ^= u; // COMPLIANT // f ^= u; // NON_COMPILABLE + // cf ^= u; // NON_COMPILABLE b |= u; // NON_COMPLIANT c |= u; // NON_COMPLIANT @@ -457,6 +546,7 @@ void testInappropriateOperands() { s |= u; // NON_COMPLIANT u |= u; // COMPLIANT // f |= u; // NON_COMPILABLE + // cf |= u; // NON_COMPILABLE u &= b; // NON_COMPLIANT u &= c; // NON_COMPLIANT @@ -464,6 +554,7 @@ void testInappropriateOperands() { u &= s; // NON_COMPLIANT u &= u; // COMPLIANT // u &= f; // NON_COMPILABLE + // u &= cf; // NON_COMPILABLE u ^= b; // NON_COMPLIANT u ^= c; // NON_COMPLIANT @@ -471,6 +562,7 @@ void testInappropriateOperands() { u ^= s; // NON_COMPLIANT u ^= u; // COMPLIANT // u ^= f; // NON_COMPILABLE + // u ^= cf; // NON_COMPILABLE u |= b; // NON_COMPLIANT u |= c; // NON_COMPLIANT @@ -478,6 +570,7 @@ void testInappropriateOperands() { u |= s; // NON_COMPLIANT u |= u; // COMPLIANT // u |= f; // NON_COMPILABLE + // u |= cf; // NON_COMPILABLE } void pointerType() { diff --git a/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected b/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected index 3867abd0ca..42af35cb47 100644 --- a/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected +++ b/c/misra/test/rules/RULE-10-3/AssignmentOfIncompatibleEssentialType.expected @@ -1,133 +1,188 @@ -| test.c:11:7:11:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | -| test.c:12:7:12:7 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | -| test.c:13:7:13:7 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | -| test.c:14:7:14:7 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | -| test.c:16:8:16:8 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | -| test.c:18:8:18:8 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | -| test.c:19:8:19:8 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | -| test.c:20:8:20:8 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | -| test.c:22:7:22:7 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | -| test.c:23:7:23:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | -| test.c:25:7:25:7 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | -| test.c:26:7:26:7 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | -| test.c:28:7:28:7 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | -| test.c:29:7:29:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | -| test.c:30:7:30:7 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:32:7:32:7 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | -| test.c:34:7:34:7 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | -| test.c:35:7:35:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | -| test.c:36:7:36:7 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | -| test.c:37:7:37:7 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | -| test.c:49:14:49:15 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | -| test.c:50:14:50:14 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | -| test.c:51:14:51:14 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | -| test.c:52:14:52:14 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | -| test.c:54:17:54:17 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | -| test.c:56:17:56:17 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | -| test.c:57:17:57:17 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | -| test.c:58:17:58:17 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | -| test.c:60:19:60:19 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | -| test.c:61:19:61:20 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | -| test.c:63:19:63:19 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | -| test.c:64:19:64:19 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | -| test.c:66:21:66:21 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | -| test.c:67:21:67:22 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | -| test.c:68:21:68:21 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:70:21:70:21 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | -| test.c:72:14:72:14 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | -| test.c:73:14:73:15 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | -| test.c:74:14:74:14 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | -| test.c:75:14:75:14 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | -| test.c:80:7:80:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | -| test.c:81:7:81:7 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | -| test.c:82:7:82:7 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | -| test.c:83:7:83:7 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | -| test.c:86:7:86:7 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | -| test.c:88:7:88:7 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | -| test.c:89:7:89:7 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | -| test.c:90:7:90:7 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | -| test.c:93:7:93:7 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | -| test.c:94:7:94:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | -| test.c:96:7:96:7 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | -| test.c:97:7:97:7 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | -| test.c:100:7:100:7 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | -| test.c:101:7:101:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | -| test.c:102:7:102:7 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:104:7:104:7 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | -| test.c:107:7:107:7 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | -| test.c:108:7:108:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | -| test.c:109:7:109:7 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | -| test.c:110:7:110:7 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | -| test.c:118:7:118:8 | - ... | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:119:7:119:16 | 4294967296 | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:131:8:131:8 | A | Assignment of essentially Enum Type value to an object of essentially Boolean type. | -| test.c:132:8:132:10 | 100 | Assignment of essentially Signed type value to an object of essentially Boolean type. | -| test.c:133:23:133:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | -| test.c:138:8:138:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Enum Type. | -| test.c:140:8:140:10 | 100 | Assignment of essentially Signed type value to an object of essentially Enum Type. | -| test.c:141:23:141:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | -| test.c:146:8:146:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Signed type. | -| test.c:147:8:147:8 | A | Assignment of essentially Enum Type value to an object of essentially Signed type. | -| test.c:149:23:149:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Signed type. | -| test.c:154:8:154:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | -| test.c:155:8:155:8 | A | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | -| test.c:174:8:174:8 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | -| test.c:175:8:175:8 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | -| test.c:176:8:176:8 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | -| test.c:177:8:177:8 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | -| test.c:180:8:180:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | -| test.c:182:8:182:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | -| test.c:183:8:183:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | -| test.c:184:8:184:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | -| test.c:187:8:187:8 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | -| test.c:188:8:188:8 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | -| test.c:190:8:190:8 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:191:8:191:8 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | -| test.c:194:8:194:8 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | -| test.c:195:8:195:8 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | -| test.c:196:8:196:8 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | -| test.c:198:8:198:8 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | -| test.c:201:8:201:8 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | -| test.c:202:8:202:8 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | -| test.c:203:8:203:8 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | -| test.c:204:8:204:8 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | -| test.c:220:12:220:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | -| test.c:222:12:222:12 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | -| test.c:224:12:224:12 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | -| test.c:226:12:226:12 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | -| test.c:239:12:239:12 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | -| test.c:243:12:243:12 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | -| test.c:245:12:245:12 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | -| test.c:247:12:247:12 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | -| test.c:260:12:260:12 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | -| test.c:262:12:262:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | -| test.c:266:12:266:12 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | -| test.c:268:12:268:12 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | -| test.c:281:12:281:12 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | -| test.c:283:12:283:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | -| test.c:285:12:285:12 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:289:12:289:12 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | -| test.c:302:12:302:12 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | -| test.c:304:12:304:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | -| test.c:306:12:306:12 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | -| test.c:308:12:308:12 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | -| test.c:332:10:332:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | -| test.c:333:10:333:10 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | -| test.c:334:10:334:10 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | -| test.c:335:10:335:10 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | -| test.c:337:11:337:11 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | -| test.c:339:11:339:11 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | -| test.c:340:11:340:11 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | -| test.c:341:11:341:11 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | -| test.c:343:10:343:10 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | -| test.c:344:10:344:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | -| test.c:346:10:346:10 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | -| test.c:347:10:347:10 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | -| test.c:349:10:349:10 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | -| test.c:350:10:350:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | -| test.c:351:10:351:10 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | -| test.c:353:10:353:10 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | -| test.c:355:10:355:10 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | -| test.c:356:10:356:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | -| test.c:357:10:357:10 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | -| test.c:358:10:358:10 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:13:7:13:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:14:7:14:7 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:15:7:15:7 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:16:7:16:7 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:17:7:17:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Boolean type. | +| test.c:19:8:19:8 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:21:8:21:8 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:22:8:22:8 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:23:8:23:8 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:24:8:24:9 | cf | Assignment of essentially Complex Floating type value to an object of essentially Enum Type. | +| test.c:26:7:26:7 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:27:7:27:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:29:7:29:7 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:30:7:30:7 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:31:7:31:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Signed type. | +| test.c:33:7:33:7 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:34:7:34:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:35:7:35:7 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:37:7:37:7 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:38:7:38:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Unsigned type. | +| test.c:40:7:40:7 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:41:7:41:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:42:7:42:7 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:43:7:43:7 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:45:7:45:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Floating type. | +| test.c:47:8:47:8 | b | Assignment of essentially Boolean type value to an object of essentially Complex Floating type. | +| test.c:48:8:48:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Complex Floating type. | +| test.c:49:8:49:8 | s | Assignment of essentially Signed type value to an object of essentially Complex Floating type. | +| test.c:50:8:50:8 | u | Assignment of essentially Unsigned type value to an object of essentially Complex Floating type. | +| test.c:64:14:64:15 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:65:14:65:14 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:66:14:66:14 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:67:14:67:14 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:68:15:68:16 | cf | Assignment of essentially Complex Floating type value to an object of essentially Boolean type. | +| test.c:70:17:70:17 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:72:17:72:17 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:73:17:73:17 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:74:17:74:17 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:75:18:75:19 | cf | Assignment of essentially Complex Floating type value to an object of essentially Enum Type. | +| test.c:77:19:77:19 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:78:19:78:20 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:80:19:80:19 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:81:19:81:19 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:82:20:82:21 | cf | Assignment of essentially Complex Floating type value to an object of essentially Signed type. | +| test.c:84:21:84:21 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:85:21:85:22 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:86:21:86:21 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:88:21:88:21 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:89:22:89:23 | cf | Assignment of essentially Complex Floating type value to an object of essentially Unsigned type. | +| test.c:91:14:91:14 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:92:14:92:15 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:93:14:93:14 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:94:14:94:14 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:96:15:96:16 | cf | Assignment of essentially Complex Floating type value to an object of essentially Floating type. | +| test.c:98:24:98:24 | b | Assignment of essentially Boolean type value to an object of essentially Complex Floating type. | +| test.c:99:24:99:25 | e1 | Assignment of essentially Enum Type value to an object of essentially Complex Floating type. | +| test.c:100:24:100:24 | s | Assignment of essentially Signed type value to an object of essentially Complex Floating type. | +| test.c:101:24:101:24 | u | Assignment of essentially Unsigned type value to an object of essentially Complex Floating type. | +| test.c:107:7:107:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:108:7:108:7 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:109:7:109:7 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:110:7:110:7 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:111:7:111:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Boolean type. | +| test.c:114:7:114:7 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:116:7:116:7 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:117:7:117:7 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:118:7:118:7 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:119:7:119:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Enum Type. | +| test.c:122:7:122:7 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:123:7:123:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:125:7:125:7 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:126:7:126:7 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:127:7:127:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Signed type. | +| test.c:130:7:130:7 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:131:7:131:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:132:7:132:7 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:134:7:134:7 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:135:7:135:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Unsigned type. | +| test.c:138:7:138:7 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:139:7:139:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:140:7:140:7 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:141:7:141:7 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:143:7:143:8 | cf | Assignment of essentially Complex Floating type value to an object of essentially Floating type. | +| test.c:146:7:146:7 | b | Assignment of essentially Boolean type value to an object of essentially Complex Floating type. | +| test.c:147:7:147:8 | e1 | Assignment of essentially Enum Type value to an object of essentially Complex Floating type. | +| test.c:148:7:148:7 | s | Assignment of essentially Signed type value to an object of essentially Complex Floating type. | +| test.c:149:7:149:7 | u | Assignment of essentially Unsigned type value to an object of essentially Complex Floating type. | +| test.c:158:7:158:8 | - ... | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:159:7:159:16 | 4294967296 | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:171:8:171:8 | A | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:172:8:172:10 | 100 | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:173:23:173:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:178:8:178:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:180:8:180:10 | 100 | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:181:23:181:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:186:8:186:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:187:8:187:8 | A | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:189:23:189:25 | 200 | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:194:8:194:11 | 1 | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:195:8:195:8 | A | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:216:8:216:8 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:217:8:217:8 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:218:8:218:8 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:219:8:219:8 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:220:8:220:8 | b | Assignment of essentially Boolean type value to an object of essentially Complex Floating type. | +| test.c:223:8:223:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:225:8:225:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:226:8:226:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:227:8:227:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:228:8:228:9 | e1 | Assignment of essentially Enum Type value to an object of essentially Complex Floating type. | +| test.c:231:8:231:8 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:232:8:232:8 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:234:8:234:8 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:235:8:235:8 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:236:8:236:8 | s | Assignment of essentially Signed type value to an object of essentially Complex Floating type. | +| test.c:239:8:239:8 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:240:8:240:8 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:241:8:241:8 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:243:8:243:8 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:244:8:244:8 | u | Assignment of essentially Unsigned type value to an object of essentially Complex Floating type. | +| test.c:247:8:247:8 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:248:8:248:8 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:249:8:249:8 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:250:8:250:8 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:255:8:255:9 | cf | Assignment of essentially Complex Floating type value to an object of essentially Boolean type. | +| test.c:256:8:256:9 | cf | Assignment of essentially Complex Floating type value to an object of essentially Enum Type. | +| test.c:257:8:257:9 | cf | Assignment of essentially Complex Floating type value to an object of essentially Signed type. | +| test.c:258:8:258:9 | cf | Assignment of essentially Complex Floating type value to an object of essentially Unsigned type. | +| test.c:259:8:259:9 | cf | Assignment of essentially Complex Floating type value to an object of essentially Floating type. | +| test.c:275:12:275:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:277:12:277:12 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:279:12:279:12 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:281:12:281:12 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:283:12:283:13 | cf | Assignment of essentially Complex Floating type value to an object of essentially Boolean type. | +| test.c:297:12:297:12 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:301:12:301:12 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:303:12:303:12 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:305:12:305:12 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:307:12:307:13 | cf | Assignment of essentially Complex Floating type value to an object of essentially Enum Type. | +| test.c:321:12:321:12 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:323:12:323:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:327:12:327:12 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:329:12:329:12 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:331:12:331:13 | cf | Assignment of essentially Complex Floating type value to an object of essentially Signed type. | +| test.c:345:12:345:12 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:347:12:347:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:349:12:349:12 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:353:12:353:12 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:355:12:355:13 | cf | Assignment of essentially Complex Floating type value to an object of essentially Unsigned type. | +| test.c:369:12:369:12 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:371:12:371:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:373:12:373:12 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:375:12:375:12 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:379:12:379:13 | cf | Assignment of essentially Complex Floating type value to an object of essentially Floating type. | +| test.c:393:12:393:12 | b | Assignment of essentially Boolean type value to an object of essentially Complex Floating type. | +| test.c:395:12:395:13 | e1 | Assignment of essentially Enum Type value to an object of essentially Complex Floating type. | +| test.c:397:12:397:12 | s | Assignment of essentially Signed type value to an object of essentially Complex Floating type. | +| test.c:399:12:399:12 | u | Assignment of essentially Unsigned type value to an object of essentially Complex Floating type. | +| test.c:427:10:427:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Boolean type. | +| test.c:428:10:428:10 | s | Assignment of essentially Signed type value to an object of essentially Boolean type. | +| test.c:429:10:429:10 | u | Assignment of essentially Unsigned type value to an object of essentially Boolean type. | +| test.c:430:10:430:10 | f | Assignment of essentially Floating type value to an object of essentially Boolean type. | +| test.c:431:10:431:11 | cf | Assignment of essentially Complex Floating type value to an object of essentially Boolean type. | +| test.c:433:11:433:11 | b | Assignment of essentially Boolean type value to an object of essentially Enum Type. | +| test.c:435:11:435:11 | s | Assignment of essentially Signed type value to an object of essentially Enum Type. | +| test.c:436:11:436:11 | u | Assignment of essentially Unsigned type value to an object of essentially Enum Type. | +| test.c:437:11:437:11 | f | Assignment of essentially Floating type value to an object of essentially Enum Type. | +| test.c:438:11:438:12 | cf | Assignment of essentially Complex Floating type value to an object of essentially Enum Type. | +| test.c:440:10:440:10 | b | Assignment of essentially Boolean type value to an object of essentially Signed type. | +| test.c:441:10:441:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Signed type. | +| test.c:443:10:443:10 | u | Assignment of essentially Unsigned type value to an object of essentially Signed type. | +| test.c:444:10:444:10 | f | Assignment of essentially Floating type value to an object of essentially Signed type. | +| test.c:445:10:445:11 | cf | Assignment of essentially Complex Floating type value to an object of essentially Signed type. | +| test.c:447:10:447:10 | b | Assignment of essentially Boolean type value to an object of essentially Unsigned type. | +| test.c:448:10:448:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Unsigned type. | +| test.c:449:10:449:10 | s | Assignment of essentially Signed type value to an object of essentially Unsigned type. | +| test.c:451:10:451:10 | f | Assignment of essentially Floating type value to an object of essentially Unsigned type. | +| test.c:452:10:452:11 | cf | Assignment of essentially Complex Floating type value to an object of essentially Unsigned type. | +| test.c:454:10:454:10 | b | Assignment of essentially Boolean type value to an object of essentially Floating type. | +| test.c:455:10:455:11 | e1 | Assignment of essentially Enum Type value to an object of essentially Floating type. | +| test.c:456:10:456:10 | s | Assignment of essentially Signed type value to an object of essentially Floating type. | +| test.c:457:10:457:10 | u | Assignment of essentially Unsigned type value to an object of essentially Floating type. | +| test.c:459:10:459:11 | cf | Assignment of essentially Complex Floating type value to an object of essentially Floating type. | +| test.c:461:11:461:11 | b | Assignment of essentially Boolean type value to an object of essentially Complex Floating type. | +| test.c:462:11:462:12 | e1 | Assignment of essentially Enum Type value to an object of essentially Complex Floating type. | +| test.c:463:11:463:11 | s | Assignment of essentially Signed type value to an object of essentially Complex Floating type. | +| test.c:464:11:464:11 | u | Assignment of essentially Unsigned type value to an object of essentially Complex Floating type. | +| test.c:473:26:473:28 | f64 | Assignment of essentially Floating type value to an object of essentially Complex Floating type. | diff --git a/c/misra/test/rules/RULE-10-3/test.c b/c/misra/test/rules/RULE-10-3/test.c index 30ab2985ae..c208890490 100644 --- a/c/misra/test/rules/RULE-10-3/test.c +++ b/c/misra/test/rules/RULE-10-3/test.c @@ -1,3 +1,4 @@ +#include #include void testAssignment() { @@ -6,36 +7,49 @@ void testAssignment() { signed int s = 100; // COMPLIANT unsigned int u = 100; // COMPLIANT - by exception 1 float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT b = false; // COMPLIANT b = e1; // NON_COMPLIANT b = s; // NON_COMPLIANT b = u; // NON_COMPLIANT b = f; // NON_COMPLIANT + b = cf; // NON_COMPLIANT e1 = b; // NON_COMPLIANT e1 = e1; // COMPLIANT e1 = s; // NON_COMPLIANT e1 = u; // NON_COMPLIANT e1 = f; // NON_COMPLIANT + e1 = cf; // NON_COMPLIANT s = b; // NON_COMPLIANT s = e1; // NON_COMPLIANT s = s; // COMPLIANT s = u; // NON_COMPLIANT s = f; // NON_COMPLIANT + s = cf; // NON_COMPLIANT u = b; // NON_COMPLIANT u = e1; // NON_COMPLIANT u = s; // NON_COMPLIANT u = u; // COMPLIANT u = f; // NON_COMPLIANT + u = cf; // NON_COMPLIANT f = b; // NON_COMPLIANT f = e1; // NON_COMPLIANT f = s; // NON_COMPLIANT f = u; // NON_COMPLIANT f = f; // COMPLIANT + f = cf; // NON-COMPLIANT + + cf = b; // NON_COMPLIANT + cf = e1; // NON_COMPLIANT + cf = s; // NON_COMPLIANT + cf = u; // NON_COMPLIANT + cf = f; // COMPLIANT + cf = cf; // COMPLIANT } void testInitializers() { @@ -44,71 +58,97 @@ void testInitializers() { signed int s = 100; // COMPLIANT unsigned int u = 100; // COMPLIANT - by exception 1 float f = 10.0f; // COMPLIANT - - _Bool bb = b; // COMPLIANT - _Bool be = e1; // NON_COMPLIANT - _Bool bs = s; // NON_COMPLIANT - _Bool bu = u; // NON_COMPLIANT - _Bool bf = f; // NON_COMPLIANT - - enum E1 e1b = b; // NON_COMPLIANT - enum E1 e1e = e1; // COMPLIANT - enum E1 e1s = s; // NON_COMPLIANT - enum E1 e1u = u; // NON_COMPLIANT - enum E1 e1f = f; // NON_COMPLIANT - - signed int sb = b; // NON_COMPLIANT - signed int se = e1; // NON_COMPLIANT - signed int ss = s; // COMPLIANT - signed int su = u; // NON_COMPLIANT - signed int sf = f; // NON_COMPLIANT - - unsigned int ub = b; // NON_COMPLIANT - unsigned int ue = e1; // NON_COMPLIANT - unsigned int us = s; // NON_COMPLIANT - unsigned int uu = u; // COMPLIANT - unsigned int uf = f; // NON_COMPLIANT - - float fb = b; // NON_COMPLIANT - float fe = e1; // NON_COMPLIANT - float fs = s; // NON_COMPLIANT - float fu = u; // NON_COMPLIANT - float ff = f; // COMPLIANT - - _Bool ba[5] = { + float _Complex cf = 10.0f; // COMPLIANT + + _Bool bb = b; // COMPLIANT + _Bool be = e1; // NON_COMPLIANT + _Bool bs = s; // NON_COMPLIANT + _Bool bu = u; // NON_COMPLIANT + _Bool bf = f; // NON_COMPLIANT + _Bool bcf = cf; // NON_COMPLIANT + + enum E1 e1b = b; // NON_COMPLIANT + enum E1 e1e = e1; // COMPLIANT + enum E1 e1s = s; // NON_COMPLIANT + enum E1 e1u = u; // NON_COMPLIANT + enum E1 e1f = f; // NON_COMPLIANT + enum E1 e1cf = cf; // NON_COMPLIANT + + signed int sb = b; // NON_COMPLIANT + signed int se = e1; // NON_COMPLIANT + signed int ss = s; // COMPLIANT + signed int su = u; // NON_COMPLIANT + signed int sf = f; // NON_COMPLIANT + signed int scf = cf; // NON_COMPLIANT + + unsigned int ub = b; // NON_COMPLIANT + unsigned int ue = e1; // NON_COMPLIANT + unsigned int us = s; // NON_COMPLIANT + unsigned int uu = u; // COMPLIANT + unsigned int uf = f; // NON_COMPLIANT + unsigned int ucf = cf; // NON_COMPLIANT + + float fb = b; // NON_COMPLIANT + float fe = e1; // NON_COMPLIANT + float fs = s; // NON_COMPLIANT + float fu = u; // NON_COMPLIANT + float ff = f; // COMPLIANT + float fcf = cf; // NON-COMPLIANT + + float _Complex cfb = b; // NON_COMPLIANT + float _Complex cfe = e1; // NON_COMPLIANT + float _Complex cfs = s; // NON_COMPLIANT + float _Complex cfu = u; // NON_COMPLIANT + float _Complex cff = f; // COMPLIANT + float _Complex cfcf = cf; // COMPLIANT + + _Bool ba[6] = { b, // COMPLIANT e1, // NON_COMPLIANT s, // NON_COMPLIANT u, // NON_COMPLIANT - f // NON_COMPLIANT + f, // NON_COMPLIANT + cf // NON_COMPLIANT }; - enum E1 ea[5] = { + enum E1 ea[6] = { b, // NON_COMPLIANT e1, // COMPLIANT s, // NON_COMPLIANT u, // NON_COMPLIANT - f // NON_COMPLIANT + f, // NON_COMPLIANT + cf // NON_COMPLIANT }; - signed int sa[5] = { + signed int sa[6] = { b, // NON_COMPLIANT e1, // NON_COMPLIANT s, // COMPLIANT u, // NON_COMPLIANT - f // NON_COMPLIANT + f, // NON_COMPLIANT + cf // NON_COMPLIANT }; - unsigned int ua[5] = { + unsigned int ua[6] = { b, // NON_COMPLIANT e1, // NON_COMPLIANT s, // NON_COMPLIANT u, // COMPLIANT - f // NON_COMPLIANT + f, // NON_COMPLIANT + cf // NON_COMPLIANT + }; + float fa[6] = { + b, // NON_COMPLIANT + e1, // NON_COMPLIANT + s, // NON_COMPLIANT + u, // NON_COMPLIANT + f, // COMPLIANT + cf // NON_COMPLIANT }; - float fa[5] = { + float _Complex cfa[6] = { b, // NON_COMPLIANT e1, // NON_COMPLIANT s, // NON_COMPLIANT u, // NON_COMPLIANT - f // COMPLIANT + f, // COMPLIANT + cf // COMPLIANT }; } @@ -161,19 +201,22 @@ void testSwitchCase() { enum EG { EGA, EGB, EGC }; -void func(_Bool b, enum EG eg, signed int i, unsigned int u, float f); +void func(_Bool b, enum EG eg, signed int i, unsigned int u, float f, + float _Complex cf); void testFunctionCall() { - _Bool b = true; // COMPLIANT - enum EG e1 = EGA; // COMPLIANT - signed int s = 100; // COMPLIANT - unsigned int u = 100; // COMPLIANT - by exception 1 - float f = 10.0f; // COMPLIANT + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT func(b, // COMPLIANT b, // NON_COMPLIANT b, // NON_COMPLIANT b, // NON_COMPLIANT + b, // NON_COMPLIANT b // NON_COMPLIANT ); @@ -181,6 +224,7 @@ void testFunctionCall() { e1, // COMPLIANT e1, // NON_COMPLIANT e1, // NON_COMPLIANT + e1, // NON_COMPLIANT e1 // NON_COMPLIANT ); @@ -188,6 +232,7 @@ void testFunctionCall() { s, // NON_COMPLIANT s, // COMPLIANT s, // NON_COMPLIANT + s, // NON_COMPLIANT s // NON_COMPLIANT ); @@ -195,6 +240,7 @@ void testFunctionCall() { u, // NON_COMPLIANT u, // NON_COMPLIANT u, // COMPLIANT + u, // NON_COMPLIANT u // NON_COMPLIANT ); @@ -202,16 +248,25 @@ void testFunctionCall() { f, // NON_COMPLIANT f, // NON_COMPLIANT f, // NON_COMPLIANT + f, // COMPLIANT f // COMPLIANT ); + + func(cf, // NON_COMPLIANT + cf, // NON_COMPLIANT + cf, // NON_COMPLIANT + cf, // NON_COMPLIANT + cf, // NON_COMPLIANT + cf); } _Bool testBoolFunctionReturn(int x) { - _Bool b = true; // COMPLIANT - enum EG e1 = EGA; // COMPLIANT - signed int s = 100; // COMPLIANT - unsigned int u = 100; // COMPLIANT - by exception 1 - float f = 10.0f; // COMPLIANT + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT switch (x) { case 0: @@ -222,17 +277,20 @@ _Bool testBoolFunctionReturn(int x) { return s; // NON_COMPLIANT case 3: return u; // NON_COMPLIANT - default: + case 4: return f; // NON_COMPLIANT + default: + return cf; // NON_COMPLIANT } } enum EG testEnumFunctionReturn(int x) { - _Bool b = true; // COMPLIANT - enum EG e1 = EGA; // COMPLIANT - signed int s = 100; // COMPLIANT - unsigned int u = 100; // COMPLIANT - by exception 1 - float f = 10.0f; // COMPLIANT + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT switch (x) { case 0: @@ -243,17 +301,20 @@ enum EG testEnumFunctionReturn(int x) { return s; // NON_COMPLIANT case 3: return u; // NON_COMPLIANT - default: + case 4: return f; // NON_COMPLIANT + default: + return cf; // NON_COMPLIANT } } signed int testSignedIntFunctionReturn(int x) { - _Bool b = true; // COMPLIANT - enum EG e1 = EGA; // COMPLIANT - signed int s = 100; // COMPLIANT - unsigned int u = 100; // COMPLIANT - by exception 1 - float f = 10.0f; // COMPLIANT + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT switch (x) { case 0: @@ -264,17 +325,20 @@ signed int testSignedIntFunctionReturn(int x) { return s; // COMPLIANT case 3: return u; // NON_COMPLIANT - default: + case 4: return f; // NON_COMPLIANT + default: + return cf; // NON_COMPLIANT } } unsigned int testUnsignedIntFunctionReturn(int x) { - _Bool b = true; // COMPLIANT - enum EG e1 = EGA; // COMPLIANT - signed int s = 100; // COMPLIANT - unsigned int u = 100; // COMPLIANT - by exception 1 - float f = 10.0f; // COMPLIANT + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT switch (x) { case 0: @@ -285,17 +349,20 @@ unsigned int testUnsignedIntFunctionReturn(int x) { return s; // NON_COMPLIANT case 3: return u; // COMPLIANT - default: + case 4: return f; // NON_COMPLIANT + default: + return cf; // NON_COMPLIANT } } float testFloatFunctionReturn(int x) { - _Bool b = true; // COMPLIANT - enum EG e1 = EGA; // COMPLIANT - signed int s = 100; // COMPLIANT - unsigned int u = 100; // COMPLIANT - by exception 1 - float f = 10.0f; // COMPLIANT + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT switch (x) { case 0: @@ -306,8 +373,34 @@ float testFloatFunctionReturn(int x) { return s; // NON_COMPLIANT case 3: return u; // NON_COMPLIANT + case 4: + return f; // COMPLIANT default: + return cf; // NON_COMPLIANT + } +} + +float _Complex testComplexFunctionReturn(int x) { + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT + + switch (x) { + case 0: + return b; // NON_COMPLIANT + case 1: + return e1; // NON_COMPLIANT + case 2: + return s; // NON_COMPLIANT + case 3: + return u; // NON_COMPLIANT + case 4: return f; // COMPLIANT + default: + return cf; // COMPLIANT } } @@ -317,14 +410,16 @@ struct S1 { signed int s; unsigned int u; float f; + float _Complex cf; }; void testStructAssignment() { - _Bool b = true; // COMPLIANT - enum EG e1 = EGA; // COMPLIANT - signed int s = 100; // COMPLIANT - unsigned int u = 100; // COMPLIANT - by exception 1 - float f = 10.0f; // COMPLIANT + _Bool b = true; // COMPLIANT + enum EG e1 = EGA; // COMPLIANT + signed int s = 100; // COMPLIANT + unsigned int u = 100; // COMPLIANT - by exception 1 + float f = 10.0f; // COMPLIANT + float _Complex cf = 10.0f; // COMPLIANT struct S1 s1; @@ -333,28 +428,54 @@ void testStructAssignment() { s1.b = s; // NON_COMPLIANT s1.b = u; // NON_COMPLIANT s1.b = f; // NON_COMPLIANT + s1.b = cf; // NON_COMPLIANT s1.e1 = b; // NON_COMPLIANT s1.e1 = e1; // COMPLIANT s1.e1 = s; // NON_COMPLIANT s1.e1 = u; // NON_COMPLIANT s1.e1 = f; // NON_COMPLIANT + s1.e1 = cf; // NON_COMPLIANT s1.s = b; // NON_COMPLIANT s1.s = e1; // NON_COMPLIANT s1.s = s; // COMPLIANT s1.s = u; // NON_COMPLIANT s1.s = f; // NON_COMPLIANT + s1.s = cf; // NON_COMPLIANT s1.u = b; // NON_COMPLIANT s1.u = e1; // NON_COMPLIANT s1.u = s; // NON_COMPLIANT s1.u = u; // COMPLIANT s1.u = f; // NON_COMPLIANT + s1.u = cf; // NON_COMPLIANT s1.f = b; // NON_COMPLIANT s1.f = e1; // NON_COMPLIANT s1.f = s; // NON_COMPLIANT s1.f = u; // NON_COMPLIANT s1.f = f; // COMPLIANT + s1.f = cf; // NON_COMPLIANT + + s1.cf = b; // NON_COMPLIANT + s1.cf = e1; // NON_COMPLIANT + s1.cf = s; // NON_COMPLIANT + s1.cf = u; // NON_COMPLIANT + s1.cf = f; // COMPLIANT + s1.cf = cf; // COMPLIANT +} + +void testException4() { + float f32 = 10.0f; // COMPLIANT + double f64 = 10.0f; // COMPLIANT + float _Complex cf32a = f32; // COMPLIANT + float _Complex cf32b = f64; // NON_COMPLIANT + double _Complex cf64a = f32; // COMPLIANT + double _Complex cf64b = f64; // COMPLIANT + + double _Complex f64byparts_a = 10.0i; // COMPLIANT + double _Complex f64byparts_b = 10.0 * I; // COMPLIANT + double _Complex f64byparts_c = 10.0f + 10.0i; // COMPLIANT + double _Complex f64byparts_d = 10.0f + 10.0f * I; // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.expected b/c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.expected index 333c3ad581..c85f2a447e 100644 --- a/c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.expected +++ b/c/misra/test/rules/RULE-10-4/OperandsWithMismatchedEssentialTypeCategory.expected @@ -1,10 +1,13 @@ -| test.c:14:3:14:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Unsigned type, right operand: essentially Signed type). | -| test.c:15:3:15:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Unsigned type). | -| test.c:16:3:16:10 | ... += ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Unsigned type). | -| test.c:17:3:17:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Floating type, right operand: essentially Signed type). | -| test.c:18:3:18:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Floating type). | -| test.c:19:3:19:10 | ... += ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Floating type). | -| test.c:27:3:27:9 | ... - ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Character type). | -| test.c:28:3:28:10 | ... -= ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Character type). | -| test.c:34:3:34:11 | ... < ... | The operands of this operator with usual arithmetic conversions have mismatched essentially Enum types (left operand: E1, right operand: E2). | -| test.c:35:3:35:7 | ... < ... | The operands of this operator with usual arithmetic conversions have mismatched essentially Enum types (left operand: E1, right operand: E2). | +| test.c:15:3:15:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Unsigned type, right operand: essentially Signed type). | +| test.c:16:3:16:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Unsigned type). | +| test.c:17:3:17:10 | ... += ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Unsigned type). | +| test.c:18:3:18:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Floating type, right operand: essentially Signed type). | +| test.c:19:3:19:9 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Floating type). | +| test.c:20:3:20:10 | ... += ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Floating type). | +| test.c:21:3:21:10 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Complex Floating type, right operand: essentially Signed type). | +| test.c:22:3:22:10 | ... + ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Complex Floating type). | +| test.c:23:3:23:11 | ... += ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Complex Floating type). | +| test.c:31:3:31:9 | ... - ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Character type). | +| test.c:32:3:32:10 | ... -= ... | The operands of this operator with usual arithmetic conversions have mismatched essential types (left operand: essentially Signed type, right operand: essentially Character type). | +| test.c:43:3:43:11 | ... < ... | The operands of this operator with usual arithmetic conversions have mismatched essentially Enum types (left operand: E1, right operand: E2). | +| test.c:44:3:44:7 | ... < ... | The operands of this operator with usual arithmetic conversions have mismatched essentially Enum types (left operand: E1, right operand: E2). | diff --git a/c/misra/test/rules/RULE-10-4/test.c b/c/misra/test/rules/RULE-10-4/test.c index cbcb7191f6..223aacbdad 100644 --- a/c/misra/test/rules/RULE-10-4/test.c +++ b/c/misra/test/rules/RULE-10-4/test.c @@ -3,6 +3,7 @@ void testOps() { signed long long s64 = 100; unsigned int u = 100; float f = 10.0f; + float _Complex cf = 10.0f; char c = 'A'; s32 + s32; // COMPLIANT @@ -17,6 +18,9 @@ void testOps() { f + s32; // NON_COMPLIANT s32 + f; // NON_COMPLIANT s32 += f; // NON_COMPLIANT + cf + s32; // NON_COMPLIANT + s32 + cf; // NON_COMPLIANT + s32 += cf; // NON_COMPLIANT c + s32; // COMPLIANT - by exception c += s32; // COMPLIANT - by exception @@ -27,6 +31,11 @@ void testOps() { s32 - c; // NON_COMPLIANT s32 -= c; // NON_COMPLIANT + cf + f; // COMPLIANT - by exception + f + cf; // COMPLIANT - by exception + cf *f; // COMPLIANT - by exception + f *cf; // COMPLIANT - by exception + enum E1 { A, B, C } e1a; enum E2 { D, E, F } e2a; e1a < e1a; // COMPLIANT diff --git a/c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.expected b/c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.expected index 731ad9f312..2f4c38eb95 100644 --- a/c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.expected +++ b/c/misra/test/rules/RULE-10-5/InappropriateEssentialTypeCast.expected @@ -1,20 +1,25 @@ -| test.c:9:3:9:9 | (char)... | Incompatible cast from essentially Boolean type to essentially Character type. | -| test.c:10:3:10:13 | (E1)... | Incompatible cast from essentially Boolean type to essentially Enum Type. | -| test.c:11:3:11:15 | (signed int)... | Incompatible cast from essentially Boolean type to essentially Signed type. | -| test.c:12:3:12:17 | (unsigned int)... | Incompatible cast from essentially Boolean type to essentially Unsigned type. | -| test.c:13:3:13:10 | (float)... | Incompatible cast from essentially Boolean type to essentially Floating type. | -| test.c:16:3:16:11 | (bool)... | Incompatible cast from essentially Character type to essentially Boolean type. | -| test.c:18:3:18:13 | (E1)... | Incompatible cast from essentially Character type to essentially Enum Type. | -| test.c:21:3:21:10 | (float)... | Incompatible cast from essentially Character type to essentially Floating type. | -| test.c:24:3:24:11 | (bool)... | Incompatible cast from essentially Enum Type to essentially Boolean type. | -| test.c:26:3:26:13 | (E1)... | Incompatible cast from E2 to E1. | -| test.c:33:3:33:11 | (bool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | -| test.c:35:3:35:13 | (E1)... | Incompatible cast from essentially Signed type to essentially Enum Type. | -| test.c:41:3:41:11 | (bool)... | Incompatible cast from essentially Unsigned type to essentially Boolean type. | -| test.c:43:3:43:13 | (E1)... | Incompatible cast from essentially Unsigned type to essentially Enum Type. | -| test.c:49:3:49:11 | (bool)... | Incompatible cast from essentially Floating type to essentially Boolean type. | -| test.c:50:3:50:9 | (char)... | Incompatible cast from essentially Floating type to essentially Character type. | -| test.c:51:3:51:13 | (E1)... | Incompatible cast from essentially Floating type to essentially Enum Type. | -| test.c:68:3:68:10 | (bool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | -| test.c:72:3:72:16 | (MyBool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | -| test.c:76:3:76:12 | (boolean)... | Incompatible cast from essentially Signed type to essentially Boolean type. | +| test.c:10:3:10:9 | (char)... | Incompatible cast from essentially Boolean type to essentially Character type. | +| test.c:11:3:11:13 | (E1)... | Incompatible cast from essentially Boolean type to essentially Enum Type. | +| test.c:12:3:12:15 | (signed int)... | Incompatible cast from essentially Boolean type to essentially Signed type. | +| test.c:13:3:13:17 | (unsigned int)... | Incompatible cast from essentially Boolean type to essentially Unsigned type. | +| test.c:14:3:14:10 | (float)... | Incompatible cast from essentially Boolean type to essentially Floating type. | +| test.c:15:3:15:20 | (_Complex float)... | Incompatible cast from essentially Boolean type to essentially Complex Floating type. | +| test.c:18:3:18:11 | (bool)... | Incompatible cast from essentially Character type to essentially Boolean type. | +| test.c:20:3:20:13 | (E1)... | Incompatible cast from essentially Character type to essentially Enum Type. | +| test.c:23:3:23:10 | (float)... | Incompatible cast from essentially Character type to essentially Floating type. | +| test.c:24:3:24:20 | (_Complex float)... | Incompatible cast from essentially Character type to essentially Complex Floating type. | +| test.c:27:3:27:11 | (bool)... | Incompatible cast from essentially Enum Type to essentially Boolean type. | +| test.c:29:3:29:13 | (E1)... | Incompatible cast from E2 to E1. | +| test.c:37:3:37:11 | (bool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | +| test.c:39:3:39:13 | (E1)... | Incompatible cast from essentially Signed type to essentially Enum Type. | +| test.c:46:3:46:11 | (bool)... | Incompatible cast from essentially Unsigned type to essentially Boolean type. | +| test.c:48:3:48:13 | (E1)... | Incompatible cast from essentially Unsigned type to essentially Enum Type. | +| test.c:55:3:55:11 | (bool)... | Incompatible cast from essentially Floating type to essentially Boolean type. | +| test.c:56:3:56:9 | (char)... | Incompatible cast from essentially Floating type to essentially Character type. | +| test.c:57:3:57:13 | (E1)... | Incompatible cast from essentially Floating type to essentially Enum Type. | +| test.c:64:3:64:12 | (bool)... | Incompatible cast from essentially Complex Floating type to essentially Boolean type. | +| test.c:65:3:65:10 | (char)... | Incompatible cast from essentially Complex Floating type to essentially Character type. | +| test.c:66:3:66:14 | (E1)... | Incompatible cast from essentially Complex Floating type to essentially Enum Type. | +| test.c:84:3:84:10 | (bool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | +| test.c:88:3:88:16 | (MyBool)... | Incompatible cast from essentially Signed type to essentially Boolean type. | +| test.c:92:3:92:12 | (boolean)... | Incompatible cast from essentially Signed type to essentially Boolean type. | diff --git a/c/misra/test/rules/RULE-10-5/test.c b/c/misra/test/rules/RULE-10-5/test.c index dbc5939f0f..d7a6d878f1 100644 --- a/c/misra/test/rules/RULE-10-5/test.c +++ b/c/misra/test/rules/RULE-10-5/test.c @@ -1,3 +1,4 @@ +#include #include void testIncompatibleCasts() { @@ -5,53 +6,68 @@ void testIncompatibleCasts() { _Bool b = true; - (_Bool) b; // COMPLIANT - (char)b; // NON_COMPLIANT - (enum E1) b; // NON_COMPLIANT - (signed int)b; // NON_COMPLIANT - (unsigned int)b; // NON_COMPLIANT - (float)b; // NON_COMPLIANT + (_Bool) b; // COMPLIANT + (char)b; // NON_COMPLIANT + (enum E1) b; // NON_COMPLIANT + (signed int)b; // NON_COMPLIANT + (unsigned int)b; // NON_COMPLIANT + (float)b; // NON_COMPLIANT + (float _Complex) b; // NON_COMPLIANT char c = 100; - (_Bool) c; // NON_COMPLIANT - (char)c; // COMPLIANT - (enum E1) c; // NON_COMPLIANT - (signed int)c; // COMPLIANT - (unsigned int)c; // COMPLIANT - (float)c; // NON_COMPLIANT + (_Bool) c; // NON_COMPLIANT + (char)c; // COMPLIANT + (enum E1) c; // NON_COMPLIANT + (signed int)c; // COMPLIANT + (unsigned int)c; // COMPLIANT + (float)c; // NON_COMPLIANT + (float _Complex) c; // NON_COMPLIANT enum E2 { C, D } e = C; - (_Bool) e; // NON_COMPLIANT - (char)e; // COMPLIANT - (enum E1) e; // NON_COMPLIANT - (enum E2) e; // COMPLIANT - (signed int)e; // COMPLIANT - (unsigned int)e; // COMPLIANT - (float)e; // COMPLIANT + (_Bool) e; // NON_COMPLIANT + (char)e; // COMPLIANT + (enum E1) e; // NON_COMPLIANT + (enum E2) e; // COMPLIANT + (signed int)e; // COMPLIANT + (unsigned int)e; // COMPLIANT + (float)e; // COMPLIANT + (float _Complex) e; // COMPLIANT signed int i = 100; - (_Bool) i; // NON_COMPLIANT - (char)i; // COMPLIANT - (enum E1) i; // NON_COMPLIANT - (signed int)i; // COMPLIANT - (unsigned int)i; // COMPLIANT - (float)i; // COMPLIANT + (_Bool) i; // NON_COMPLIANT + (char)i; // COMPLIANT + (enum E1) i; // NON_COMPLIANT + (signed int)i; // COMPLIANT + (unsigned int)i; // COMPLIANT + (float)i; // COMPLIANT + (float _Complex) i; // COMPLIANT unsigned int u = 100; - (_Bool) u; // NON_COMPLIANT - (char)u; // COMPLIANT - (enum E1) u; // NON_COMPLIANT - (signed int)u; // COMPLIANT - (unsigned int)u; // COMPLIANT - (float)u; // COMPLIANT + (_Bool) u; // NON_COMPLIANT + (char)u; // COMPLIANT + (enum E1) u; // NON_COMPLIANT + (signed int)u; // COMPLIANT + (unsigned int)u; // COMPLIANT + (float)u; // COMPLIANT + (float _Complex) u; // COMPLIANT float f = 100.0; - (_Bool) f; // NON_COMPLIANT - (char)f; // NON_COMPLIANT - (enum E1) f; // NON_COMPLIANT - (signed int)f; // COMPLIANT - (unsigned int)f; // COMPLIANT - (float)f; // COMPLIANT + (_Bool) f; // NON_COMPLIANT + (char)f; // NON_COMPLIANT + (enum E1) f; // NON_COMPLIANT + (signed int)f; // COMPLIANT + (unsigned int)f; // COMPLIANT + (float)f; // COMPLIANT + (float _Complex) f; // COMPLIANT + + float _Complex cf = 100.0; + (_Bool) cf; // NON_COMPLIANT + (char)cf; // NON_COMPLIANT + (enum E1) cf; // NON_COMPLIANT + (signed int)cf; // COMPLIANT + (unsigned int)cf; // COMPLIANT + (float)cf; // COMPLIANT + (float _Complex) cf; // COMPLIANT } void testImplicit() { diff --git a/c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.expected b/c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.expected index 30b5e1efb7..ea8fc433b1 100644 --- a/c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.expected +++ b/c/misra/test/rules/RULE-10-7/ImplicitConversionOfCompositeExpression.expected @@ -1,3 +1,7 @@ | test.c:5:3:5:16 | ... + ... | Implicit conversion of $@ from unsigned short to unsigned int | test.c:5:9:5:16 | ... * ... | composite op | | test.c:6:3:6:18 | ... * ... | Implicit conversion of $@ from unsigned short to unsigned int | test.c:6:9:6:17 | ... + ... | composite op | | test.c:9:3:9:20 | ... += ... | Implicit conversion of $@ from unsigned short to unsigned int | test.c:9:11:9:19 | ... + ... | composite op | +| test.c:24:3:24:19 | ... + ... | Implicit conversion of $@ from float to double | test.c:24:10:24:18 | ... + ... | composite op | +| test.c:25:3:25:21 | ... + ... | Implicit conversion of $@ from _Complex float to double | test.c:25:10:25:20 | ... + ... | composite op | +| test.c:26:3:26:20 | ... + ... | Implicit conversion of $@ from float to _Complex double | test.c:26:11:26:19 | ... + ... | composite op | +| test.c:27:3:27:22 | ... + ... | Implicit conversion of $@ from _Complex float to _Complex double | test.c:27:11:27:21 | ... + ... | composite op | diff --git a/c/misra/test/rules/RULE-10-7/test.c b/c/misra/test/rules/RULE-10-7/test.c index 59d0ed1437..7aaa1847e4 100644 --- a/c/misra/test/rules/RULE-10-7/test.c +++ b/c/misra/test/rules/RULE-10-7/test.c @@ -11,4 +11,18 @@ void testComposite() { signed int s32 = 100; s32 += (u16 + u16); // // ignored - prohibited by Rule 10.4 + + float f32 = 10.0f; + double f64 = 10.0f; + float _Complex cf32 = 10.0f; + double _Complex cf64 = 10.0f; + + f32 + (f32 + f32); // COMPLIANT + cf32 + (cf32 + cf32); // COMPLIANT + f32 + (cf32 + cf32); // COMPLIANT + cf32 + (f32 + f32); // COMPLIANT + f64 + (f32 + f32); // NON_COMPLIANT + f64 + (cf32 + cf32); // NON_COMPLIANT + cf64 + (f32 + f32); // NON_COMPLIANT + cf64 + (cf32 + cf32); // NON_COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.expected b/c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.expected index 85e2471a41..659b41199d 100644 --- a/c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.expected +++ b/c/misra/test/rules/RULE-10-8/InappropriateCastOfCompositeExpression.expected @@ -1,4 +1,10 @@ | test.c:4:16:4:20 | ... + ... | Cast from essentially Unsigned type to essentially Signed type changes type category. | | test.c:5:18:5:22 | ... + ... | Cast from essentially Signed type to essentially Unsigned type changes type category. | -| test.c:14:18:14:24 | ... + ... | Cast from essentially Unsigned type to essentially Unsigned type widens type. | -| test.c:20:16:20:22 | ... + ... | Cast from essentially Signed type to essentially Signed type widens type. | +| test.c:11:11:11:15 | ... + ... | Cast from essentially Unsigned type to essentially Floating type changes type category. | +| test.c:12:20:12:24 | ... + ... | Cast from essentially Unsigned type to essentially Complex Floating type changes type category. | +| test.c:13:18:13:22 | ... + ... | Cast from essentially Floating type to essentially Unsigned type changes type category. | +| test.c:14:18:14:24 | ... + ... | Cast from essentially Complex Floating type to essentially Unsigned type changes type category. | +| test.c:25:18:25:24 | ... + ... | Cast from essentially Unsigned type to essentially Unsigned type widens type. | +| test.c:31:16:31:22 | ... + ... | Cast from essentially Signed type to essentially Signed type widens type. | +| test.c:43:12:43:20 | ... + ... | Cast from essentially Floating type to essentially Floating type widens type. | +| test.c:44:12:44:22 | ... + ... | Cast from essentially Complex Floating type to essentially Floating type widens type. | diff --git a/c/misra/test/rules/RULE-10-8/test.c b/c/misra/test/rules/RULE-10-8/test.c index 41efb6b8d8..31294ed550 100644 --- a/c/misra/test/rules/RULE-10-8/test.c +++ b/c/misra/test/rules/RULE-10-8/test.c @@ -5,6 +5,17 @@ void testDifferentEssentialType() { (unsigned int)(s + s); // NON_COMPLIANT (signed int)(s + s); // COMPLIANT (unsigned int)(u + u); // COMPLIANT + + float f = 1.0; + float _Complex cf = 1.0; + (float)(u + u); // NON_COMPLIANT + (float _Complex)(u + u); // NON_COMPLIANT + (unsigned int)(f + f); // NON_COMPLIANT + (unsigned int)(cf + cf); // NON_COMPLIANT + (float)(f + f); // COMPLIANT + (float)(cf + cf); // COMPLIANT + (float _Complex)(f + f); // COMPLIANT + (float _Complex)(cf + cf); // COMPLIANT } void testWiderType() { @@ -19,4 +30,18 @@ void testWiderType() { (signed int)(ss + ss); // NON_COMPLIANT (signed short)(s + s); // COMPLIANT + + float f32 = 1.0; + double f64 = 1.0; + float _Complex cf32 = 1.0; + double _Complex cf64 = 1.0; + + (float)(f32 + f32); // COMPLIANT + (float)(cf32 + cf32); // COMPLIANT + (float _Complex)(f32 + f32); // COMPLIANT + (float _Complex)(cf32 + cf32); // COMPLIANT + (double)(f32 + f32); // NON_COMPLIANT + (double)(cf32 + cf32); // NON_COMPLIANT + (double _Complex)(f64 + f64); // COMPLIANT + (double _Complex)(cf64 + cf64); // COMPLIANT } \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Emergent.qll b/cpp/common/src/codingstandards/cpp/Emergent.qll index 9036c12bd7..30f1df58e4 100644 --- a/cpp/common/src/codingstandards/cpp/Emergent.qll +++ b/cpp/common/src/codingstandards/cpp/Emergent.qll @@ -6,44 +6,10 @@ import cpp module C11 { abstract class EmergentLanguageFeature extends Element { } - class AlignAsAttribute extends EmergentLanguageFeature, Attribute { - AlignAsAttribute() { getName() = "_Alignas" } - } - - class AtomicVariableSpecifier extends EmergentLanguageFeature, Variable { - AtomicVariableSpecifier() { - getType().(DerivedType).getBaseType*().getASpecifier().getName() = "atomic" - } - } - - class AtomicDeclaration extends EmergentLanguageFeature, Declaration { - AtomicDeclaration() { getASpecifier().getName() = "atomic" } - } - - class ThreadLocalDeclaration extends EmergentLanguageFeature, Declaration { - ThreadLocalDeclaration() { getASpecifier().getName() = "is_thread_local" } - } - - class EmergentHeader extends EmergentLanguageFeature, Include { - EmergentHeader() { - getIncludedFile().getBaseName() = ["stdalign.h", "stdatomic.h", "stdnoreturn.h", "threads.h"] - } - } - class LibExt1Macro extends EmergentLanguageFeature, Macro { LibExt1Macro() { getName() = "__STDC_WANT_LIB_EXT1__" and getBody() = "1" } } - - class GenericMacro extends EmergentLanguageFeature, Macro { - GenericMacro() { getBody().indexOf("_Generic") = 0 } - } - - class NoReturnSpecificer extends EmergentLanguageFeature, Function { - NoReturnSpecificer() { getASpecifier().getName() = "noreturn" } - } - - class AlignOf extends EmergentLanguageFeature, AlignofTypeOperator { } } From 72250d74fb596b8403e0da0d1b315bc783b3c1fd Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 12 Dec 2024 17:26:47 -0800 Subject: [PATCH 155/628] Add changelog --- .../2024-12-12-complex-floating-essential-types.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 change_notes/2024-12-12-complex-floating-essential-types.md diff --git a/change_notes/2024-12-12-complex-floating-essential-types.md b/change_notes/2024-12-12-complex-floating-essential-types.md new file mode 100644 index 0000000000..5f5b6b519f --- /dev/null +++ b/change_notes/2024-12-12-complex-floating-essential-types.md @@ -0,0 +1,8 @@ + - `EssentialType` - for all queries related to essential types: + - Complex floating types are now considered a different essential type than real floating types. + - `RULE-10-1` `RULE-10-3`, `RULE-10-4`, `RULE-10-5`, `RULE-10-7`, `RULE-10-8` - `OperandsOfAnInappropriateEssentialType.ql`, `AssignmentOfIncompatibleEssentialType.ql`, `OperandsWithMismatchedEssentialTypeCategory.ql`, `InappropriateEssentialTypeCast.ql`, `ImplicitConversionOfCompositeExpression.ql`, `InappropriateCastOfCompositeExpression.ql`: + - Updates to rules handling complex floating types in MISRA-C 2012 Amendment 3 have been implemented. +- `RULE-14-1`, `LoopOverEssentiallyFloatType.ql`: + - Query updated to account for the existence of complex essentially floating point types. No change in query results or performance expected. + - `DIR-4-6` - `PlainNumericalTypeUsedOverExplicitTypedef.ql`: + - Updates from MISRA-C 2012 Amendment 3 specifying complex fixed width typedef support has been implemented. \ No newline at end of file From 6625d1ba9ff6dfaa5d4efe71c96c288b1dd0bb81 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 12 Dec 2024 17:36:09 -0800 Subject: [PATCH 156/628] format test case --- c/misra/test/rules/RULE-10-1/test.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/c/misra/test/rules/RULE-10-1/test.c b/c/misra/test/rules/RULE-10-1/test.c index f8d1a4fca5..3b96c7151d 100644 --- a/c/misra/test/rules/RULE-10-1/test.c +++ b/c/misra/test/rules/RULE-10-1/test.c @@ -340,11 +340,11 @@ void testInappropriateOperands() { // u >> f; // NON_COMPILABLE // u >> cf; // NON_COMPILABLE - b & u; // NON_COMPLIANT - c & u; // NON_COMPLIANT - e1 & u; // NON_COMPLIANT - s & u; // NON_COMPLIANT - u & u; // COMPLIANT + b &u; // NON_COMPLIANT + c &u; // NON_COMPLIANT + e1 &u; // NON_COMPLIANT + s &u; // NON_COMPLIANT + u &u; // COMPLIANT // f &u; // NON_COMPILABLE // cf &u; // NON_COMPILABLE @@ -364,11 +364,11 @@ void testInappropriateOperands() { // f ^ u; // NON_COMPILABLE // cf ^ u; // NON_COMPILABLE - u & b; // NON_COMPLIANT - u & c; // NON_COMPLIANT - u & e1; // NON_COMPLIANT - u & s; // NON_COMPLIANT - u & u; // COMPLIANT + u &b; // NON_COMPLIANT + u &c; // NON_COMPLIANT + u &e1; // NON_COMPLIANT + u &s; // NON_COMPLIANT + u &u; // COMPLIANT // u &f; // NON_COMPILABLE // u &cf; // NON_COMPILABLE From a7d2c136f6a7734788005190ca359faee5624789 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 13 Dec 2024 11:07:04 -0800 Subject: [PATCH 157/628] Attempt fix tests --- .../ListGuidelineRecategorizations.expected | 2 +- .../guideline_recategorizations/invalid/coding-standards.xml | 2 +- .../guideline_recategorizations/invalid/coding-standards.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/common/test/guideline_recategorizations/ListGuidelineRecategorizations.expected b/cpp/common/test/guideline_recategorizations/ListGuidelineRecategorizations.expected index 0a8aeb9ba1..8e6a397620 100644 --- a/cpp/common/test/guideline_recategorizations/ListGuidelineRecategorizations.expected +++ b/cpp/common/test/guideline_recategorizations/ListGuidelineRecategorizations.expected @@ -5,4 +5,4 @@ | A10-4-1 | advisory | required | | A11-0-1 | advisory | mandatory | | CON50-CPP | rule | required | -| RULE-13-6 | mandatory | required | +| RULE-9-1 | mandatory | required | diff --git a/cpp/common/test/guideline_recategorizations/invalid/coding-standards.xml b/cpp/common/test/guideline_recategorizations/invalid/coding-standards.xml index d89f27050b..dfb7b6f13c 100644 --- a/cpp/common/test/guideline_recategorizations/invalid/coding-standards.xml +++ b/cpp/common/test/guideline_recategorizations/invalid/coding-standards.xml @@ -15,7 +15,7 @@ mandatory - RULE-13-6 + RULE-9-1 required diff --git a/cpp/common/test/guideline_recategorizations/invalid/coding-standards.yml b/cpp/common/test/guideline_recategorizations/invalid/coding-standards.yml index 89e562c05c..cd6abbf120 100644 --- a/cpp/common/test/guideline_recategorizations/invalid/coding-standards.yml +++ b/cpp/common/test/guideline_recategorizations/invalid/coding-standards.yml @@ -5,7 +5,7 @@ guideline-recategorizations: category: "disapplied" - rule-id: "A1-4-3" category: "mandatory" - - rule-id: "RULE-13-6" + - rule-id: "RULE-9-1" category: "required" - rule-id: "CON50-CPP" category: "required" From 9f60b60991ea74450c65b1d0ae6975c4dab2c4aa Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 13 Dec 2024 11:11:30 -0800 Subject: [PATCH 158/628] Fix test expectations post format --- .../OperandsOfAnInappropriateEssentialType.expected | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected b/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected index aad8dadf99..7a8fd1e07c 100644 --- a/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected +++ b/c/misra/test/rules/RULE-10-1/OperandsOfAnInappropriateEssentialType.expected @@ -119,10 +119,10 @@ | test.c:360:3:360:3 | c | Operand of essentially Charater type interpreted as a numeric value. | | test.c:361:3:361:4 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | | test.c:362:3:362:3 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | -| test.c:367:7:367:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | -| test.c:368:7:368:7 | c | Operand of essentially Charater type interpreted as a numeric value. | -| test.c:369:7:369:8 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | -| test.c:370:7:370:7 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | +| test.c:367:6:367:6 | b | Operand of essentially Boolean type interpreted as a numeric value. | +| test.c:368:6:368:6 | c | Operand of essentially Charater type interpreted as a numeric value. | +| test.c:369:6:369:7 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | +| test.c:370:6:370:6 | s | Bitwise operator applied to operand of essentially Signed type and not essentially unsigned. | | test.c:375:7:375:7 | b | Operand of essentially Boolean type interpreted as a numeric value. | | test.c:376:7:376:7 | c | Operand of essentially Charater type interpreted as a numeric value. | | test.c:377:7:377:8 | e1 | Bitwise operator applied to operand of essentially Enum Type and not essentially unsigned. | From b5e55952c362062eab6efb1f1424682c8d20aa0e Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 13 Dec 2024 11:42:50 -0800 Subject: [PATCH 159/628] Fix deviations report tests --- .../reports/test-data/deviations/invalid/coding-standards.yml | 4 ++-- .../guideline_recategorizations_report.md.expected | 4 ++-- .../guideline-recategorizations/invalid/coding-standards.yml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/reports/test-data/deviations/invalid/coding-standards.yml b/scripts/reports/test-data/deviations/invalid/coding-standards.yml index 7b12c7a8c2..1ce8cc718a 100644 --- a/scripts/reports/test-data/deviations/invalid/coding-standards.yml +++ b/scripts/reports/test-data/deviations/invalid/coding-standards.yml @@ -44,8 +44,8 @@ deviations: permit-id: non-existing-permit - permit-id: DP1 - permit-id: DP2 - - rule-id: RULE-13-6 - query-id: c/misra/sizeof-operand-with-side-effect + - rule-id: RULE-9-1 + query-id: c/misra/object-with-auto-storage-duration-read-before-init deviation-permits: - permit-id: DP1 justification: foo bar baz diff --git a/scripts/reports/test-data/guideline-recategorizations/guideline_recategorizations_report.md.expected b/scripts/reports/test-data/guideline-recategorizations/guideline_recategorizations_report.md.expected index 54fb25ae83..425eba1bc3 100644 --- a/scripts/reports/test-data/guideline-recategorizations/guideline_recategorizations_report.md.expected +++ b/scripts/reports/test-data/guideline-recategorizations/guideline_recategorizations_report.md.expected @@ -13,7 +13,7 @@ | A0-1-1 | required | advisory | | A0-1-1 | required | mandatory | | A0-1-2 | required | disapplied | -| RULE-13-6 | mandatory | required | +| RULE-9-1 | mandatory | required | | CON50-CPP | rule | required | | A0-1-6 | advisory | disapplied | | A10-4-1 | advisory | required | @@ -25,5 +25,5 @@ | invalid/coding-standards.xml:5:7:8:43 | 'Invalid recategorization from 'required' to 'advisory'.' for rule A0-1-1. | | invalid/coding-standards.xml:9:7:12:43 | 'Invalid recategorization from 'required' to 'disapplied'.' for rule A0-1-2. | | invalid/coding-standards.xml:13:7:16:43 | 'Unknown rule id 'A1-4-3'.' for rule A1-4-3. | -| invalid/coding-standards.xml:17:7:20:43 | 'Invalid recategorization from 'mandatory' to 'required'.' for rule RULE-13-6. | +| invalid/coding-standards.xml:17:7:20:43 | 'Invalid recategorization from 'mandatory' to 'required'.' for rule RULE-9-1. | | invalid/coding-standards.xml:21:7:24:43 | 'Invalid recategorization from 'rule' to 'required'.' for rule CON50-CPP. | diff --git a/scripts/reports/test-data/guideline-recategorizations/invalid/coding-standards.yml b/scripts/reports/test-data/guideline-recategorizations/invalid/coding-standards.yml index 89e562c05c..cd6abbf120 100644 --- a/scripts/reports/test-data/guideline-recategorizations/invalid/coding-standards.yml +++ b/scripts/reports/test-data/guideline-recategorizations/invalid/coding-standards.yml @@ -5,7 +5,7 @@ guideline-recategorizations: category: "disapplied" - rule-id: "A1-4-3" category: "mandatory" - - rule-id: "RULE-13-6" + - rule-id: "RULE-9-1" category: "required" - rule-id: "CON50-CPP" category: "required" From fde9973bff0ca359f1df9b175c9b78e4783a4f41 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 13 Dec 2024 13:13:47 -0800 Subject: [PATCH 160/628] Add draft 0.1 of document ID detection-infinities-nans --- ...ection_of_genenated_infinities_and_nans.md | 294 ++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 docs/design/detection_of_genenated_infinities_and_nans.md diff --git a/docs/design/detection_of_genenated_infinities_and_nans.md b/docs/design/detection_of_genenated_infinities_and_nans.md new file mode 100644 index 0000000000..62396eea99 --- /dev/null +++ b/docs/design/detection_of_genenated_infinities_and_nans.md @@ -0,0 +1,294 @@ +# Coding Standards: Detection of generated Infinities and NaNs + +- [Coding Standards: Detection of generated Infinities and NaNs](#coding-standards-detection-of-generated-infinities-and-nans) + - [Document management](#document-management) + - [Background](#background) + - [Critical problems](#critical-problems) + - [TL;DR](#tldr) + - [Range / Source Analysis, In Detail](#range-source-analysis-in-detail) + - [Mathematical Operations](#mathematical-operations) + - [Range / Source Proposal #1 (Recommended)](#range-source-proposal-1-recommended) + - [Range / Source Proposal #2 (Not Recommended)](#range-source-proposal-2-not-recommended) + - [Range / Source Proposal #3 (Not Recommended)](#range-source-proposal-3-not-recommended) + - [Range / Source Proposal #4 (Not Recommended)](#range-source-proposal-4-not-recommended) + - [Detection / Sink Analysis, In Detail](#detection-sink-analysis-in-detail) + - [Detection / Sink Proposal #1 (Recommended)](#range-source-proposal-1-recommended) + - [Detection / Sink Proposal #2 (Not Recommended)](#range-source-proposal-2-not-recommended) + - [Case study examples](#case-study-examples) + +## Document management + +**ID**: codeql-coding-standards/design/detection-infinities-nans
    +**Status**: Draft + +| Version | Date | Author(s) | Reviewer (s) | +| ------- | ---------- | -------------- | ---------------------------------------------------------------------------------------------- | +| 0.1 | 12/13/2024 | Mike Fairhurst | Robert C. Seacord, J.F. Bastien, Luke Cartey, Vincent Mailhol, Fernando Jose, Rakesh Pothengil | + +## Background + +Directive 4-15 of MISRA-C 2023 states that a program shall not have undetected generation of Infinities and NaNs. It also states that infinities and NaNs may propagate across various FLOPs, but may not propagate into sections of code not designed to handle infinities and NaNs. + +This directive is intentionally open to a large degree of interpretation. This document is intended to help guide the decision making for how to implement this directive in the most useful way. + +## Critical problems + +There are two fundamental problems to decide on before implementing this directive: +- **Range / source analysis**, even a simple expression like `a + b` can be a source of infinity or NaN if there is no estimated value for `a` and/or `b`, which violates developer expectations and produces false positives. +- **Detection / sink analysis**, how we decide which sources need to be reported to users. This can be flow analysis with sinks, or it can be modeled as a resource leak analysis where certain actions (`isnan(x), x < 10`) are handled as freeing the NaN/infinite value. + +## TL;DR + +This document proposes to create a float-specialized copy of standard range analysis which assumes most values are in the range of +/-1e15, which covers most valid program use cases, and allows `a * b` without generating `Infinity`. Then standard flow analysis will be used to detect when these values flow into underflowing operations (`x / infinity` and `x % infinity`, etc.), and when NaNs flow into comparison operations (`>`, `>=`, `<`, `<=`). If the query is noisy, we may ignore NaNs and/or infinities that come from the mostly safe basic operations (`+`, `-`, `*`). + +## Range / Source Analysis, In Detail: + +Default CodeQL range analysis is limited for performance reasons (etc): + +- Range analysis is local, not interprocedural +- Global variables are assumed to be in the range of [-Infinity, Infinity] +- Struct members, array values are assumed to be in the range of [-Infinity, Infinity] +- Guards (e.g. `x != 0 ? y / x : ...`) are not always tracked + +This creates a scenario where even `a + b` can be `Infinity` or `NaN`; if either `a` or `b` is `Inf` then the expression is `Inf`, and if `a` is `+Inf` while `b` is `-Inf` then the result is `NaN`. + +Perhaps the flaw is in assuming `a` or `b` may be an infinite value. However, if the analysis considered `a` and `b` to be between the largest positive and negative finite floating values, then still `a + b` can produce an infinity, and only offers a single step of protection from false positives and negatives. + +There are a few proposals to handle this. + +#### Mathematical Operations + +IEEE 754-1985 specifies floating point semantics for “add, subtract, multiply, divide, square root, remainder, and compare operations,” including invalid use of these operators that produce NaN, propagating NaNs, and overflows that produce +/- Infinity. These semantics shall be used in the analysis. + +The C17 standard states that implementations compiling with IEEE 754-1985 shall define `__STDC_IEC_559__`. Under this proposal we will detect compilations where this macro is not defined and report a warning. + +Beyond the standard binary operators defined by IEEE 754-1985, programs may generate Infinity and/or NaN in the standard library mathematical functions. Note that technically, the c spec is vague in certain ways about when range errors, pole errors, and invalid operation errors in the standard math functions produce infinities or NaNs. We propose to assume IEEE 754-2019 behavior in this regard as a practical matter, though there is no guarantee that is the case. An alternative approach which we do not plan to take would be to broadly assume that all range errors, pole errors, invalid operation errors produce both Infinities and NaNs. This alternative would increase false positives. + +### Range / Source Proposal #1 (Recommended): + +We will create a new float-specific version of range analysis. The actual values stored in floating point variables in real programs are very unlikely to be close to the limits of finite floating point numbers (+/- 3.4e38 for floats, 1.8e308 for doubles). This proposal is that we, for the purposes of this rule, create a new range analysis for floats where otherwise undeterminable values are assumed to be a very large range that is small compared to the range of floating point values, such as +/-1e15. + +Creating a new version of float analysis rather than extending previous analysis is likely to have better performance than extending standard range analysis. When floats and integers interact, the integer from standard range analysis can be used. + +Implications of this approach (assuming values `a` and `b` have no estimated range): +- `a + b` will be finite +- `a * b` will be finite +- `a * b * c` will be possibly infinite +- `a / b` will be possibly infinite, as the range includes small values such as 1e-30, as well as zero +- `acos(a)` will be considered out of domain + +**Additional option**: If this query is still noisy, we may simply exclude reporting NaN’s and Infinities that come from a basic float operation such as `+`, `-`, or `*`. We would most likely still choose to report `/`, as divide-by-zero errors are the most common and most important to catch. + +### Range / Source Proposal #2 (Not Recommended): + +This proposal mirrors Proposal #1 except that otherwise undeterminable values will be treated as the max finite value +/-3.4e38 (floats) or 1.7e308 (doubles). + +The implications are as above except: +- `a + b` will be possibly infinite +- `a * b` will be possibly infinite + +### Range / Source Proposal #3 (Not Recommended): + +Under this proposal, standard CodeQL range analysis is used to detect generation of NaN/Infinity. All uses of a global or otherwise undeterminable value will be considered possibly infinite. + +### Range / Source Proposal #4 (Recommended): + +Under this proposal, standard CodeQL range analysis is extended to provide the support of proposal #1. While this should mostly have the same results, it will likely create performance problems, as it would rerun all range analysis code on every expression in order to have different findings in a subset of them. + +## Detection / Sink Analysis, In Detail: + +The directive states that: + +- Generated Infinities and NaNs may not be unchecked +- Infinities and NaNs may propagate to delay NaN/Infinity checking for performance reasons +- Infinities and NaNs may not reach sections of code not designed to handle them + +This leaves open some questions. For instance, is `printf("%f", a * b)` possibly sending an infinity to code prepared to handle it? + +### Detection / Sink Proposal #1 (recommended): + +This proposal is to identify sinks that should not accept Infinity or NaN, and then rely on standard flow analysis as the backbone of supporting this directive. + +If a valid propagation of a NaN or an Infinity can be distinguished from cases where a program was not prepared to receive a NaN or Infinity, then flow analysis is the only thing that is needed, and a resource-leak approach is not necessary. This proposes that the following cases are detected as sinks, such that if NaN or Infinity flows into them they are reported. + +**Case 1**: _NaNs shall not be compared, except to themselves_ +```c +void f(float x, float y) { + float z = x / y; // Could be 0.0 / 0.0 which produces NaN + + if (x < 10) { ... } // Not allowed + if (x != x) { ... } // OK +} +``` + +**Case 2**: _NaNs and infinities shall not be cast to integers_ +```c +void f(float x, float y) { + int z = x / y; // 0.0 / 0.0 may produce Infinity or NaN +} +``` + +**Case 3**: _Infinite values shall not underflow or otherwise produce finite values_ +```c +float f(void) { + float x = ...; // Could be a positive number / 0.0, which produces Infinity + 1 / x; // If x is Infinity, this underflows to 0.0 + 1 % x; // If x is Infinity, this is defined to produce 1. +} +``` + +**Case 4**: _Functions shall not return NaNs and infinities_ +```c +void f(float* p) { + float local1 = ...; // Could be infinity + + return local1; +} +``` + +**Case 5**: _NaNs and infinities shall only be stored in local stack variables_ +```c +float global; +void f(float* p) { + float local1 = ...; // Could be infinity + + // The following assignments could store an infinity in the heap: + global = local1; + extern_function(local1); + *p = local1; + + // The following cases should be possible to analyze correctly as well + // with modest effort: + float arr[10] = ...; + struct my_struct = ...; + arr[0] = local2; + my_struct.member = local1; +} +``` + +**Case 6 (not planned, compiler specific)**: _Functions can use assume() to declare they are not prepared for Infinity or NaN_ +```c +void f(float x, float[] y, struct foo z) { + assume(!isnan(x)); // May be supportable, not planned + assert(!isnan(y[0])); // Not supportable + assert(!isnan(z.member)); // Not supportable +} +``` + +With these cases specified, we can detect invalid usage of Infinity and NaN with simple flow analysis. + +## Detection / Sink Proposal #2 (not recommended): + +This proposed solution takes inspiration from resource leak detection. In this metaphor, a generated infinity or NaN is treated like a resource that must be disposed. [There is a draft WIP of this approach here.](https://github.com/github/codeql-coding-standards/compare/main...michaelrfairhurst/implement-floatingtype-package) + +The advantage of this solution is that we do not need to define every way in which a NaN or an Infinity could be misused. Rather, we only need to define a few ways that a NaN or Infinity can be checked, and then find possible Infinities and NaNs that are not checked (or propagated to a value that is checked). + +Under this proposal, the following are echecks for infinity and NaN: + +- The macros `isnan(x)`, `isinf(x)`, `isfinite(x)` should be considered checks for infinity. +- Reflexive equality checks (`x == x` or `x != x`) should be considered checks for NaN. +- Any comparison operation (`>`, `>=`, `<`, and `<=`) should be considered a check on both positive and negative and positive infinities for an operand if the other is finite. + - If `a` may only be positive infinity, `a < b` and `a > b` both create a branch of the code where `a` is not positive infinity. + - If `a` may only be negative infinity, the same as above is the case for negative infinity cases. + - If `a` may be both positive or negative infinity, then a single check is not sufficient, however detecting an appropriate pair of checks would be a much more difficult implementation + +Only local leak detection analysis is feasible at this time. Therefore, this proposal suggests that an infinite or NaN value should be flagged if it goes out of scope before it is checked. _(In other leak detection problems, this would typically be considered a free event to avoid false positives, and that is an option here as well)_. + +```c +float g; +void f(void) { + float l = 1 / 0; // Must be checked + g = l; // May send Infinity to code not prepared to handle it + isinf(l); // check occurs too late +} +``` + +Overall, this option is not recommended for the following reasons: + +- Slower performance than Proposal #1 +- Limited benefits over Proposal #1 +- Detecting out-of-scope cases heavily resembles Proposal #1 +- Unused values will be flagged, which is not useful to developers +- Intraprocedural analysis will be difficult to support +- High false positive rate if too few checks are detected, as opposed to the alternative where missing sinks do not create false positives + +In this analysis, a method or function call which can generate an infinity, such as `x / y` is treated somewhat like opening a file descriptor, and calls to `isinf(x)` or `isnan(x)` are treated as closing that file descriptor. _There are some differences between how we would approach this and how an actual resource leak detection would be modeled. For instance, we are not searching for use-after-free or double-free bugs, in this metaphor._ + +Note that resource leak detection is not the same as standard CodeQL flow analysis. For instance, if the below example is analyzed with flow analysis, CodeQL will detect that the result of `fopen` flows into a call to `fclose`. However, this only means it is possible that the program will close the file, it does not mean the file descriptor cannot leak. + +```c +void f(bool p) { + FILE* fd = fopen(...); + if (p) { + fclose(fd); + } +} +``` + +The drafted leak detection algorithm follows [this paper](https://arxiv.org/html/2312.01912v2/#S2.SS2). In this approach, the program flow from the exit of `f()` is walked backwards. The walk stops upon reaching a call to `fclose()`, and if a call to `fopen()` is reached by this iterative process then that resource could leak. + +_Note that this approach still uses flow analysis to determine that fclose(fd) is referring to an initial fopen() call. In the paper, flow analysis is used to find aliases of resources, so that disposing an alias of a resource is handled correctly._ + +This approach is still neither 100% accurate nor precise. It can generate both false positives and false negatives, though it is hopefully accurate and precise enough for our purposes: + +```c +// FALSE POSITIVE: See fprintf call marked (1). Not all successors from (1) + // call fclose(), and not all predecessors of (1) call fclose() either. + // All paths dispose fd, but this algorithm does not see that. + fd = fopen(...); + if (!cond) { + fclose(fd); + } + fprintf(...); // (1) + if (cond) { + fclose(fd); + } + + // FALSE NEGATIVE: The file descriptor opened at (2) flows into the dispose + // call at (3) if the values of x and y are not known. However, the resource + // is only closed when x == y, which is not necessarily the case. + fds[x] = fopen(...); // (2) + fclose(fds[y]); // (3) +``` + +Nevertheless, their approach is sensible and likely good enough. + +Lastly, this approach has the unfortunate downside that unused float values which could be NaN or Infinity will be reported, when they do not have any negative effect on a program (as opposed to the negative effects of leaking unused file descriptors, or unused memory, etc). + +## Case study examples + +The following is an interesting set of examples and code snippets that come from the open source project [pandas](https://github.com/commaai/panda), which aims to be MISRA compliant and is used for self-driving cars. + +These examples are hand picked results from a query that selected expressions with a floating point type along with their upper and lower bounds. + +**Example 1**: +```c +float filtered_pcm_speed = + ((to_push->data[6] << 8) | to_push->data[7]) + * 0.01 / 3.6; +// Disable controls if speeds from ABS and PCM ECUs are too far apart. +bool is_invalid_speed = ABS(filtered_pcm_speed + - ((float)vehicle_speed.values[0] / VEHICLE_SPEED_FACTOR)) + > FORD_MAX_SPEED_DELTA; +``` + +While `filter_pcm_speed` cannot be infinity or NaN, it is interesting to see how this value is sanity checked. If this code were refactored such that it could produce NaN, the greater-than check would return false, resulting in a bug. If the condition were flipped (check inside valid range, rather than outside), it would handle NaN correctly. This cannot be captured via static analysis. + +**Example 2**: +```c + float x0 = xy.x[i]; + float y0 = xy.y[i]; + float dx = xy.x[i+1] - x0; + float dy = xy.y[i+1] - y0; + // dx should not be zero as xy.x is supposed to be monotonic + dx = MAX(dx, 0.0001); + ret = (dy * (x - x0) / dx) + y0; +``` + +This is an [interpolation function](https://github.com/commaai/panda/blob/dec9223f9726e400e4a4eb91ca19fffcd745f97a/board/safety.h#L538), where `xy` is a struct parameter, with array members `x` and `y` that represent points in the domain and range to interpolate across. + +Range analysis is performed with local information only, and therefore, the expression `xy.x[i]` is given the range [-Infinity, Infinity]. This is not a generated infinity. However, the computations of `dx` and `dy` could generate a positive or negative infinity (if both numbers are finite and the result exceeds the maximum float value), they could propagate a positive or negative infinity, and/or they could generate a NaN (if an infinite value is subtracted from itself). + +The call to `MAX()` will not check if `dx` = positive infinity, and is unsafe to use with NaN. It prevents a divide-by-zero error, but `ret` could still propagate or generate a NaN or one of the infinities since we know so little about `dy`, `x0`, and `y0`. + +It’s worth noting that if `dx` is positive Infinity, then `(x - x0) / dx` will produce zero, rather than propagating the infinity. This may be worth flagging. \ No newline at end of file From ad066bb4d4550e15a194f66f1559bc414df84744 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 13 Dec 2024 13:24:35 -0800 Subject: [PATCH 161/628] Continued attempts to resolve deviations tests --- .../test/deviations/invalid_deviations/coding-standards.xml | 4 ++-- .../test/deviations/invalid_deviations/coding-standards.yml | 4 ++-- .../InvalidGuidelineRecategorizations.expected | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/common/test/deviations/invalid_deviations/coding-standards.xml b/cpp/common/test/deviations/invalid_deviations/coding-standards.xml index 179227a13d..36dedead00 100644 --- a/cpp/common/test/deviations/invalid_deviations/coding-standards.xml +++ b/cpp/common/test/deviations/invalid_deviations/coding-standards.xml @@ -83,8 +83,8 @@ DP2 - RULE-13-6 - c/misra/sizeof-operand-with-side-effect + RULE-9-1 + c/misra/object-with-auto-storage-duration-read-before-init diff --git a/cpp/common/test/deviations/invalid_deviations/coding-standards.yml b/cpp/common/test/deviations/invalid_deviations/coding-standards.yml index 7b12c7a8c2..1ce8cc718a 100644 --- a/cpp/common/test/deviations/invalid_deviations/coding-standards.yml +++ b/cpp/common/test/deviations/invalid_deviations/coding-standards.yml @@ -44,8 +44,8 @@ deviations: permit-id: non-existing-permit - permit-id: DP1 - permit-id: DP2 - - rule-id: RULE-13-6 - query-id: c/misra/sizeof-operand-with-side-effect + - rule-id: RULE-9-1 + query-id: c/misra/object-with-auto-storage-duration-read-before-init deviation-permits: - permit-id: DP1 justification: foo bar baz diff --git a/cpp/common/test/guideline_recategorizations/InvalidGuidelineRecategorizations.expected b/cpp/common/test/guideline_recategorizations/InvalidGuidelineRecategorizations.expected index 971c70a9b6..d41c27f23a 100644 --- a/cpp/common/test/guideline_recategorizations/InvalidGuidelineRecategorizations.expected +++ b/cpp/common/test/guideline_recategorizations/InvalidGuidelineRecategorizations.expected @@ -1,5 +1,5 @@ | invalid/coding-standards.xml:5:7:8:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'required' to 'advisory'.' for rule A0-1-1. | | invalid/coding-standards.xml:9:7:12:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'required' to 'disapplied'.' for rule A0-1-2. | | invalid/coding-standards.xml:13:7:16:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Unknown rule id 'A1-4-3'.' for rule A1-4-3. | -| invalid/coding-standards.xml:17:7:20:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'mandatory' to 'required'.' for rule RULE-13-6. | +| invalid/coding-standards.xml:17:7:20:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'mandatory' to 'required'.' for rule RULE-9-1. | | invalid/coding-standards.xml:21:7:24:43 | guideline-recategorizations-entry | guideline_recategorizations/invalid/coding-standards.xml: 'Invalid recategorization from 'rule' to 'required'.' for rule CON50-CPP. | From 3342bb525e410e4c8d2b4232e73a5c3f06b00659 Mon Sep 17 00:00:00 2001 From: "rakesh.pothengil" Date: Tue, 17 Dec 2024 16:07:55 +0900 Subject: [PATCH 162/628] Fixes #824 --- change_notes/2024-12-17-fix-fp-824-a15-4-4 | 2 ++ cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql | 3 +++ 2 files changed, 5 insertions(+) create mode 100644 change_notes/2024-12-17-fix-fp-824-a15-4-4 diff --git a/change_notes/2024-12-17-fix-fp-824-a15-4-4 b/change_notes/2024-12-17-fix-fp-824-a15-4-4 new file mode 100644 index 0000000000..0908c14ffa --- /dev/null +++ b/change_notes/2024-12-17-fix-fp-824-a15-4-4 @@ -0,0 +1,2 @@ + - `A15-4-4` - `MissingNoExcept.ql`: + - Reduce false positives by not reporting on functions that have a noexcept specification with a complex expression. diff --git a/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql b/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql index 7701a8a1ea..2721b42af3 100644 --- a/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql +++ b/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql @@ -28,6 +28,9 @@ where not isNoExceptTrue(f) and // Not explicitly marked noexcept(false) not isNoExceptExplicitlyFalse(f) and + // Not having a noexcept specification that + // could not be computed as true or false above. + not exists(f.getADeclarationEntry().getNoExceptExpr()) and // Not compiler generated not f.isCompilerGenerated() and // The function is defined in this database From 40d7800f77d588e67b394a1604682cb7320e1236 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 17 Dec 2024 19:23:18 +0100 Subject: [PATCH 163/628] Update expected test results --- .../RULE-5-4/MacroIdentifiersNotDistinct.expected | 6 +++--- .../identifierhidden/IdentifierHidden.expected | 13 +------------ 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/c/misra/test/rules/RULE-5-4/MacroIdentifiersNotDistinct.expected b/c/misra/test/rules/RULE-5-4/MacroIdentifiersNotDistinct.expected index d44164d116..b079b7e94d 100644 --- a/c/misra/test/rules/RULE-5-4/MacroIdentifiersNotDistinct.expected +++ b/c/misra/test/rules/RULE-5-4/MacroIdentifiersNotDistinct.expected @@ -1,4 +1,4 @@ -| header3.h:7:1:7:24 | #define MULTIPLE_INCLUDE | Definition of macro MULTIPLE_INCLUDE is not distinct from alternative definition of $@ in rules/RULE-5-4/header4.h. | header4.h:1:1:1:24 | #define MULTIPLE_INCLUDE | MULTIPLE_INCLUDE | -| header3.h:14:1:14:21 | #define NOT_PROTECTED | Definition of macro NOT_PROTECTED is not distinct from alternative definition of $@ in rules/RULE-5-4/header4.h. | header4.h:12:1:12:23 | #define NOT_PROTECTED 1 | NOT_PROTECTED | +| header3.h:7:1:7:24 | #define MULTIPLE_INCLUDE | Definition of macro MULTIPLE_INCLUDE is not distinct from alternative definition of $@ in header4.h. | header4.h:1:1:1:24 | #define MULTIPLE_INCLUDE | MULTIPLE_INCLUDE | +| header3.h:14:1:14:21 | #define NOT_PROTECTED | Definition of macro NOT_PROTECTED is not distinct from alternative definition of $@ in header4.h. | header4.h:12:1:12:23 | #define NOT_PROTECTED 1 | NOT_PROTECTED | | test.c:2:1:2:72 | #define iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyB | Macro identifer iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyB is nondistinct in first 63 characters, compared to $@. | test.c:1:1:1:72 | #define iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyA | iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyA | -| test.c:8:1:8:31 | #define FUNCTION_MACRO(X) X + 1 | Definition of macro FUNCTION_MACRO is not distinct from alternative definition of $@ in rules/RULE-5-4/test.c. | test.c:7:1:7:57 | #define FUNCTION_MACRO(FUNCTION_MACRO) FUNCTION_MACRO + 1 | FUNCTION_MACRO | +| test.c:8:1:8:31 | #define FUNCTION_MACRO(X) X + 1 | Definition of macro FUNCTION_MACRO is not distinct from alternative definition of $@ in test.c. | test.c:7:1:7:57 | #define FUNCTION_MACRO(FUNCTION_MACRO) FUNCTION_MACRO + 1 | FUNCTION_MACRO | diff --git a/cpp/common/test/rules/identifierhidden/IdentifierHidden.expected b/cpp/common/test/rules/identifierhidden/IdentifierHidden.expected index 47d191d758..fd657590ef 100644 --- a/cpp/common/test/rules/identifierhidden/IdentifierHidden.expected +++ b/cpp/common/test/rules/identifierhidden/IdentifierHidden.expected @@ -4,21 +4,10 @@ | test.cpp:23:13:23:15 | id1 | Variable is hiding variable $@. | test.cpp:1:5:1:7 | id1 | id1 | | test.cpp:26:12:26:14 | id1 | Variable is hiding variable $@. | test.cpp:1:5:1:7 | id1 | id1 | | test.cpp:27:14:27:16 | id1 | Variable is hiding variable $@. | test.cpp:26:12:26:14 | id1 | id1 | -| test.cpp:48:11:48:11 | i | Variable is hiding variable $@. | test.cpp:58:16:58:16 | i | i | -| test.cpp:48:11:48:11 | i | Variable is hiding variable $@. | test.cpp:75:16:75:16 | i | i | -| test.cpp:50:9:50:9 | i | Variable is hiding variable $@. | test.cpp:58:16:58:16 | i | i | -| test.cpp:50:9:50:9 | i | Variable is hiding variable $@. | test.cpp:75:16:75:16 | i | i | -| test.cpp:53:12:53:12 | i | Variable is hiding variable $@. | test.cpp:58:16:58:16 | i | i | -| test.cpp:53:12:53:12 | i | Variable is hiding variable $@. | test.cpp:75:16:75:16 | i | i | -| test.cpp:65:11:65:11 | i | Variable is hiding variable $@. | test.cpp:58:16:58:16 | i | i | | test.cpp:65:11:65:11 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i | -| test.cpp:65:11:65:11 | i | Variable is hiding variable $@. | test.cpp:75:16:75:16 | i | i | -| test.cpp:67:9:67:9 | i | Variable is hiding variable $@. | test.cpp:58:16:58:16 | i | i | | test.cpp:67:9:67:9 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i | -| test.cpp:67:9:67:9 | i | Variable is hiding variable $@. | test.cpp:75:16:75:16 | i | i | -| test.cpp:70:12:70:12 | i | Variable is hiding variable $@. | test.cpp:58:16:58:16 | i | i | | test.cpp:70:12:70:12 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i | -| test.cpp:70:12:70:12 | i | Variable is hiding variable $@. | test.cpp:75:16:75:16 | i | i | +| test.cpp:75:16:75:16 | i | Variable is hiding variable $@. | test.cpp:61:7:61:7 | i | i | | test.cpp:86:9:86:9 | b | Variable is hiding variable $@. | test.cpp:80:11:80:11 | b | b | | test.cpp:94:9:94:17 | globalvar | Variable is hiding variable $@. | test.cpp:91:5:91:13 | globalvar | globalvar | | test.cpp:113:11:113:11 | b | Variable is hiding variable $@. | test.cpp:107:13:107:13 | b | b | From 065dc013edd676c420fa86f9fe6cebb9a7ae9394 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 17 Dec 2024 20:18:18 +0100 Subject: [PATCH 164/628] Update queries after `TemplateParameter` deprecation --- .../rules/RULE-2-4/UnusedTagDeclaration.ql | 2 +- ...wardingReferenceAsItsArgumentOverloaded.ql | 3 +- .../NonTemplateMemberDefinedInTemplate.ql | 28 +++++++++---------- .../NonMemberGenericOperatorCondition.ql | 2 +- ...tionAndInitializationNotOnSeparateLines.ql | 2 +- .../CopyAssignmentOperatorNotDeclared.ql | 4 +-- .../DisappliedQuery.ql | 2 +- 7 files changed, 22 insertions(+), 21 deletions(-) diff --git a/c/misra/src/rules/RULE-2-4/UnusedTagDeclaration.ql b/c/misra/src/rules/RULE-2-4/UnusedTagDeclaration.ql index 08fe2568e9..e277139c1a 100644 --- a/c/misra/src/rules/RULE-2-4/UnusedTagDeclaration.ql +++ b/c/misra/src/rules/RULE-2-4/UnusedTagDeclaration.ql @@ -32,5 +32,5 @@ where // `isInMacroExpansion` is broken for `UserType`s. not s.isInMacroExpansion() and // Exclude template parameters, in case this is run on C++ code. - not s instanceof TemplateParameter + not s instanceof TypeTemplateParameter select s, "struct " + s.getName() + " has an unused tag." diff --git a/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql b/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql index 1ae2bc87ab..7b31ae5d9e 100644 --- a/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql +++ b/cpp/autosar/src/rules/A13-3-1/FunctionThatContainsForwardingReferenceAsItsArgumentOverloaded.ql @@ -18,7 +18,8 @@ import codingstandards.cpp.FunctionEquivalence class Candidate extends TemplateFunction { Candidate() { - this.getAParameter().getType().(RValueReferenceType).getBaseType() instanceof TemplateParameter + this.getAParameter().getType().(RValueReferenceType).getBaseType() instanceof + TypeTemplateParameter } } diff --git a/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql b/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql index 7f9ced9909..95465bbb6a 100644 --- a/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql +++ b/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql @@ -18,7 +18,7 @@ import codingstandards.cpp.autosar import codingstandards.cpp.TypeUses import codingstandards.cpp.Operator -predicate templateDefinitionMentionsTypeParameter(Declaration d, TemplateParameter tp) { +predicate templateDefinitionMentionsTypeParameter(Declaration d, TypeTemplateParameter tp) { exists(Type t | ( // direct reference, e.g., fields. @@ -50,36 +50,36 @@ predicate templateDefinitionMentionsTypeParameter(Declaration d, TemplateParamet } /** - * The set of `TemplateParameter` references within an `Enum`. + * The set of `TypeTemplateParameter` references within an `Enum`. */ -TemplateParameter enumTemplateReferences(Enum e) { +TypeTemplateParameter enumTemplateReferences(Enum e) { templateDefinitionMentionsTypeParameter(e.getADeclaration(), result) or result = e.getExplicitUnderlyingType() } /** - * The set of `TemplateParameter` references within an `Class`. + * The set of `TypeTemplateParameter` references within an `Class`. */ -TemplateParameter classTemplateReferences(Class c) { +TypeTemplateParameter classTemplateReferences(Class c) { templateDefinitionMentionsTypeParameter(c.getAMember(), result) or c.getADerivation().getBaseType() = result } /** - * The set of all of the `TemplateParameter`s referenced by a `EnumConstant`. + * The set of all of the `TypeTemplateParameter`s referenced by a `EnumConstant`. */ -TemplateParameter enumConstantTemplateReferences(EnumConstant ec) { +TypeTemplateParameter enumConstantTemplateReferences(EnumConstant ec) { templateDefinitionMentionsTypeParameter(ec.getDeclaringType(), result) } /** - * The set of all `TemplateParameter`s referenced by a `Function`. + * The set of all `TypeTemplateParameter`s referenced by a `Function`. */ -TemplateParameter functionTemplateReferences(Function mf) { +TypeTemplateParameter functionTemplateReferences(Function mf) { // the type of the function - exists(TemplateParameter tp | + exists(TypeTemplateParameter tp | result = tp and ( mf.getType().refersTo(result) @@ -115,10 +115,10 @@ TemplateParameter functionTemplateReferences(Function mf) { } /** - * The set of all `TemplateParameters` available as arguments to the declaring + * The set of all `TypeTemplateParameters` available as arguments to the declaring * element of some `Declarations`. */ -TemplateParameter templateParametersOfDeclaringTemplateClass(Declaration d) { +TypeTemplateParameter templateParametersOfDeclaringTemplateClass(Declaration d) { result = d.getDeclaringType().getATemplateArgument() } @@ -149,7 +149,7 @@ where not d instanceof UserNegationOperator and // for each declaration within a template class get the // template parameters of the declaring class - not exists(TemplateParameter t | + not exists(TypeTemplateParameter t | t = templateParametersOfDeclaringTemplateClass(d) and // and require that the declaration depends on at least // one of those template parameters. @@ -170,7 +170,7 @@ where ) and // Omit using alias (cf. https://github.com/github/codeql-coding-standards/issues/739) // Exclude Using alias which refer directly to a TypeParameter - not d.(UsingAliasTypedefType).getBaseType() instanceof TemplateParameter + not d.(UsingAliasTypedefType).getBaseType() instanceof TypeTemplateParameter select d, "Member " + d.getName() + " template class does not use any of template arguments of its $@.", d.getDeclaringType(), "declaring type" diff --git a/cpp/autosar/src/rules/A14-5-3/NonMemberGenericOperatorCondition.ql b/cpp/autosar/src/rules/A14-5-3/NonMemberGenericOperatorCondition.ql index a2211368ed..c2d28d3ef9 100644 --- a/cpp/autosar/src/rules/A14-5-3/NonMemberGenericOperatorCondition.ql +++ b/cpp/autosar/src/rules/A14-5-3/NonMemberGenericOperatorCondition.ql @@ -18,7 +18,7 @@ import codingstandards.cpp.autosar class NonMemberGenericOperator extends TemplateFunction { NonMemberGenericOperator() { this instanceof Operator and - exists(TemplateParameter tp, Type pType | + exists(TypeTemplateParameter tp, Type pType | pType = getAParameter().getType().getUnspecifiedType() //Parameter Type | pType = tp or diff --git a/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql b/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql index 89aca8048e..ac98fe699d 100644 --- a/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql +++ b/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql @@ -23,7 +23,7 @@ class UniqueLineStmt extends Locatable { exists(Declaration d | this = d.getADeclarationEntry() and not d instanceof Parameter and - not d instanceof TemplateParameter and + not d instanceof TypeTemplateParameter and // TODO - Needs to be enhanced to solve issues with // templated inner classes. not d instanceof Function and diff --git a/cpp/autosar/src/rules/M14-5-3/CopyAssignmentOperatorNotDeclared.ql b/cpp/autosar/src/rules/M14-5-3/CopyAssignmentOperatorNotDeclared.ql index 05e99d6e66..1b41fe81bc 100644 --- a/cpp/autosar/src/rules/M14-5-3/CopyAssignmentOperatorNotDeclared.ql +++ b/cpp/autosar/src/rules/M14-5-3/CopyAssignmentOperatorNotDeclared.ql @@ -34,10 +34,10 @@ class TemplateAssignmentOperatorMember extends MemberFunction { } /** - * is a copy assigment operator candidate if it has only one param and form in [T, T&, const T&, volatile T&, const volatile T&] + * is a copy assignment operator candidate if it has only one param and form in [T, T&, const T&, volatile T&, const volatile T&] */ predicate hasGenericCopyCompatibleParameter() { - exists(TemplateParameter tp, Type pType | + exists(TypeTemplateParameter tp, Type pType | pType = this.getAParameter().getType().getUnspecifiedType() and //Parameter Type ( tp = pType //T diff --git a/cpp/common/test/guideline_recategorizations/DisappliedQuery.ql b/cpp/common/test/guideline_recategorizations/DisappliedQuery.ql index 0254eca9bd..9c6f732aa9 100644 --- a/cpp/common/test/guideline_recategorizations/DisappliedQuery.ql +++ b/cpp/common/test/guideline_recategorizations/DisappliedQuery.ql @@ -17,7 +17,7 @@ from UserType ut, string reason where isExcluded(ut, DeadCodePackage::unusedTypeDeclarationsQuery(), reason) and exists(ut.getFile()) and - not ut instanceof TemplateParameter and + not ut instanceof TypeTemplateParameter and not ut instanceof ProxyClass and not exists(getATypeUse(ut)) and not ut.isFromUninstantiatedTemplate(_) From 23ddafa76ec60d06ef5f339062647f41cfb436ef Mon Sep 17 00:00:00 2001 From: "rakesh.pothengil" Date: Wed, 18 Dec 2024 11:13:46 +0900 Subject: [PATCH 165/628] Fix #540 --- change_notes/2024-12-18-fix-fp-540-a3-9-1.md | 2 ++ .../rules/A3-9-1/VariableWidthIntegerTypesUsed.ql | 4 ++++ cpp/autosar/test/rules/A3-9-1/test.cpp | 13 ++++++++++++- 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 change_notes/2024-12-18-fix-fp-540-a3-9-1.md diff --git a/change_notes/2024-12-18-fix-fp-540-a3-9-1.md b/change_notes/2024-12-18-fix-fp-540-a3-9-1.md new file mode 100644 index 0000000000..fbd09ca840 --- /dev/null +++ b/change_notes/2024-12-18-fix-fp-540-a3-9-1.md @@ -0,0 +1,2 @@ + - `A3-9-1` - `VariableWidthIntegerTypesUsed.ql`: + - Reduce false positives by not considering variables from template instantiations. diff --git a/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql b/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql index 84a38b0f6a..fa19ad998f 100644 --- a/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql +++ b/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql @@ -32,6 +32,10 @@ where typeStrippedOfSpecifiers instanceof SignedCharType ) and not v instanceof ExcludedVariable and + // Dont consider template instantiations because instantiations with + // Fixed Width Types are recorded after stripping their typedef'd type, + // thereby, causing false positives (#540). + not v.isFromTemplateInstantiation(_) and //post-increment/post-decrement operators are required by the standard to have a dummy int parameter not v.(Parameter).getFunction() instanceof PostIncrementOperator and not v.(Parameter).getFunction() instanceof PostDecrementOperator diff --git a/cpp/autosar/test/rules/A3-9-1/test.cpp b/cpp/autosar/test/rules/A3-9-1/test.cpp index 882738eea1..7ffb87ca39 100644 --- a/cpp/autosar/test/rules/A3-9-1/test.cpp +++ b/cpp/autosar/test/rules/A3-9-1/test.cpp @@ -75,4 +75,15 @@ void test_variable_width_type_qualified_variables() { struct test_fix_fp_614 { test_fix_fp_614 operator++(int); // COMPLIANT test_fix_fp_614 operator--(int); // COMPLIANT -}; \ No newline at end of file +}; + +// COMPLIANT - instantiated with Fixed Width Types. +template constexpr void test_fix_fp_540(MyType value) { + value++; +} + +int call_test_fix_fp_540() { + test_fix_fp_540(19); + test_fix_fp_540(20); + return 0; +} From f5394d0b1ef8bad2b32ef07298eebb7803a902b6 Mon Sep 17 00:00:00 2001 From: "rakesh.pothengil" Date: Thu, 19 Dec 2024 11:17:11 +0900 Subject: [PATCH 166/628] Check called functions with noexcept(unknown) --- change_notes/2024-12-17-fix-fp-824-a15-4-4 | 2 +- .../src/rules/A15-4-4/MissingNoExcept.ql | 33 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/change_notes/2024-12-17-fix-fp-824-a15-4-4 b/change_notes/2024-12-17-fix-fp-824-a15-4-4 index 0908c14ffa..89ccf49815 100644 --- a/change_notes/2024-12-17-fix-fp-824-a15-4-4 +++ b/change_notes/2024-12-17-fix-fp-824-a15-4-4 @@ -1,2 +1,2 @@ - `A15-4-4` - `MissingNoExcept.ql`: - - Reduce false positives by not reporting on functions that have a noexcept specification with a complex expression. + - Reduce false positives by not reporting on functions that have a noexcept specification with a complex expression or call other such functions. diff --git a/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql b/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql index 2721b42af3..33369e00a4 100644 --- a/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql +++ b/cpp/autosar/src/rules/A15-4-4/MissingNoExcept.ql @@ -19,6 +19,36 @@ import codingstandards.cpp.autosar import codingstandards.cpp.exceptions.ExceptionSpecifications import codingstandards.cpp.exceptions.ExceptionFlow +// These functions have a noexcept specification that could not be resolved +// to noexcept(true). So either, they are noexcept(false) functions which +// means, they can throw an exception OR they have an expression which +// could not be resolved to "true" or "false". Even in this case, lets +// be more conservative and assume they may thrown an exception. +class FunctionWithUnknownNoExcept extends Function { + FunctionWithUnknownNoExcept() { + // Exists a noexcept specification but not noexcept(true) + exists(this.getADeclarationEntry().getNoExceptExpr()) and + not isNoExceptTrue(this) + } +} + +// This predicate checks if a function can call to other functions +// that may have a noexcept specification which cannot be resolved to +// noexcept(true). +predicate mayCallThrowingFunctions(Function f) { + // Exists a call in this function + exists(Call fc | + fc.getEnclosingFunction() = f and + ( + // Either this call is to a function with an unknown noexcept OR + fc.getTarget() instanceof FunctionWithUnknownNoExcept + or + // That function can further have calls to unknown noexcept functions. + mayCallThrowingFunctions(fc.getTarget()) + ) + ) +} + from Function f where not isExcluded(f, Exceptions1Package::missingNoExceptQuery()) and @@ -31,6 +61,9 @@ where // Not having a noexcept specification that // could not be computed as true or false above. not exists(f.getADeclarationEntry().getNoExceptExpr()) and + // Not calling function(s) which have a noexcept specification that + // could not be computed as true. + not mayCallThrowingFunctions(f) and // Not compiler generated not f.isCompilerGenerated() and // The function is defined in this database From ae63dcbd93178c83693ec7c06b0105be3088c445 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 18 Dec 2024 18:28:45 -0800 Subject: [PATCH 167/628] Implement most MISRA-C amendment4 rule amendments --- amendments.csv | 10 +- .../includes/standard-library/stdatomic.h | 74 +++++++++++++-- .../rules/readofuninitializedmemory/test.c | 2 + ...weenObjectPointerAndDifferentObjectType.ql | 6 +- ...CastRemovesConstOrVolatileQualification.ql | 4 + .../rules/RULE-13-2/UnsequencedAtomicReads.ql | 94 +++++++++++++++++++ ...CharacterSequencesAndUsedWithinAComment.ql | 33 ++++--- ...jectPointerAndDifferentObjectType.expected | 4 + c/misra/test/rules/RULE-11-3/test.c | 6 ++ ...movesConstOrVolatileQualification.expected | 4 + c/misra/test/rules/RULE-11-8/test.c | 7 ++ .../RULE-13-2/UnsequencedAtomicReads.expected | 5 + .../RULE-13-2/UnsequencedAtomicReads.qlref | 1 + .../RULE-13-2/UnsequencedSideEffects.expected | 12 +-- c/misra/test/rules/RULE-13-2/test.c | 13 +++ ...terSequencesAndUsedWithinAComment.expected | 2 + c/misra/test/rules/RULE-3-1/test.c | 15 +++ ...ment-misra-c-amendment4-rule-amendments.md | 10 ++ .../cpp/exclusions/c/SideEffects3.qll | 20 +++- .../ReadOfUninitializedMemory.qll | 2 + .../rules/readofuninitializedmemory/test.cpp | 2 + rule_packages/c/SideEffects3.json | 12 +++ 22 files changed, 307 insertions(+), 31 deletions(-) create mode 100644 c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql create mode 100644 c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected create mode 100644 c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.qlref create mode 100644 change_notes/2024-12-13-implement-misra-c-amendment4-rule-amendments.md diff --git a/amendments.csv b/amendments.csv index ce285a29ba..bb2ceac27a 100644 --- a/amendments.csv +++ b/amendments.csv @@ -11,21 +11,21 @@ c,MISRA-C-2012,Amendment3,RULE-10-7,Yes,Refine,No,Import c,MISRA-C-2012,Amendment3,RULE-10-8,Yes,Refine,No,Import c,MISRA-C-2012,Amendment3,RULE-21-11,Yes,Clarification,No,Import c,MISRA-C-2012,Amendment3,RULE-21-12,Yes,Replace,No,Easy -c,MISRA-C-2012,Amendment4,RULE-11-3,Yes,Expand,No,Easy -c,MISRA-C-2012,Amendment4,RULE-11-8,Yes,Expand,No,Easy -c,MISRA-C-2012,Amendment4,RULE-13-2,Yes,Expand,No,Very Hard +c,MISRA-C-2012,Amendment4,RULE-11-3,Yes,Expand,Yes,Easy +c,MISRA-C-2012,Amendment4,RULE-11-8,Yes,Expand,Yes,Easy +c,MISRA-C-2012,Amendment4,RULE-13-2,Yes,Expand,Yes,Very Hard c,MISRA-C-2012,Amendment4,RULE-18-6,Yes,Expand,No,Medium c,MISRA-C-2012,Amendment4,RULE-18-8,Yes,Split,Yes,Easy c,MISRA-C-2012,Corrigendum2,RULE-2-2,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-2-7,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-3-1,Yes,Refine,No,Easy +c,MISRA-C-2012,Corrigendum2,RULE-3-1,Yes,Refine,Yes,Easy c,MISRA-C-2012,Corrigendum2,RULE-8-6,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-8-9,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-9-4,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-10-1,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-18-3,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-1-4,Yes,Replace,No,Easy -c,MISRA-C-2012,Corrigendum2,RULE-9-1,Yes,Refine,No,Easy +c,MISRA-C-2012,Corrigendum2,RULE-9-1,Yes,Refine,Yes,Easy c,MISRA-C-2012,Corrigendum2,RULE-9-2,Yes,Refine,No,Import c,MISRA-C-2012,Corrigendum2,DIR-4-10,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-7-4,Yes,Refine,No,Easy diff --git a/c/common/test/includes/standard-library/stdatomic.h b/c/common/test/includes/standard-library/stdatomic.h index 66b74ae61a..49a5b3cfcd 100644 --- a/c/common/test/includes/standard-library/stdatomic.h +++ b/c/common/test/includes/standard-library/stdatomic.h @@ -1,9 +1,69 @@ -#define atomic_compare_exchange_weak(a, b, c) 0 -#define atomic_compare_exchange_weak_explicit(a, b, c, d, e) 0 -#define atomic_load(a) 0 -#define atomic_load_explicit(a, b) -#define atomic_store(a, b) 0 -#define atomic_store_explicit(a, b, c) 0 #define ATOMIC_VAR_INIT(value) (value) #define atomic_is_lock_free(obj) __c11_atomic_is_lock_free(sizeof(*(obj))) -typedef _Atomic(int) atomic_int; \ No newline at end of file +typedef _Atomic(int) atomic_int; + +#define __ATOMIC_RELAXED 0 +#define __ATOMIC_CONSUME 1 +#define __ATOMIC_ACQUIRE 2 +#define __ATOMIC_RELEASE 3 +#define __ATOMIC_ACQ_REL 4 +#define __ATOMIC_SEQ_CST 5 + +typedef enum memory_order { + memory_order_relaxed = __ATOMIC_RELAXED, + memory_order_consume = __ATOMIC_CONSUME, + memory_order_acquire = __ATOMIC_ACQUIRE, + memory_order_release = __ATOMIC_RELEASE, + memory_order_acq_rel = __ATOMIC_ACQ_REL, + memory_order_seq_cst = __ATOMIC_SEQ_CST +} memory_order; + +void atomic_thread_fence(memory_order); +void atomic_signal_fence(memory_order); + +#define atomic_thread_fence(order) __c11_atomic_thread_fence(order) +#define atomic_signal_fence(order) __c11_atomic_signal_fence(order) + +#define atomic_store(object, desired) __c11_atomic_store(object, desired, __ATOMIC_SEQ_CST) +#define atomic_store_explicit __c11_atomic_store + +#define atomic_load(object) __c11_atomic_load(object, __ATOMIC_SEQ_CST) +#define atomic_load_explicit __c11_atomic_load + +#define atomic_exchange(object, desired) __c11_atomic_exchange(object, desired, __ATOMIC_SEQ_CST) +#define atomic_exchange_explicit __c11_atomic_exchange + +#define atomic_compare_exchange_strong(object, expected, desired) __c11_atomic_compare_exchange_strong(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_strong_explicit __c11_atomic_compare_exchange_strong + +#define atomic_compare_exchange_weak(object, expected, desired) __c11_atomic_compare_exchange_weak(object, expected, desired, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) +#define atomic_compare_exchange_weak_explicit __c11_atomic_compare_exchange_weak + +#define atomic_fetch_add(object, operand) __c11_atomic_fetch_add(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_add_explicit __c11_atomic_fetch_add + +#define atomic_fetch_sub(object, operand) __c11_atomic_fetch_sub(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_sub_explicit __c11_atomic_fetch_sub + +#define atomic_fetch_or(object, operand) __c11_atomic_fetch_or(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_or_explicit __c11_atomic_fetch_or + +#define atomic_fetch_xor(object, operand) __c11_atomic_fetch_xor(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_xor_explicit __c11_atomic_fetch_xor + +#define atomic_fetch_and(object, operand) __c11_atomic_fetch_and(object, operand, __ATOMIC_SEQ_CST) +#define atomic_fetch_and_explicit __c11_atomic_fetch_and + +typedef struct atomic_flag { _Atomic(_Bool) _Value; } atomic_flag; + +_Bool atomic_flag_test_and_set(volatile atomic_flag *); +_Bool atomic_flag_test_and_set_explicit(volatile atomic_flag *, memory_order); + +void atomic_flag_clear(volatile atomic_flag *); +void atomic_flag_clear_explicit(volatile atomic_flag *, memory_order); + +#define atomic_flag_test_and_set(object) __c11_atomic_exchange(&(object)->_Value, 1, __ATOMIC_SEQ_CST) +#define atomic_flag_test_and_set_explicit(object, order) __c11_atomic_exchange(&(object)->_Value, 1, order) + +#define atomic_flag_clear(object) __c11_atomic_store(&(object)->_Value, 0, __ATOMIC_SEQ_CST) +#define atomic_flag_clear_explicit(object, order) __c11_atomic_store(&(object)->_Value, 0, order) \ No newline at end of file diff --git a/c/common/test/rules/readofuninitializedmemory/test.c b/c/common/test/rules/readofuninitializedmemory/test.c index ce2c60484e..e76c5a22b3 100644 --- a/c/common/test/rules/readofuninitializedmemory/test.c +++ b/c/common/test/rules/readofuninitializedmemory/test.c @@ -94,4 +94,6 @@ void test_non_default_init() { static struct A ss; use_struct_A( ss); // COMPLIANT - static struct type variables are zero initialized + _Atomic int x; + use_int(x); // COMPLIANT - atomics are special, covered by other rules } \ No newline at end of file diff --git a/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql b/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql index 8292bd3b6f..c51ecbc81d 100644 --- a/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql +++ b/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql @@ -23,7 +23,11 @@ where baseTypeFrom = cast.getExpr().getType().(PointerToObjectType).getBaseType() and baseTypeTo = cast.getType().(PointerToObjectType).getBaseType() and // exception: cast to a char, signed char, or unsigned char is permitted - not baseTypeTo.stripType() instanceof CharType and + not ( + baseTypeTo.stripType() instanceof CharType and + // Exception does not apply to _Atomic types + not baseTypeFrom.hasSpecifier("atomic") + ) and ( ( baseTypeFrom.isVolatile() and not baseTypeTo.isVolatile() diff --git a/c/misra/src/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.ql b/c/misra/src/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.ql index 17b12aaf99..c0f447d5b5 100644 --- a/c/misra/src/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.ql +++ b/c/misra/src/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.ql @@ -24,5 +24,9 @@ where baseTypeFrom.isVolatile() and not baseTypeTo.isVolatile() and qualificationName = "volatile" or baseTypeFrom.isConst() and not baseTypeTo.isConst() and qualificationName = "const" + or + baseTypeFrom.hasSpecifier("atomic") and + not baseTypeTo.hasSpecifier("atomic") and + qualificationName = "atomic" ) select cast, "Cast of pointer removes " + qualificationName + " qualification from its base type." diff --git a/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql b/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql new file mode 100644 index 0000000000..d7638229d6 --- /dev/null +++ b/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql @@ -0,0 +1,94 @@ +/** + * @id c/misra/unsequenced-atomic-reads + * @name RULE-13-2: The value of an atomic variable depend on its evaluation order and interleave of threads + * @description The value of an atomic variable shall not depend on evaluation order and + * interleaving of threads. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-13-2 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import semmle.code.cpp.dataflow.TaintTracking +import codingstandards.c.misra +import codingstandards.c.Ordering +import codingstandards.c.orderofevaluation.VariableAccessOrdering + +class AtomicAccessInFullExpressionOrdering extends Ordering::Configuration { + AtomicAccessInFullExpressionOrdering() { this = "AtomicAccessInFullExpressionOrdering" } + + override predicate isCandidate(Expr e1, Expr e2) { + exists(AtomicVariableAccess a, AtomicVariableAccess b, FullExpr e | a = e1 and b = e2 | + a.getTarget() = b.getTarget() and + a.(ConstituentExpr).getFullExpr() = e and + b.(ConstituentExpr).getFullExpr() = e and + not a = b + ) + } +} + +/** + * A read of a variable specified as `_Atomic`. + * + * Note, it may be accessed directly, or by passing its address into the std atomic functions. + */ +class AtomicVariableAccess extends VariableAccess { + pragma[noinline] + AtomicVariableAccess() { + getTarget().getType().hasSpecifier("atomic") + } + + /* Get the `atomic_()` call this VarAccess occurs in. */ + FunctionCall getAtomicFunctionCall() { + exists(AddressOfExpr addrParent, FunctionCall fc | + fc.getTarget().getName().matches("__c11_atomic%") and + addrParent = fc.getArgument(0) and + addrParent.getAnOperand() = this + and result = fc + ) + } + + /** + * Gets an assigned expr, either in the form `x = ` or `atomic_store(&x, )`. + */ + Expr getAnAssignedExpr() { + result = getAtomicFunctionCall().getArgument(1) + or + exists(AssignExpr assign | + assign.getLValue() = this + and result = assign.getRValue() + ) + } + + /** + * Gets the expression holding this variable access, either in the form `x` or `atomic_read(&x)`. + */ + Expr getARead() { + result = getAtomicFunctionCall() + or + result = this + } +} + +from + AtomicAccessInFullExpressionOrdering config, FullExpr e, Variable v, + AtomicVariableAccess va1, AtomicVariableAccess va2 +where + not isExcluded(e, SideEffects3Package::unsequencedAtomicReadsQuery()) and + e = va1.(ConstituentExpr).getFullExpr() and + config.isUnsequenced(va1, va2) and + v = va1.getTarget() and + v = va2.getTarget() and + // Exclude cases where the variable is assigned a value tainted by the other variable access. + not exists(Expr write | + write = va1.getAnAssignedExpr() and + TaintTracking::localTaint(DataFlow::exprNode(va2.getARead()), DataFlow::exprNode(write)) + ) and + // Impose an ordering, show the first access. + va1.getLocation().isBefore(va2.getLocation(), _) +select e, "Atomic variable $@ has a $@ that is unsequenced with $@.", + v, v.getName(), va1, "previous read", va2, "another read" diff --git a/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql b/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql index 6eb605dbd9..58d449a59b 100644 --- a/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql +++ b/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql @@ -16,27 +16,38 @@ import cpp import codingstandards.c.misra -class IllegalCCommentCharacter extends string { - IllegalCCommentCharacter() { - this = "/*" or - this = "//" - } +/* Character sequence is banned from all comment types */ +class IllegalCommentSequence extends string { + IllegalCommentSequence() { this = "/*" } } -class IllegalCPPCommentCharacter extends string { - IllegalCPPCommentCharacter() { this = "/*" } +/* A regexp to check for illegal C-style comments */ +class IllegalCCommentRegexp extends string { + IllegalCCommentRegexp() { + // Regexp to match "//" in C-style comments, which do not appear to be URLs. General format + // uses negative lookahead/lookbehind to match like `.*(? 0 + exists(IllegalCommentSequence c | illegalSequence = c | + comment.getContents().indexOf(illegalSequence) > 0 ) or - exists(IllegalCPPCommentCharacter c | illegalSequence = c | - comment.(CppStyleComment).getContents().indexOf(illegalSequence) > 0 + exists(IllegalCCommentRegexp c | illegalSequence = c.getDescription() | + comment.(CStyleComment).getContents().regexpMatch(c) ) ) select comment, "Comment contains an illegal sequence '" + illegalSequence + "'" diff --git a/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected b/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected index 94cf6ee635..24e6c4d5af 100644 --- a/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected +++ b/c/misra/test/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.expected @@ -6,3 +6,7 @@ | test.c:21:3:21:16 | (int *)... | Cast performed between a pointer to object type (char) and a pointer to a different object type (int). | | test.c:22:20:22:21 | (int *)... | Cast performed between a pointer to object type (char) and a pointer to a different object type (int). | | test.c:23:3:23:18 | (long long *)... | Cast performed between a pointer to object type (int) and a pointer to a different object type (long long). | +| test.c:26:3:26:13 | (char *)... | Cast performed between a pointer to object type (_Atomic(int)) and a pointer to a different object type (char). | +| test.c:27:8:27:10 | (char *)... | Cast performed between a pointer to object type (_Atomic(int)) and a pointer to a different object type (char). | +| test.c:28:3:28:21 | (_Atomic(char) *)... | Cast performed between a pointer to object type (_Atomic(int)) and a pointer to a different object type (_Atomic(char)). | +| test.c:29:23:29:25 | (_Atomic(char) *)... | Cast performed between a pointer to object type (_Atomic(int)) and a pointer to a different object type (_Atomic(char)). | diff --git a/c/misra/test/rules/RULE-11-3/test.c b/c/misra/test/rules/RULE-11-3/test.c index 4730aeac03..0d91740438 100644 --- a/c/misra/test/rules/RULE-11-3/test.c +++ b/c/misra/test/rules/RULE-11-3/test.c @@ -21,4 +21,10 @@ void f1(void) { (int *const)v2; // NON_COMPLIANT int *const v10 = v2; // NON_COMPLIANT (long long *)v10; // NON_COMPLIANT + + _Atomic int *v11 = 0; + (char *)v11; // NON_COMPLIANT + v2 = v11; // NON_COMPLIANT + (_Atomic char *)v11; // NON_COMPLIANT + _Atomic char *v12 = v11; // NON_COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.expected b/c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.expected index 48658e2176..aa7752d28a 100644 --- a/c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.expected +++ b/c/misra/test/rules/RULE-11-8/CastRemovesConstOrVolatileQualification.expected @@ -1,2 +1,6 @@ | test.c:4:19:4:33 | (const char *)... | Cast of pointer removes volatile qualification from its base type. | | test.c:6:13:6:21 | (char *)... | Cast of pointer removes const qualification from its base type. | +| test.c:9:3:9:11 | (char *)... | Cast of pointer removes atomic qualification from its base type. | +| test.c:10:7:10:7 | (char *)... | Cast of pointer removes atomic qualification from its base type. | +| test.c:11:3:11:17 | (const char *)... | Cast of pointer removes atomic qualification from its base type. | +| test.c:12:7:12:7 | (const char *)... | Cast of pointer removes atomic qualification from its base type. | diff --git a/c/misra/test/rules/RULE-11-8/test.c b/c/misra/test/rules/RULE-11-8/test.c index 75c7fc189a..e0e3b3a2fb 100644 --- a/c/misra/test/rules/RULE-11-8/test.c +++ b/c/misra/test/rules/RULE-11-8/test.c @@ -5,5 +5,12 @@ int f1(void) { const char *c2 = (const char *)c; // COMPLIANT char *d = (char *)c; // NON_COMPLIANT const char *e = (const char *)d; // COMPLIANT + _Atomic char *f = 0; + (char *)f; // NON_COMPLIANT + d = f; // NON_COMPLIANT + (const char *)f; // NON_COMPLIANT + e = f; // NON_COMPLIANT + (const _Atomic char *)f; // COMPLIANT + (const _Atomic char *)f; // COMPLIANT return 0; } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected new file mode 100644 index 0000000000..e84aef7128 --- /dev/null +++ b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected @@ -0,0 +1,5 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:89,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:89,67-75) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:89,5-18) +| test.c:44:12:44:18 | ... + ... | Atomic variable $@ has a $@ that is unsequenced with $@. | test.c:42:15:42:16 | a1 | a1 | test.c:44:12:44:13 | a1 | previous read | test.c:44:17:44:18 | a1 | another read | +| test.c:46:3:46:37 | ... + ... | Atomic variable $@ has a $@ that is unsequenced with $@. | test.c:42:15:42:16 | a1 | a1 | test.c:46:16:46:17 | a1 | previous read | test.c:46:35:46:36 | a1 | another read | diff --git a/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.qlref b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.qlref new file mode 100644 index 0000000000..46242df1b0 --- /dev/null +++ b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.qlref @@ -0,0 +1 @@ +rules/RULE-13-2/UnsequencedAtomicReads.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-2/UnsequencedSideEffects.expected b/c/misra/test/rules/RULE-13-2/UnsequencedSideEffects.expected index 75bd8169ba..b6c704322c 100644 --- a/c/misra/test/rules/RULE-13-2/UnsequencedSideEffects.expected +++ b/c/misra/test/rules/RULE-13-2/UnsequencedSideEffects.expected @@ -1,6 +1,6 @@ -| test.c:6:12:6:18 | ... + ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:6:12:6:13 | l1 | side effect | test.c:6:12:6:13 | l1 | l1 | test.c:6:17:6:18 | l1 | side effect | test.c:6:17:6:18 | l1 | l1 | -| test.c:7:12:7:18 | ... + ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:7:12:7:13 | l1 | side effect | test.c:7:12:7:13 | l1 | l1 | test.c:7:17:7:18 | l2 | side effect | test.c:7:17:7:18 | l2 | l2 | -| test.c:17:3:17:21 | ... = ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:17:8:17:9 | l1 | side effect | test.c:17:8:17:9 | l1 | l1 | test.c:17:13:17:14 | l1 | side effect | test.c:17:13:17:14 | l1 | l1 | -| test.c:19:3:19:5 | call to foo | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:19:7:19:8 | l1 | side effect | test.c:19:7:19:8 | l1 | l1 | test.c:19:11:19:12 | l2 | side effect | test.c:19:11:19:12 | l2 | l2 | -| test.c:25:3:25:5 | call to foo | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:25:7:25:10 | ... ++ | side effect | test.c:25:7:25:8 | l8 | l8 | test.c:25:13:25:14 | l8 | read | test.c:25:13:25:14 | l8 | l8 | -| test.c:35:5:35:13 | ... = ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:35:10:35:12 | ... ++ | side effect | test.c:35:10:35:10 | i | i | test.c:35:10:35:12 | ... ++ | side effect | test.c:35:10:35:10 | i | i | \ No newline at end of file +| test.c:8:12:8:18 | ... + ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:8:12:8:13 | l1 | side effect | test.c:8:12:8:13 | l1 | l1 | test.c:8:17:8:18 | l1 | side effect | test.c:8:17:8:18 | l1 | l1 | +| test.c:9:12:9:18 | ... + ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:9:12:9:13 | l1 | side effect | test.c:9:12:9:13 | l1 | l1 | test.c:9:17:9:18 | l2 | side effect | test.c:9:17:9:18 | l2 | l2 | +| test.c:19:3:19:21 | ... = ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:19:8:19:9 | l1 | side effect | test.c:19:8:19:9 | l1 | l1 | test.c:19:13:19:14 | l1 | side effect | test.c:19:13:19:14 | l1 | l1 | +| test.c:21:3:21:5 | call to foo | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:21:7:21:8 | l1 | side effect | test.c:21:7:21:8 | l1 | l1 | test.c:21:11:21:12 | l2 | side effect | test.c:21:11:21:12 | l2 | l2 | +| test.c:27:3:27:5 | call to foo | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:27:7:27:10 | ... ++ | side effect | test.c:27:7:27:8 | l8 | l8 | test.c:27:13:27:14 | l8 | read | test.c:27:13:27:14 | l8 | l8 | +| test.c:37:5:37:13 | ... = ... | The expression contains unsequenced $@ to $@ and $@ to $@. | test.c:37:10:37:12 | ... ++ | side effect | test.c:37:10:37:10 | i | i | test.c:37:10:37:12 | ... ++ | side effect | test.c:37:10:37:10 | i | i | diff --git a/c/misra/test/rules/RULE-13-2/test.c b/c/misra/test/rules/RULE-13-2/test.c index 1bebec3775..6821a37296 100644 --- a/c/misra/test/rules/RULE-13-2/test.c +++ b/c/misra/test/rules/RULE-13-2/test.c @@ -1,3 +1,5 @@ +#include + void foo(int, int); void unsequenced_sideeffects1() { @@ -34,4 +36,15 @@ void unsequenced_sideeffects2() { for (i = 0; i < 10; i++) { test(i++); // NON_COMPLIANT } +} + +void atomics() { + _Atomic int a1, a2; + int l3 = a1 + a2; // COMPLIANT + int l4 = a1 + a1; // NON_COMPLIANT + a1 = a1 + 1; // COMPLIANT + atomic_load(&a1) + atomic_load(&a1); // NON_COMPLIANT + atomic_load(&a1) + atomic_load(&a2); // COMPLIANT + atomic_store(&a1, atomic_load(&a1)); // COMPLIANT + atomic_store(&a1, a1); // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected b/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected index 5e876cecc3..5008fb100d 100644 --- a/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected +++ b/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected @@ -1,3 +1,5 @@ | test.c:9:1:9:8 | /* /* */ | Comment contains an illegal sequence '/*' | | test.c:12:1:12:8 | /* // */ | Comment contains an illegal sequence '//' | | test.c:21:1:21:7 | // /* | Comment contains an illegal sequence '/*' | +| test.c:30:1:30:27 | /* https://github.com // */ | Comment contains an illegal sequence '//' | +| test.c:33:1:33:60 | /* a://b, a://b., ://a.b, a://b., a://.b, ://, a://, ://b */ | Comment contains an illegal sequence '//' | diff --git a/c/misra/test/rules/RULE-3-1/test.c b/c/misra/test/rules/RULE-3-1/test.c index c1a135f972..ad61fd0f91 100644 --- a/c/misra/test/rules/RULE-3-1/test.c +++ b/c/misra/test/rules/RULE-3-1/test.c @@ -20,4 +20,19 @@ // NON_COMPLIANT // /* +// COMPLIANT +/* https://github.com */ + +// COMPLIANT +/* https://name-with-hyphen-and-num-12345.com */ + +// NON_COMPLIANT +/* https://github.com // */ + +// NON_COMPLIANT +/* a://b, a://b., ://a.b, a://b., a://.b, ://, a://, ://b */ + +// COMPLIANT +// https://github.com + void f(){} \ No newline at end of file diff --git a/change_notes/2024-12-13-implement-misra-c-amendment4-rule-amendments.md b/change_notes/2024-12-13-implement-misra-c-amendment4-rule-amendments.md new file mode 100644 index 0000000000..a8fbd282d8 --- /dev/null +++ b/change_notes/2024-12-13-implement-misra-c-amendment4-rule-amendments.md @@ -0,0 +1,10 @@ + - `RULE-11-3` - `CastBetweenObjectPointerAndDifferentObjectType.ql` + - Constrain exception that pointer types to may be cast to char types, so that it does not apply to atomic pointer types, in compliance with MISRA-C 2012 Amendment 4. + - `RULE-11-8` - `CastRemovesConstOrVolatileQualification.ql` + - Query expanded to detect cases of removing `_Atomic` qualification, in compliance with MISRA-C 2012 Amendment 4. + - `EXP33-C`, `RULE-9-1`, `A8-5-0`, `EXP53-CPP` - `DoNotReadUninitializedMemory.ql`, `ObjectWithAutoStorageDurationReadBeforeInit.ql`, `MemoryNotInitializedBeforeItIsRead.ql`, `DoNotReadUninitializedMemory.ql` + - Atomic local variables excluded from query results, in compliance with MISRA-C 2012 Amendment 4, and to reduce false positives in the other standards. + - `RULE-13-2` - `UnsequencedAtomicReads.ql` + - New query to find expressions which read an atomic variable more than once between sequence points, to address new case from MISRA-C 2012 Amendment 4. + - `RULE-3-1` - `CharacterSequencesAndUsedWithinAComment.ql` + - Add exception allowing URLs inside of cpp-style `/* ... */` comments, in compliance with MISRA-C 2012 Amendment 4 \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects3.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects3.qll index eff4f2caf9..7b01c18099 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects3.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/SideEffects3.qll @@ -3,7 +3,9 @@ import cpp import RuleMetadata import codingstandards.cpp.exclusions.RuleMetadata -newtype SideEffects3Query = TUnsequencedSideEffectsQuery() +newtype SideEffects3Query = + TUnsequencedSideEffectsQuery() or + TUnsequencedAtomicReadsQuery() predicate isSideEffects3QueryMetadata(Query query, string queryId, string ruleId, string category) { query = @@ -14,6 +16,15 @@ predicate isSideEffects3QueryMetadata(Query query, string queryId, string ruleId "c/misra/unsequenced-side-effects" and ruleId = "RULE-13-2" and category = "required" + or + query = + // `Query` instance for the `unsequencedAtomicReads` query + SideEffects3Package::unsequencedAtomicReadsQuery() and + queryId = + // `@id` for the `unsequencedAtomicReads` query + "c/misra/unsequenced-atomic-reads" and + ruleId = "RULE-13-2" and + category = "required" } module SideEffects3Package { @@ -23,4 +34,11 @@ module SideEffects3Package { // `Query` type for `unsequencedSideEffects` query TQueryC(TSideEffects3PackageQuery(TUnsequencedSideEffectsQuery())) } + + Query unsequencedAtomicReadsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unsequencedAtomicReads` query + TQueryC(TSideEffects3PackageQuery(TUnsequencedAtomicReadsQuery())) + } } diff --git a/cpp/common/src/codingstandards/cpp/rules/readofuninitializedmemory/ReadOfUninitializedMemory.qll b/cpp/common/src/codingstandards/cpp/rules/readofuninitializedmemory/ReadOfUninitializedMemory.qll index 9de640db9c..8d701cb26c 100644 --- a/cpp/common/src/codingstandards/cpp/rules/readofuninitializedmemory/ReadOfUninitializedMemory.qll +++ b/cpp/common/src/codingstandards/cpp/rules/readofuninitializedmemory/ReadOfUninitializedMemory.qll @@ -131,6 +131,8 @@ class UninitializedVariable extends LocalVariable { // Not static or thread local, because they are not initialized with indeterminate values not isStatic() and not isThreadLocal() and + // Not atomic, which have special initialization rules + not getType().hasSpecifier("atomic") and // Not a class type, because default initialization of a class calls the default constructor // The default constructor may leave certain fields uninitialized, but that would be a separate // field-wise analysis diff --git a/cpp/common/test/rules/readofuninitializedmemory/test.cpp b/cpp/common/test/rules/readofuninitializedmemory/test.cpp index bdd3fdc203..6ed07d795f 100644 --- a/cpp/common/test/rules/readofuninitializedmemory/test.cpp +++ b/cpp/common/test/rules/readofuninitializedmemory/test.cpp @@ -121,4 +121,6 @@ void test_non_default_init() { use(slp); // COMPLIANT - static variables are zero initialized thread_local int *tlp; use(tlp); // COMPLIANT - thread local variables are zero initialized + _Atomic int ai; + use(ai); // COMPLIANT - atomics are special and not covered by this rule } \ No newline at end of file diff --git a/rule_packages/c/SideEffects3.json b/rule_packages/c/SideEffects3.json index 2bf91d77b9..369f5db9ee 100644 --- a/rule_packages/c/SideEffects3.json +++ b/rule_packages/c/SideEffects3.json @@ -16,6 +16,18 @@ "correctness", "external/misra/c/2012/third-edition-first-revision" ] + }, + { + "description": "The value of an atomic variable shall not depend on evaluation order and interleaving of threads.", + "kind": "problem", + "name": "The value of an atomic variable depend on its evaluation order and interleave of threads", + "precision": "very-high", + "severity": "error", + "short_name": "UnsequencedAtomicReads", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] } ], "title": "The value of an expression and its persistent side effects shall be the same under all permitted evaluation orders" From 8403a4bcd6d5f52afd8ab29441b33b52c002e3bd Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 18 Dec 2024 18:39:46 -0800 Subject: [PATCH 168/628] Fix format --- .../rules/RULE-13-2/UnsequencedAtomicReads.ql | 24 +++++++++---------- c/misra/test/rules/RULE-13-2/test.c | 8 +++---- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql b/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql index d7638229d6..68f00be15f 100644 --- a/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql +++ b/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql @@ -33,22 +33,20 @@ class AtomicAccessInFullExpressionOrdering extends Ordering::Configuration { /** * A read of a variable specified as `_Atomic`. - * + * * Note, it may be accessed directly, or by passing its address into the std atomic functions. */ class AtomicVariableAccess extends VariableAccess { pragma[noinline] - AtomicVariableAccess() { - getTarget().getType().hasSpecifier("atomic") - } + AtomicVariableAccess() { getTarget().getType().hasSpecifier("atomic") } /* Get the `atomic_()` call this VarAccess occurs in. */ FunctionCall getAtomicFunctionCall() { exists(AddressOfExpr addrParent, FunctionCall fc | fc.getTarget().getName().matches("__c11_atomic%") and addrParent = fc.getArgument(0) and - addrParent.getAnOperand() = this - and result = fc + addrParent.getAnOperand() = this and + result = fc ) } @@ -59,8 +57,8 @@ class AtomicVariableAccess extends VariableAccess { result = getAtomicFunctionCall().getArgument(1) or exists(AssignExpr assign | - assign.getLValue() = this - and result = assign.getRValue() + assign.getLValue() = this and + result = assign.getRValue() ) } @@ -75,8 +73,8 @@ class AtomicVariableAccess extends VariableAccess { } from - AtomicAccessInFullExpressionOrdering config, FullExpr e, Variable v, - AtomicVariableAccess va1, AtomicVariableAccess va2 + AtomicAccessInFullExpressionOrdering config, FullExpr e, Variable v, AtomicVariableAccess va1, + AtomicVariableAccess va2 where not isExcluded(e, SideEffects3Package::unsequencedAtomicReadsQuery()) and e = va1.(ConstituentExpr).getFullExpr() and @@ -89,6 +87,6 @@ where TaintTracking::localTaint(DataFlow::exprNode(va2.getARead()), DataFlow::exprNode(write)) ) and // Impose an ordering, show the first access. - va1.getLocation().isBefore(va2.getLocation(), _) -select e, "Atomic variable $@ has a $@ that is unsequenced with $@.", - v, v.getName(), va1, "previous read", va2, "another read" + va1.getLocation().isBefore(va2.getLocation(), _) +select e, "Atomic variable $@ has a $@ that is unsequenced with $@.", v, v.getName(), va1, + "previous read", va2, "another read" diff --git a/c/misra/test/rules/RULE-13-2/test.c b/c/misra/test/rules/RULE-13-2/test.c index 6821a37296..e1be53a037 100644 --- a/c/misra/test/rules/RULE-13-2/test.c +++ b/c/misra/test/rules/RULE-13-2/test.c @@ -40,11 +40,11 @@ void unsequenced_sideeffects2() { void atomics() { _Atomic int a1, a2; - int l3 = a1 + a2; // COMPLIANT - int l4 = a1 + a1; // NON_COMPLIANT - a1 = a1 + 1; // COMPLIANT + int l3 = a1 + a2; // COMPLIANT + int l4 = a1 + a1; // NON_COMPLIANT + a1 = a1 + 1; // COMPLIANT atomic_load(&a1) + atomic_load(&a1); // NON_COMPLIANT atomic_load(&a1) + atomic_load(&a2); // COMPLIANT atomic_store(&a1, atomic_load(&a1)); // COMPLIANT - atomic_store(&a1, a1); // COMPLIANT + atomic_store(&a1, a1); // COMPLIANT } \ No newline at end of file From 7732fd690d5704f939acc732e96581f83e00772b Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 19 Dec 2024 12:49:47 -0800 Subject: [PATCH 169/628] Fix cert test --- .../CON40-C/AtomicVariableTwiceInExpression.expected | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/c/cert/test/rules/CON40-C/AtomicVariableTwiceInExpression.expected b/c/cert/test/rules/CON40-C/AtomicVariableTwiceInExpression.expected index ddff311b59..42d3ea924d 100644 --- a/c/cert/test/rules/CON40-C/AtomicVariableTwiceInExpression.expected +++ b/c/cert/test/rules/CON40-C/AtomicVariableTwiceInExpression.expected @@ -1,6 +1,6 @@ | test.c:7:18:7:39 | ATOMIC_VAR_INIT(value) | Atomic variable possibly referred to twice in an $@. | test.c:33:3:33:10 | ... += ... | expression | | test.c:7:18:7:39 | ATOMIC_VAR_INIT(value) | Atomic variable possibly referred to twice in an $@. | test.c:34:3:34:13 | ... = ... | expression | -| test.c:11:3:11:23 | atomic_store(a,b) | Atomic variable possibly referred to twice in an $@. | test.c:11:3:11:23 | atomic_store(a,b) | expression | -| test.c:12:3:12:35 | atomic_store_explicit(a,b,c) | Atomic variable possibly referred to twice in an $@. | test.c:12:3:12:35 | atomic_store_explicit(a,b,c) | expression | -| test.c:25:3:25:49 | atomic_compare_exchange_weak(a,b,c) | Atomic variable possibly referred to twice in an $@. | test.c:25:3:25:49 | atomic_compare_exchange_weak(a,b,c) | expression | -| test.c:26:3:27:42 | atomic_compare_exchange_weak_explicit(a,b,c,d,e) | Atomic variable possibly referred to twice in an $@. | test.c:26:3:27:42 | atomic_compare_exchange_weak_explicit(a,b,c,d,e) | expression | +| test.c:11:3:11:23 | atomic_store(object,desired) | Atomic variable possibly referred to twice in an $@. | test.c:11:3:11:23 | atomic_store(object,desired) | expression | +| test.c:12:3:12:23 | atomic_store_explicit | Atomic variable possibly referred to twice in an $@. | test.c:12:3:12:23 | atomic_store_explicit | expression | +| test.c:25:3:25:49 | atomic_compare_exchange_weak(object,expected,desired) | Atomic variable possibly referred to twice in an $@. | test.c:25:3:25:49 | atomic_compare_exchange_weak(object,expected,desired) | expression | +| test.c:26:3:26:39 | atomic_compare_exchange_weak_explicit | Atomic variable possibly referred to twice in an $@. | test.c:26:3:26:39 | atomic_compare_exchange_weak_explicit | expression | From 45e6b5289862db731a59e025ec5b2fab5ff8bc2a Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 20 Dec 2024 13:43:59 -0800 Subject: [PATCH 170/628] fix tests --- .../WrapFunctionsThatCanFailSpuriouslyInLoop.expected | 8 ++++---- .../test/rules/RULE-13-2/UnsequencedAtomicReads.expected | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/c/cert/test/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.expected b/c/cert/test/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.expected index 0c1e25cd00..b1c224173e 100644 --- a/c/cert/test/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.expected +++ b/c/cert/test/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.expected @@ -1,4 +1,4 @@ -| test.c:6:8:6:46 | atomic_compare_exchange_weak(a,b,c) | Function that can spuriously fail not wrapped in a loop. | -| test.c:10:3:10:41 | atomic_compare_exchange_weak(a,b,c) | Function that can spuriously fail not wrapped in a loop. | -| test.c:12:8:13:47 | atomic_compare_exchange_weak_explicit(a,b,c,d,e) | Function that can spuriously fail not wrapped in a loop. | -| test.c:17:3:17:56 | atomic_compare_exchange_weak_explicit(a,b,c,d,e) | Function that can spuriously fail not wrapped in a loop. | +| test.c:6:8:6:46 | atomic_compare_exchange_weak(object,expected,desired) | Function that can spuriously fail not wrapped in a loop. | +| test.c:10:3:10:41 | atomic_compare_exchange_weak(object,expected,desired) | Function that can spuriously fail not wrapped in a loop. | +| test.c:12:8:12:44 | atomic_compare_exchange_weak_explicit | Function that can spuriously fail not wrapped in a loop. | +| test.c:17:3:17:39 | atomic_compare_exchange_weak_explicit | Function that can spuriously fail not wrapped in a loop. | diff --git a/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected index e84aef7128..2231a83735 100644 --- a/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected +++ b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected @@ -1,5 +1,5 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:89,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:89,67-75) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:89,5-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:87,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:87,67-75) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:87,5-18) | test.c:44:12:44:18 | ... + ... | Atomic variable $@ has a $@ that is unsequenced with $@. | test.c:42:15:42:16 | a1 | a1 | test.c:44:12:44:13 | a1 | previous read | test.c:44:17:44:18 | a1 | another read | | test.c:46:3:46:37 | ... + ... | Atomic variable $@ has a $@ that is unsequenced with $@. | test.c:42:15:42:16 | a1 | a1 | test.c:46:16:46:17 | a1 | previous read | test.c:46:35:46:36 | a1 | another read | From 81ff0c08005b59e4b2bcd87c97b30da738e4e435 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 27 Dec 2024 23:38:55 +0000 Subject: [PATCH 171/628] Skip external help integration from forks PRs from forks do not have access to the help repo. --- .github/workflows/code-scanning-pack-gen.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/code-scanning-pack-gen.yml b/.github/workflows/code-scanning-pack-gen.yml index 1b620260c3..51ffb1edb7 100644 --- a/.github/workflows/code-scanning-pack-gen.yml +++ b/.github/workflows/code-scanning-pack-gen.yml @@ -80,6 +80,8 @@ jobs: - name: Checkout external help files id: checkout-external-help-files + # Forks do not have access to an appropriate token for the help files + if: !github.event.pull_request.head.repo.fork uses: actions/checkout@v4 with: ssh-key: ${{ secrets.CODEQL_CODING_STANDARDS_HELP_KEY }} @@ -88,7 +90,7 @@ jobs: path: external-help-files - name: Include external help files - if: steps.checkout-external-help-files.outcome == 'success' + if: !github.event.pull_request.head.repo.fork && steps.checkout-external-help-files.outcome == 'success' run: | pushd external-help-files find . -name '*.md' -exec rsync -av --relative {} "$GITHUB_WORKSPACE" \; From 30fdad18a36ea99fa6049748373b8b7bc2b59a38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 30 Dec 2024 04:17:43 +0000 Subject: [PATCH 172/628] Bump peter-evans/create-pull-request from 7.0.5 to 7.0.6 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 7.0.5 to 7.0.6. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/5e914681df9dc83aa4e4905692ca88beb2f9e91f...67ccf781d68cd99b580ae25a5c18a1cc84ffff1f) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/upgrade_codeql_dependencies.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/upgrade_codeql_dependencies.yml b/.github/workflows/upgrade_codeql_dependencies.yml index 841b78fcd6..ca6779871e 100644 --- a/.github/workflows/upgrade_codeql_dependencies.yml +++ b/.github/workflows/upgrade_codeql_dependencies.yml @@ -53,7 +53,7 @@ jobs: find c \( -name '*.ql' -or -name '*.qll' \) -print0 | xargs -0 --max-procs "$XARGS_MAX_PROCS" codeql query format --in-place - name: Create Pull Request - uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7.0.5 + uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6 with: title: "Upgrade `github/codeql` dependency to ${{ github.event.inputs.codeql_cli_version }}" body: | From 99af17c4b0737a51b460456bc82f6757f4f8868a Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sat, 4 Jan 2025 21:00:10 -0800 Subject: [PATCH 173/628] Implement RULE-11-10 banning atomic void. --- .../AtomicQualifierAppliedToVoid.ql | 36 +++++++++++++++++++ .../AtomicQualifierAppliedToVoid.expected | 3 ++ .../AtomicQualifierAppliedToVoid.qlref | 1 + c/misra/test/rules/RULE-11-10/test.c | 18 ++++++++++ .../cpp/exclusions/c/Declarations9.qll | 26 ++++++++++++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 ++ rule_packages/c/Declarations9.json | 25 +++++++++++++ rules.csv | 2 +- 8 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 c/misra/src/rules/RULE-11-10/AtomicQualifierAppliedToVoid.ql create mode 100644 c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected create mode 100644 c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.qlref create mode 100644 c/misra/test/rules/RULE-11-10/test.c create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Declarations9.qll create mode 100644 rule_packages/c/Declarations9.json diff --git a/c/misra/src/rules/RULE-11-10/AtomicQualifierAppliedToVoid.ql b/c/misra/src/rules/RULE-11-10/AtomicQualifierAppliedToVoid.ql new file mode 100644 index 0000000000..d867241518 --- /dev/null +++ b/c/misra/src/rules/RULE-11-10/AtomicQualifierAppliedToVoid.ql @@ -0,0 +1,36 @@ +/** + * @id c/misra/atomic-qualifier-applied-to-void + * @name RULE-11-10: The _Atomic qualifier shall not be applied to the incomplete type void + * @description Conversions between types by using an _Atomic void type may result in undefined + * behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-11-10 + * correctness + * external/misra/c/2012/third-edition-first-revision + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +class AtomicVoidType extends Type { + AtomicVoidType() { + hasSpecifier("atomic") and + getUnspecifiedType() instanceof VoidType + } +} + +Type getNestedType(Type root) { + result = root + or + exists(DerivedType derived | derived = root | result = getNestedType(derived.getBaseType())) +} + +from DeclarationEntry decl, AtomicVoidType atomicVoid +where + not isExcluded(decl, Declarations9Package::atomicQualifierAppliedToVoidQuery()) and + atomicVoid = getNestedType(decl.getType()) +select decl, decl.getName() + " declared with an atomic void type." diff --git a/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected b/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected new file mode 100644 index 0000000000..e3a6746ae7 --- /dev/null +++ b/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected @@ -0,0 +1,3 @@ +| test.c:3:15:3:16 | definition of g3 | g3 declared with an atomic void type. | +| test.c:10:17:10:18 | definition of m3 | m3 declared with an atomic void type. | +| test.c:15:22:15:23 | definition of p2 | p2 declared with an atomic void type. | diff --git a/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.qlref b/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.qlref new file mode 100644 index 0000000000..2046575237 --- /dev/null +++ b/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.qlref @@ -0,0 +1 @@ +rules/RULE-11-10/AtomicQualifierAppliedToVoid.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-11-10/test.c b/c/misra/test/rules/RULE-11-10/test.c new file mode 100644 index 0000000000..e030345dde --- /dev/null +++ b/c/misra/test/rules/RULE-11-10/test.c @@ -0,0 +1,18 @@ +// _Atomic void g1; // doesn't compile +_Atomic int g2; // COMPLIANT +_Atomic void *g3; // NON_COMPLIANT +// _Atomic void g4[]; // doesn't compile +void *_Atomic g5; // COMPLIANT + +struct { + _Atomic int m1; // COMPLIANT + // _Atomic void m2; // doesn't compile + _Atomic void *m3; // NON_COMPLIANT + void *_Atomic m4; // COMPLIANT +} s1; + +void f(_Atomic int p1, // COMPLIANT + _Atomic void *p2 // NON_COMPLIANT + // _Atomic void p3[] // doesn't compile, even though it perhaps should as + // it is adjusted to void*. +) {} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations9.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations9.qll new file mode 100644 index 0000000000..8a63e50ed4 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations9.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Declarations9Query = TAtomicQualifierAppliedToVoidQuery() + +predicate isDeclarations9QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `atomicQualifierAppliedToVoid` query + Declarations9Package::atomicQualifierAppliedToVoidQuery() and + queryId = + // `@id` for the `atomicQualifierAppliedToVoid` query + "c/misra/atomic-qualifier-applied-to-void" and + ruleId = "RULE-11-10" and + category = "required" +} + +module Declarations9Package { + Query atomicQualifierAppliedToVoidQuery() { + //autogenerate `Query` type + result = + // `Query` type for `atomicQualifierAppliedToVoid` query + TQueryC(TDeclarations9PackageQuery(TAtomicQualifierAppliedToVoidQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 1562ba7894..448b764526 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -28,6 +28,7 @@ import Declarations5 import Declarations6 import Declarations7 import Declarations8 +import Declarations9 import EssentialTypes import Expressions import FloatingTypes @@ -107,6 +108,7 @@ newtype TCQuery = TDeclarations6PackageQuery(Declarations6Query q) or TDeclarations7PackageQuery(Declarations7Query q) or TDeclarations8PackageQuery(Declarations8Query q) or + TDeclarations9PackageQuery(Declarations9Query q) or TEssentialTypesPackageQuery(EssentialTypesQuery q) or TExpressionsPackageQuery(ExpressionsQuery q) or TFloatingTypesPackageQuery(FloatingTypesQuery q) or @@ -186,6 +188,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isDeclarations6QueryMetadata(query, queryId, ruleId, category) or isDeclarations7QueryMetadata(query, queryId, ruleId, category) or isDeclarations8QueryMetadata(query, queryId, ruleId, category) or + isDeclarations9QueryMetadata(query, queryId, ruleId, category) or isEssentialTypesQueryMetadata(query, queryId, ruleId, category) or isExpressionsQueryMetadata(query, queryId, ruleId, category) or isFloatingTypesQueryMetadata(query, queryId, ruleId, category) or diff --git a/rule_packages/c/Declarations9.json b/rule_packages/c/Declarations9.json new file mode 100644 index 0000000000..ebfcf7c41f --- /dev/null +++ b/rule_packages/c/Declarations9.json @@ -0,0 +1,25 @@ +{ + "MISRA-C-2012": { + "RULE-11-10": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Conversions between types by using an _Atomic void type may result in undefined behavior.", + "kind": "problem", + "name": "The _Atomic qualifier shall not be applied to the incomplete type void", + "precision": "very-high", + "severity": "error", + "short_name": "AtomicQualifierAppliedToVoid", + "tags": [ + "correctness", + "external/misra/c/2012/third-edition-first-revision", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "The _Atomic qualifier shall not be applied to the incomplete type void" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index 475ea1d66c..6657055cad 100644 --- a/rules.csv +++ b/rules.csv @@ -677,7 +677,7 @@ c,MISRA-C-2012,RULE-9-2,Yes,Required,,,The initializer for an aggregate or union c,MISRA-C-2012,RULE-9-3,Yes,Required,,,Arrays shall not be partially initialized,,Memory1,Medium, c,MISRA-C-2012,RULE-9-4,Yes,Required,,,An element of an object shall not be initialized more than once,,Memory1,Medium, c,MISRA-C-2012,RULE-9-5,No,Required,,,Where designated initializers are used to initialize an array object the size of the array shall be specified explicitly,,,Medium, -c,MISRA-C-2012,RULE-9-6,Yes,Required,,,An initializer using chained designators shall not contain initializers without designators,,Declarations9,Hard, +c,MISRA-C-2012,RULE-9-6,Yes,Required,,,An initializer using chained designators shall not contain initializers without designators,,Declarations10,Hard, c,MISRA-C-2012,RULE-9-7,Yes,Mandatory,,,Atomic objects shall be appropriately initialized before being accessed,,Concurrency6,Hard, c,MISRA-C-2012,RULE-10-1,Yes,Required,,,Operands shall not be of an inappropriate essential type,,EssentialTypes,Hard, c,MISRA-C-2012,RULE-10-2,Yes,Required,,,Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations,,EssentialTypes,Medium, From 6b8ba85dea62ff4ebac192b15db278e51cb431c0 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Sun, 5 Jan 2025 23:05:14 +0000 Subject: [PATCH 174/628] Update rules.csv Use Contracts8 as next entry --- rules.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules.csv b/rules.csv index 8391149b9f..a7f6c1f0db 100644 --- a/rules.csv +++ b/rules.csv @@ -615,7 +615,7 @@ c,MISRA-C-2012,DIR-4-10,Yes,Required,,,Precautions shall be taken in order to pr c,MISRA-C-2012,DIR-4-11,Yes,Required,,,The validity of values passed to library functions shall be checked,,Contracts,Hard, c,MISRA-C-2012,DIR-4-12,Yes,Required,,,Dynamic memory allocation shall not be used,,Banned,Medium, c,MISRA-C-2012,DIR-4-13,No,Advisory,,,Functions which are designed to provide operations on a resource should be called in an appropriate sequence,,,,"Rule 22.1, 22.2 and 22.6 cover aspects of this rule. In other cases this is a design issue and needs to be checked manually." -c,MISRA-C-2012,DIR-4-14,Yes,Required,,,The validity of values received from external sources shall be checked,,Contracts9,Hard,This is supported by CodeQLs default C security queries. +c,MISRA-C-2012,DIR-4-14,Yes,Required,,,The validity of values received from external sources shall be checked,,Contracts8,Hard,This is supported by CodeQLs default C security queries. c,MISRA-C-2012,RULE-1-1,No,Required,,,"The program shall contain no violations of the standard C syntax and constraints, and shall not exceed the implementation's translation limits",,,Easy,"This should be checked via the compiler output, rather than CodeQL, which adds unnecessary steps." c,MISRA-C-2012,RULE-1-2,Yes,Advisory,,,Language extensions should not be used,,Language3,Hard, c,MISRA-C-2012,RULE-1-3,Yes,Required,,,There shall be no occurrence of undefined or critical unspecified behaviour,,Language3,Hard, From 6f595af4c404c3d77e6eea7f7f0568ecb4d5c189 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Mon, 6 Jan 2025 10:21:17 +0000 Subject: [PATCH 175/628] Exclude Dependabot PRs from help checkout Dependabot does not have access to the external help repo. --- .github/workflows/code-scanning-pack-gen.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code-scanning-pack-gen.yml b/.github/workflows/code-scanning-pack-gen.yml index 51ffb1edb7..b67db3d413 100644 --- a/.github/workflows/code-scanning-pack-gen.yml +++ b/.github/workflows/code-scanning-pack-gen.yml @@ -81,7 +81,7 @@ jobs: - name: Checkout external help files id: checkout-external-help-files # Forks do not have access to an appropriate token for the help files - if: !github.event.pull_request.head.repo.fork + if: !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' uses: actions/checkout@v4 with: ssh-key: ${{ secrets.CODEQL_CODING_STANDARDS_HELP_KEY }} @@ -90,7 +90,7 @@ jobs: path: external-help-files - name: Include external help files - if: !github.event.pull_request.head.repo.fork && steps.checkout-external-help-files.outcome == 'success' + if: !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]'&& steps.checkout-external-help-files.outcome == 'success' run: | pushd external-help-files find . -name '*.md' -exec rsync -av --relative {} "$GITHUB_WORKSPACE" \; From b817d0cde9701c3d2b1e343a9eb37ab224f6aff7 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:17:03 +0000 Subject: [PATCH 176/628] Improve comment Explain why we exclude dependabot PRs. --- .github/workflows/code-scanning-pack-gen.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-scanning-pack-gen.yml b/.github/workflows/code-scanning-pack-gen.yml index b67db3d413..85a157d8b6 100644 --- a/.github/workflows/code-scanning-pack-gen.yml +++ b/.github/workflows/code-scanning-pack-gen.yml @@ -80,7 +80,7 @@ jobs: - name: Checkout external help files id: checkout-external-help-files - # Forks do not have access to an appropriate token for the help files + # PRs from forks and dependabot do not have access to an appropriate token for cloning the help files repos if: !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' uses: actions/checkout@v4 with: From b952fc8595c121804533c184eeeed739d138c09e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 6 Jan 2025 23:27:04 +0000 Subject: [PATCH 177/628] Use expression syntax --- .github/workflows/code-scanning-pack-gen.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code-scanning-pack-gen.yml b/.github/workflows/code-scanning-pack-gen.yml index 85a157d8b6..678b3be403 100644 --- a/.github/workflows/code-scanning-pack-gen.yml +++ b/.github/workflows/code-scanning-pack-gen.yml @@ -81,7 +81,7 @@ jobs: - name: Checkout external help files id: checkout-external-help-files # PRs from forks and dependabot do not have access to an appropriate token for cloning the help files repos - if: !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' + if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' }} uses: actions/checkout@v4 with: ssh-key: ${{ secrets.CODEQL_CODING_STANDARDS_HELP_KEY }} @@ -90,7 +90,7 @@ jobs: path: external-help-files - name: Include external help files - if: !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]'&& steps.checkout-external-help-files.outcome == 'success' + if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]'&& steps.checkout-external-help-files.outcome == 'success' }} run: | pushd external-help-files find . -name '*.md' -exec rsync -av --relative {} "$GITHUB_WORKSPACE" \; From d9a41f0f5b559e44753bdf25fa1b6f84e6a2ac60 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Thu, 9 Jan 2025 14:14:17 +0100 Subject: [PATCH 178/628] Update A2-10-4 after QL changes --- .../IdentifierNameOfStaticNonMemberObjectReusedInNamespace.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/autosar/src/rules/A2-10-4/IdentifierNameOfStaticNonMemberObjectReusedInNamespace.ql b/cpp/autosar/src/rules/A2-10-4/IdentifierNameOfStaticNonMemberObjectReusedInNamespace.ql index e04bb89cfa..79e17305fb 100644 --- a/cpp/autosar/src/rules/A2-10-4/IdentifierNameOfStaticNonMemberObjectReusedInNamespace.ql +++ b/cpp/autosar/src/rules/A2-10-4/IdentifierNameOfStaticNonMemberObjectReusedInNamespace.ql @@ -22,7 +22,7 @@ class CandidateVariable extends Variable { isStatic() and not this instanceof MemberVariable and //exclude partially specialized template variables - not exists(TemplateVariable v | this = v.getAnInstantiation()) + not this.isSpecialization() } } From 0c7b50321f47936b7857e7e5f788a62c2596bae4 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 10 Jan 2025 20:06:49 -0800 Subject: [PATCH 179/628] save work --- amendments.csv | 12 +- .../c/misra/EssentialTypes.qll | 10 +- ...dditionSubtractionOnEssentiallyCharType.ql | 2 +- ...nSubtractionOnEssentiallyCharType.expected | 34 ++-- c/misra/test/rules/RULE-10-2/test.c | 14 +- .../ControllingExprInvariant.expected | 1 + c/misra/test/rules/RULE-14-3/test.c | 7 + ...ringLiteralAssignedToNonConstChar.expected | 1 + c/misra/test/rules/RULE-7-4/test.c | 12 ++ c/misra/test/rules/RULE-8-3/function1.c | 4 + c/misra/test/rules/RULE-8-3/function2.c | 4 +- ...025-1-04-misra-c-technical-corrigenda-2.md | 11 ++ .../src/codingstandards/cpp/Compatible.qll | 8 +- ...nterArithmeticToAddressDifferentArrays.qll | 158 ++++++++++++++---- .../InvalidatedEnvStringPointers.qll | 6 + ...rithmeticToAddressDifferentArrays.expected | 14 +- .../test.cpp | 24 +++ .../InvalidatedEnvStringPointers.expected | 5 + .../invalidatedenvstringpointers/test.cpp | 37 ++++ 19 files changed, 298 insertions(+), 66 deletions(-) create mode 100644 change_notes/2025-1-04-misra-c-technical-corrigenda-2.md diff --git a/amendments.csv b/amendments.csv index ce285a29ba..20eb874fde 100644 --- a/amendments.csv +++ b/amendments.csv @@ -28,22 +28,22 @@ c,MISRA-C-2012,Corrigendum2,RULE-1-4,Yes,Replace,No,Easy c,MISRA-C-2012,Corrigendum2,RULE-9-1,Yes,Refine,No,Easy c,MISRA-C-2012,Corrigendum2,RULE-9-2,Yes,Refine,No,Import c,MISRA-C-2012,Corrigendum2,DIR-4-10,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-7-4,Yes,Refine,No,Easy +c,MISRA-C-2012,Corrigendum2,RULE-7-4,Yes,Refine,Yes,Easy c,MISRA-C-2012,Corrigendum2,RULE-8-2,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-8-3,Yes,Refine,No,Easy +c,MISRA-C-2012,Corrigendum2,RULE-8-3,Yes,Refine,Yes,Easy c,MISRA-C-2012,Corrigendum2,RULE-8-7,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-10-2,Yes,Refine,No,Easy +c,MISRA-C-2012,Corrigendum2,RULE-10-2,Yes,Refine,Yes,Easy c,MISRA-C-2012,Corrigendum2,RULE-10-3,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-11-3,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-11-6,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-13-2,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-13-6,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-14-3,Yes,Refine,No,Easy +c,MISRA-C-2012,Corrigendum2,RULE-14-3,Yes,Refine,Yes,Easy c,MISRA-C-2012,Corrigendum2,RULE-15-7,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-17-4,Yes,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-17-5,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-18-1,Yes,Refine,No,Easy +c,MISRA-C-2012,Corrigendum2,RULE-18-1,Yes,Refine,Yes,Easy c,MISRA-C-2012,Corrigendum2,RULE-20-14,No,Clarification,No,Import c,MISRA-C-2012,Corrigendum2,RULE-21-19,Yes,Clarification,No,Import -c,MISRA-C-2012,Corrigendum2,RULE-21-20,Yes,Refine,No,Easy +c,MISRA-C-2012,Corrigendum2,RULE-21-20,Yes,Refine,Yes,Easy c,MISRA-C-2012,Corrigendum2,RULE-22-9,Yes,Clarification,No,Import \ No newline at end of file diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 4783547ed2..b229bd54e2 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -297,12 +297,15 @@ class EssentialBinaryArithmeticExpr extends EssentialExpr, BinaryArithmeticOpera exists( Type leftEssentialType, Type rightEssentialType, EssentialTypeCategory leftEssentialTypeCategory, - EssentialTypeCategory rightEssentialTypeCategory + EssentialTypeCategory rightEssentialTypeCategory, + int intTypeSize | leftEssentialType = getEssentialType(getLeftOperand()) and rightEssentialType = getEssentialType(getRightOperand()) and leftEssentialTypeCategory = getEssentialTypeCategory(leftEssentialType) and - rightEssentialTypeCategory = getEssentialTypeCategory(rightEssentialType) + rightEssentialTypeCategory = getEssentialTypeCategory(rightEssentialType) and + // For rules around addition/subtraction with char types: + intTypeSize = any(IntType i | i.isSigned()).getSize() | if leftEssentialTypeCategory = EssentiallySignedType() and @@ -338,15 +341,18 @@ class EssentialBinaryArithmeticExpr extends EssentialExpr, BinaryArithmeticOpera ( leftEssentialTypeCategory = [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] + and leftEssentialType.getSize() <= intTypeSize or rightEssentialTypeCategory = [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] + and rightEssentialType.getSize() <= intTypeSize ) or this instanceof SubExpr and leftEssentialTypeCategory = EssentiallyCharacterType() and rightEssentialTypeCategory = [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] + and rightEssentialType.getSize() <= intTypeSize then result instanceof PlainCharType else result = this.getStandardType() ) diff --git a/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql b/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql index 750e589a1c..0e98c6c570 100644 --- a/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql +++ b/c/misra/src/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.ql @@ -32,7 +32,7 @@ where // But the overall essential type is not essentially character type getEssentialTypeCategory(getEssentialType(addOrSub)) = EssentiallyCharacterType() or - // Or this is a subtration of one character with another, which is permitted, but produces an integral type + // Or this is a subtraction of one character with another, which is permitted, but produces an integral type getEssentialTypeCategory(getEssentialType(addOrSub.getLeftOperand())) = EssentiallyCharacterType() and getEssentialTypeCategory(getEssentialType(addOrSub.getRightOperand())) = diff --git a/c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.expected b/c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.expected index 0a5c7ae0bb..a1d3657a1e 100644 --- a/c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.expected +++ b/c/misra/test/rules/RULE-10-2/AdditionSubtractionOnEssentiallyCharType.expected @@ -1,15 +1,19 @@ -| test.c:15:3:15:11 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:16:3:16:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:17:3:17:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:18:3:18:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:19:3:19:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:20:3:20:10 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:21:3:21:10 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:27:3:27:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:28:3:28:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:29:3:29:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:30:3:30:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:31:3:31:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:32:3:32:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:33:3:33:10 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | -| test.c:34:3:34:10 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:19:3:19:11 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:20:3:20:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:21:3:21:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:22:3:22:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:23:3:23:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:24:3:24:10 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:25:3:25:10 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:28:3:28:9 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:29:3:29:10 | ... + ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:35:3:35:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:36:3:36:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:37:3:37:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:38:3:38:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:39:3:39:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:40:3:40:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:41:3:41:10 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:42:3:42:10 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:45:3:45:9 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | +| test.c:46:3:46:10 | ... - ... | Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations | diff --git a/c/misra/test/rules/RULE-10-2/test.c b/c/misra/test/rules/RULE-10-2/test.c index 186c49226e..1d86013c07 100644 --- a/c/misra/test/rules/RULE-10-2/test.c +++ b/c/misra/test/rules/RULE-10-2/test.c @@ -5,6 +5,10 @@ void testRules() { enum E1 { A, B, C } e1 = A; signed int i = 100; unsigned int u = 100; + signed short s = 100; + unsigned short us = 100; + signed long l = 100L; + unsigned long ul = 100UL; float f = 10.0f; // Addition cases @@ -19,8 +23,12 @@ void testRules() { b + 'a'; // NON_COMPLIANT 'a' + e1; // NON_COMPLIANT e1 + 'a'; // NON_COMPLIANT + 'a' + s; // COMPLIANT + 'a' + us; // COMPLIANT + 'a' + l; // NON_COMPLIANT + 'a' + ul; // NON_COMPLIANT - // Subtration cases + // Subtraction cases 'a' - i; // COMPLIANT 'a' - u; // COMPLIANT 'a' - 'a'; // COMPLIANT @@ -32,4 +40,8 @@ void testRules() { 'a' - b; // NON_COMPLIANT e1 - 'a'; // NON_COMPLIANT 'a' - e1; // NON_COMPLIANT + 'a' - s; // COMPLIANT + 'a' - us; // COMPLIANT + 'a' - l; // NON_COMPLIANT + 'a' - ul; // NON_COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected b/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected index c03c04d6cc..3beb834f84 100644 --- a/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected +++ b/c/misra/test/rules/RULE-14-3/ControllingExprInvariant.expected @@ -5,3 +5,4 @@ | test.c:27:10:27:14 | ... < ... | Controlling expression in loop statement has an invariant value. | | test.c:37:3:37:6 | 1 | Controlling expression in conditional statement has an invariant value. | | test.c:38:3:38:3 | 1 | Controlling expression in conditional statement has an invariant value. | +| test.c:45:10:45:26 | ... && ... | Controlling expression in loop statement has an invariant value. | diff --git a/c/misra/test/rules/RULE-14-3/test.c b/c/misra/test/rules/RULE-14-3/test.c index 38db3e1286..ed8854afd2 100644 --- a/c/misra/test/rules/RULE-14-3/test.c +++ b/c/misra/test/rules/RULE-14-3/test.c @@ -37,4 +37,11 @@ void f5(bool b1) { true ? 1 : 2; // NON_COMPLIANT 1 ? 1 : 2; // NON_COMPLIANT b1 ? 1 : 2; // COMPLIANT +} + +void f6(int p1) { + while (p1 < 10 && p1 > 12) { // NON_COMPLIANT[FALSE_NEGATIVE] + } + while (1 == 0 && p1 > 12) { // NON_COMPLIANT + } } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-7-4/StringLiteralAssignedToNonConstChar.expected b/c/misra/test/rules/RULE-7-4/StringLiteralAssignedToNonConstChar.expected index 46b8e5a47b..208e98f632 100644 --- a/c/misra/test/rules/RULE-7-4/StringLiteralAssignedToNonConstChar.expected +++ b/c/misra/test/rules/RULE-7-4/StringLiteralAssignedToNonConstChar.expected @@ -6,3 +6,4 @@ | test.c:58:5:58:22 | return ... | wchar_t * function w_sample3 is returning a string literal. | | test.c:69:3:69:9 | call to sample4 | char * parameter of sample4 is passed a string literal. | | test.c:78:3:78:11 | call to w_sample4 | wchar_t * parameter of w_sample4 is passed a string literal. | +| test.c:91:3:91:11 | call to w_sample7 | char * parameter of w_sample7 is passed a string literal. | diff --git a/c/misra/test/rules/RULE-7-4/test.c b/c/misra/test/rules/RULE-7-4/test.c index c178915200..ff270b611f 100644 --- a/c/misra/test/rules/RULE-7-4/test.c +++ b/c/misra/test/rules/RULE-7-4/test.c @@ -79,4 +79,16 @@ void w_call45() { w_sample5(L"string9"); // COMPLIANT: passing string literal to const char* } +void w_sample6(int x, ...) {} + +void w_call6() { + w_sample6(1, "string10"); // COMPLIANT by first (and only) exception +} + +void w_sample7(char* x, ...) {} + +void w_call7() { + w_sample7("string11", 1); // NON_COMPLIANT, does not fit exceptional case +} + int main() { return 0; } diff --git a/c/misra/test/rules/RULE-8-3/function1.c b/c/misra/test/rules/RULE-8-3/function1.c index 2072748047..7f42f87f53 100644 --- a/c/misra/test/rules/RULE-8-3/function1.c +++ b/c/misra/test/rules/RULE-8-3/function1.c @@ -24,4 +24,8 @@ a f21(wi w, wi h) { // NON_COMPLIANT void f22(int f22b, int f22a) { // NON_COMPLIANT return; +} + +void f23(int f23a) { // COMPLIANT + return; } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-3/function2.c b/c/misra/test/rules/RULE-8-3/function2.c index 979e002466..159dbe105d 100644 --- a/c/misra/test/rules/RULE-8-3/function2.c +++ b/c/misra/test/rules/RULE-8-3/function2.c @@ -16,4 +16,6 @@ typedef long a; extern a f21(wi w, hi h); // NON_COMPLIANT -extern void f22(int f22a, int f22b); // NON_COMPLIANT \ No newline at end of file +extern void f22(int f22a, int f22b); // NON_COMPLIANT + +extern void f23(int); // COMPLIANT \ No newline at end of file diff --git a/change_notes/2025-1-04-misra-c-technical-corrigenda-2.md b/change_notes/2025-1-04-misra-c-technical-corrigenda-2.md new file mode 100644 index 0000000000..81ae3eb561 --- /dev/null +++ b/change_notes/2025-1-04-misra-c-technical-corrigenda-2.md @@ -0,0 +1,11 @@ + - `RULE-8-3` - `DeclarationsOfAFunctionSameNameAndType.ql`: + - Implement new exception, unnamed parameters are not covered by this rule. + - `RULE-10-2` - `AdditionSubtractionOnEssentiallCharType.ql`: + - Disallow `+` and `-` operations with an essentially char type and other types larger than int type. + - Note, this change affects the essential type of such expressions, which may affect other essential types rules. + - `RULE-18-1`, `M5-0-16` - `PointerAndDerivedPointerMustAddressSameArray.ql`, `PointerAndDerivedPointerAccessDifferentArray.ql`: + - Treat casts to byte pointers as pointers to arrays of the size of the pointed-to type + - Fix typo in report message, "passed" replaced with "past." + - `RULE-21-10`, `RULE-25-5-3`, `ENV34-C` - `CallToSetlocaleInvalidatesOldPointers.ql`, `CallToSetlocaleInvalidatesOldPointersMisra.ql`, `DoNotStorePointersReturnedByEnvFunctions.ql`: + - Report usage of returned pointers from `asctime`, `ctime`, during a call to either of the former. + - Report usage of returned pointers from `gmtime`, `localtime`, during a call to either of the former. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Compatible.qll b/cpp/common/src/codingstandards/cpp/Compatible.qll index 0f6e2108ff..d2dbc55778 100644 --- a/cpp/common/src/codingstandards/cpp/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/Compatible.qll @@ -21,10 +21,10 @@ predicate parameterTypesIncompatible(FunctionDeclarationEntry f1, FunctionDeclar predicate parameterNamesIncompatible(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { f1.getDeclaration() = f2.getDeclaration() and - exists(ParameterDeclarationEntry p1, ParameterDeclarationEntry p2, int i | - p1 = f1.getParameterDeclarationEntry(i) and - p2 = f2.getParameterDeclarationEntry(i) + exists(string p1Name, string p2Name, int i | + p1Name = f1.getParameterDeclarationEntry(i).getName() and + p2Name = f2.getParameterDeclarationEntry(i).getName() | - not p1.getName() = p2.getName() + not p1Name = p2Name ) } diff --git a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll index 57b4eb0bfb..9728bc1f6d 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll @@ -7,20 +7,118 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import semmle.code.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.new.DataFlow import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +import codeql.util.Boolean abstract class DoNotUsePointerArithmeticToAddressDifferentArraysSharedQuery extends Query { } Query getQuery() { result instanceof DoNotUsePointerArithmeticToAddressDifferentArraysSharedQuery } +/** + * A `VariableAccess` of a variable that is an array, or a pointer type casted to a byte pointer. + */ +abstract class ArrayLikeAccess extends Expr { + abstract Element getElement(); + + abstract string getName(); + + abstract int getSize(); + + abstract DataFlow::Node getNode(); +} + +/** + * A `VariableAccess` of a variable that is an array. + */ +class ArrayVariableAccess extends ArrayLikeAccess, VariableAccess { + int size; + + ArrayVariableAccess() { size = getType().(ArrayType).getArraySize() } + + override Variable getElement() { result = getTarget() } + + override string getName() { result = getElement().getName() } + + override int getSize() { result = size } + + override DataFlow::Node getNode() { result.asExpr() = this } +} + +/** + * Get the size of the object pointed to by a type (pointer or array). + * + * Depth of type unwrapping depends on the type. Pointer will be dereferenced only once: the element + * size of `T*` is `sizeof(T)` while the element size of `T**` is `sizeof(T*)`. However, array types + * will be deeply unwrapped, as the pointed to size of `T[][]` is `sizeof(T)`. These processes + * interact, so the element size of a pointer to an array of `T` has an element size of `sizeof(T)` + * and not `sizeof(T[length])`. + */ +int elementSize(Type type, Boolean deref) { + if type instanceof ArrayType + then result = elementSize(type.(ArrayType).getBaseType(), false) + else + if deref = true and type instanceof PointerType + then result = elementSize(type.(PointerType).getBaseType(), false) + else result = type.getSize() +} + +/** + * A pointer type casted to a byte pointer, which is effectively a pointer to a byte array whose + * length depends on `elementSize()` of the original pointed-to type. + */ +class CastedToBytePointer extends ArrayLikeAccess, Conversion { + int size; + + CastedToBytePointer() { + getType().(PointerType).getBaseType().getSize() = 1 and + size = elementSize(getExpr().getType(), true) + } + + override Element getElement() { result = this } + + override string getName() { + result = "cast to btye pointer " + this.toString() + or + exists(Cast cast | + cast.getExpr() = this and + result = cast.getType().(PointerType).getBaseType().toString() + ) + } + + override int getSize() { result = size } + + override DataFlow::Node getNode() { result.asConvertedExpr() = this } +} + +/** + * A data-flow configuration that tracks access to an array to type to an array index expression. + * This is used to determine possible pointer to array creations. + */ +module ByteArrayToArrayExprConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { exists(CastedToBytePointer a | a.getNode() = source) } + + // TODO: casting to different size pointed-to-type invalidates + predicate isSink(DataFlow::Node sink) { exists(ArrayExpr c | c.getArrayBase() = sink.asExpr()) } +} + +module BytePointerToArrayExprFlow = DataFlow::Global; + /** * A data-flow configuration that tracks access to an array to type to an array index expression. * This is used to determine possible pointer to array creations. */ module ArrayToArrayExprConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node source) { - source.asExpr().(VariableAccess).getType() instanceof ArrayType + predicate isSource(DataFlow::Node source) { exists(ArrayVariableAccess a | a.getNode() = source) } + + predicate isBarrier(DataFlow::Node barrier) { + // Casting to a differently sized pointer invalidates this analysis. + exists(CStyleCast cast, Expr casted | + cast.getExpr() = casted and casted = barrier.asConvertedExpr() + | + not casted.getType().(PointerType).getBaseType().getSize() = + cast.getType().(PointerType).getBaseType().getSize() + ) } predicate isSink(DataFlow::Node sink) { exists(ArrayExpr c | c.getArrayBase() = sink.asExpr()) } @@ -28,12 +126,19 @@ module ArrayToArrayExprConfig implements DataFlow::ConfigSig { module ArrayToArrayExprFlow = DataFlow::Global; -/** Holds if the address taken expression `addressOf` takes the address of an array element at `index` of `array` with size `arraySize`. */ -predicate pointerOperandCreation(AddressOfExpr addressOf, Variable array, int arraySize, int index) { - arraySize = array.getType().(ArrayType).getArraySize() and +/** Holds if the address taken expression `addressOf` takes the address of an array element at `index` of `array`. */ +predicate pointerOperandCreation(AddressOfExpr addressOf, ArrayLikeAccess array, int index) { exists(ArrayExpr ae | - ArrayToArrayExprFlow::flow(DataFlow::exprNode(array.getAnAccess()), - DataFlow::exprNode(ae.getArrayBase())) and + ( + ArrayToArrayExprFlow::flow(array.getNode(), DataFlow::exprNode(ae.getArrayBase())) and + array instanceof ArrayVariableAccess + or + // Since casts can occur in the middle of flow, barriers are not perfect for modeling the + // desired behavior. Handle casts to byte pointers as sources in a separate flow analysis. + BytePointerToArrayExprFlow::flow(array.getNode(), DataFlow::exprNode(ae.getArrayBase())) and + // flow() may hold for `ArrayVariableAccess` in the above, even though they aren't sources + array instanceof CastedToBytePointer + ) and index = lowerBound(ae.getArrayOffset().getFullyConverted()) and addressOf.getOperand() = ae ) @@ -41,19 +146,16 @@ predicate pointerOperandCreation(AddressOfExpr addressOf, Variable array, int ar /** A variable that points to an element of an array. */ class PointerOperand extends Variable { - Variable array; - int arraySize; + ArrayLikeAccess array; int index; AddressOfExpr source; PointerOperand() { - pointerOperandCreation(source, array, arraySize, index) and + pointerOperandCreation(source, array, index) and this.getAnAssignedValue() = source } - Variable getArray() { result = array } - - int getArraySize() { result = arraySize } + ArrayLikeAccess getArray() { result = array } int getIndex() { result = index } @@ -111,9 +213,7 @@ class DerivedArrayPointer extends Variable { DerivedArrayPointer() { derivedPointer(this, source, operand, index) } - Variable getArray() { result = operand.getArray() } - - int getArraySize() { result = operand.getArraySize() } + ArrayLikeAccess getArray() { result = operand.getArray() } int getIndex() { result = index } @@ -131,15 +231,10 @@ class DerivedArrayPointerOrPointerOperand extends Variable { this instanceof PointerOperand } - Variable getArray() { + ArrayLikeAccess getArray() { result = this.(DerivedArrayPointer).getArray() or result = this.(PointerOperand).getArray() } - int getArraySize() { - result = this.(DerivedArrayPointer).getArraySize() or - result = this.(PointerOperand).getArraySize() - } - int getIndex() { result = this.(DerivedArrayPointer).getIndex() or result = this.(PointerOperand).getIndex() } @@ -149,14 +244,16 @@ class DerivedArrayPointerOrPointerOperand extends Variable { } } -query predicate problems(Expr arrayPointerCreation, string message, Variable array, string arrayName) { +query predicate problems(Expr arrayPointerCreation, string message, Element array, string arrayName) { not isExcluded(arrayPointerCreation, getQuery()) and exists( DerivedArrayPointerOrPointerOperand derivedArrayPointerOrPointerOperand, int index, - int arraySize, int difference, string denomination + ArrayLikeAccess arrayAccess, int arraySize, int difference, string denomination | - array = derivedArrayPointerOrPointerOperand.getArray() and - arraySize = derivedArrayPointerOrPointerOperand.getArraySize() and + arrayAccess = derivedArrayPointerOrPointerOperand.getArray() and + array = arrayAccess.getElement() and + arrayName = arrayAccess.getName() and + arraySize = arrayAccess.getSize() and index = derivedArrayPointerOrPointerOperand.getIndex() and arrayPointerCreation = derivedArrayPointerOrPointerOperand.getSource() and difference = index - arraySize and @@ -173,7 +270,6 @@ query predicate problems(Expr arrayPointerCreation, string message, Variable arr ) and message = "Array pointer " + derivedArrayPointerOrPointerOperand.getName() + " points " + - (index - arraySize).toString() + " " + denomination + " passed the end of $@." - ) and - arrayName = array.getName() -} + difference.toString() + " " + denomination + " past the end of $@." + ) +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll b/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll index 3949ff50a8..0f4a98cf6f 100644 --- a/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll +++ b/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll @@ -45,6 +45,12 @@ predicate incompatibleFunctions(GetenvFunction f1, GetenvFunction f2) { or f1.getName() = ["setlocale", "localeconv"] and f2.getName() = ["setlocale", "localeconv"] + or + f1.getName() = ["asctime", "ctime"] and + f2.getName() = ["asctime", "ctime"] + or + f1.getName() = ["gmtime", "localtime"] and + f2.getName() = ["gmtime", "localtime"] } query predicate problems( diff --git a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected index fa181755e8..438b697775 100644 --- a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected +++ b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected @@ -1,5 +1,9 @@ -| test.cpp:4:13:4:18 | ... + ... | Array pointer p2 points 1 element passed the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | -| test.cpp:5:13:5:18 | ... + ... | Array pointer p3 points 1 element passed the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | -| test.cpp:6:13:6:18 | & ... | Array pointer p4 points 1 element passed the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | -| test.cpp:11:8:11:11 | ... -- | Array pointer p7 points 1 element passed the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | -| test.cpp:12:8:12:9 | p3 | Array pointer p8 points 1 element passed the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | +| test.cpp:4:13:4:18 | ... + ... | Array pointer p2 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | +| test.cpp:5:13:5:18 | ... + ... | Array pointer p3 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | +| test.cpp:6:13:6:18 | & ... | Array pointer p4 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | +| test.cpp:11:8:11:11 | ... -- | Array pointer p7 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | +| test.cpp:12:8:12:9 | p3 | Array pointer p8 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | +| test.cpp:25:15:25:21 | & ... | Array pointer p14 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | +| test.cpp:30:15:30:21 | & ... | Array pointer p17 points 1 element past the end of $@. | test.cpp:28:24:28:42 | (unsigned char *)... | cast to btye pointer (unsigned char *)... | +| test.cpp:35:15:35:21 | & ... | Array pointer p20 points 1 element past the end of $@. | test.cpp:33:24:33:43 | (unsigned char *)... | cast to btye pointer (unsigned char *)... | +| test.cpp:43:15:43:23 | & ... | Array pointer p23 points 96 elements past the end of $@. | test.cpp:28:24:28:42 | (unsigned char *)... | cast to btye pointer (unsigned char *)... | diff --git a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp index c1032ee735..f81026870d 100644 --- a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp +++ b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp @@ -17,4 +17,28 @@ void f1() { 3 + p1; // COMPLIANT - points to an element on beyond the end of the array int *p11 = &l1[3]; // COMPLIANT - points to an element on beyond the end of the array + + // Casting to a pointer to a type of the same size doesn't invalidate the + // analysis + unsigned int *p12 = (unsigned int *)l1; + void *p13 = &p12[3]; // COMPLIANT + void *p14 = &p12[4]; // NON_COMPLIANT + + // Casting to a char* is effectively a new array of length sizeof(T) + unsigned char *p15 = (unsigned char *)l1; + void *p16 = &p15[4]; // COMPLIANT + void *p17 = &p15[5]; // NON_COMPLIANT + + long l2[3]; + unsigned char *p18 = (unsigned char *)&l2; + void *p19 = &p18[8]; // COMPLIANT + void *p20 = &p18[9]; // NON_COMPLIANT + + // Casting to a pointer to a differently sized type that isn't char + // invalidates analysis + int l3[3]; + long *p21 = (long*)&l1; + void *p22 = &p21[0]; // COMPLIANT + // Not compliant, but we shouldn't detect it, but we do for the wrong reason: + void *p23 = &p21[100]; // NON_COMPLIANT[FALSE_NEGATIVE][FALSE_POSITIVE] } \ No newline at end of file diff --git a/cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected b/cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected index 9a39d3a88d..36c66a94fe 100644 --- a/cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected +++ b/cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected @@ -4,3 +4,8 @@ | test.cpp:165:14:165:26 | tmpvar_global | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:157:19:157:24 | call to getenv | call to getenv | test.cpp:161:20:161:25 | call to getenv | call to getenv | | test.cpp:188:18:188:18 | r | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:185:7:185:15 | call to setlocale | call to setlocale | test.cpp:187:8:187:17 | call to localeconv | call to localeconv | | test.cpp:208:10:208:15 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:202:12:202:17 | call to getenv | call to getenv | test.cpp:206:3:206:8 | call to f11fun | call to f11fun | +| test.cpp:216:16:216:17 | r1 | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:214:14:214:18 | call to ctime | call to ctime | test.cpp:215:3:215:9 | call to asctime | call to asctime | +| test.cpp:226:16:226:17 | r1 | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:222:14:222:18 | call to ctime | call to ctime | test.cpp:225:14:225:20 | call to asctime | call to asctime | +| test.cpp:231:16:231:17 | r2 | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:225:14:225:20 | call to asctime | call to asctime | test.cpp:229:8:229:12 | call to ctime | call to ctime | +| test.cpp:240:16:240:17 | r1 | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:236:19:236:27 | call to localtime | call to localtime | test.cpp:239:19:239:24 | call to gmtime | call to gmtime | +| test.cpp:245:16:245:17 | r2 | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:239:19:239:24 | call to gmtime | call to gmtime | test.cpp:243:8:243:16 | call to localtime | call to localtime | diff --git a/cpp/common/test/rules/invalidatedenvstringpointers/test.cpp b/cpp/common/test/rules/invalidatedenvstringpointers/test.cpp index 74e3d1b8f5..167d770ef6 100644 --- a/cpp/common/test/rules/invalidatedenvstringpointers/test.cpp +++ b/cpp/common/test/rules/invalidatedenvstringpointers/test.cpp @@ -207,3 +207,40 @@ void f11(void) { printf(tmpvar); // NON_COMPLIANT } + +void f12(void) { + time_t rawtime; + time(&rawtime); + char* r1 = ctime(&rawtime); + asctime(localtime(&rawtime)); + printf("%s", r1); // NON_COMPLIANT +} + +void f13(void) { + time_t rawtime; + time(&rawtime); + char* r1 = ctime(&rawtime); + printf("%s", r1); // COMPLIANT + + char* r2 = asctime(localtime(&rawtime)); + printf("%s", r1); // NON_COMPLIANT + printf("%s", r2); // COMPLIANT + + r1 = ctime(&rawtime); + printf("%s", r1); // COMPLIANT + printf("%s", r2); // NON_COMPLIANT +} + +void f14(void) { + time_t rawtime; + struct tm *r1 = localtime(&rawtime); + printf("%d", r1->tm_year); // COMPLIANT + + struct tm *r2 = gmtime(&rawtime); + printf("%s", r1->tm_year); // NON_COMPLIANT + printf("%s", r2->tm_year); // COMPLIANT + + r1 = localtime(&rawtime); + printf("%s", r1->tm_year); // COMPLIANT + printf("%s", r2->tm_year); // NON_COMPLIANT +} \ No newline at end of file From 6316375dfcd09132d0f1759571f1da5959a0f1b3 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 12 Jan 2025 22:00:41 +0000 Subject: [PATCH 180/628] ReturnRefOrPointerToAutoVar: Exclude global or member variables This false positive case was introduced when the rule was shared during the creation of RULE-6-8-2, where `Variable` was used instead of `StackVariable`. --- change_notes/2025-01-09-return-reference.md | 2 ++ ...rnReferenceOrPointerToAutomaticLocalVariable.qll | 2 +- .../test.cpp | 13 +++++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 change_notes/2025-01-09-return-reference.md diff --git a/change_notes/2025-01-09-return-reference.md b/change_notes/2025-01-09-return-reference.md new file mode 100644 index 0000000000..69480916c7 --- /dev/null +++ b/change_notes/2025-01-09-return-reference.md @@ -0,0 +1,2 @@ + - `M7-5-1`, `RULE-6-8-2` - `FunctionReturnAutomaticVarCondition.ql`, `ReturnReferenceOrPointerToAutomaticLocalVariable.ql`: + - Remove false positives for member and global variables reported under this rule. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/returnreferenceorpointertoautomaticlocalvariable/ReturnReferenceOrPointerToAutomaticLocalVariable.qll b/cpp/common/src/codingstandards/cpp/rules/returnreferenceorpointertoautomaticlocalvariable/ReturnReferenceOrPointerToAutomaticLocalVariable.qll index cd623f711c..b37a9cd02b 100644 --- a/cpp/common/src/codingstandards/cpp/rules/returnreferenceorpointertoautomaticlocalvariable/ReturnReferenceOrPointerToAutomaticLocalVariable.qll +++ b/cpp/common/src/codingstandards/cpp/rules/returnreferenceorpointertoautomaticlocalvariable/ReturnReferenceOrPointerToAutomaticLocalVariable.qll @@ -13,7 +13,7 @@ abstract class ReturnReferenceOrPointerToAutomaticLocalVariableSharedQuery exten Query getQuery() { result instanceof ReturnReferenceOrPointerToAutomaticLocalVariableSharedQuery } query predicate problems( - ReturnStmt rs, string message, Function f, string f_string, Variable auto, string auto_string + ReturnStmt rs, string message, Function f, string f_string, StackVariable auto, string auto_string ) { exists(VariableAccess va, string returnType | not isExcluded(rs, getQuery()) and diff --git a/cpp/common/test/rules/returnreferenceorpointertoautomaticlocalvariable/test.cpp b/cpp/common/test/rules/returnreferenceorpointertoautomaticlocalvariable/test.cpp index bc4fbf8f1d..d383d7859f 100644 --- a/cpp/common/test/rules/returnreferenceorpointertoautomaticlocalvariable/test.cpp +++ b/cpp/common/test/rules/returnreferenceorpointertoautomaticlocalvariable/test.cpp @@ -32,4 +32,17 @@ void test_templatefunction_return() { int j = 2; int k = 3; t1(j, k); +} + +class C1 { +private: + int x; + +public: + int test() { return x; } // COMPLIANT - ignore member vars +}; + +int x; +int test_global() { + return x; // COMPLIANT - ignore global vars } \ No newline at end of file From 99a310642c211ff13204cbbe624ea999b6d545a0 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 12 Jan 2025 22:08:19 +0000 Subject: [PATCH 181/628] Contracts: Add MISRA C 2012 tags --- rule_packages/c/Contracts.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rule_packages/c/Contracts.json b/rule_packages/c/Contracts.json index 735e84d9da..40bf3d8b0b 100644 --- a/rule_packages/c/Contracts.json +++ b/rule_packages/c/Contracts.json @@ -38,7 +38,8 @@ "short_name": "CheckMathLibraryFunctionParameters", "shared_implementation_short_name": "UncheckedRangeDomainPoleErrors", "tags": [ - "correctness" + "correctness", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query identifies possible domain, pole and range errors on a selection of C standard library fuctions from math.h." @@ -61,7 +62,8 @@ "short_name": "FunctionErrorInformationUntested", "shared_implementation_short_name": "FunctionErroneousReturnValueNotTested", "tags": [ - "maintainability" + "maintainability", + "external/misra/c/2012/third-edition-first-revision" ], "implementation_scope": { "description": "This query enforces checking on some C standard library functions that may return error codes." From 82440695528fce9e12846cb92298572cd7aa1fdd Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 12 Jan 2025 22:15:43 +0000 Subject: [PATCH 182/628] Regenerate package files --- c/misra/src/rules/DIR-4-11/CheckMathLibraryFunctionParameters.ql | 1 + c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql | 1 + 2 files changed, 2 insertions(+) diff --git a/c/misra/src/rules/DIR-4-11/CheckMathLibraryFunctionParameters.ql b/c/misra/src/rules/DIR-4-11/CheckMathLibraryFunctionParameters.ql index 6810784a0e..4011b210f8 100644 --- a/c/misra/src/rules/DIR-4-11/CheckMathLibraryFunctionParameters.ql +++ b/c/misra/src/rules/DIR-4-11/CheckMathLibraryFunctionParameters.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/dir-4-11 * correctness + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ diff --git a/c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql b/c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql index 63236d422d..0c0a3d7b1a 100644 --- a/c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql +++ b/c/misra/src/rules/DIR-4-7/FunctionErrorInformationUntested.ql @@ -12,6 +12,7 @@ * @problem.severity recommendation * @tags external/misra/id/dir-4-7 * maintainability + * external/misra/c/2012/third-edition-first-revision * external/misra/obligation/required */ From 37ac088223e3cab5e000fb36103d4fa70056e84a Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 12 Jan 2025 23:03:53 +0000 Subject: [PATCH 183/628] EssentialType: Merge binary operation implementations EssentialBinaryArithmeticOperation and EssentialBinaryBitwiseOperation only differ in their handling of + and - operations, so combine the two implementations to reduce duplication. In addition, change the characteristic predicate to an allow list. This ensures we only capture the intended binary operations, and exclude any others. --- .../c/misra/EssentialTypes.qll | 71 ++++++------------- 1 file changed, 21 insertions(+), 50 deletions(-) diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 4dbe8dbb34..57250d42c5 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -286,11 +286,26 @@ class EssentialConditionalExpr extends EssentialExpr, ConditionalExpr { } } -class EssentialBinaryArithmeticExpr extends EssentialExpr, BinaryArithmeticOperation { - EssentialBinaryArithmeticExpr() { - // GNU C extension has min/max which we can ignore - not this instanceof MinExpr and - not this instanceof MaxExpr +/** + * A binary operation subject to usual conversions, with essential type behaviour as specified by D.7.9. + */ +class EssentialBinaryOperationSubjectToUsualConversions extends EssentialExpr, BinaryOperation { + EssentialBinaryOperationSubjectToUsualConversions() { + this instanceof MulExpr + or + this instanceof DivExpr + or + this instanceof RemExpr + or + this instanceof AddExpr + or + this instanceof SubExpr + or + this instanceof BitwiseAndExpr + or + this instanceof BitwiseOrExpr + or + this instanceof BitwiseXorExpr } override Type getEssentialType() { @@ -353,51 +368,7 @@ class EssentialBinaryArithmeticExpr extends EssentialExpr, BinaryArithmeticOpera } } -class EssentialBinaryBitwiseExpr extends EssentialExpr, BinaryBitwiseOperation { - EssentialBinaryBitwiseExpr() { - not this instanceof LShiftExpr and - not this instanceof RShiftExpr - } - - override Type getEssentialType() { - exists( - Type leftEssentialType, Type rightEssentialType, - EssentialTypeCategory leftEssentialTypeCategory, - EssentialTypeCategory rightEssentialTypeCategory - | - leftEssentialType = getEssentialType(getLeftOperand()) and - rightEssentialType = getEssentialType(getRightOperand()) and - leftEssentialTypeCategory = getEssentialTypeCategory(leftEssentialType) and - rightEssentialTypeCategory = getEssentialTypeCategory(rightEssentialType) - | - if - leftEssentialTypeCategory = EssentiallySignedType() and - rightEssentialTypeCategory = EssentiallySignedType() - then - if exists(getValue()) - then result = stlr(this) - else ( - if leftEssentialType.getSize() > rightEssentialType.getSize() - then result = leftEssentialType - else result = rightEssentialType - ) - else - if - leftEssentialTypeCategory = EssentiallyUnsignedType() and - rightEssentialTypeCategory = EssentiallyUnsignedType() - then - if exists(getValue()) - then result = utlr(this) - else ( - if leftEssentialType.getSize() > rightEssentialType.getSize() - then result = leftEssentialType - else result = rightEssentialType - ) - else result = this.getStandardType() - ) - } -} - +// } /** * A named Enum type, as per D.5. */ From 9dc3f1894b3b853c7c8459cc25715698d06eaff2 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 12 Jan 2025 23:19:27 +0000 Subject: [PATCH 184/628] EssentialType: extract Add/Sub expressions Extract out add/sub expressions special behaviour to improve clarity. This commit also simplifies the add case by avoiding referring to left/right explicitly. --- .../c/misra/EssentialTypes.qll | 66 ++++++++++++------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 57250d42c5..2852f5d842 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -342,28 +342,50 @@ class EssentialBinaryOperationSubjectToUsualConversions extends EssentialExpr, B then result = leftEssentialType else result = rightEssentialType ) - else - if - this instanceof AddExpr and - ( - leftEssentialTypeCategory = EssentiallyCharacterType() - or - rightEssentialTypeCategory = EssentiallyCharacterType() - ) and - ( - leftEssentialTypeCategory = - [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] - or - rightEssentialTypeCategory = - [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] - ) - or - this instanceof SubExpr and - leftEssentialTypeCategory = EssentiallyCharacterType() and - rightEssentialTypeCategory = - [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] - then result instanceof PlainCharType - else result = this.getStandardType() + else result = this.getStandardType() + ) + } +} + +/** + * An add expression, with essential type behaviour as specified by D.7.9. + */ +class EssentialAddExpr extends EssentialBinaryOperationSubjectToUsualConversions, AddExpr { + override Type getEssentialType() { + exists( + EssentialTypeCategory operandTypeCategory, EssentialTypeCategory otherOperandTypeCategory + | + operandTypeCategory = getEssentialTypeCategory(getEssentialType(getAnOperand())) and + otherOperandTypeCategory = getEssentialTypeCategory(getEssentialType(getAnOperand())) + | + if + operandTypeCategory = EssentiallyCharacterType() and + otherOperandTypeCategory = + [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] + then result instanceof PlainCharType + else result = super.getEssentialType() + ) + } +} + +/** + * A sub expression, with essential type behaviour as specified by D.7.9. + */ +class EssentialSubExpr extends EssentialBinaryOperationSubjectToUsualConversions, SubExpr { + override Type getEssentialType() { + exists( + EssentialTypeCategory leftEssentialTypeCategory, + EssentialTypeCategory rightEssentialTypeCategory + | + leftEssentialTypeCategory = getEssentialTypeCategory(getEssentialType(getLeftOperand())) and + rightEssentialTypeCategory = getEssentialTypeCategory(getEssentialType(getRightOperand())) + | + if + leftEssentialTypeCategory = EssentiallyCharacterType() and + rightEssentialTypeCategory = + [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] + then result instanceof PlainCharType + else result = super.getEssentialType() ) } } From 29420e93e0f286a6cafe06a6ef44989c2e517676 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 12 Jan 2025 23:33:13 +0000 Subject: [PATCH 185/628] EssentialType: Combine binary cases Reduce repitition through combining cases. --- .../c/misra/EssentialTypes.qll | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 2852f5d842..633660b952 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -320,29 +320,21 @@ class EssentialBinaryOperationSubjectToUsualConversions extends EssentialExpr, B rightEssentialTypeCategory = getEssentialTypeCategory(rightEssentialType) | if - leftEssentialTypeCategory = EssentiallySignedType() and - rightEssentialTypeCategory = EssentiallySignedType() + leftEssentialTypeCategory = rightEssentialTypeCategory and + leftEssentialTypeCategory = + [EssentiallyUnsignedType(), EssentiallySignedType().(TEssentialTypeCategory)] then if exists(getValue()) - then result = stlr(this) - else ( + then ( + leftEssentialTypeCategory = EssentiallySignedType() and result = stlr(this) + or + leftEssentialTypeCategory = EssentiallyUnsignedType() and result = utlr(this) + ) else ( if leftEssentialType.getSize() > rightEssentialType.getSize() then result = leftEssentialType else result = rightEssentialType ) - else - if - leftEssentialTypeCategory = EssentiallyUnsignedType() and - rightEssentialTypeCategory = EssentiallyUnsignedType() - then - if exists(getValue()) - then result = utlr(this) - else ( - if leftEssentialType.getSize() > rightEssentialType.getSize() - then result = leftEssentialType - else result = rightEssentialType - ) - else result = this.getStandardType() + else result = this.getStandardType() ) } } From 62da9c88ba9c6a5acb88f79a94405947f3505a4c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 12 Jan 2025 23:45:14 +0000 Subject: [PATCH 186/628] EssentialType: Simplify (Signed or Unsigned) --- .../c/misra/EssentialTypes.qll | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 633660b952..555d3d2b2d 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -31,17 +31,19 @@ class EssentialTypeCategory extends TEssentialTypeCategory { } } +class EssentiallySignedOrUnsignedType extends EssentialTypeCategory { + EssentiallySignedOrUnsignedType() { + this = EssentiallySignedType() or this = EssentiallyUnsignedType() + } +} + /** * An expression in the program that evaluates to a compile time constant signed or unsigned integer. */ private class ConstantIntegerExpr extends Expr { pragma[noinline] ConstantIntegerExpr() { - getEssentialTypeCategory(this.getType()) = - [ - EssentiallyUnsignedType().(EssentialTypeCategory), - EssentiallySignedType().(EssentialTypeCategory) - ] and + getEssentialTypeCategory(this.getType()) instanceof EssentiallySignedOrUnsignedType and exists(this.getValue().toFloat()) and not this instanceof Conversion } @@ -235,9 +237,7 @@ class EssentialUnaryPlusExpr extends EssentialExpr, UnaryPlusExpr { operandEssentialType = getEssentialType(getOperand()) and operandEssentialTypeCategory = getEssentialTypeCategory(operandEssentialType) | - if - operandEssentialTypeCategory = - [EssentiallyUnsignedType().(TEssentialTypeCategory), EssentiallySignedType()] + if operandEssentialTypeCategory instanceof EssentiallySignedOrUnsignedType then result = operandEssentialType else result = getStandardType() ) @@ -321,8 +321,7 @@ class EssentialBinaryOperationSubjectToUsualConversions extends EssentialExpr, B | if leftEssentialTypeCategory = rightEssentialTypeCategory and - leftEssentialTypeCategory = - [EssentiallyUnsignedType(), EssentiallySignedType().(TEssentialTypeCategory)] + leftEssentialTypeCategory instanceof EssentiallySignedOrUnsignedType then if exists(getValue()) then ( @@ -352,8 +351,7 @@ class EssentialAddExpr extends EssentialBinaryOperationSubjectToUsualConversions | if operandTypeCategory = EssentiallyCharacterType() and - otherOperandTypeCategory = - [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] + otherOperandTypeCategory instanceof EssentiallySignedOrUnsignedType then result instanceof PlainCharType else result = super.getEssentialType() ) @@ -374,8 +372,7 @@ class EssentialSubExpr extends EssentialBinaryOperationSubjectToUsualConversions | if leftEssentialTypeCategory = EssentiallyCharacterType() and - rightEssentialTypeCategory = - [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] + rightEssentialTypeCategory instanceof EssentiallySignedOrUnsignedType then result instanceof PlainCharType else result = super.getEssentialType() ) From cd8ea6767da83d0783502e826a4c7be6b86bdb05 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 12 Jan 2025 23:48:01 +0000 Subject: [PATCH 187/628] EssentialType: Reduce duplication in conditional calc Avoid repeating code for both the signed and unsigned cases. --- .../src/codingstandards/c/misra/EssentialTypes.qll | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 555d3d2b2d..97a9604f58 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -267,21 +267,13 @@ class EssentialConditionalExpr extends EssentialExpr, ConditionalExpr { then result = thenEssentialType else if - getEssentialTypeCategory(thenEssentialType) = EssentiallySignedType() and - getEssentialTypeCategory(elseEssentialType) = EssentiallySignedType() + getEssentialTypeCategory(thenEssentialType) = getEssentialTypeCategory(elseEssentialType) and + getEssentialTypeCategory(thenEssentialType) instanceof EssentiallySignedOrUnsignedType then if thenEssentialType.getSize() > elseEssentialType.getSize() then result = thenEssentialType else result = elseEssentialType - else - if - getEssentialTypeCategory(thenEssentialType) = EssentiallyUnsignedType() and - getEssentialTypeCategory(elseEssentialType) = EssentiallyUnsignedType() - then - if thenEssentialType.getSize() > elseEssentialType.getSize() - then result = thenEssentialType - else result = elseEssentialType - else result = this.getStandardType() + else result = this.getStandardType() ) } } From 7a465dd340948eb3a6a5a0e6f5b14c068bc601a7 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 12 Jan 2025 23:52:35 +0000 Subject: [PATCH 188/628] EssentialType: Add maxRank predicate --- .../c/misra/EssentialTypes.qll | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 97a9604f58..0a4e64e98d 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -257,6 +257,13 @@ class EssentialUnaryMinusExpr extends EssentialExpr, UnaryMinusExpr { } } +bindingset[essentialTypeA, essentialTypeB] +private Type maxRankType(Type essentialTypeA, Type essentialTypeB) { + if essentialTypeA.getSize() > essentialTypeB.getSize() + then result = essentialTypeA + else result = essentialTypeB +} + class EssentialConditionalExpr extends EssentialExpr, ConditionalExpr { override Type getEssentialType() { exists(Type thenEssentialType, Type elseEssentialType | @@ -269,10 +276,7 @@ class EssentialConditionalExpr extends EssentialExpr, ConditionalExpr { if getEssentialTypeCategory(thenEssentialType) = getEssentialTypeCategory(elseEssentialType) and getEssentialTypeCategory(thenEssentialType) instanceof EssentiallySignedOrUnsignedType - then - if thenEssentialType.getSize() > elseEssentialType.getSize() - then result = thenEssentialType - else result = elseEssentialType + then result = maxRankType(thenEssentialType, elseEssentialType) else result = this.getStandardType() ) } @@ -316,15 +320,11 @@ class EssentialBinaryOperationSubjectToUsualConversions extends EssentialExpr, B leftEssentialTypeCategory instanceof EssentiallySignedOrUnsignedType then if exists(getValue()) - then ( + then leftEssentialTypeCategory = EssentiallySignedType() and result = stlr(this) or leftEssentialTypeCategory = EssentiallyUnsignedType() and result = utlr(this) - ) else ( - if leftEssentialType.getSize() > rightEssentialType.getSize() - then result = leftEssentialType - else result = rightEssentialType - ) + else result = maxRankType(leftEssentialType, rightEssentialType) else result = this.getStandardType() ) } From 3fd82fd7bf2cb2a61f2c1c476d53806f2e932834 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 13 Jan 2025 00:06:10 +0000 Subject: [PATCH 189/628] EssentialType: Fix test comments --- c/misra/test/c/misra/test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/c/misra/test/c/misra/test.c b/c/misra/test/c/misra/test.c index e271a67e30..7bcb5d7bad 100644 --- a/c/misra/test/c/misra/test.c +++ b/c/misra/test/c/misra/test.c @@ -139,8 +139,8 @@ void testBitwise() { s32 ^ s16; // Essentially signed, int s16 ^ s32; // Essentially signed, int - u32 & s32; // Essentially signed, int - s32 & u32; // Essentially signed, int + u32 & s32; // Essentially unsigned, int + s32 & u32; // Essentially unsigned, int u8 & s32; // Essentially signed, int s32 & u8; // Essentially signed, int u8 & s8; // Essentially signed, int From 8a070839bb679f5eb7ed57638cfb3ed4ab662485 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 13 Jan 2025 00:11:41 +0000 Subject: [PATCH 190/628] Avoid formatting colisions --- c/misra/test/c/misra/test.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/c/misra/test/c/misra/test.c b/c/misra/test/c/misra/test.c index 7bcb5d7bad..36a3eb0b10 100644 --- a/c/misra/test/c/misra/test.c +++ b/c/misra/test/c/misra/test.c @@ -82,8 +82,8 @@ void testControlChar() { } #include - -void testBitwise() { +// clang-format off +void testBitwise() { // Clang format disabled to avoid confusion with variable declarations uint8_t u8 = 0; uint16_t u16 = 0; uint32_t u32 = 0; @@ -160,7 +160,7 @@ void testBitwise() { u8 ^ s8; // Essentially signed, int s8 ^ u8; // Essentially signed, int } - +// clang-format on void testShifts() { int32_t s32 = 1; From 2c2c3fbac9f7efeca6199d9ee626ccc67092e863 Mon Sep 17 00:00:00 2001 From: knewbury01 Date: Tue, 14 Jan 2025 14:59:01 +0000 Subject: [PATCH 191/628] Bump version to 2.41.0-dev --- c/cert/src/qlpack.yml | 2 +- c/cert/test/qlpack.yml | 2 +- c/common/src/qlpack.yml | 2 +- c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- c/misra/test/qlpack.yml | 2 +- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/qlpack.yml | 2 +- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- docs/user_manual.md | 12 ++++++------ 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 2778e44435..4945abe49c 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.40.0-dev +version: 2.41.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index 461ebe9677..af5e71d2a1 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.40.0-dev +version: 2.41.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index f39f3cb1c4..9545a88178 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.40.0-dev +version: 2.41.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index d417a17df2..febda7a63b 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.40.0-dev +version: 2.41.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 9aceed1a49..758c059c01 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.40.0-dev +version: 2.41.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index d53bc95f28..d367e8d06d 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.40.0-dev +version: 2.41.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index f44ad54c74..565cfc12db 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.40.0-dev +version: 2.41.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index 178d8cc314..66755fe907 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.40.0-dev +version: 2.41.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 735dd9f5b4..cc981411c2 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.40.0-dev +version: 2.41.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index 3a6d02e7d4..af6e4f8659 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.40.0-dev +version: 2.41.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index 1ae6dfd997..4d0aeb01f1 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards -version: 2.40.0-dev +version: 2.41.0-dev license: MIT dependencies: codeql/cpp-all: 1.4.2 diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index 90236b203e..a6d2ae30eb 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.40.0-dev +version: 2.41.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 96fc96ce24..a6ac09f1b1 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.40.0-dev +version: 2.41.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index 207facda4e..0265144f4f 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.40.0-dev +version: 2.41.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index e569153ae8..d1c854206c 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.40.0-dev +version: 2.41.0-dev license: MIT dependencies: codeql/cpp-all: 1.4.2 diff --git a/docs/user_manual.md b/docs/user_manual.md index 952a9a3c99..d076759571 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -33,14 +33,14 @@ ## Release information -This user manual documents release `2.40.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.41.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: - `coding-standards-codeql-packs-2.37.0-dev.zip`: CodeQL packs that can be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `code-scanning-cpp-query-pack-2.40.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.40.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.40.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.40.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.41.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.41.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.41.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.41.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -573,7 +573,7 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.40.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.41.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | From a75dc0af9db6f80aaff1ca18af5839912c9edc8c Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 15 Jan 2025 20:01:39 -0800 Subject: [PATCH 192/628] Address feedback --- .../rules/RULE-2-8/UnusedObjectDefinition.ql | 2 +- .../RULE-2-8/UnusedObjectDefinitionInMacro.ql | 24 ---- .../UnusedObjectDefinitionInMacroStrict.ql | 27 ---- .../RULE-2-8/UnusedObjectDefinitionStrict.ql | 2 +- .../RULE-2-8/UnusedObjectDefinition.expected | 22 +-- .../UnusedObjectDefinitionInMacro.expected | 2 - .../UnusedObjectDefinitionInMacro.qlref | 1 - ...usedObjectDefinitionInMacroStrict.expected | 2 - .../UnusedObjectDefinitionInMacroStrict.qlref | 1 - .../UnusedObjectDefinitionStrict.expected | 6 +- c/misra/test/rules/RULE-2-8/test.c | 2 + .../DeduplicateMacroResults.qll | 55 ++++++-- .../cpp/deadcode/UnusedObjects.qll | 129 ++---------------- .../cpp/exclusions/c/DeadCode2.qll | 36 +---- .../DeduplicateMacroResults.expected | 1 + .../alertreporting/DeduplicateMacroResults.ql | 7 +- .../deduplicatemacroresults.cpp | 2 +- docs/development_handbook.md | 1 + docs/user_manual.md | 3 +- rule_packages/c/DeadCode2.json | 27 ---- 20 files changed, 84 insertions(+), 268 deletions(-) delete mode 100644 c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacro.ql delete mode 100644 c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.ql delete mode 100644 c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.expected delete mode 100644 c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.qlref delete mode 100644 c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.expected delete mode 100644 c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.qlref diff --git a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql index 420733d4ac..2230a74592 100644 --- a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql +++ b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.deadcode.UnusedObjects -from ReportDeadObjectAtDefinition report +from ReportDeadObject report where not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionQuery()) and not report.hasAttrUnused() diff --git a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacro.ql b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacro.ql deleted file mode 100644 index d5c339c157..0000000000 --- a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacro.ql +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @id c/misra/unused-object-definition-in-macro - * @name RULE-2-8: Project macros should not include unused object definitions - * @description Macros should not have unused object definitions. - * @kind problem - * @precision very-high - * @problem.severity recommendation - * @tags external/misra/id/rule-2-8 - * maintainability - * performance - * external/misra/c/2012/amendment4 - * external/misra/obligation/advisory - */ - -import cpp -import codingstandards.c.misra -import codingstandards.cpp.deadcode.UnusedObjects - -from ReportDeadObjectInMacro report -where - not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionInMacroQuery()) and - not report.hasAttrUnused() -select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(), - report.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.ql b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.ql deleted file mode 100644 index 7eead60424..0000000000 --- a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @id c/misra/unused-object-definition-in-macro-strict - * @name RULE-2-8: Project macros should not include '__attribute__((unused))' object definitions - * @description A strict query which reports all unused object definitions in macros with - * '__attribute__((unused))'. - * @kind problem - * @precision very-high - * @problem.severity recommendation - * @tags external/misra/id/rule-2-8 - * maintainability - * performance - * external/misra/c/2012/amendment4 - * external/misra/c/strict - * external/misra/obligation/advisory - */ - -import cpp -import codingstandards.c.misra -import codingstandards.cpp.deadcode.UnusedObjects - -from ReportDeadObjectInMacro report -where - not isExcluded(report.getPrimaryElement(), - DeadCode2Package::unusedObjectDefinitionInMacroStrictQuery()) and - report.hasAttrUnused() -select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(), - report.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql index ad92c79481..cc117763ee 100644 --- a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql +++ b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql @@ -18,7 +18,7 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.deadcode.UnusedObjects -from ReportDeadObjectAtDefinition report +from ReportDeadObject report where not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionStrictQuery()) and report.hasAttrUnused() diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected index ce7e198122..731aebb1be 100644 --- a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected @@ -1,10 +1,12 @@ -| test.c:6:5:6:6 | definition of g2 | Unused object definition 'g2'. | test.c:6:5:6:6 | test.c:6:5:6:6 | | -| test.c:9:5:9:6 | definition of g3 | Unused object definition 'g3'. | test.c:9:5:9:6 | test.c:9:5:9:6 | | -| test.c:20:7:20:8 | definition of l2 | Unused object definition 'l2'. | test.c:20:7:20:8 | test.c:20:7:20:8 | | -| test.c:27:7:27:8 | definition of l5 | Unused object definition 'l5'. | test.c:27:7:27:8 | test.c:27:7:27:8 | | -| test.c:37:10:37:11 | definition of g5 | Unused object definition 'g5'. | test.c:37:10:37:11 | test.c:37:10:37:11 | | -| test.c:45:9:45:10 | definition of g6 | Unused object definition 'g6'. | test.c:45:9:45:10 | test.c:45:9:45:10 | | -| test.c:51:5:51:6 | definition of g7 | Unused object definition 'g7'. | test.c:51:5:51:6 | test.c:51:5:51:6 | | -| test.c:64:3:64:18 | ONLY_DEF_VAR(x) | Unused object definition 'l2' from macro '$@'. | test.c:60:1:60:34 | test.c:60:1:60:34 | ONLY_DEF_VAR | -| test.c:117:11:117:13 | definition of g10 | Unused object definition 'g10'. | test.c:117:11:117:13 | test.c:117:11:117:13 | | -| test.c:122:13:122:14 | definition of l2 | Unused object definition 'l2'. | test.c:122:13:122:14 | test.c:122:13:122:14 | | +| test.c:6:5:6:6 | definition of g2 | Unused object 'g2'. | test.c:6:5:6:6 | test.c:6:5:6:6 | (ignored) | +| test.c:9:5:9:6 | definition of g3 | Unused object 'g3'. | test.c:9:5:9:6 | test.c:9:5:9:6 | (ignored) | +| test.c:20:7:20:8 | definition of l2 | Unused object 'l2'. | test.c:20:7:20:8 | test.c:20:7:20:8 | (ignored) | +| test.c:27:7:27:8 | definition of l5 | Unused object 'l5'. | test.c:27:7:27:8 | test.c:27:7:27:8 | (ignored) | +| test.c:37:10:37:11 | definition of g5 | Unused object 'g5'. | test.c:37:10:37:11 | test.c:37:10:37:11 | (ignored) | +| test.c:45:9:45:10 | definition of g6 | Unused object 'g6'. | test.c:45:9:45:10 | test.c:45:9:45:10 | (ignored) | +| test.c:51:5:51:6 | definition of g7 | Unused object 'g7'. | test.c:51:5:51:6 | test.c:51:5:51:6 | (ignored) | +| test.c:64:3:64:18 | ONLY_DEF_VAR(x) | Invocation of macro '$@' defines unused object 'l2'. | test.c:60:1:60:34 | test.c:60:1:60:34 | ONLY_DEF_VAR | +| test.c:68:1:71:5 | #define ALSO_DEF_VAR(x) int x = 0; while (1) ; | Macro 'ALSO_DEF_VAR' defines unused object with an invocation-dependent name, for example, '$@'. | test.c:73:16:73:17 | test.c:73:16:73:17 | l1 | +| test.c:77:1:82:3 | #define DEF_UNUSED_INNER_VAR() { int _v = 0; while (1) ; } | Macro 'DEF_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:77:1:82:3 | test.c:77:1:82:3 | (ignored) | +| test.c:119:11:119:13 | definition of g10 | Unused object 'g10'. | test.c:119:11:119:13 | test.c:119:11:119:13 | (ignored) | +| test.c:124:13:124:14 | definition of l2 | Unused object 'l2'. | test.c:124:13:124:14 | test.c:124:13:124:14 | (ignored) | diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.expected b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.expected deleted file mode 100644 index c25c136789..0000000000 --- a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.expected +++ /dev/null @@ -1,2 +0,0 @@ -| test.c:68:1:71:5 | #define ALSO_DEF_VAR(x) int x = 0; while (1) ; | Macro 'ALSO_DEF_VAR' defines unused object of varied names, for example, '$@'. | test.c:73:16:73:17 | test.c:73:16:73:17 | l1 | -| test.c:77:1:82:3 | #define DEF_UNUSED_INNER_VAR() { int _v = 0; while (1) ; } | Macro 'DEF_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:77:1:82:3 | test.c:77:1:82:3 | (ignored) | diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.qlref b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.qlref deleted file mode 100644 index 057e684fd0..0000000000 --- a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacro.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-2-8/UnusedObjectDefinitionInMacro.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.expected b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.expected deleted file mode 100644 index 2919c65cb7..0000000000 --- a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.expected +++ /dev/null @@ -1,2 +0,0 @@ -| test.c:94:1:97:5 | #define ALSO_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0; while (1) ; | Macro 'ALSO_DEF_ATTR_UNUSED_VAR' defines unused object of varied names, for example, '$@'. | test.c:99:28:99:29 | test.c:99:28:99:29 | l1 | -| test.c:104:1:109:3 | #define DEF_ATTR_UNUSED_INNER_VAR() { __attribute__((unused)) int _v = 0; while (1) ; } | Macro 'DEF_ATTR_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:104:1:109:3 | test.c:104:1:109:3 | (ignored) | diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.qlref b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.qlref deleted file mode 100644 index f04653dcb6..0000000000 --- a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-2-8/UnusedObjectDefinitionInMacroStrict.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected index 624368ac54..cf3c0b64e1 100644 --- a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected @@ -1,2 +1,4 @@ -| test.c:87:29:87:30 | definition of g8 | Unused object definition 'g8'. | test.c:87:29:87:30 | test.c:87:29:87:30 | | -| test.c:90:3:90:30 | ONLY_DEF_ATTR_UNUSED_VAR(x) | Unused object definition 'l2' from macro '$@'. | test.c:88:1:88:70 | test.c:88:1:88:70 | ONLY_DEF_ATTR_UNUSED_VAR | +| test.c:87:29:87:30 | definition of g8 | Unused object 'g8'. | test.c:87:29:87:30 | test.c:87:29:87:30 | (ignored) | +| test.c:92:3:92:30 | ONLY_DEF_ATTR_UNUSED_VAR(x) | Invocation of macro '$@' defines unused object 'l2'. | test.c:88:1:88:70 | test.c:88:1:88:70 | ONLY_DEF_ATTR_UNUSED_VAR | +| test.c:96:1:99:5 | #define ALSO_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0; while (1) ; | Macro 'ALSO_DEF_ATTR_UNUSED_VAR' defines unused object with an invocation-dependent name, for example, '$@'. | test.c:101:28:101:29 | test.c:101:28:101:29 | l1 | +| test.c:106:1:111:3 | #define DEF_ATTR_UNUSED_INNER_VAR() { __attribute__((unused)) int _v = 0; while (1) ; } | Macro 'DEF_ATTR_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:106:1:111:3 | test.c:106:1:111:3 | (ignored) | diff --git a/c/misra/test/rules/RULE-2-8/test.c b/c/misra/test/rules/RULE-2-8/test.c index ef40dfb2a4..e35bf15567 100644 --- a/c/misra/test/rules/RULE-2-8/test.c +++ b/c/misra/test/rules/RULE-2-8/test.c @@ -87,6 +87,8 @@ void f6() { __attribute__((unused)) int g8 = 1; // NON-COMPLIANT #define ONLY_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0; void f7() { + ONLY_DEF_ATTR_UNUSED_VAR(l1); // COMPLIANT + l1; ONLY_DEF_ATTR_UNUSED_VAR(l2); // NON-COMPLIANT } diff --git a/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll b/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll index 7c4e8ef41d..6462ac855a 100644 --- a/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll +++ b/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll @@ -29,12 +29,16 @@ signature module MacroReportConfigSig { /* Create a message to describe this macro, using '$@' to describe an example `ResultElement`. */ string getMessageVariedResultInAllExpansions(Macro m); - /* + /** * Create a message to describe this macro expansion which produces a `ResultElement`, using '$@' * to describe the relevant macro. */ - string getMessageResultInIsolatedExpansion(ResultElement element); + + /** + * Create a message to describe a `ResultElement` which is not generated by a macro expansion. + */ + string getMessageNotInMacro(ResultElement element); } /** @@ -88,7 +92,7 @@ signature module MacroReportConfigSig { * ## Generating Report Objects * * This module also can be used to more easily report issues across these cases, by implementing - * `MacroReportConfigSig` and importing `DeduplicateMacroResults::Report::ReportResultInMacro`. + * `MacroReportConfigSig` and importing `DeduplicateMacroResults::Report::ReportResult`. * * ``` * module InvalidFooInMacroReportConfig implements MacroReportConfigSig { @@ -106,11 +110,15 @@ signature module MacroReportConfigSig { * string getMessageResultInIsolatedExpansion(InvalidFoo foo) { * result = "Invocation of macro $@ has invalid foo '" + foo.getName() + "'." * } + * + * string getMessageNotInMacro(ResultElement element) { + * result = "Invalid foo '" + element.getName() + "'." + * } * } * * import DeduplicateFooInMacros::Report as Report; * - * from Report::ReportResultInMacro report + * from Report::ReportResult report * where not excluded(report.getPrimaryElement(), ...) * select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(), * report.getOptionalPlaceholderMessage() @@ -234,11 +242,10 @@ module DeduplicateMacroResults< } } - /* + /** * Convenience predicate to know when invalid macro expansions have been reported at their macro * definition. */ - private predicate reported(Macro macro) { macro instanceof PrimaryMacroSameResultElementInAllInvocations or macro instanceof PrimaryMacroDifferentResultElementInAllInvocations @@ -248,7 +255,7 @@ module DeduplicateMacroResults< * A macro invocation for which the target macro does not always produce a `ResultElement`, but * this specific invocation of it does. * - * This is "primary" / most specific macro for these result elements. It will also does not match + * This is the "primary" / most specific macro for these result elements. It also does not match * `MacroInvocation`s inside of a `MacroInvocation` of a `Macro` which always produces a * `ResultElement`, indicating that the real problem lies with that other `Macro` instead of with * this particular invocation. @@ -274,10 +281,15 @@ module DeduplicateMacroResults< * See the doc comment for the `DeduplicateMacroResults` module for more info. */ module Report ReportConfig> { - newtype TReportResultInMacro = + newtype TReportResult = TReportMacroResultWithSameName(PrimaryMacroSameResultElementInAllInvocations def) or TReportMacroResultWithVariedName(PrimaryMacroDifferentResultElementInAllInvocations def) or - TReportIsolatedMacroResult(IsolatedMacroExpansionWithResultElement def) + TReportIsolatedMacroResult(IsolatedMacroExpansionWithResultElement def) or + TReportNotInMacro(ResultElement def) { + not exists (ResultMacroExpansion macroExpansion | + macroExpansion.getResultElement() = def + ) + } /** * An instance of a `ResultElement` to be reported to a user. @@ -291,7 +303,7 @@ module DeduplicateMacroResults< * The values returned by these methods are configured by the `MacroReportConfigSig` * signature parameter. */ - class ReportResultInMacro extends TReportResultInMacro { + class ReportResult extends TReportResult { string toString() { result = getMessage() } string getMessage() { @@ -310,6 +322,11 @@ module DeduplicateMacroResults< this = TReportIsolatedMacroResult(def) and result = ReportConfig::getMessageResultInIsolatedExpansion(def.getResultElement()) ) + or + exists(ResultElement def | + this = TReportNotInMacro(def) and + result = ReportConfig::getMessageNotInMacro(def) + ) } Element getPrimaryElement() { @@ -318,6 +335,8 @@ module DeduplicateMacroResults< this = TReportMacroResultWithVariedName(result) or this = TReportIsolatedMacroResult(result) + or + this = TReportNotInMacro(result) } Location getOptionalPlaceholderLocation() { @@ -335,6 +354,11 @@ module DeduplicateMacroResults< this = TReportIsolatedMacroResult(def) and result = def.getMacro().getLocation() ) + or + exists(ResultElement def | + this = TReportNotInMacro(def) and + result = def.getLocation() + ) } string getOptionalPlaceholderMessage() { @@ -343,7 +367,10 @@ module DeduplicateMacroResults< result = Config::describe(def.getExampleResultElement()) ) or - this = TReportMacroResultWithSameName(_) and + ( + this = TReportMacroResultWithSameName(_) + or this = TReportNotInMacro(_) + ) and result = "(ignored)" or this = TReportIsolatedMacroResult(_) and @@ -374,6 +401,12 @@ module DeduplicateMacroResults< or this = TReportIsolatedMacroResult(result) } + + ResultElement getAResultElement() { + result = getAResultMacroExpansion().getResultElement() + or + this = TReportNotInMacro(result) + } } } } diff --git a/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll b/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll index 96dcc8d315..fc262b5d93 100644 --- a/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll +++ b/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll @@ -40,141 +40,28 @@ module UnusedObjectDefinitionDedupeConfig implements import DeduplicateMacroResults as DeduplicateUnusedMacroObjects -/** - * A macro invocation that only defines one unused variable. - * - * These are reported at the invocation site when the variable is unused. - */ -class MacroExpansionWithOnlyUnusedObjectDefinition extends MacroInvocation { - UnusedObjectDefinition unusedObject; - - MacroExpansionWithOnlyUnusedObjectDefinition() { - exists(DeclStmt stmt, Declaration decl | - stmt = getStmt() and - count(getStmt()) = 1 and - count(stmt.getADeclaration()) = 1 and - decl = stmt.getADeclaration() and - count(decl.getADeclarationEntry()) = 1 and - unusedObject = decl.getADeclarationEntry() - ) and - not exists(this.getParentInvocation()) - } - - UnusedObjectDefinition getUnusedObject() { result = unusedObject } -} - -/** - * An object definition which is not from a macro, and for which all copies are unused. - * - * Extends the `HoldForAllCopies::LogicalResultElement` class, because these dead objects are often - * duplicated across defines and sometimes aren't marked used due to extractor bugs. - */ -class SimpleDeadObjectDefinition extends HoldsForAllCopies::LogicalResultElement -{ - SimpleDeadObjectDefinition() { not getAnElementInstance().isInMacroExpansion() } - - string getName() { result = getAnElementInstance().getName() } -} - -/* Make a type for reporting these two results in one query */ -newtype TReportDeadObjectAtDefinition = - TSimpleDeadObjectDefinition(SimpleDeadObjectDefinition def) or - TMacroExpansionWithOnlyUnusedObject(MacroExpansionWithOnlyUnusedObjectDefinition def) - -/** - * Class to report simple dead object definitions, and dead objects from macros that do nothing but - * define an object. - * - * To report all cases, make sure to also use the `DeduplicateUnusedMacroObjects::Report` module. - * - * To report these cases, use the methods: - * - `getMessage()` - * - `getPrimaryElement()`, - * - `getOptionalPlaceholderLocation()` - * - `getOptionalPlaceholderMessage()` - */ -class ReportDeadObjectAtDefinition extends TReportDeadObjectAtDefinition { - string toString() { result = getMessage() } - - string getMessage() { - exists(MacroExpansionWithOnlyUnusedObjectDefinition def | - this = TMacroExpansionWithOnlyUnusedObject(def) and - result = "Unused object definition '" + def.getUnusedObject().getName() + "' from macro '$@'." - ) - or - exists(SimpleDeadObjectDefinition def | - this = TSimpleDeadObjectDefinition(def) and - result = "Unused object definition '" + def.getName() + "'." - ) - } - - predicate hasAttrUnused() { - exists(MacroExpansionWithOnlyUnusedObjectDefinition def | - this = TMacroExpansionWithOnlyUnusedObject(def) and - def.getUnusedObject().hasAttrUnused() - ) - or - exists(SimpleDeadObjectDefinition def | - this = TSimpleDeadObjectDefinition(def) and - def.getAnElementInstance().hasAttrUnused() - ) - } - - Element getPrimaryElement() { - this = TMacroExpansionWithOnlyUnusedObject(result) - or - exists(SimpleDeadObjectDefinition def | - this = TSimpleDeadObjectDefinition(def) and - result = def.getAnElementInstance() - ) - } - - Location getOptionalPlaceholderLocation() { - exists(MacroExpansionWithOnlyUnusedObjectDefinition def | - this = TMacroExpansionWithOnlyUnusedObject(def) and - result = def.getMacro().getLocation() - ) - or - exists(SimpleDeadObjectDefinition def | - this = TSimpleDeadObjectDefinition(def) and - result = def.getAnElementInstance().getLocation() - ) - } - - string getOptionalPlaceholderMessage() { - exists(MacroExpansionWithOnlyUnusedObjectDefinition def | - this = TMacroExpansionWithOnlyUnusedObject(def) and - result = def.getMacroName() - ) - or - this = TSimpleDeadObjectDefinition(_) and - result = "" - } -} - /* Module config to use the `DeduplicateUnusedMacroObjects::Report` module */ -module ReportDeadObjectInMacroConfig implements MacroReportConfigSig { +module ReportDeadObjectConfig implements MacroReportConfigSig { bindingset[description] string getMessageSameResultInAllExpansions(Macro m, string description) { result = "Macro '" + m.getName() + "' defines unused object '" + description + "'." } string getMessageVariedResultInAllExpansions(Macro m) { - result = "Macro '" + m.getName() + "' defines unused object of varied names, for example, '$@'." + result = "Macro '" + m.getName() + "' defines unused object with an invocation-dependent name, for example, '$@'." } string getMessageResultInIsolatedExpansion(UnusedObjectDefinition unused) { result = "Invocation of macro '$@' defines unused object '" + unused.getName() + "'." } + + string getMessageNotInMacro(UnusedObjectDefinition unused) { + result = "Unused object '" + unused.getName() + "'." + } } /* The object to report in queries of dead objects used in macros */ -class ReportDeadObjectInMacro extends DeduplicateUnusedMacroObjects::Report::ReportResultInMacro +class ReportDeadObject extends DeduplicateUnusedMacroObjects::Report::ReportResult { - ReportDeadObjectInMacro() { - // `MacroExpansionWithOnlyUnusedObjectDefinition` is reported by class `ReportDeadObjectAtDefinition` - not getAResultMacroExpansion() instanceof MacroExpansionWithOnlyUnusedObjectDefinition - } - - predicate hasAttrUnused() { getAResultMacroExpansion().getResultElement().hasAttrUnused() } + predicate hasAttrUnused() { getAResultElement().hasAttrUnused() } } diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/DeadCode2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/DeadCode2.qll index 8f8edc03fa..611062a5ac 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/DeadCode2.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/DeadCode2.qll @@ -5,9 +5,7 @@ import codingstandards.cpp.exclusions.RuleMetadata newtype DeadCode2Query = TUnusedObjectDefinitionQuery() or - TUnusedObjectDefinitionInMacroQuery() or - TUnusedObjectDefinitionStrictQuery() or - TUnusedObjectDefinitionInMacroStrictQuery() + TUnusedObjectDefinitionStrictQuery() predicate isDeadCode2QueryMetadata(Query query, string queryId, string ruleId, string category) { query = @@ -19,15 +17,6 @@ predicate isDeadCode2QueryMetadata(Query query, string queryId, string ruleId, s ruleId = "RULE-2-8" and category = "advisory" or - query = - // `Query` instance for the `unusedObjectDefinitionInMacro` query - DeadCode2Package::unusedObjectDefinitionInMacroQuery() and - queryId = - // `@id` for the `unusedObjectDefinitionInMacro` query - "c/misra/unused-object-definition-in-macro" and - ruleId = "RULE-2-8" and - category = "advisory" - or query = // `Query` instance for the `unusedObjectDefinitionStrict` query DeadCode2Package::unusedObjectDefinitionStrictQuery() and @@ -36,15 +25,6 @@ predicate isDeadCode2QueryMetadata(Query query, string queryId, string ruleId, s "c/misra/unused-object-definition-strict" and ruleId = "RULE-2-8" and category = "advisory" - or - query = - // `Query` instance for the `unusedObjectDefinitionInMacroStrict` query - DeadCode2Package::unusedObjectDefinitionInMacroStrictQuery() and - queryId = - // `@id` for the `unusedObjectDefinitionInMacroStrict` query - "c/misra/unused-object-definition-in-macro-strict" and - ruleId = "RULE-2-8" and - category = "advisory" } module DeadCode2Package { @@ -55,24 +35,10 @@ module DeadCode2Package { TQueryC(TDeadCode2PackageQuery(TUnusedObjectDefinitionQuery())) } - Query unusedObjectDefinitionInMacroQuery() { - //autogenerate `Query` type - result = - // `Query` type for `unusedObjectDefinitionInMacro` query - TQueryC(TDeadCode2PackageQuery(TUnusedObjectDefinitionInMacroQuery())) - } - Query unusedObjectDefinitionStrictQuery() { //autogenerate `Query` type result = // `Query` type for `unusedObjectDefinitionStrict` query TQueryC(TDeadCode2PackageQuery(TUnusedObjectDefinitionStrictQuery())) } - - Query unusedObjectDefinitionInMacroStrictQuery() { - //autogenerate `Query` type - result = - // `Query` type for `unusedObjectDefinitionInMacroStrict` query - TQueryC(TDeadCode2PackageQuery(TUnusedObjectDefinitionInMacroStrictQuery())) - } } diff --git a/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected index eb55b83924..d9a7fe6a07 100644 --- a/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected +++ b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected @@ -1,3 +1,4 @@ +| deduplicatemacroresults.cpp:4:8:4:9 | definition of g1 | Findme var 'g1'. | deduplicatemacroresults.cpp:4:8:4:9 | deduplicatemacroresults.cpp:4:8:4:9 | (ignored) | | deduplicatemacroresults.cpp:10:1:10:34 | SOMETIMES_HAS_RESULTS1(type,name) | Invocation of macro $@ has findme var 'g3'. | deduplicatemacroresults.cpp:6:1:6:52 | deduplicatemacroresults.cpp:6:1:6:52 | SOMETIMES_HAS_RESULTS1 | | deduplicatemacroresults.cpp:13:1:13:34 | SOMETIMES_HAS_RESULTS2(type,name) | Invocation of macro $@ has findme var 'g5'. | deduplicatemacroresults.cpp:7:1:7:53 | deduplicatemacroresults.cpp:7:1:7:53 | SOMETIMES_HAS_RESULTS2 | | deduplicatemacroresults.cpp:15:1:15:50 | #define ALWAYS_HAS_SAME_RESULT() extern findme g6; | Macro ALWAYS_HAS_SAME_RESULT always has findme var named g6 | deduplicatemacroresults.cpp:15:1:15:50 | deduplicatemacroresults.cpp:15:1:15:50 | (ignored) | diff --git a/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql index cd999d72c9..9cae8d4ae8 100644 --- a/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql +++ b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql @@ -22,11 +22,16 @@ module FindMeReportConfig implements MacroReportConfigSig { string getMessageResultInIsolatedExpansion(FindMe f) { result = "Invocation of macro $@ has findme var '" + f.getName() + "'." } + + string getMessageNotInMacro(FindMe f) { + result = "Findme var '" + f.getName() + "'." + + } } import DeduplicateMacroResults import DeduplicateMacroResults::Report -from ReportResultInMacro report +from ReportResult report select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(), report.getOptionalPlaceholderMessage() diff --git a/cpp/common/test/library/codingstandards/cpp/alertreporting/deduplicatemacroresults.cpp b/cpp/common/test/library/codingstandards/cpp/alertreporting/deduplicatemacroresults.cpp index 3c5d8bca5b..d9b3659bf6 100644 --- a/cpp/common/test/library/codingstandards/cpp/alertreporting/deduplicatemacroresults.cpp +++ b/cpp/common/test/library/codingstandards/cpp/alertreporting/deduplicatemacroresults.cpp @@ -1,7 +1,7 @@ typedef struct { } findme; -findme g1; // ignore -- not in a macro +findme g1; // baseline report, not in a macro #define SOMETIMES_HAS_RESULTS1(type, name) type name // ignore #define SOMETIMES_HAS_RESULTS2(type, name) type name; // ignore diff --git a/docs/development_handbook.md b/docs/development_handbook.md index 97c615ba2e..83670dbbc8 100644 --- a/docs/development_handbook.md +++ b/docs/development_handbook.md @@ -42,6 +42,7 @@ | 0.32.0 | 2024-05-01 | Luke Cartey | Refer to the user manual for the list of supported standards. | | 0.33.0 | 2024-07-30 | Kristen Newbury | Remove out dated references to codeql modules directory usage. | | 0.34.0 | 2024-08-22 | Kristen Newbury | Remove out dated references to git submodules usage. | +| 0.35.0 | 2025-01-15 | Mike Fairhurst | Add guidance for the addition of 'strict' queries. | ## Scope of work diff --git a/docs/user_manual.md b/docs/user_manual.md index 5e808a1401..ae02555091 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -29,7 +29,8 @@ | 0.21.0 | 2024-05-01 | Luke Cartey | Add MISRA C++ 2023 as under development, and clarify MISRA C 2012 coverage. | | 0.22.0 | 2024-10-02 | Luke Cartey | Add MISRA C 2023 as under development, and clarify MISRA C 2012 coverage. | | 0.23.0 | 2024-10-21 | Luke Cartey | Add assembly as a hazard. | -| 0.24.0 | 2024-10-22 | Luke Cartey | Add CodeQL packs as a usable output, update release artifacts list. | +| 0.24.0 | 2024-10-22 | Luke Cartey | Add CodeQL packs as a usable output, update release artifacts list. | +| 0.25.0 | 2025-01-15 | Mike Fairhurst | Add guidance for the usage of 'strict' queries. | ## Release information diff --git a/rule_packages/c/DeadCode2.json b/rule_packages/c/DeadCode2.json index b897f595e6..8b373c31b6 100644 --- a/rule_packages/c/DeadCode2.json +++ b/rule_packages/c/DeadCode2.json @@ -18,19 +18,6 @@ "external/misra/c/2012/amendment4" ] }, - { - "description": "Macros should not have unused object definitions.", - "kind": "problem", - "name": "Project macros should not include unused object definitions", - "precision": "very-high", - "severity": "recommendation", - "short_name": "UnusedObjectDefinitionInMacro", - "tags": [ - "maintainability", - "performance", - "external/misra/c/2012/amendment4" - ] - }, { "description": "A strict query which reports all unused object definitions with '__attribute__((unused))'.", "kind": "problem", @@ -44,20 +31,6 @@ "external/misra/c/2012/amendment4", "external/misra/c/strict" ] - }, - { - "description": "A strict query which reports all unused object definitions in macros with '__attribute__((unused))'.", - "kind": "problem", - "name": "Project macros should not include '__attribute__((unused))' object definitions", - "precision": "very-high", - "severity": "recommendation", - "short_name": "UnusedObjectDefinitionInMacroStrict", - "tags": [ - "maintainability", - "performance", - "external/misra/c/2012/amendment4", - "external/misra/c/strict" - ] } ], "title": "A project should not contain unused object definitions", From 333cc77a08606fc3ecf089791555647b295aef98 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 15 Jan 2025 20:04:29 -0800 Subject: [PATCH 193/628] Code format --- .../cpp/alertreporting/DeduplicateMacroResults.qll | 10 ++++------ .../src/codingstandards/cpp/deadcode/UnusedObjects.qll | 4 +++- .../cpp/alertreporting/DeduplicateMacroResults.ql | 5 +---- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll b/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll index 6462ac855a..c56c40b730 100644 --- a/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll +++ b/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll @@ -110,7 +110,7 @@ signature module MacroReportConfigSig { * string getMessageResultInIsolatedExpansion(InvalidFoo foo) { * result = "Invocation of macro $@ has invalid foo '" + foo.getName() + "'." * } - * + * * string getMessageNotInMacro(ResultElement element) { * result = "Invalid foo '" + element.getName() + "'." * } @@ -286,9 +286,7 @@ module DeduplicateMacroResults< TReportMacroResultWithVariedName(PrimaryMacroDifferentResultElementInAllInvocations def) or TReportIsolatedMacroResult(IsolatedMacroExpansionWithResultElement def) or TReportNotInMacro(ResultElement def) { - not exists (ResultMacroExpansion macroExpansion | - macroExpansion.getResultElement() = def - ) + not exists(ResultMacroExpansion macroExpansion | macroExpansion.getResultElement() = def) } /** @@ -368,8 +366,8 @@ module DeduplicateMacroResults< ) or ( - this = TReportMacroResultWithSameName(_) - or this = TReportNotInMacro(_) + this = TReportMacroResultWithSameName(_) or + this = TReportNotInMacro(_) ) and result = "(ignored)" or diff --git a/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll b/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll index fc262b5d93..60e732873a 100644 --- a/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll +++ b/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll @@ -48,7 +48,9 @@ module ReportDeadObjectConfig implements MacroReportConfigSig { result = "Invocation of macro $@ has findme var '" + f.getName() + "'." } - string getMessageNotInMacro(FindMe f) { - result = "Findme var '" + f.getName() + "'." - - } + string getMessageNotInMacro(FindMe f) { result = "Findme var '" + f.getName() + "'." } } import DeduplicateMacroResults From bd3e06bc63297ab0dd992e2e5f2ad8be2ce15d87 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 15 Jan 2025 20:47:22 -0800 Subject: [PATCH 194/628] Fix 18-1 amendment use-use flow --- ...interArithmeticToAddressDifferentArrays.qll | 18 ++++++++++++++---- ...ArithmeticToAddressDifferentArrays.expected | 1 - .../test.cpp | 6 ++---- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll index 9728bc1f6d..b19df81570 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll @@ -33,7 +33,7 @@ abstract class ArrayLikeAccess extends Expr { */ class ArrayVariableAccess extends ArrayLikeAccess, VariableAccess { int size; - + ArrayVariableAccess() { size = getType().(ArrayType).getArraySize() } override Variable getElement() { result = getTarget() } @@ -47,7 +47,7 @@ class ArrayVariableAccess extends ArrayLikeAccess, VariableAccess { /** * Get the size of the object pointed to by a type (pointer or array). - * + * * Depth of type unwrapping depends on the type. Pointer will be dereferenced only once: the element * size of `T*` is `sizeof(T)` while the element size of `T**` is `sizeof(T*)`. However, array types * will be deeply unwrapped, as the pointed to size of `T[][]` is `sizeof(T)`. These processes @@ -88,7 +88,17 @@ class CastedToBytePointer extends ArrayLikeAccess, Conversion { override int getSize() { result = size } - override DataFlow::Node getNode() { result.asConvertedExpr() = this } + override DataFlow::Node getNode() { + // Carefully avoid use-use flow, which would mean any later usage of the original pointer value + // after the cast would be considered a usage of the byte pointer value. + // + // To fix this, we currently assume the value is assigned to a variable, and find that variable + // with `.asDefinition()` like so: + exists(DataFlow::Node conversion | + conversion.asConvertedExpr() = this and + result.asDefinition() = conversion.asExpr() + ) + } } /** @@ -272,4 +282,4 @@ query predicate problems(Expr arrayPointerCreation, string message, Element arra "Array pointer " + derivedArrayPointerOrPointerOperand.getName() + " points " + difference.toString() + " " + denomination + " past the end of $@." ) -} \ No newline at end of file +} diff --git a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected index 438b697775..5bb4881b81 100644 --- a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected +++ b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected @@ -6,4 +6,3 @@ | test.cpp:25:15:25:21 | & ... | Array pointer p14 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | | test.cpp:30:15:30:21 | & ... | Array pointer p17 points 1 element past the end of $@. | test.cpp:28:24:28:42 | (unsigned char *)... | cast to btye pointer (unsigned char *)... | | test.cpp:35:15:35:21 | & ... | Array pointer p20 points 1 element past the end of $@. | test.cpp:33:24:33:43 | (unsigned char *)... | cast to btye pointer (unsigned char *)... | -| test.cpp:43:15:43:23 | & ... | Array pointer p23 points 96 elements past the end of $@. | test.cpp:28:24:28:42 | (unsigned char *)... | cast to btye pointer (unsigned char *)... | diff --git a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp index f81026870d..70b26a2a57 100644 --- a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp +++ b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp @@ -36,9 +36,7 @@ void f1() { // Casting to a pointer to a differently sized type that isn't char // invalidates analysis - int l3[3]; - long *p21 = (long*)&l1; + long *p21 = (long *)&l1; void *p22 = &p21[0]; // COMPLIANT - // Not compliant, but we shouldn't detect it, but we do for the wrong reason: - void *p23 = &p21[100]; // NON_COMPLIANT[FALSE_NEGATIVE][FALSE_POSITIVE] + void *p23 = &p21[100]; // NON_COMPLIANT[FALSE_NEGATIVE] } \ No newline at end of file From a5eb426ee248936e93dc1e51b8c7298094091038 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 15 Jan 2025 21:07:49 -0800 Subject: [PATCH 195/628] Fix format issues --- .../codingstandards/c/misra/EssentialTypes.qll | 15 +++++++-------- c/misra/test/rules/RULE-7-4/test.c | 2 +- .../rules/invalidatedenvstringpointers/test.cpp | 6 +++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index b229bd54e2..7120921eed 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -297,8 +297,7 @@ class EssentialBinaryArithmeticExpr extends EssentialExpr, BinaryArithmeticOpera exists( Type leftEssentialType, Type rightEssentialType, EssentialTypeCategory leftEssentialTypeCategory, - EssentialTypeCategory rightEssentialTypeCategory, - int intTypeSize + EssentialTypeCategory rightEssentialTypeCategory, int intTypeSize | leftEssentialType = getEssentialType(getLeftOperand()) and rightEssentialType = getEssentialType(getRightOperand()) and @@ -340,19 +339,19 @@ class EssentialBinaryArithmeticExpr extends EssentialExpr, BinaryArithmeticOpera ) and ( leftEssentialTypeCategory = - [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] - and leftEssentialType.getSize() <= intTypeSize + [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] and + leftEssentialType.getSize() <= intTypeSize or rightEssentialTypeCategory = - [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] - and rightEssentialType.getSize() <= intTypeSize + [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] and + rightEssentialType.getSize() <= intTypeSize ) or this instanceof SubExpr and leftEssentialTypeCategory = EssentiallyCharacterType() and rightEssentialTypeCategory = - [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] - and rightEssentialType.getSize() <= intTypeSize + [EssentiallySignedType(), EssentiallyUnsignedType().(TEssentialTypeCategory)] and + rightEssentialType.getSize() <= intTypeSize then result instanceof PlainCharType else result = this.getStandardType() ) diff --git a/c/misra/test/rules/RULE-7-4/test.c b/c/misra/test/rules/RULE-7-4/test.c index ff270b611f..ab7ea21ce9 100644 --- a/c/misra/test/rules/RULE-7-4/test.c +++ b/c/misra/test/rules/RULE-7-4/test.c @@ -85,7 +85,7 @@ void w_call6() { w_sample6(1, "string10"); // COMPLIANT by first (and only) exception } -void w_sample7(char* x, ...) {} +void w_sample7(char *x, ...) {} void w_call7() { w_sample7("string11", 1); // NON_COMPLIANT, does not fit exceptional case diff --git a/cpp/common/test/rules/invalidatedenvstringpointers/test.cpp b/cpp/common/test/rules/invalidatedenvstringpointers/test.cpp index 167d770ef6..920d97c657 100644 --- a/cpp/common/test/rules/invalidatedenvstringpointers/test.cpp +++ b/cpp/common/test/rules/invalidatedenvstringpointers/test.cpp @@ -211,7 +211,7 @@ void f11(void) { void f12(void) { time_t rawtime; time(&rawtime); - char* r1 = ctime(&rawtime); + char *r1 = ctime(&rawtime); asctime(localtime(&rawtime)); printf("%s", r1); // NON_COMPLIANT } @@ -219,10 +219,10 @@ void f12(void) { void f13(void) { time_t rawtime; time(&rawtime); - char* r1 = ctime(&rawtime); + char *r1 = ctime(&rawtime); printf("%s", r1); // COMPLIANT - char* r2 = asctime(localtime(&rawtime)); + char *r2 = asctime(localtime(&rawtime)); printf("%s", r1); // NON_COMPLIANT printf("%s", r2); // COMPLIANT From 57b2067abce8fe8b55080bb6bfd560e60bc6fd4e Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 16 Jan 2025 10:14:18 -0800 Subject: [PATCH 196/628] Improve 18-1, void* casts and FPs where lowerBound appears incorrect --- .../2025-1-04-misra-c-technical-corrigenda-2.md | 3 ++- ...tUsePointerArithmeticToAddressDifferentArrays.qll | 12 +++++++++--- .../test.cpp | 6 ++++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/change_notes/2025-1-04-misra-c-technical-corrigenda-2.md b/change_notes/2025-1-04-misra-c-technical-corrigenda-2.md index 81ae3eb561..be037074f6 100644 --- a/change_notes/2025-1-04-misra-c-technical-corrigenda-2.md +++ b/change_notes/2025-1-04-misra-c-technical-corrigenda-2.md @@ -4,8 +4,9 @@ - Disallow `+` and `-` operations with an essentially char type and other types larger than int type. - Note, this change affects the essential type of such expressions, which may affect other essential types rules. - `RULE-18-1`, `M5-0-16` - `PointerAndDerivedPointerMustAddressSameArray.ql`, `PointerAndDerivedPointerAccessDifferentArray.ql`: - - Treat casts to byte pointers as pointers to arrays of the size of the pointed-to type + - Treat casts to byte pointers as pointers to arrays of the size of the pointed-to type. - Fix typo in report message, "passed" replaced with "past." + - Suppress results where range analysis appears potentially unreliable. - `RULE-21-10`, `RULE-25-5-3`, `ENV34-C` - `CallToSetlocaleInvalidatesOldPointers.ql`, `CallToSetlocaleInvalidatesOldPointersMisra.ql`, `DoNotStorePointersReturnedByEnvFunctions.ql`: - Report usage of returned pointers from `asctime`, `ctime`, during a call to either of the former. - Report usage of returned pointers from `gmtime`, `localtime`, during a call to either of the former. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll index b19df81570..5a45ff703e 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll @@ -9,6 +9,7 @@ import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import semmle.code.cpp.dataflow.new.DataFlow import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis +import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils import codeql.util.Boolean abstract class DoNotUsePointerArithmeticToAddressDifferentArraysSharedQuery extends Query { } @@ -68,11 +69,13 @@ int elementSize(Type type, Boolean deref) { * length depends on `elementSize()` of the original pointed-to type. */ class CastedToBytePointer extends ArrayLikeAccess, Conversion { + /** The sizeof() the pointed-to type */ int size; CastedToBytePointer() { getType().(PointerType).getBaseType().getSize() = 1 and - size = elementSize(getExpr().getType(), true) + size = elementSize(getExpr().getType(), true) and + size > 1 } override Element getElement() { result = this } @@ -138,7 +141,7 @@ module ArrayToArrayExprFlow = DataFlow::Global; /** Holds if the address taken expression `addressOf` takes the address of an array element at `index` of `array`. */ predicate pointerOperandCreation(AddressOfExpr addressOf, ArrayLikeAccess array, int index) { - exists(ArrayExpr ae | + exists(ArrayExpr ae, Expr arrayOffset | ( ArrayToArrayExprFlow::flow(array.getNode(), DataFlow::exprNode(ae.getArrayBase())) and array instanceof ArrayVariableAccess @@ -149,7 +152,10 @@ predicate pointerOperandCreation(AddressOfExpr addressOf, ArrayLikeAccess array, // flow() may hold for `ArrayVariableAccess` in the above, even though they aren't sources array instanceof CastedToBytePointer ) and - index = lowerBound(ae.getArrayOffset().getFullyConverted()) and + arrayOffset = ae.getArrayOffset().getFullyConverted() and + index = lowerBound(arrayOffset) and + // This case typically indicates range analysis has gone wrong: + not index = exprMaxVal(arrayOffset) and addressOf.getOperand() = ae ) } diff --git a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp index 70b26a2a57..4e373420e6 100644 --- a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp +++ b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp @@ -39,4 +39,10 @@ void f1() { long *p21 = (long *)&l1; void *p22 = &p21[0]; // COMPLIANT void *p23 = &p21[100]; // NON_COMPLIANT[FALSE_NEGATIVE] + + // Void pointers have size zero and can't be analyzed. + void *p24 = 0; + unsigned char* p25 = (unsigned char*)p24; + void *p26 = &p25[100]; // COMPLIANT + } \ No newline at end of file From 2d1cc22a68c1245831d66c483703deb4223db690 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 16 Jan 2025 10:14:29 -0800 Subject: [PATCH 197/628] Fix c tests --- ...ePointerArithmeticToAddressDifferentArrays.expected | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected b/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected index 1d487765df..bc471c0dc4 100644 --- a/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected +++ b/c/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected @@ -1,5 +1,5 @@ -| test.c:4:13:4:18 | ... + ... | Array pointer p2 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | -| test.c:5:13:5:18 | ... + ... | Array pointer p3 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | -| test.c:6:13:6:18 | & ... | Array pointer p4 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | -| test.c:11:8:11:11 | ... -- | Array pointer p7 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | -| test.c:12:8:12:9 | p3 | Array pointer p8 points 1 element passed the end of $@. | test.c:2:7:2:8 | l1 | l1 | +| test.c:4:13:4:18 | ... + ... | Array pointer p2 points 1 element past the end of $@. | test.c:2:7:2:8 | l1 | l1 | +| test.c:5:13:5:18 | ... + ... | Array pointer p3 points 1 element past the end of $@. | test.c:2:7:2:8 | l1 | l1 | +| test.c:6:13:6:18 | & ... | Array pointer p4 points 1 element past the end of $@. | test.c:2:7:2:8 | l1 | l1 | +| test.c:11:8:11:11 | ... -- | Array pointer p7 points 1 element past the end of $@. | test.c:2:7:2:8 | l1 | l1 | +| test.c:12:8:12:9 | p3 | Array pointer p8 points 1 element past the end of $@. | test.c:2:7:2:8 | l1 | l1 | From 5289894bc6a592628bda47bf24b806dfc16d11a8 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 16 Jan 2025 12:10:32 -0800 Subject: [PATCH 198/628] Fix test case format --- .../donotusepointerarithmetictoaddressdifferentarrays/test.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp index 4e373420e6..3a86d7963e 100644 --- a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp +++ b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp @@ -42,7 +42,6 @@ void f1() { // Void pointers have size zero and can't be analyzed. void *p24 = 0; - unsigned char* p25 = (unsigned char*)p24; + unsigned char *p25 = (unsigned char *)p24; void *p26 = &p25[100]; // COMPLIANT - } \ No newline at end of file From eae738532551f269a1c5cf07f6748c6ed708d6ee Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 16 Jan 2025 23:02:20 +0000 Subject: [PATCH 199/628] Remove stray comment --- c/misra/src/codingstandards/c/misra/EssentialTypes.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 0a4e64e98d..50b588d422 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -371,7 +371,6 @@ class EssentialSubExpr extends EssentialBinaryOperationSubjectToUsualConversions } } -// } /** * A named Enum type, as per D.5. */ From a8784e1c26bc68622cb16389f9a0e1562db436e5 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 19 Jan 2025 17:26:38 -0800 Subject: [PATCH 200/628] Simplify DeduplicateMacroResults::Report::ReportResult::toString() for performance reasons --- .../alertreporting/DeduplicateMacroResults.qll | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll b/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll index c56c40b730..b3c3d44ff4 100644 --- a/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll +++ b/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll @@ -302,7 +302,21 @@ module DeduplicateMacroResults< * signature parameter. */ class ReportResult extends TReportResult { - string toString() { result = getMessage() } + string toString() { + this = TReportMacroResultWithVariedName(_) and + result = + "Macro that always expands to a result element with invocation-dependent description" + or + this = TReportMacroResultWithSameName(_) and + result = "Macro that always expands to a result element with a constant description" + or + this = TReportIsolatedMacroResult(_) and + result = + "Specific macro expansion which produces a result element, but not all expansions do" + or + this = TReportNotInMacro(_) and + result = "Result element that is not in a macro" + } string getMessage() { exists(PrimaryMacroDifferentResultElementInAllInvocations def | From 0ba3359671fee9bb186aaf35cc3ce8794a3dfc01 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 21 Jan 2025 23:14:56 +0000 Subject: [PATCH 201/628] A7-1-2: Remove FunctionMissingConstexpr query As per #843 --- .../rules/A7-1-2/FunctionMissingConstexpr.ql | 160 ------------------ .../A7-1-2/FunctionMissingConstexpr.expected | 16 -- .../A7-1-2/FunctionMissingConstexpr.qlref | 1 - .../cpp/exclusions/cpp/Const.qll | 17 -- rule_packages/cpp/Const.json | 11 -- 5 files changed, 205 deletions(-) delete mode 100644 cpp/autosar/src/rules/A7-1-2/FunctionMissingConstexpr.ql delete mode 100644 cpp/autosar/test/rules/A7-1-2/FunctionMissingConstexpr.expected delete mode 100644 cpp/autosar/test/rules/A7-1-2/FunctionMissingConstexpr.qlref diff --git a/cpp/autosar/src/rules/A7-1-2/FunctionMissingConstexpr.ql b/cpp/autosar/src/rules/A7-1-2/FunctionMissingConstexpr.ql deleted file mode 100644 index 1cd68447fe..0000000000 --- a/cpp/autosar/src/rules/A7-1-2/FunctionMissingConstexpr.ql +++ /dev/null @@ -1,160 +0,0 @@ -/** - * @id cpp/autosar/function-missing-constexpr - * @name A7-1-2: The constexpr specifier shall be used for functions whose return value can be determined at compile time - * @description Using 'constexpr' makes it clear that a function is intended to return a compile - * time constant. - * @kind problem - * @precision high - * @problem.severity recommendation - * @tags external/autosar/id/a7-1-2 - * maintainability - * external/autosar/allocated-target/implementation - * external/autosar/enforcement/automated - * external/autosar/obligation/required - */ - -import cpp -import codingstandards.cpp.autosar -import codingstandards.cpp.TrivialType - -/** Gets a non-variant member field. */ -Field getANonVariantField(Class c) { - result = c.getAField() and - result.isInitializable() and - not result instanceof AnonymousUnionField -} - -/** - * A `Field` holding an "anonymous union" as described by `[class.union]`. - * - * For example, the union in this example: - * ``` - * class C { - * union { - * int x; - * short y; - * }; - * } - * ``` - */ -class AnonymousUnionField extends Field { - AnonymousUnionField() { hasName("(unknown field)") } - - /** - * Get a direct or indirect union member. - * - * Indirect members can come from nested anonymous unions. - */ - Field getAVariantMember() { - exists(Field f | f = getType().(Union).getAField() | - if f instanceof AnonymousUnionField - then result = f.(AnonymousUnionField).getAVariantMember() - else result = f - ) - } - - /** - * Holds if one variant member of this anonymous union field is initialized using NSDMI. - */ - predicate isExplicitlyInitialized() { exists(getAVariantMember().getInitializer().getExpr()) } -} - -/** - * Get a union which is not initialized by NSDMI. - */ -AnonymousUnionField getAnUninitializedAnonymousUnionField(Class c) { - result = c.getAField() and - not result.isExplicitlyInitialized() -} - -/** - * A function that can be `constexpr` specified according to the constraints for a `constexpr` - * function as specified in `[dcl.constexpr]/3`. - */ -class EffectivelyConstExprFunction extends Function { - EffectivelyConstExprFunction() { - // Not already marked as constexpr - not isDeclaredConstexpr() and - // Not virtual - not isVirtual() and - // Returns a literal type (which can be 'void') - (isLiteralType(getType()) or this instanceof Constructor) and - // Exclude cases that shouldn't be const or can't be const - not this instanceof Destructor and - not this instanceof CopyAssignmentOperator and - not this instanceof MoveAssignmentOperator and - not this.isCompilerGenerated() and - // All parameters are literal types - forall(Parameter p | p = getAParameter() | isLiteralType(p.getType())) and - // The function body is either deleted, defaulted or does not include one of the precluding - // statement kinds and is both side-effect free and created by the user - ( - isDeleted() - or - isDefaulted() - or - not this = any(AsmStmt a).getEnclosingFunction() and - not this = any(GotoStmt g).getEnclosingFunction() and - not this = any(TryStmt t).getEnclosingFunction() and - not exists(LocalVariable lv | this = lv.getFunction() | - not isLiteralType(lv.getType()) - or - lv instanceof StaticStorageDurationVariable - or - lv.isThreadLocal() - or - not exists(lv.getInitializer().getExpr()) - ) and - // For `constexpr` functions, the compiler only checks the rules above - it doesn't check - // whether the function can be evaluated as a compile time constant until the function is used, - // and then only confirms that it evaluates to a compile-time constant for a specific set of - // arguments used in another constexpr calculation. We approximate this by identifying the set - // of functions that are (conservatively) side-effect free. - isSideEffectFree() and - // "User defined" in some way - hasDefinition() and - not isCompilerGenerated() - ) and - ( - // A constructor should satisfy the constraints as specified in `[dcl.constexpr]/4`. - this instanceof Constructor - implies - ( - // No virtual base class - not getDeclaringType().getDerivation(_).isVirtual() and - ( - // All non-variant members initialized by this constructor - forall(Field f | f = getANonVariantField(getDeclaringType()) | - exists(ConstructorFieldInit cfi | - // Even if this field has a `getInitializer()` a `ConstructorFieldInit` will also be - // present on each constructor - cfi.getEnclosingFunction() = this and cfi.getTarget() = f - ) - ) and - // At least one variant member is initialized for each `AnonymousUnionField` which is not - // initialized with a `Field.getInitializer()`. This is different to the non-variant - // member case above - forall(AnonymousUnionField f | - f = getAnUninitializedAnonymousUnionField(getDeclaringType()) - | - exists(ConstructorFieldInit cfi | - cfi.getEnclosingFunction() = this and cfi.getTarget() = f.getAVariantMember() - ) - ) - or - // The function is deleted or defaulted, and every field has an NSDMI, and there are no - // uninitialized anonymous union fields - (isDeleted() or isDefaulted()) and - forall(Field f | f = getANonVariantField(getDeclaringType()) | - exists(f.getInitializer().getExpr()) - ) and - not exists(getAnUninitializedAnonymousUnionField(getDeclaringType())) - ) - ) - ) - } -} - -from EffectivelyConstExprFunction ecef -where not isExcluded(ecef, ConstPackage::functionMissingConstexprQuery()) -select ecef, ecef.getName() + " function could be marked as 'constexpr'." diff --git a/cpp/autosar/test/rules/A7-1-2/FunctionMissingConstexpr.expected b/cpp/autosar/test/rules/A7-1-2/FunctionMissingConstexpr.expected deleted file mode 100644 index a6de3fd724..0000000000 --- a/cpp/autosar/test/rules/A7-1-2/FunctionMissingConstexpr.expected +++ /dev/null @@ -1,16 +0,0 @@ -| test.cpp:30:3:30:17 | NonLiteralClass | NonLiteralClass function could be marked as 'constexpr'. | -| test.cpp:59:5:59:6 | h1 | h1 function could be marked as 'constexpr'. | -| test.cpp:67:5:67:6 | h2 | h2 function could be marked as 'constexpr'. | -| test.cpp:100:5:100:6 | h8 | h8 function could be marked as 'constexpr'. | -| test.cpp:117:7:117:9 | mf1 | mf1 function could be marked as 'constexpr'. | -| test.cpp:126:3:126:23 | MissingConstexprClass | MissingConstexprClass function could be marked as 'constexpr'. | -| test.cpp:127:3:127:23 | MissingConstexprClass | MissingConstexprClass function could be marked as 'constexpr'. | -| test.cpp:128:3:128:23 | MissingConstexprClass | MissingConstexprClass function could be marked as 'constexpr'. | -| test.cpp:161:3:161:26 | VariantMemberInitialized | VariantMemberInitialized function could be marked as 'constexpr'. | -| test.cpp:162:3:162:26 | VariantMemberInitialized | VariantMemberInitialized function could be marked as 'constexpr'. | -| test.cpp:163:3:163:26 | VariantMemberInitialized | VariantMemberInitialized function could be marked as 'constexpr'. | -| test.cpp:190:3:190:22 | VariantMemberNotInit | VariantMemberNotInit function could be marked as 'constexpr'. | -| test.cpp:269:26:269:26 | init | init function could be marked as 'constexpr'. | -| test.cpp:269:26:269:29 | init | init function could be marked as 'constexpr'. | -| test.cpp:271:26:271:26 | init | init function could be marked as 'constexpr'. | -| test.cpp:277:6:277:32 | test_template_instantiation | test_template_instantiation function could be marked as 'constexpr'. | diff --git a/cpp/autosar/test/rules/A7-1-2/FunctionMissingConstexpr.qlref b/cpp/autosar/test/rules/A7-1-2/FunctionMissingConstexpr.qlref deleted file mode 100644 index 723a910948..0000000000 --- a/cpp/autosar/test/rules/A7-1-2/FunctionMissingConstexpr.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A7-1-2/FunctionMissingConstexpr.ql \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Const.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Const.qll index 09f40388cc..f542ddf486 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Const.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Const.qll @@ -7,7 +7,6 @@ newtype ConstQuery = TRemoveConstOrVolatileQualificationAutosarQuery() or TDeclarationUnmodifiedObjectMissingConstSpecifierQuery() or TVariableMissingConstexprQuery() or - TFunctionMissingConstexprQuery() or TCvQualifiersNotPlacedOnTheRightHandSideQuery() or TOutputParametersUsedQuery() or TInOutParametersDeclaredAsTNotModifiedQuery() or @@ -45,15 +44,6 @@ predicate isConstQueryMetadata(Query query, string queryId, string ruleId, strin ruleId = "A7-1-2" and category = "required" or - query = - // `Query` instance for the `functionMissingConstexpr` query - ConstPackage::functionMissingConstexprQuery() and - queryId = - // `@id` for the `functionMissingConstexpr` query - "cpp/autosar/function-missing-constexpr" and - ruleId = "A7-1-2" and - category = "required" - or query = // `Query` instance for the `cvQualifiersNotPlacedOnTheRightHandSide` query ConstPackage::cvQualifiersNotPlacedOnTheRightHandSideQuery() and @@ -149,13 +139,6 @@ module ConstPackage { TQueryCPP(TConstPackageQuery(TVariableMissingConstexprQuery())) } - Query functionMissingConstexprQuery() { - //autogenerate `Query` type - result = - // `Query` type for `functionMissingConstexpr` query - TQueryCPP(TConstPackageQuery(TFunctionMissingConstexprQuery())) - } - Query cvQualifiersNotPlacedOnTheRightHandSideQuery() { //autogenerate `Query` type result = diff --git a/rule_packages/cpp/Const.json b/rule_packages/cpp/Const.json index c574e547bf..55c5ed6f90 100644 --- a/rule_packages/cpp/Const.json +++ b/rule_packages/cpp/Const.json @@ -71,17 +71,6 @@ "tags": [ "maintainability" ] - }, - { - "description": "Using 'constexpr' makes it clear that a function is intended to return a compile time constant.", - "kind": "problem", - "name": "The constexpr specifier shall be used for functions whose return value can be determined at compile time", - "precision": "high", - "severity": "recommendation", - "short_name": "FunctionMissingConstexpr", - "tags": [ - "maintainability" - ] } ], "title": "The constexpr specifier shall be used for values that can be determined at compile time." From f0e3c45740e1605d26108446809147f135c5cae2 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 21 Jan 2025 23:17:00 +0000 Subject: [PATCH 202/628] A7-1-2: Refactor test case to reflect rule intention Change the test case related to constexpr functions to highlight expected behaviour for local variables. --- .../A7-1-2/VariableMissingConstexpr.expected | 2 ++ cpp/autosar/test/rules/A7-1-2/test.cpp | 16 ++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected index 31c26a11ff..20fbeebe4a 100644 --- a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected +++ b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected @@ -8,6 +8,8 @@ | test.cpp:44:16:44:17 | lc | Variable 'lc' could be marked 'constexpr'. | | test.cpp:45:17:45:19 | lc2 | Variable 'lc2' could be marked 'constexpr'. | | test.cpp:55:7:55:8 | m2 | Variable 'm2' could be marked 'constexpr' and static. | +| test.cpp:65:7:65:8 | x2 | Variable 'x2' could be marked 'constexpr'. | +| test.cpp:66:13:66:14 | x3 | Variable 'x3' could be marked 'constexpr'. | | test.cpp:130:7:130:8 | m1 | Variable 'm1' could be marked 'constexpr' and static. | | test.cpp:141:7:141:8 | m1 | Variable 'm1' could be marked 'constexpr' and static. | | test.cpp:221:7:221:8 | l1 | Variable 'l1' could be marked 'constexpr'. | diff --git a/cpp/autosar/test/rules/A7-1-2/test.cpp b/cpp/autosar/test/rules/A7-1-2/test.cpp index 664a9cb8e7..12c4fed384 100644 --- a/cpp/autosar/test/rules/A7-1-2/test.cpp +++ b/cpp/autosar/test/rules/A7-1-2/test.cpp @@ -56,16 +56,16 @@ class MemberConstExpr { int m3 = 0; // COMPLIANT - can be set by constructor }; -int h1(int x, int y) { // NON_COMPLIANT - return x + y; -} +int h1(int x, int y) { return x + y; } -constexpr int h1_correct(int x, int y) { // COMPLIANT - return x + y; -} +constexpr int h1_const(int x, int y) { return x + y; } -int h2(int x) { return h1(x, 1) + 1; } // NON_COMPLIANT -constexpr int h2_correct(int x) { return h1_correct(x, 1) + 1; } // COMPLIANT +int h2() { + int x1 = h1(1, 1); // COMPLIANT + int x2 = h1_const(1, 1); // NON_COMPLIANT + const int x3 = h1_const(1, 1); // NON_COMPLIANT + constexpr int x4 = h1_const(1, 1); // COMPLIANT +} int h3(int x) { // COMPLIANT - uses goto, so can't be constexpr if (x) { From 5d0bfeeb5203c7a71cc57d1e4e6d3d36a076b5c0 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 21 Jan 2025 23:22:28 +0000 Subject: [PATCH 203/628] A7-1-2: Remove function constexpr test cases --- .../A7-1-2/VariableMissingConstexpr.expected | 25 ++-- cpp/autosar/test/rules/A7-1-2/test.cpp | 130 ------------------ 2 files changed, 12 insertions(+), 143 deletions(-) diff --git a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected index 20fbeebe4a..5feec712b8 100644 --- a/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected +++ b/cpp/autosar/test/rules/A7-1-2/VariableMissingConstexpr.expected @@ -10,16 +10,15 @@ | test.cpp:55:7:55:8 | m2 | Variable 'm2' could be marked 'constexpr' and static. | | test.cpp:65:7:65:8 | x2 | Variable 'x2' could be marked 'constexpr'. | | test.cpp:66:13:66:14 | x3 | Variable 'x3' could be marked 'constexpr'. | -| test.cpp:130:7:130:8 | m1 | Variable 'm1' could be marked 'constexpr' and static. | -| test.cpp:141:7:141:8 | m1 | Variable 'm1' could be marked 'constexpr' and static. | -| test.cpp:221:7:221:8 | l1 | Variable 'l1' could be marked 'constexpr'. | -| test.cpp:235:7:235:8 | l6 | Variable 'l6' could be marked 'constexpr'. | -| test.cpp:237:7:237:8 | l8 | Variable 'l8' could be marked 'constexpr'. | -| test.cpp:240:7:240:9 | l10 | Variable 'l10' could be marked 'constexpr'. | -| test.cpp:243:7:243:9 | l12 | Variable 'l12' could be marked 'constexpr'. | -| test.cpp:248:7:248:9 | l15 | Variable 'l15' could be marked 'constexpr'. | -| test.cpp:250:7:250:9 | l16 | Variable 'l16' could be marked 'constexpr'. | -| test.cpp:251:7:251:9 | l17 | Variable 'l17' could be marked 'constexpr'. | -| test.cpp:257:7:257:9 | l21 | Variable 'l21' could be marked 'constexpr'. | -| test.cpp:262:7:262:9 | l24 | Variable 'l24' could be marked 'constexpr'. | -| test.cpp:263:7:263:9 | l25 | Variable 'l25' could be marked 'constexpr'. | +| test.cpp:76:7:76:8 | m1 | Variable 'm1' could be marked 'constexpr' and static. | +| test.cpp:91:7:91:8 | l1 | Variable 'l1' could be marked 'constexpr'. | +| test.cpp:105:7:105:8 | l6 | Variable 'l6' could be marked 'constexpr'. | +| test.cpp:107:7:107:8 | l8 | Variable 'l8' could be marked 'constexpr'. | +| test.cpp:110:7:110:9 | l10 | Variable 'l10' could be marked 'constexpr'. | +| test.cpp:113:7:113:9 | l12 | Variable 'l12' could be marked 'constexpr'. | +| test.cpp:118:7:118:9 | l15 | Variable 'l15' could be marked 'constexpr'. | +| test.cpp:120:7:120:9 | l16 | Variable 'l16' could be marked 'constexpr'. | +| test.cpp:121:7:121:9 | l17 | Variable 'l17' could be marked 'constexpr'. | +| test.cpp:127:7:127:9 | l21 | Variable 'l21' could be marked 'constexpr'. | +| test.cpp:132:7:132:9 | l24 | Variable 'l24' could be marked 'constexpr'. | +| test.cpp:133:7:133:9 | l25 | Variable 'l25' could be marked 'constexpr'. | diff --git a/cpp/autosar/test/rules/A7-1-2/test.cpp b/cpp/autosar/test/rules/A7-1-2/test.cpp index 12c4fed384..5366a59f95 100644 --- a/cpp/autosar/test/rules/A7-1-2/test.cpp +++ b/cpp/autosar/test/rules/A7-1-2/test.cpp @@ -67,60 +67,6 @@ int h2() { constexpr int x4 = h1_const(1, 1); // COMPLIANT } -int h3(int x) { // COMPLIANT - uses goto, so can't be constexpr - if (x) { - goto l1; - } else { - return 10; - } -l1: - return 1; -} - -int h4(int x) { // COMPLIANT - uses try, so can't be constexpr - try { - return 1; - } catch (...) { - } -} - -int h5(int x) { // COMPLIANT - declares non literal local var - NonLiteralClass nlc; -} - -int h6(int x) { // COMPLIANT - declares static variable - static int i = x; - return x; -} - -int h7(int x) { // COMPLIANT - declares no init variable - int i; -} - -int h8(int x) { // NON_COMPLIANT - could be constexpr - int i = x; - return i; -} - -constexpr int h8_correct(int x) { // COMPLIANT - int i = x; - return i; -} - -int h9(int x) { // COMPLIANT - declares thread local variable - thread_local int i = x; - return x; -} - -class ConstexprFunctionClass { -public: - int mf1(int x) { return m1 + x; } // NON_COMPLIANT - constexpr int mf1_correct(int x) { return m1 + x; } // COMPLIANT - -private: - int m1; -}; - class MissingConstexprClass { public: MissingConstexprClass() = default; // NON_COMPLIANT @@ -130,82 +76,6 @@ class MissingConstexprClass { int m1 = 0; // NON_COMPLIANT }; -class VirtualBaseClass {}; - -class DerivedClass : public virtual VirtualBaseClass { -public: - DerivedClass() = default; // COMPLIANT - DerivedClass(int i) = delete; // COMPLIANT - DerivedClass(int i, LiteralClass lc) {} // COMPLIANT -private: - int m1 = 0; // NON_COMPLIANT -}; - -class NotAllMembersInitializedClass { -public: - NotAllMembersInitializedClass() = default; // COMPLIANT - NotAllMembersInitializedClass(int i) = delete; // COMPLIANT - NotAllMembersInitializedClass(int i, LiteralClass lc) {} // COMPLIANT -private: - int m1; -}; - -class NonLiteralParamsClass { -public: - NonLiteralParamsClass(int i, NonLiteralClass lc) {} // COMPLIANT -}; - -// Variant members are always initialized, so this can be marked constexpr -class VariantMemberInitialized { -public: - VariantMemberInitialized() = default; // NON_COMPLIANT - VariantMemberInitialized(int i) = delete; // NON_COMPLIANT - VariantMemberInitialized(int i, LiteralClass lc) {} // NON_COMPLIANT -private: - union { - int i = 0; - short s; - }; -}; - -class VariantMemberInitConstexpr { -public: - constexpr VariantMemberInitConstexpr() = default; // COMPLIANT - constexpr VariantMemberInitConstexpr(int i) = delete; // COMPLIANT - constexpr VariantMemberInitConstexpr(int i, LiteralClass lc) {} // COMPLIANT -private: - union { - int i = 0; - short s; - }; -}; - -// Variant members are not initialized at declaration, so we can only mark the -// constructors as constexpr if we explicitly initialize the variant member -class VariantMemberNotInit { -public: - VariantMemberNotInit() = default; // COMPLIANT - VariantMemberNotInit(int pi) = delete; // COMPLIANT - VariantMemberNotInit(int pi, LiteralClass lc) {} // COMPLIANT - VariantMemberNotInit(LiteralClass lc, int pi) : i(pi) {} // NON_COMPLIANT - constexpr VariantMemberNotInit(LiteralClass lc, short pi) // COMPLIANT - : i(pi) {} - -private: - union { - int i; - short s; - }; -}; - -class ExcludedCases { -public: - ~ExcludedCases() {} // COMPLIANT - - void operator=(ExcludedCases &) {} // COMPLIANT - void operator=(ExcludedCases &&) {} // COMPLIANT -}; - extern int random(); constexpr int add(int x, int y) { return x + y; } // Example with compile time constant literal value as default argument From 07cea2acc07dd2854bee201d52dade4e4b5ca41b Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 21 Jan 2025 23:23:49 +0000 Subject: [PATCH 204/628] Add A7-1-2 change note --- change_notes/2025-01-21-a7-1-2-remove-function-constexpr.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change_notes/2025-01-21-a7-1-2-remove-function-constexpr.md diff --git a/change_notes/2025-01-21-a7-1-2-remove-function-constexpr.md b/change_notes/2025-01-21-a7-1-2-remove-function-constexpr.md new file mode 100644 index 0000000000..ac9964adc9 --- /dev/null +++ b/change_notes/2025-01-21-a7-1-2-remove-function-constexpr.md @@ -0,0 +1,2 @@ + - `A7-1-2` - `FunctionMissingConstexpr.ql` + - Address false positives by removing the query - the rule is not intended to cover functions. \ No newline at end of file From 3180bfb0cfb2050e04773049a3baa69e5469837a Mon Sep 17 00:00:00 2001 From: Fernando Jose Date: Wed, 22 Jan 2025 09:56:51 +0900 Subject: [PATCH 205/628] Update A7-1-1 test for the exclusion of rvalue references. --- cpp/autosar/test/rules/A7-1-1/test.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/cpp/autosar/test/rules/A7-1-1/test.cpp b/cpp/autosar/test/rules/A7-1-1/test.cpp index 7895fd950f..1fdc0d66eb 100644 --- a/cpp/autosar/test/rules/A7-1-1/test.cpp +++ b/cpp/autosar/test/rules/A7-1-1/test.cpp @@ -83,4 +83,16 @@ template extern constexpr bool recurse_var = true; // COMPLIANT template extern constexpr bool recurse_var = B1 &&recurse_var; -void fp_621() { recurse_var; } \ No newline at end of file +void fp_621() { recurse_var; } + +#include + +void variadic_forwarding() {} + +template +void variadic_forwarding(T &&first, Args &&...rest) { + first; + variadic_forwarding(std::forward(rest)...); +} + +int test_variadic_forwarding() { variadic_forwarding(1, 1.1, "a"); } From dd892ffc18a6b60e56b83c288779bf60fbf8b8a7 Mon Sep 17 00:00:00 2001 From: Fernando Jose Date: Wed, 22 Jan 2025 12:49:55 +0900 Subject: [PATCH 206/628] Formatting fix in test. --- cpp/autosar/test/rules/A7-1-1/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/autosar/test/rules/A7-1-1/test.cpp b/cpp/autosar/test/rules/A7-1-1/test.cpp index 1fdc0d66eb..5e47b9c0bf 100644 --- a/cpp/autosar/test/rules/A7-1-1/test.cpp +++ b/cpp/autosar/test/rules/A7-1-1/test.cpp @@ -90,7 +90,7 @@ void fp_621() { recurse_var; } void variadic_forwarding() {} template -void variadic_forwarding(T &&first, Args &&...rest) { +void variadic_forwarding(T &&first, Args &&... rest) { first; variadic_forwarding(std::forward(rest)...); } From 6e68fb86452eb386a972aae9c81c14e4f85347b1 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 23 Jan 2025 23:08:40 +0000 Subject: [PATCH 207/628] Deviations: Support an attribute like comment syntax --- .../deviations/CodeIdentifierDeviation.qll | 39 +++++++++++-------- .../deviations/deviations_basic_test/main.cpp | 14 +++---- docs/user_manual.md | 28 ++++++------- 3 files changed, 43 insertions(+), 38 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll index e6220711a9..94587dca34 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -5,10 +5,10 @@ * some range of lines in the file containing the comment based on the annotation. The supported marker annotation * formats are: * - `` - the deviation applies to results on the current line. - * - `DEVIATION()` - same as above. - * - `DEVIATION_NEXT_LINE()` - this deviation applies to results on the next line. - * - `DEVIATION_BEGIN()` - marks the beginning of a range of lines where the deviation applies. - * - `DEVIATION_END()` - marks the end of a range of lines where the deviation applies. + * - `[[codingstandards::deviation()]]` - same as above. + * - `[[codingstandards::deviation_next_line()]]` - this deviation applies to results on the next line. + * - `[[codingstandards::deviation_begin()]]` - marks the beginning of a range of lines where the deviation applies. + * - `[[codingstandards::deviation_end()]]` - marks the end of a range of lines where the deviation applies. * * The valid `code-identifier`s are specified in deviation records, which also specify the query whose results are * suppressed by the deviation. @@ -53,7 +53,7 @@ private predicate commentMatches(Comment comment, string codeIdentifier) { /** * A deviation marker in the code. */ -abstract class DeviationMarker extends Comment { +abstract class CommentDeviationMarker extends Comment { DeviationRecord record; /** @@ -65,45 +65,50 @@ abstract class DeviationMarker extends Comment { /** * A deviation marker for a deviation that applies to the current line. */ -class DeviationEndOfLineMarker extends DeviationMarker { +class DeviationEndOfLineMarker extends CommentDeviationMarker { DeviationEndOfLineMarker() { - commentMatches(this, "DEVIATION(" + record.getCodeIdentifier() + ")") + commentMatches(this, "[[codingstandards::deviation(" + record.getCodeIdentifier() + ")]]") } } /** * A deviation marker for a deviation that applies to the next line. */ -class DeviationNextLineMarker extends DeviationMarker { +class DeviationNextLineMarker extends CommentDeviationMarker { DeviationNextLineMarker() { - commentMatches(this, "DEVIATION_NEXT_LINE(" + record.getCodeIdentifier() + ")") + commentMatches(this, + "[[codingstandards::deviation_next_line(" + record.getCodeIdentifier() + ")]]") } } /** * A deviation marker for a deviation that applies to a range of lines */ -abstract class DeviationRangeMarker extends DeviationMarker { } +abstract class CommentDeviationRangeMarker extends CommentDeviationMarker { } /** * A deviation marker for a deviation that begins on this line. */ -class DeviationBegin extends DeviationRangeMarker { - DeviationBegin() { commentMatches(this, "DEVIATION_BEGIN(" + record.getCodeIdentifier() + ")") } +class DeviationBegin extends CommentDeviationRangeMarker { + DeviationBegin() { + commentMatches(this, "[[codingstandards::deviation_begin(" + record.getCodeIdentifier() + ")]]") + } } /** * A deviation marker for a deviation that ends on this line. */ -class DeviationEnd extends DeviationRangeMarker { - DeviationEnd() { commentMatches(this, "DEVIATION_END(" + record.getCodeIdentifier() + ")") } +class DeviationEnd extends CommentDeviationRangeMarker { + DeviationEnd() { + commentMatches(this, "[[codingstandards::deviation_end(" + record.getCodeIdentifier() + ")]]") + } } private predicate hasDeviationCommentFileOrdering( - DeviationRecord record, DeviationRangeMarker comment, File file, int index + DeviationRecord record, CommentDeviationRangeMarker comment, File file, int index ) { comment = - rank[index](DeviationRangeMarker c | + rank[index](CommentDeviationRangeMarker c | c.getRecord() = record and file = c.getFile() | @@ -115,7 +120,7 @@ private predicate mkBeginStack(DeviationRecord record, File file, BeginStack sta // Stack is empty at the start index = 0 and stack = TEmptyBeginStack() and - exists(DeviationRangeMarker marker | + exists(CommentDeviationRangeMarker marker | marker.getRecord() = record and marker.getLocation().getFile() = file ) or diff --git a/cpp/common/test/deviations/deviations_basic_test/main.cpp b/cpp/common/test/deviations/deviations_basic_test/main.cpp index 53258f00fd..e1faaec68c 100644 --- a/cpp/common/test/deviations/deviations_basic_test/main.cpp +++ b/cpp/common/test/deviations/deviations_basic_test/main.cpp @@ -13,28 +13,28 @@ int main(int argc, char **argv) { long double d1; // NON_COMPLIANT (A0-4-2) long double d2; // a-0-4-2-deviation COMPLIANT[DEVIATED] - long double d3; // DEVIATION(a-0-4-2-deviation) COMPLIANT[DEVIATED] - + long double d3; // [[codingstandards::deviation(a-0-4-2-deviation)]] + // COMPLIANT[DEVIATED] long double d4; // NON_COMPLIANT (A0-4-2) - // DEVIATION_NEXT_LINE(a-0-4-2-deviation) + // [[codingstandards::deviation_next_line(a-0-4-2-deviation)]] long double d5; // COMPLIANT[DEVIATED] long double d6; // NON_COMPLIANT (A0-4-2) - // DEVIATION_BEGIN(a-0-4-2-deviation) + // [[codingstandards::deviation_begin(a-0-4-2-deviation)]] long double d7; // COMPLIANT[DEVIATED] getX(); // NON_COMPLIANT (A0-1-2) long double d8; // COMPLIANT[DEVIATED] getX(); // NON_COMPLIANT (A0-1-2) long double d9; // COMPLIANT[DEVIATED] - // DEVIATION_END(a-0-4-2-deviation) + // [[codingstandards::deviation_end(a-0-4-2-deviation)]] long double d10; // NON_COMPLIANT (A0-4-2) - // DEVIATION_BEGIN(a-0-4-2-deviation) + // [[codingstandards::deviation_begin(a-0-4-2-deviation)]] long double d11; // COMPLIANT[DEVIATED] getX(); // NON_COMPLIANT (A0-1-2) long double d12; // COMPLIANT[DEVIATED] getX(); // NON_COMPLIANT (A0-1-2) long double d13; // COMPLIANT[DEVIATED] - // DEVIATION_END(a-0-4-2-deviation) + // [[codingstandards::deviation_end(a-0-4-2-deviation)]] long double d14; // NON_COMPLIANT (A0-4-2) getX(); // NON_COMPLIANT (A0-1-2) return 0; diff --git a/docs/user_manual.md b/docs/user_manual.md index 7ad4dc4208..a936118758 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -426,8 +426,8 @@ The `process_coding_standards_config.py` has a dependency on the package `pyyaml A code identifier specified in a deviation record can be applied to certain results in the code by adding a comment marker consisting of a `code-identifier` with some optional annotations. The supported marker annotation formats are: - `` - the deviation applies to results on the current line. - - `DEVIATION()` - the deviation applies to results on the current line. - - `DEVIATION_NEXT_LINE()` - this deviation applies to results on the next line. + - `codingstandards::deviation()` - the deviation applies to results on the current line. + - `codingstandards::deviation_next_line()` - this deviation applies to results on the next line. - `DEVIATION_BEGIN()` - marks the beginning of a range of lines where the deviation applies. - `DEVIATION_END()` - marks the end of a range of lines where the deviation applies. @@ -438,32 +438,32 @@ Here are some examples, using the deviation record with the `a-0-4-2-deviation` long double x2; // a-0-4-2-deviation - COMPLIANT long double x3; // COMPLIANT - a-0-4-2-deviation - long double x4; // DEVIATION(a-0-4-2-deviation) - COMPLIANT - long double x5; // COMPLIANT - DEVIATION(a-0-4-2-deviation) + long double x4; // [[codingstandards::deviation(a-0-4-2-deviation)]] - COMPLIANT + long double x5; // COMPLIANT - [[codingstandards::deviation(a-0-4-2-deviation)]] - // DEVIATION_NEXT_LINE(a-0-4-2-deviation) + // [[codingstandards::deviation_next_line(a-0-4-2-deviation)]] long double x6; // COMPLIANT - // DEVIATION_BEGIN(a-0-4-2-deviation) + // [[codingstandards::deviation_begin(a-0-4-2-deviation)]] long double x7; // COMPLIANT - // DEVIATION_END(a-0-4-2-deviation) + // [[codingstandards::deviation_end(a-0-4-2-deviation)]] ``` -`DEVIATION_END` markers will pair with the closest unmatched `DEVIATION_BEGIN` for the same `code-identifier`. Consider this example: +`codingstandards::deviation_end` markers will pair with the closest unmatched `codingstandards::deviation_begin` for the same `code-identifier`. Consider this example: ```cpp -1 | // DEVIATION_BEGIN(a-0-4-2-deviation) +1 | // [[codingstandards::deviation_begin(a-0-4-2-deviation)]] 2 | -3 | // DEVIATION_BEGIN(a-0-4-2-deviation) +3 | // [[codingstandards::deviation_begin(a-0-4-2-deviation)]] 4 | -5 | // DEVIATION_END(a-0-4-2-deviation) +5 | // [[codingstandards::deviation_end(a-0-4-2-deviation)]] 6 | -7 | // DEVIATION_END(a-0-4-2-deviation) +7 | // [[codingstandards::deviation_end(a-0-4-2-deviation)]] ``` Here, Line 1 will pair with Line 7, and Line 3 will pair with Line 8. -A `DEVIATION_END` without a matching `DEVIATION_BEGIN`, or `DEVIATION_BEGIN` without a matching `DEVIATION_END` is invalid and will be ignored. +A `codingstandards::deviation_end` without a matching `codingstandards::deviation_begin`, or `codingstandards::deviation_begin` without a matching `codingstandards::deviation_end` is invalid and will be ignored. -`DEVIATION_BEGIN` and `DEVIATION_END` markers only apply within a single file. Markers cannot be paired across files, and deviations do not apply to included files. +`codingstandards::deviation_begin` and `codingstandards::deviation_end` markers only apply within a single file. Markers cannot be paired across files, and deviations do not apply to included files. ##### Deviation permit From a19965e7643c5efdd7cb8cf10d3d9ed0c620cf4d Mon Sep 17 00:00:00 2001 From: Michael R Fairhurst Date: Fri, 24 Jan 2025 19:32:56 -0800 Subject: [PATCH 208/628] Fix typo Co-authored-by: Luke Cartey <5377966+lcartey@users.noreply.github.com> --- c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql b/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql index b0945db559..6c03d32dab 100644 --- a/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql +++ b/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql @@ -149,7 +149,7 @@ import MemoryOrderFlow::PathGraph /** * If the node is a memory order constant, or shares a value with a memory order constant, then - * return the name of that cnonstant. Otherwise, simply print the node. + * return the name of that constant. Otherwise, simply print the node. */ string describeMemoryOrderNode(DataFlow::Node node) { if node.asExpr() instanceof MemoryOrderConstantExpr From 74867cc66ab0f70941255a99620543a695d9d69a Mon Sep 17 00:00:00 2001 From: knewbury01 Date: Mon, 27 Jan 2025 20:59:21 +0000 Subject: [PATCH 209/628] Bump version to 2.42.0-dev --- c/cert/src/qlpack.yml | 2 +- c/cert/test/qlpack.yml | 2 +- c/common/src/qlpack.yml | 2 +- c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- c/misra/test/qlpack.yml | 2 +- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/qlpack.yml | 2 +- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- docs/user_manual.md | 12 ++++++------ 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 4945abe49c..d5ba524b14 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.41.0-dev +version: 2.42.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index af5e71d2a1..98d9895612 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.41.0-dev +version: 2.42.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 9545a88178..e775358108 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.41.0-dev +version: 2.42.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index febda7a63b..f76badccfc 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.41.0-dev +version: 2.42.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 758c059c01..0ed5ef8b97 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.41.0-dev +version: 2.42.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index d367e8d06d..bf45171e18 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.41.0-dev +version: 2.42.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index 565cfc12db..80f6d1b0d2 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.41.0-dev +version: 2.42.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index 66755fe907..a1c802fec5 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.41.0-dev +version: 2.42.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index cc981411c2..3005c15ec3 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.41.0-dev +version: 2.42.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index af6e4f8659..9c49caac9f 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.41.0-dev +version: 2.42.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index 4d0aeb01f1..d97b322120 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards -version: 2.41.0-dev +version: 2.42.0-dev license: MIT dependencies: codeql/cpp-all: 1.4.2 diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index a6d2ae30eb..a207965a5e 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.41.0-dev +version: 2.42.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index a6ac09f1b1..fc3162ffb4 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.41.0-dev +version: 2.42.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index 0265144f4f..d0bd3a8b5a 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.41.0-dev +version: 2.42.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index d1c854206c..1a8ea75e77 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.41.0-dev +version: 2.42.0-dev license: MIT dependencies: codeql/cpp-all: 1.4.2 diff --git a/docs/user_manual.md b/docs/user_manual.md index b45b32639a..df3ce9a6b8 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -34,14 +34,14 @@ ## Release information -This user manual documents release `2.41.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.42.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: - `coding-standards-codeql-packs-2.37.0-dev.zip`: CodeQL packs that can be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `code-scanning-cpp-query-pack-2.41.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.41.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.41.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.41.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.42.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.42.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.42.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.42.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -583,7 +583,7 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.41.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.42.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | From d26d960cda7d843cef8d8f5b326246b6051e7e89 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 27 Jan 2025 15:56:52 -0800 Subject: [PATCH 210/628] Address feedback --- c/misra/src/codeql-suites/misra-c-audit.qls | 8 ++++ .../rules/DIR-5-3/ThreadCreatedByThread.ql | 29 +++++------- .../AtomicAggregateObjectDirectlyAccessed.ql | 4 +- .../RULE-21-25/InvalidMemoryOrderArgument.ql | 46 ++++++------------- ...icAggregateObjectDirectlyAccessed.expected | 9 ++++ c/misra/test/rules/RULE-12-6/test.c | 28 +++++++++++ .../InvalidMemoryOrderArgument.expected | 13 ++++-- c/misra/test/rules/RULE-21-25/test.c | 2 +- 8 files changed, 84 insertions(+), 55 deletions(-) create mode 100644 c/misra/src/codeql-suites/misra-c-audit.qls diff --git a/c/misra/src/codeql-suites/misra-c-audit.qls b/c/misra/src/codeql-suites/misra-c-audit.qls new file mode 100644 index 0000000000..ce1b9fed68 --- /dev/null +++ b/c/misra/src/codeql-suites/misra-c-audit.qls @@ -0,0 +1,8 @@ +- description: MISRA C 2012 (Audit) +- qlpack: codeql/misra-c-coding-standards +- include: + kind: + - problem + - path-problem + tags contain: + - external/misra/c/audit diff --git a/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql b/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql index 25b8b4cb9f..355b30808d 100644 --- a/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql +++ b/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql @@ -19,27 +19,22 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.Concurrency -Function callers(Function f) { result = f.getACallToThisFunction().getEnclosingFunction() } +class CThreadRoot extends Function { + CThreadCreateCall threadCreate; -class ThreadReachableFunction extends Function { - /* The root threaded function from which this function is reachable */ - Function threadRoot; - - ThreadReachableFunction() { - exists(CThreadCreateCall tc | - tc.getFunction() = callers*(this) and - threadRoot = tc.getFunction() - ) + CThreadRoot() { + threadCreate.getFunction() = this } - /* Get the root threaded function from which this function is reachable */ - Function getThreadRoot() { result = threadRoot } + /* Get a function which is reachable from this function */ + Function getAReachableFunction() { calls*(result) } + + CThreadCreateCall getCThreadCreateCall() { result = threadCreate } } -from CThreadCreateCall tc, ThreadReachableFunction enclosingFunction, Function threadRoot + from CThreadCreateCall tc, CThreadRoot threadRoot where not isExcluded(tc, Concurrency6Package::threadCreatedByThreadQuery()) and - enclosingFunction = tc.getEnclosingFunction() and - threadRoot = enclosingFunction.getThreadRoot() -select tc, "Thread creation call reachable from threaded function '$@'.", threadRoot, - threadRoot.toString() + tc.getEnclosingFunction() = threadRoot.getAReachableFunction() +select tc, "Thread creation call reachable from function '$@', which may also be $@.", threadRoot, + threadRoot.toString(), threadRoot.getCThreadCreateCall(), "started as a thread" diff --git a/c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql b/c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql index 4e65fa3f91..7478bb2787 100644 --- a/c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql +++ b/c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql @@ -22,13 +22,13 @@ where ( exists(FieldAccess fa | expr = fa and - fa.getQualifier().getUnderlyingType().hasSpecifier("atomic") and + fa.getQualifier().getType().hasSpecifier("atomic") and field = fa.getTarget() ) or exists(PointerFieldAccess fa | expr = fa and - fa.getQualifier().getUnderlyingType().(PointerType).getBaseType().hasSpecifier("atomic") and + fa.getQualifier().getType().stripTopLevelSpecifiers().(PointerType).getBaseType().hasSpecifier("atomic") and field = fa.getTarget() ) ) diff --git a/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql b/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql index 6c03d32dab..92ec2694b3 100644 --- a/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql +++ b/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql @@ -46,7 +46,7 @@ class MemoryOrderConstantExpr extends Expr { } /* Get the name of the `MemoryOrder` this expression is valued as. */ - string getMemoryOrderString() { result = ord.toString() } + string getMemoryOrderString() { result = ord.getName() } } /** @@ -56,26 +56,26 @@ class MemoryOrderedStdAtomicFunction extends Function { int orderParamIdx; MemoryOrderedStdAtomicFunction() { - exists(int baseParamIdx, int baseParams, string prefix, string suffix | - prefix = ["__", "__c11_"] and - suffix = ["", ".*", "_explicit"] and + exists(int baseParamIdx, int baseParams, string prefix, string regex, string basename | + regex = "__(c11_)?atomic_([a-z_]+)" and + prefix = getName().regexpCapture(regex, 1) and + basename = "atomic_" + getName().regexpCapture(regex, 2) + ["", "_explicit"] and ( - getName().regexpMatch(prefix + ["atomic_thread_fence", "atomic_signal_fence"] + suffix) and + basename in ["atomic_thread_fence", "atomic_signal_fence"] and baseParamIdx = 0 and baseParams = 1 or - getName() - .regexpMatch(prefix + ["atomic_load", "atomic_flag_clear", "atomic_flag_test_and_set"] + - suffix) and + basename in ["atomic_load", "atomic_flag_clear", "atomic_flag_test_and_set"] and baseParamIdx = 1 and baseParams = 2 or - getName() - .regexpMatch(prefix + ["atomic_store", "atomic_fetch_.*", "atomic_exchange"] + suffix) and + basename in [ + "atomic_store", "atomic_fetch_" + ["add", "sub", "or", "xor", "and"], "atomic_exchange" + ] and baseParamIdx = 2 and baseParams = 3 or - getName().regexpMatch(prefix + "atomic_compare_exchange_.*" + suffix) and + basename in ["atomic_compare_exchange_" + ["strong", "weak"]] and baseParamIdx = [3, 4] and baseParams = 5 ) and @@ -84,8 +84,7 @@ class MemoryOrderedStdAtomicFunction extends Function { // __atomic_load(8, &repr->a, &desired, order) // or // __atomic_load_8(&repr->a, &desired, order) - prefix = "__" and - suffix = ".*" and + prefix = "" and exists(int extraParams | extraParams = getNumberOfParameters() - baseParams and extraParams >= 0 and @@ -94,13 +93,7 @@ class MemoryOrderedStdAtomicFunction extends Function { or // Clang case, no inserted parameters: // __c11_atomic_load(object, order) - suffix = "" and - prefix = "__c11_" and - orderParamIdx = baseParamIdx - or - // Non-macro case, may occur in a subset of gcc/clang functions: - prefix = "" and - suffix = "_explicit" and + prefix = "c11_" and orderParamIdx = baseParamIdx ) ) @@ -122,17 +115,6 @@ module MemoryOrderFlowConfig implements DataFlow::ConfigSig { node.asExpr() = literal and not literal.getValue().toInt() = any(AllowedMemoryOrder a).getValue().toInt() ) - or - // Everything else: not a memory order constant or an integer valued literal, also exclude - // variables and functions, things that flow further back. - exists(Expr e | - node.asExpr() = e and - not e instanceof MemoryOrderConstantAccess and - not e instanceof Literal and - not e instanceof VariableAccess and - not e instanceof FunctionCall and - not DataFlow::localFlowStep(_, node) - ) } predicate isSink(DataFlow::Node node) { @@ -169,4 +151,4 @@ where not value = any(AllowedMemoryOrder e).getName() and function.getACallToThisFunction().getAnArgument() = argument select argument, source, sink, "Invalid memory order '$@' in call to function '$@'.", value, value, - function, function.toString() + function, function.getName() diff --git a/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected b/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected index df7f149fcc..5a92fc72fd 100644 --- a/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected +++ b/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected @@ -2,3 +2,12 @@ | test.c:44:18:44:18 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | | test.c:45:13:45:13 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | | test.c:46:18:46:18 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:65:6:65:6 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:71:9:71:9 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:82:18:82:18 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:83:3:83:31 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:84:3:84:39 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:85:3:85:19 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:86:3:86:23 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:87:3:87:19 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | +| test.c:88:3:88:23 | x | Invalid access to member '$@' on atomic struct or union. | test.c:5:7:5:7 | x | x | diff --git a/c/misra/test/rules/RULE-12-6/test.c b/c/misra/test/rules/RULE-12-6/test.c index ae6125da96..0281e6b0d8 100644 --- a/c/misra/test/rules/RULE-12-6/test.c +++ b/c/misra/test/rules/RULE-12-6/test.c @@ -58,4 +58,32 @@ void f1() { *s1_atomic_ptr = (s1){0}; // COMPLIANT s1_atomic_ptr = l2; // COMPLIANT s1_atomic_ptr->x; // COMPLIANT + + // Atomic specifier hidden behind a typedef, still atomic: + typedef _Atomic s1 atomic_s1; + atomic_s1 l3; + l3.x; // NON_COMPLIANT + + // Worst case scenario: a typedef of a volatile const pointer to an atomic + // typedef type. + typedef atomic_s1 *volatile const atomic_s1_specified_ptr; + atomic_s1_specified_ptr l4; + (l4)->x; // NON_COMPLIANT +} + +#define NOOP(x) (x) +#define DOT_FIELD_ACCESS_X(v) (v).x +#define POINTER_FIELD_ACCESS_X(v) (v)->x +#define GET_X_ATOMIC_S1() atomic_s1.x +#define GET_X_PTR_ATOMIC_S1() atomic_s1.x + +void f2() { + // Banned UB with user macros: + NOOP(atomic_s1.x); // NON-COMPLIANT + DOT_FIELD_ACCESS_X(atomic_s1); // NON-COMPLIANT + POINTER_FIELD_ACCESS_X(ptr_atomic_s1); // NON-COMPLIANT + GET_X_ATOMIC_S1(); // NON-COMPLIANT + GET_X_PTR_ATOMIC_S1(); // NON-COMPLIANT + GET_X_ATOMIC_S1() = 0; // NON-COMPLIANT + GET_X_PTR_ATOMIC_S1() = 0; // NON-COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected index 07229ff975..967621d71f 100644 --- a/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected +++ b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected @@ -17,25 +17,35 @@ edges | test.c:4:5:4:6 | *g2 | test.c:68:23:68:24 | g2 | provenance | | | test.c:4:5:4:6 | *g2 | test.c:71:23:71:24 | g2 | provenance | | | test.c:4:10:4:29 | memory_order_relaxed | test.c:4:5:4:6 | *g2 | provenance | | +| test.c:4:10:4:29 | memory_order_relaxed | test.c:4:10:4:29 | memory_order_relaxed | provenance | | | test.c:5:5:5:6 | *g3 | test.c:72:23:72:24 | g3 | provenance | | | test.c:5:10:5:29 | memory_order_acquire | test.c:5:5:5:6 | *g3 | provenance | | +| test.c:5:10:5:29 | memory_order_acquire | test.c:5:10:5:29 | memory_order_acquire | provenance | | | test.c:6:5:6:6 | *g4 | test.c:73:23:73:24 | g4 | provenance | | | test.c:6:10:6:29 | memory_order_consume | test.c:6:5:6:6 | *g4 | provenance | | +| test.c:6:10:6:29 | memory_order_consume | test.c:6:10:6:29 | memory_order_consume | provenance | | | test.c:7:5:7:6 | *g5 | test.c:74:23:74:24 | g5 | provenance | | | test.c:7:10:7:29 | memory_order_acq_rel | test.c:7:5:7:6 | *g5 | provenance | | +| test.c:7:10:7:29 | memory_order_acq_rel | test.c:7:10:7:29 | memory_order_acq_rel | provenance | | | test.c:8:5:8:6 | *g6 | test.c:75:23:75:24 | g6 | provenance | | | test.c:8:10:8:29 | memory_order_release | test.c:8:5:8:6 | *g6 | provenance | | +| test.c:8:10:8:29 | memory_order_release | test.c:8:10:8:29 | memory_order_release | provenance | | nodes | test.c:4:5:4:6 | *g2 | semmle.label | *g2 | | test.c:4:10:4:29 | memory_order_relaxed | semmle.label | memory_order_relaxed | +| test.c:4:10:4:29 | memory_order_relaxed | semmle.label | memory_order_relaxed | | test.c:5:5:5:6 | *g3 | semmle.label | *g3 | | test.c:5:10:5:29 | memory_order_acquire | semmle.label | memory_order_acquire | +| test.c:5:10:5:29 | memory_order_acquire | semmle.label | memory_order_acquire | | test.c:6:5:6:6 | *g4 | semmle.label | *g4 | | test.c:6:10:6:29 | memory_order_consume | semmle.label | memory_order_consume | +| test.c:6:10:6:29 | memory_order_consume | semmle.label | memory_order_consume | | test.c:7:5:7:6 | *g5 | semmle.label | *g5 | | test.c:7:10:7:29 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | +| test.c:7:10:7:29 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | | test.c:8:5:8:6 | *g6 | semmle.label | *g6 | | test.c:8:10:8:29 | memory_order_release | semmle.label | memory_order_release | +| test.c:8:10:8:29 | memory_order_release | semmle.label | memory_order_release | | test.c:16:29:16:48 | memory_order_relaxed | semmle.label | memory_order_relaxed | | test.c:17:29:17:48 | memory_order_acquire | semmle.label | memory_order_acquire | | test.c:18:29:18:48 | memory_order_consume | semmle.label | memory_order_consume | @@ -62,10 +72,8 @@ nodes | test.c:73:23:73:24 | g4 | semmle.label | g4 | | test.c:74:23:74:24 | g5 | semmle.label | g5 | | test.c:75:23:75:24 | g6 | semmle.label | g6 | -| test.c:78:23:78:46 | ... * ... | semmle.label | ... * ... | | test.c:79:23:79:23 | 1 | semmle.label | 1 | | test.c:80:23:80:25 | 100 | semmle.label | 100 | -| test.c:81:23:81:28 | ... + ... | semmle.label | ... + ... | subpaths #select | test.c:16:29:16:48 | memory_order_relaxed | test.c:16:29:16:48 | memory_order_relaxed | test.c:16:29:16:48 | memory_order_relaxed | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_load | __c11_atomic_load | @@ -96,4 +104,3 @@ subpaths | test.c:75:23:75:24 | g6 | test.c:8:10:8:29 | memory_order_release | test.c:75:23:75:24 | g6 | Invalid memory order '$@' in call to function '$@'. | memory_order_release | memory_order_release | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | | test.c:79:23:79:23 | 1 | test.c:79:23:79:23 | 1 | test.c:79:23:79:23 | 1 | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | | test.c:80:23:80:25 | 100 | test.c:80:23:80:25 | 100 | test.c:80:23:80:25 | 100 | Invalid memory order '$@' in call to function '$@'. | 100 | 100 | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | -| test.c:81:23:81:28 | ... + ... | test.c:81:23:81:28 | ... + ... | test.c:81:23:81:28 | ... + ... | Invalid memory order '$@' in call to function '$@'. | ... + ... | ... + ... | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | diff --git a/c/misra/test/rules/RULE-21-25/test.c b/c/misra/test/rules/RULE-21-25/test.c index 51df24555c..2e8c641032 100644 --- a/c/misra/test/rules/RULE-21-25/test.c +++ b/c/misra/test/rules/RULE-21-25/test.c @@ -78,7 +78,7 @@ void f(int p) { atomic_thread_fence(memory_order_seq_cst * 1); // COMPLIANT atomic_thread_fence(1); // NON-COMPLIANT atomic_thread_fence(100); // NON-COMPLIANT - atomic_thread_fence(g1 + 1); // NON-COMPLIANT + atomic_thread_fence(g1 + 1); // NON_COMPLIANT[FALSE_NEGATIVE] // No unsafe flow, currently accepted: atomic_thread_fence(p); // COMPLIANT From 763f4c1fa710055290a137c15ed8dc8290f7f10c Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 27 Jan 2025 16:06:01 -0800 Subject: [PATCH 211/628] Fix formatting --- c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql | 6 ++---- .../RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql | 7 ++++++- c/misra/test/rules/RULE-21-25/test.c | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql b/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql index 355b30808d..d780437141 100644 --- a/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql +++ b/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql @@ -22,9 +22,7 @@ import codingstandards.cpp.Concurrency class CThreadRoot extends Function { CThreadCreateCall threadCreate; - CThreadRoot() { - threadCreate.getFunction() = this - } + CThreadRoot() { threadCreate.getFunction() = this } /* Get a function which is reachable from this function */ Function getAReachableFunction() { calls*(result) } @@ -32,7 +30,7 @@ class CThreadRoot extends Function { CThreadCreateCall getCThreadCreateCall() { result = threadCreate } } - from CThreadCreateCall tc, CThreadRoot threadRoot +from CThreadCreateCall tc, CThreadRoot threadRoot where not isExcluded(tc, Concurrency6Package::threadCreatedByThreadQuery()) and tc.getEnclosingFunction() = threadRoot.getAReachableFunction() diff --git a/c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql b/c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql index 7478bb2787..5085e5dc7b 100644 --- a/c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql +++ b/c/misra/src/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.ql @@ -28,7 +28,12 @@ where or exists(PointerFieldAccess fa | expr = fa and - fa.getQualifier().getType().stripTopLevelSpecifiers().(PointerType).getBaseType().hasSpecifier("atomic") and + fa.getQualifier() + .getType() + .stripTopLevelSpecifiers() + .(PointerType) + .getBaseType() + .hasSpecifier("atomic") and field = fa.getTarget() ) ) diff --git a/c/misra/test/rules/RULE-21-25/test.c b/c/misra/test/rules/RULE-21-25/test.c index 2e8c641032..d1831785ba 100644 --- a/c/misra/test/rules/RULE-21-25/test.c +++ b/c/misra/test/rules/RULE-21-25/test.c @@ -78,7 +78,7 @@ void f(int p) { atomic_thread_fence(memory_order_seq_cst * 1); // COMPLIANT atomic_thread_fence(1); // NON-COMPLIANT atomic_thread_fence(100); // NON-COMPLIANT - atomic_thread_fence(g1 + 1); // NON_COMPLIANT[FALSE_NEGATIVE] + atomic_thread_fence(g1 + 1); // NON_COMPLIANT[FALSE_NEGATIVE] // No unsafe flow, currently accepted: atomic_thread_fence(p); // COMPLIANT From 1a2454165d16e8babd686b19727c6c7b6f77674b Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 28 Jan 2025 13:17:02 +0000 Subject: [PATCH 212/628] Deviations: Support C/C++ attributes This commit adds support for C/C++ attributes to specify deviations with code identifiers in the code. Attributes are inherited from parents, and support multiple code identifiers in a single definition. --- .../deviations/CodeIdentifierDeviation.qll | 49 +++++++++++++++++++ .../TypeLongDoubleUsed.expected | 4 ++ .../UnusedReturnValue.expected | 12 +++++ .../attribute_syntax.cpp | 44 +++++++++++++++++ docs/user_manual.md | 47 ++++++++++++++++-- 5 files changed, 151 insertions(+), 5 deletions(-) create mode 100644 cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll index 94587dca34..bd7100021a 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -177,6 +177,40 @@ private predicate isDeviationRangePaired( ) } +/** + * A standard attribute that either deviates a result. + */ +class DeviationAttribute extends StdAttribute { + DeviationRecord record; + + DeviationAttribute() { + this.hasQualifiedName("codingstandards", "deviation") and + // Support multiple argument deviations + "\"" + record.getCodeIdentifier() + "\"" = this.getAnArgument().getValueText() + } + + DeviationRecord getDeviationRecord() { result = record } + + pragma[nomagic] + Element getASuppressedElement() { + result.(Type).getAnAttribute() = this + or + result.(Stmt).getAnAttribute() = this + or + result.(Variable).getAnAttribute() = this + or + result.(Function).getAnAttribute() = this + or + result.(Expr).getEnclosingStmt() = this.getASuppressedElement() + or + result.(Stmt).getParentStmt() = this.getASuppressedElement() + or + result.(Stmt).getEnclosingFunction() = this.getASuppressedElement() + or + result.(LocalVariable) = this.getASuppressedElement().(DeclStmt).getADeclaration() + } +} + newtype TCodeIndentifierDeviation = TSingleLineDeviation(DeviationRecord record, Comment comment, string filepath, int suppressedLine) { ( @@ -195,6 +229,9 @@ newtype TCodeIndentifierDeviation = isDeviationRangePaired(record, beginComment, endComment) and beginComment.getLocation().hasLocationInfo(filepath, suppressedStartLine, _, _, _) and endComment.getLocation().hasLocationInfo(filepath, suppressedEndLine, _, _, _) + } or + TCodeIdentifierDeviation(DeviationRecord record, DeviationAttribute attribute) { + attribute.getDeviationRecord() = record } class CodeIdentifierDeviation extends TCodeIndentifierDeviation { @@ -203,6 +240,8 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { this = TSingleLineDeviation(result, _, _, _) or this = TMultiLineDeviation(result, _, _, _, _, _) + or + this = TCodeIdentifierDeviation(result, _) } /** @@ -225,6 +264,11 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { suppressedEndLine > elementLocationStart ) ) + or + exists(DeviationAttribute attribute | + this = TCodeIdentifierDeviation(_, attribute) and + attribute.getASuppressedElement() = e + ) } string toString() { @@ -243,5 +287,10 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { suppressedStartLine + ":" + suppressedEndLine ) ) + or + exists(DeviationAttribute attribute | + this = TCodeIdentifierDeviation(_, attribute) and + result = "Deviation record " + getDeviationRecord() + " applied to " + attribute + ) } } diff --git a/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected b/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected index a4e045edcf..99b3c89bfb 100644 --- a/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected +++ b/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected @@ -1,3 +1,7 @@ +| attribute_syntax.cpp:6:15:6:17 | dd1 | Use of long double type. | +| attribute_syntax.cpp:22:15:22:17 | d10 | Use of long double type. | +| attribute_syntax.cpp:30:15:30:17 | d14 | Use of long double type. | +| attribute_syntax.cpp:34:20:34:22 | d16 | Use of long double type. | | main.cpp:13:15:13:16 | d1 | Use of long double type. | | main.cpp:18:15:18:16 | d4 | Use of long double type. | | main.cpp:21:15:21:16 | d6 | Use of long double type. | diff --git a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected index 7cc5d2e1ab..7538df2195 100644 --- a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected +++ b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected @@ -1,3 +1,15 @@ +| attribute_syntax.cpp:5:3:5:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:17:5:17:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:19:5:19:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:25:5:25:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:27:5:27:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:31:3:31:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:42:3:42:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | | main.cpp:12:3:12:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | +| main.cpp:25:3:25:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | +| main.cpp:27:3:27:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | +| main.cpp:33:3:33:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | +| main.cpp:35:3:35:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | +| main.cpp:39:3:39:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | | nested/nested3/test3.h:5:3:5:7 | call to getZ3 | Return value from call to $@ is unused. | nested/nested3/test3.h:1:5:1:9 | getZ3 | getZ3 | | nested/test.h:5:3:5:6 | call to getY | Return value from call to $@ is unused. | nested/test.h:1:5:1:8 | getY | getY | diff --git a/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp b/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp new file mode 100644 index 0000000000..97b4ba987d --- /dev/null +++ b/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp @@ -0,0 +1,44 @@ +int getZ() { return 5; } + +int alt() { + int x = 0; // COMPLIANT[DEVIATED] + getZ(); // NON_COMPLIANT + long double dd1; // NON_COMPLIANT (A0-4-2) + + long double [[codingstandards::deviation( + "a-0-4-2-deviation")]] dd3; // COMPLIANT[DEVIATED] + long double [[codingstandards::deviation("a")]] dd3a; // NON_COMPLIAT + + [[codingstandards::deviation( + "a-0-4-2-deviation")]] long double dd4; // COMPLIANT[DEVIATED] + + [[codingstandards::deviation("a-0-4-2-deviation")]] { + long double d7; // COMPLIANT[DEVIATED] + getZ(); // NON_COMPLIANT (A0-1-2) + long double d8; // COMPLIANT[DEVIATED] + getZ(); // NON_COMPLIANT (A0-1-2) + long double d9; // COMPLIANT[DEVIATED] + } + long double d10; // NON_COMPLIANT (A0-4-2) + [[codingstandards::deviation("a-0-4-2-deviation")]] { + long double d11; // COMPLIANT[DEVIATED] + getZ(); // NON_COMPLIANT (A0-1-2) + long double d12; // COMPLIANT[DEVIATED] + getZ(); // NON_COMPLIANT (A0-1-2) + long double d13; // COMPLIANT[DEVIATED] + } + long double d14; // NON_COMPLIANT (A0-4-2) + getZ(); // NON_COMPLIANT (A0-1-2) + [[codingstandards::deviation("a-0-4-2-deviation")]] + for (long double d15 = 0.0; true;) {} // COMPLIANT[DEVIATED] + for (long double d16 = 0.0; true;) { // NON_COMPLIANT (A0-4-2) + } + return 0; +} + +[[codingstandards::deviation("a-0-4-2-deviation")]] +int alt2() { + int x = 0; // COMPLIANT[DEVIATED] + getZ(); // NON_COMPLIANT + long double dd1; // COMPLIANT[DEVIATED] +} \ No newline at end of file diff --git a/docs/user_manual.md b/docs/user_manual.md index a936118758..5d2236ed10 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -421,15 +421,50 @@ The `process_coding_standards_config.py` has a dependency on the package `pyyaml `pip3 install -r path/to/codeql-coding-standards/scripts/configuration/requirements.txt` -##### Deviation code identifiers +##### Deviation code identifier attributes -A code identifier specified in a deviation record can be applied to certain results in the code by adding a comment marker consisting of a `code-identifier` with some optional annotations. The supported marker annotation formats are: +A code identifier specified in a deviation record can be applied to certain results in the code by adding a C or C++ attribute of the following format: + +``` +[[codingstandards::deviation("code-identifier")]] +``` + +This attribute may be added to the following program elements: + * Functions + * Statements + * Variables + * Type declarations + +Deviation attributes are inherited from parents in the code structure. For example, a deviation attribute applied to a function will apply the deviation to all code within the function. Note: deviations are not inherited by lambda expressions. + +Multiple code identifiers may be passed in a single attribute to apply multiple deviations, for example: + +``` +[[codingstandards::deviation("code-identifier-1", "code-identifier-2")]] +``` + +Note - considation should be taken to ensure the use of custom attributes for deviations is compatible with your chosen language version, compiler, compiler configuration and coding standard. + +**Use of attributes in C Coding Standards**: The C Standard introduces attributes in C23, however some compilers support attributes as a language extension in prior versions. You should: + * Confirm that your compiler supports attributes for your chosen compiler configuration, if necessary as a language extension. + * Confirm that unknown attributes are ignored by the compiler. + * For MISRA C, add a project deviation against "Rule 1.2: Language extensions should not be used", if attribute support is a language extension in your language version. + +**Use of attributes in C++ Coding Standards**: The C++ Standard supports attributes in C++14, however the handling of unknown attributes is implementation defined. From C++17 onwards, unknown attributes are mandated to be ignored. Unknown attributes will usually raise an "unknown attribute" warning. You should: + * If using C++14, confirm that your compiler ignores unknown attributes. + * If using AUTOSAR and a compiler which produces warnings on unknown attributes, the compiler warning should be disabled (as per `A1-1-2: A warning level of the compilation process shall be set in compliance with project policies`), to ensure compliance with `A1-4-3: All code should compiler free of compiler warnings`. + +If you cannot satisfy these condition, please use the deviation code identifier comment format instead. + +##### Deviation code identifier comments + +As an alternative to attributes, a code identifier specified in a deviation record can be applied to certain results in the code by adding a comment marker consisting of a `code-identifier` with some optional annotations. The supported marker annotation formats are: - `` - the deviation applies to results on the current line. - `codingstandards::deviation()` - the deviation applies to results on the current line. - `codingstandards::deviation_next_line()` - this deviation applies to results on the next line. - - `DEVIATION_BEGIN()` - marks the beginning of a range of lines where the deviation applies. - - `DEVIATION_END()` - marks the end of a range of lines where the deviation applies. + - `codingstandards::deviation_begin()` - marks the beginning of a range of lines where the deviation applies. + - `codingstandards::deviation_end()` - marks the end of a range of lines where the deviation applies. Here are some examples, using the deviation record with the `a-0-4-2-deviation` code-identifier specified above: ```cpp @@ -465,7 +500,9 @@ A `codingstandards::deviation_end` without a matching `codingstandards::deviatio `codingstandards::deviation_begin` and `codingstandards::deviation_end` markers only apply within a single file. Markers cannot be paired across files, and deviations do not apply to included files. -##### Deviation permit +Note: deviation markers cannot be applied to the body of a macro. Please apply the deviation to macro expansion, or use the attribute deviation format. + +##### Deviation permits The current implementation supports _deviation permits_ as described in the [MISRA Compliance:2020](https://www.misra.org.uk/app/uploads/2021/06/MISRA-Compliance-2020.pdf) section _4.3 Deviation permits_. From 5ad258842d90afd1d10ca1ef3b1227f518ebca45 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 28 Jan 2025 10:30:15 -0800 Subject: [PATCH 213/628] fix test --- .../rules/DIR-5-3/ThreadCreatedByThread.ql | 4 +- .../DIR-5-3/ThreadCreatedByThread.expected | 28 +++++++------- c/misra/test/rules/DIR-5-3/test.c | 38 ++++++++++--------- 3 files changed, 36 insertions(+), 34 deletions(-) diff --git a/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql b/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql index d780437141..207e763fa7 100644 --- a/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql +++ b/c/misra/src/rules/DIR-5-3/ThreadCreatedByThread.ql @@ -27,7 +27,7 @@ class CThreadRoot extends Function { /* Get a function which is reachable from this function */ Function getAReachableFunction() { calls*(result) } - CThreadCreateCall getCThreadCreateCall() { result = threadCreate } + CThreadCreateCall getACThreadCreateCall() { result = threadCreate } } from CThreadCreateCall tc, CThreadRoot threadRoot @@ -35,4 +35,4 @@ where not isExcluded(tc, Concurrency6Package::threadCreatedByThreadQuery()) and tc.getEnclosingFunction() = threadRoot.getAReachableFunction() select tc, "Thread creation call reachable from function '$@', which may also be $@.", threadRoot, - threadRoot.toString(), threadRoot.getCThreadCreateCall(), "started as a thread" + threadRoot.toString(), threadRoot.getACThreadCreateCall(), "started as a thread" diff --git a/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected b/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected index 5b73fd97aa..b8dc2bfe4b 100644 --- a/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected +++ b/c/misra/test/rules/DIR-5-3/ThreadCreatedByThread.expected @@ -1,14 +1,14 @@ -| test.c:47:3:47:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | -| test.c:48:3:48:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | -| test.c:56:3:56:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | -| test.c:57:3:57:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | -| test.c:65:3:65:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | -| test.c:66:3:66:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | -| test.c:74:3:74:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | -| test.c:74:3:74:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | -| test.c:75:3:75:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | -| test.c:75:3:75:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | -| test.c:79:3:79:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | -| test.c:79:3:79:13 | call to thrd_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | -| test.c:80:3:80:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | -| test.c:80:3:80:16 | call to pthread_create | Thread creation call reachable from threaded function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | +| test.c:49:3:49:13 | call to thrd_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:48:7:48:18 | pthread_func | pthread_func | test.c:19:3:19:16 | call to pthread_create | started as a thread | +| test.c:50:3:50:16 | call to pthread_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:48:7:48:18 | pthread_func | pthread_func | test.c:19:3:19:16 | call to pthread_create | started as a thread | +| test.c:58:3:58:13 | call to thrd_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | +| test.c:59:3:59:16 | call to pthread_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | +| test.c:67:3:67:13 | call to thrd_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | +| test.c:68:3:68:16 | call to pthread_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | +| test.c:76:3:76:13 | call to thrd_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:48:7:48:18 | pthread_func | pthread_func | test.c:19:3:19:16 | call to pthread_create | started as a thread | +| test.c:76:3:76:13 | call to thrd_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | +| test.c:77:3:77:16 | call to pthread_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:48:7:48:18 | pthread_func | pthread_func | test.c:19:3:19:16 | call to pthread_create | started as a thread | +| test.c:77:3:77:16 | call to pthread_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | +| test.c:81:3:81:13 | call to thrd_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:48:7:48:18 | pthread_func | pthread_func | test.c:19:3:19:16 | call to pthread_create | started as a thread | +| test.c:81:3:81:13 | call to thrd_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | +| test.c:82:3:82:16 | call to pthread_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:48:7:48:18 | pthread_func | pthread_func | test.c:19:3:19:16 | call to pthread_create | started as a thread | +| test.c:82:3:82:16 | call to pthread_create | Thread creation call reachable from function '$@', which may also be $@. | test.c:57:5:57:13 | thrd_func | thrd_func | test.c:18:3:18:13 | call to thrd_create | started as a thread | diff --git a/c/misra/test/rules/DIR-5-3/test.c b/c/misra/test/rules/DIR-5-3/test.c index 24e03d9a33..ebdf53cfb4 100644 --- a/c/misra/test/rules/DIR-5-3/test.c +++ b/c/misra/test/rules/DIR-5-3/test.c @@ -5,7 +5,9 @@ thrd_t g1; // COMPLIANT pthread_t g2; // COMPLIANT void *pthread_func(void *arg); +void *pthread_func_inner(void *arg); int thrd_func(void *arg); +int thrd_func_inner(void *arg); void make_threads_called_from_main(void); void func_called_from_main(void); @@ -16,8 +18,8 @@ void main() { thrd_create(&g1, &thrd_func, NULL); // COMPLIANT pthread_create(&g2, NULL, &pthread_func, NULL); // COMPLIANT - thrd_create(&g1, &thrd_func, NULL); // COMPLIANT - pthread_create(&g2, NULL, &pthread_func, NULL); // COMPLIANT + thrd_create(&g1, &thrd_func_inner, NULL); // COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // COMPLIANT make_threads_called_from_main(); func_called_from_main(); @@ -25,8 +27,8 @@ void main() { } void make_threads_called_from_main() { - thrd_create(&g1, &thrd_func, NULL); // COMPLIANT - pthread_create(&g2, NULL, &pthread_func, NULL); // COMPLIANT + thrd_create(&g1, &thrd_func_inner, NULL); // COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // COMPLIANT } void func_called_from_main() { @@ -34,8 +36,8 @@ void func_called_from_main() { } void make_threads_called_from_func_called_from_main() { - thrd_create(&g1, &thrd_func, NULL); // COMPLIANT - pthread_create(&g2, NULL, &pthread_func, NULL); // COMPLIANT + thrd_create(&g1, &thrd_func_inner, NULL); // COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // COMPLIANT } void make_threads_called_from_pthread_func(void); @@ -44,8 +46,8 @@ void func_called_from_pthread_thrd(void); void make_threads_called_from_func_called_from_pthread_thrd(void); void *pthread_func(void *arg) { - thrd_create(&g1, &thrd_func, NULL); // NON-COMPLIANT - pthread_create(&g2, NULL, &pthread_func, NULL); // NON-COMPLIANT + thrd_create(&g1, &thrd_func_inner, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // NON-COMPLIANT make_threads_called_from_pthread_func(); func_called_from_pthread_thrd(); @@ -53,8 +55,8 @@ void *pthread_func(void *arg) { } int thrd_func(void *arg) { - thrd_create(&g1, &thrd_func, NULL); // NON-COMPLIANT - pthread_create(&g2, NULL, &pthread_func, NULL); // NON-COMPLIANT + thrd_create(&g1, &thrd_func_inner, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // NON-COMPLIANT make_threads_called_from_thrd_func(); func_called_from_pthread_thrd(); @@ -62,8 +64,8 @@ int thrd_func(void *arg) { } void make_threads_called_from_thrd_func(void) { - thrd_create(&g1, &thrd_func, NULL); // NON-COMPLIANT - pthread_create(&g2, NULL, &pthread_func, NULL); // NON-COMPLIANT + thrd_create(&g1, &thrd_func_inner, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // NON-COMPLIANT } void func_called_from_pthread_thrd(void) { @@ -71,16 +73,16 @@ void func_called_from_pthread_thrd(void) { } void make_threads_called_from_func_called_from_pthread_thrd(void) { - thrd_create(&g1, &thrd_func, NULL); // NON-COMPLIANT - pthread_create(&g2, NULL, &pthread_func, NULL); // NON-COMPLIANT + thrd_create(&g1, &thrd_func_inner, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // NON-COMPLIANT } void make_threads_called_from_main_pthread_thrd() { - thrd_create(&g1, &thrd_func, NULL); // NON-COMPLIANT - pthread_create(&g2, NULL, &pthread_func, NULL); // NON-COMPLIANT + thrd_create(&g1, &thrd_func_inner, NULL); // NON-COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // NON-COMPLIANT } void make_threads_not_called_by_anyone() { - thrd_create(&g1, &thrd_func, NULL); // COMPLIANT - pthread_create(&g2, NULL, &pthread_func, NULL); // COMPLIANT + thrd_create(&g1, &thrd_func_inner, NULL); // COMPLIANT + pthread_create(&g2, NULL, &pthread_func_inner, NULL); // COMPLIANT } From 22e4fd3e0775f3aa17ee57c199b73cf5bd72f8f4 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 28 Jan 2025 14:07:32 -0800 Subject: [PATCH 214/628] fix test affected by changes in test.c --- .../BannedDynamicThreadCreation.expected | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected b/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected index fa12a62f41..3bc3ab579a 100644 --- a/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected +++ b/c/misra/test/rules/DIR-5-3/BannedDynamicThreadCreation.expected @@ -1,16 +1,16 @@ -| test.c:28:3:28:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:27:6:27:34 | make_threads_called_from_main | make_threads_called_from_main | -| test.c:29:3:29:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:27:6:27:34 | make_threads_called_from_main | make_threads_called_from_main | -| test.c:37:3:37:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:36:6:36:51 | make_threads_called_from_func_called_from_main | make_threads_called_from_func_called_from_main | -| test.c:38:3:38:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:36:6:36:51 | make_threads_called_from_func_called_from_main | make_threads_called_from_func_called_from_main | -| test.c:47:3:47:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | -| test.c:48:3:48:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:46:7:46:18 | pthread_func | pthread_func | -| test.c:56:3:56:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | -| test.c:57:3:57:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:55:5:55:13 | thrd_func | thrd_func | -| test.c:65:3:65:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:64:6:64:39 | make_threads_called_from_thrd_func | make_threads_called_from_thrd_func | -| test.c:66:3:66:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:64:6:64:39 | make_threads_called_from_thrd_func | make_threads_called_from_thrd_func | -| test.c:74:3:74:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:73:6:73:59 | make_threads_called_from_func_called_from_pthread_thrd | make_threads_called_from_func_called_from_pthread_thrd | -| test.c:75:3:75:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:73:6:73:59 | make_threads_called_from_func_called_from_pthread_thrd | make_threads_called_from_func_called_from_pthread_thrd | -| test.c:79:3:79:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:78:6:78:47 | make_threads_called_from_main_pthread_thrd | make_threads_called_from_main_pthread_thrd | -| test.c:80:3:80:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:78:6:78:47 | make_threads_called_from_main_pthread_thrd | make_threads_called_from_main_pthread_thrd | -| test.c:84:3:84:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:83:6:83:38 | make_threads_not_called_by_anyone | make_threads_not_called_by_anyone | -| test.c:85:3:85:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:83:6:83:38 | make_threads_not_called_by_anyone | make_threads_not_called_by_anyone | +| test.c:30:3:30:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:29:6:29:34 | make_threads_called_from_main | make_threads_called_from_main | +| test.c:31:3:31:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:29:6:29:34 | make_threads_called_from_main | make_threads_called_from_main | +| test.c:39:3:39:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:38:6:38:51 | make_threads_called_from_func_called_from_main | make_threads_called_from_func_called_from_main | +| test.c:40:3:40:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:38:6:38:51 | make_threads_called_from_func_called_from_main | make_threads_called_from_func_called_from_main | +| test.c:49:3:49:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:48:7:48:18 | pthread_func | pthread_func | +| test.c:50:3:50:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:48:7:48:18 | pthread_func | pthread_func | +| test.c:58:3:58:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:57:5:57:13 | thrd_func | thrd_func | +| test.c:59:3:59:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:57:5:57:13 | thrd_func | thrd_func | +| test.c:67:3:67:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:66:6:66:39 | make_threads_called_from_thrd_func | make_threads_called_from_thrd_func | +| test.c:68:3:68:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:66:6:66:39 | make_threads_called_from_thrd_func | make_threads_called_from_thrd_func | +| test.c:76:3:76:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:75:6:75:59 | make_threads_called_from_func_called_from_pthread_thrd | make_threads_called_from_func_called_from_pthread_thrd | +| test.c:77:3:77:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:75:6:75:59 | make_threads_called_from_func_called_from_pthread_thrd | make_threads_called_from_func_called_from_pthread_thrd | +| test.c:81:3:81:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:80:6:80:47 | make_threads_called_from_main_pthread_thrd | make_threads_called_from_main_pthread_thrd | +| test.c:82:3:82:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:80:6:80:47 | make_threads_called_from_main_pthread_thrd | make_threads_called_from_main_pthread_thrd | +| test.c:86:3:86:13 | call to thrd_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:85:6:85:38 | make_threads_not_called_by_anyone | make_threads_not_called_by_anyone | +| test.c:87:3:87:16 | call to pthread_create | Possible dynamic creation of thread outside initialization in function '$@'. | test.c:85:6:85:38 | make_threads_not_called_by_anyone | make_threads_not_called_by_anyone | From 93a773c00482a8b25d933759830cdda8684212c9 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 28 Jan 2025 19:51:11 -0800 Subject: [PATCH 215/628] Add comments where intention was unclear --- .../CON34-C/AppropriateThreadObjectStorageDurations.ql | 6 +++++- c/common/src/codingstandards/c/Objects.qll | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql index 5a1dd3c461..4115a801e6 100644 --- a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql +++ b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql @@ -39,7 +39,11 @@ where ) ) or - // TODO: Remove/replace with tss_t type check, see #801. + // TODO: This case is handling threadlocals in a useful way that's not intended to be covered + // by the rule. See issue #801. The actual rule should expect no tss_t objects is used, and + // this check that this is initialized doesn't seem to belong here. However, it is a useful + // check in and of itself, so we should figure out if this is part of an optional rule we + // haven't yet implemented and move this behavior there. exists(TSSGetFunctionCall tsg | TaintTracking::localTaint(DataFlow::exprNode(tsg), DataFlow::exprNode(arg)) and not exists(TSSSetFunctionCall tss, DataFlow::Node src | diff --git a/c/common/src/codingstandards/c/Objects.qll b/c/common/src/codingstandards/c/Objects.qll index 105291c688..9a0206771b 100644 --- a/c/common/src/codingstandards/c/Objects.qll +++ b/c/common/src/codingstandards/c/Objects.qll @@ -106,9 +106,14 @@ abstract class ObjectIdentityBase extends Element { exists(Expr subobject | subobject = getASubobjectAccess() and ( + // Holds for address-of expressions. result = any(AddressOfExpr e | e.getOperand() = subobject) or + // Holds for array-to-pointer conversions, which evaluate to a usable subobject address. exists(ArrayToPointerConversion c | c.getExpr() = subobject) and + // Note that `arr[x]` has an array-to-pointer conversion, and returns the `x`th item by + // value, not the address of the `x`th item. Therefore, exclude `arr` if `arr` is part of + // an expression `arr[x]`. not exists(ArrayExpr a | a.getArrayBase() = subobject) and result = subobject ) From 22f95addf5d7fcfbcc850480b266fb8577c01459 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 29 Jan 2025 11:12:40 +0000 Subject: [PATCH 216/628] Add deviation file --- cpp/autosar/test/rules/A15-4-4/coding-standards.xml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 cpp/autosar/test/rules/A15-4-4/coding-standards.xml diff --git a/cpp/autosar/test/rules/A15-4-4/coding-standards.xml b/cpp/autosar/test/rules/A15-4-4/coding-standards.xml new file mode 100644 index 0000000000..6ae9c299fa --- /dev/null +++ b/cpp/autosar/test/rules/A15-4-4/coding-standards.xml @@ -0,0 +1,11 @@ + + + + + + A15-4-4 + Suppress entry. + a-15-4-4-deviation + + + From d307ab3db791b689f6664ff6bc33d4b1a84efeda Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 29 Jan 2025 12:41:31 -0800 Subject: [PATCH 217/628] Fix DataFlow imports --- .../AppropriateStorageDurationsFunctionReturn.ql | 1 + .../AppropriateStorageDurationsFunctionReturn.expected | 10 +++++----- .../cpp/resources/ResourceLeakAnalysis.qll | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql index 773d71acca..e4f5341014 100644 --- a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql +++ b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql @@ -14,6 +14,7 @@ import cpp import codingstandards.c.cert import codingstandards.c.Objects +import semmle.code.cpp.dataflow.DataFlow class Source extends Expr { ObjectIdentity rootObject; diff --git a/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected b/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected index 905c9cc22b..f60689dbb1 100644 --- a/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected +++ b/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected @@ -1,7 +1,7 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:22,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:26,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:39,6-14) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:39,26-34) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:45,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:28,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:32,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:45,6-14) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:45,26-34) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:51,3-11) | test.c:3:10:3:10 | a | $@ with automatic storage may be accessible outside of its lifetime. | test.c:3:10:3:10 | a | a | | test.c:15:4:15:8 | param [inner post update] | $@ with automatic storage may be accessible outside of its lifetime. | test.c:15:12:15:13 | a2 | a2 | diff --git a/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll b/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll index 2f932870b3..7d767b5cb4 100644 --- a/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll +++ b/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.dataflow.DataFlow +import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.valuenumbering.GlobalValueNumbering import semmle.code.cpp.controlflow.Dominance import codeql.util.Boolean From 127c6045f10de0895116dc17ee22107780291eac Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 29 Jan 2025 13:07:47 -0800 Subject: [PATCH 218/628] Address feedback --- ...1-29-implement-misra-clarifications-change-categories.md | 6 ++++++ rules.csv | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 change_notes/2025-01-29-implement-misra-clarifications-change-categories.md diff --git a/change_notes/2025-01-29-implement-misra-clarifications-change-categories.md b/change_notes/2025-01-29-implement-misra-clarifications-change-categories.md new file mode 100644 index 0000000000..04ef636392 --- /dev/null +++ b/change_notes/2025-01-29-implement-misra-clarifications-change-categories.md @@ -0,0 +1,6 @@ + - `RULE-13-6` - `SizeofOperandWithSideEffect.ql`: + - Changed from Mandatory to Required in implementation of Technical Corrigenda 2. + - `RULE-17-5` - `ArrayFunctionArgumentNumberOfElements.ql`: + - Changed from Advisory to Required in implementation of Technical Corrigenda 2. + - `RULE-21-11` - `StandardHeaderFileTgmathhUsed.ql`: + - Changed from Required to Advisory in implementation of Amendment 3. \ No newline at end of file diff --git a/rules.csv b/rules.csv index 475ea1d66c..ec3f80dab3 100644 --- a/rules.csv +++ b/rules.csv @@ -708,7 +708,7 @@ c,MISRA-C-2012,RULE-13-2,Yes,Required,,,The value of an expression and its persi c,MISRA-C-2012,RULE-13-3,Yes,Advisory,,,A full expression containing an increment (++) or decrement (--) operator should have no other potential side effects other than that caused by the increment or decrement operator,,SideEffects2,Medium, c,MISRA-C-2012,RULE-13-4,Yes,Advisory,,,The result of an assignment operator should not be used,M6-2-1,SideEffects1,Easy, c,MISRA-C-2012,RULE-13-5,Yes,Required,,,The right hand operand of a logical && or || operator shall not contain persistent side effects,M5-14-1,SideEffects1,Import, -c,MISRA-C-2012,RULE-13-6,Yes,Mandatory,,,The operand of the sizeof operator shall not contain any expressiosn which has potential side effects,M5-3-4,SideEffects1,Import, +c,MISRA-C-2012,RULE-13-6,Yes,Required,,,The operand of the sizeof operator shall not contain any expressiosn which has potential side effects,M5-3-4,SideEffects1,Import, c,MISRA-C-2012,RULE-14-1,Yes,Required,,,A loop counter shall not have essentially floating type,FLP30-C A6-5-2,EssentialTypes,Hard, c,MISRA-C-2012,RULE-14-2,Yes,Required,,,A for loop shall be well-formed,M6-5-1...M6-5-6,Statements4,Medium, c,MISRA-C-2012,RULE-14-3,Yes,Required,,,Controlling expressions shall not be invariant,,Statements5,Medium, @@ -731,7 +731,7 @@ c,MISRA-C-2012,RULE-17-1,Yes,Required,,,The features of shall not be c,MISRA-C-2012,RULE-17-2,Yes,Required,,,"Functions shall not call themselves, either directly or indirectly",A7-5-2,Statements3,Import, c,MISRA-C-2012,RULE-17-3,Yes,Mandatory,,,A function shall not be declared implicitly,,Declarations6,Medium, c,MISRA-C-2012,RULE-17-4,Yes,Mandatory,,,All exit paths from a function with non-void return type shall have an explicit return statement with an expression,MSC52-CPP,Statements5,Medium, -c,MISRA-C-2012,RULE-17-5,Yes,Advisory,,,The function argument corresponding to a parameter declared to have an array type shall have an appropriate number of elements,,Contracts6,Hard, +c,MISRA-C-2012,RULE-17-5,Yes,Required,,,The function argument corresponding to a parameter declared to have an array type shall have an appropriate number of elements,,Contracts6,Hard, c,MISRA-C-2012,RULE-17-6,Yes,Mandatory,,,The declaration of an array parameter shall not contain the static keyword between the [ ],,Static,Easy, c,MISRA-C-2012,RULE-17-7,Yes,Required,,,The value returned by a function having non-void return type shall be used,A0-1-2,Contracts6,Easy, c,MISRA-C-2012,RULE-17-8,Yes,Advisory,,,A function parameter should not be modified,,SideEffects2,Medium, @@ -776,7 +776,7 @@ c,MISRA-C-2012,RULE-21-7,Yes,Required,,,"The Standard Library functions atof, at c,MISRA-C-2012,RULE-21-8,Yes,Required,,,The Standard Library termination functions of shall not be used,ERR50-CPP,Banned,Easy, c,MISRA-C-2012,RULE-21-9,Yes,Required,,,The Standard Library functions bsearch and qsort of shall not be used,,Banned,Easy, c,MISRA-C-2012,RULE-21-10,Yes,Required,,,The Standard Library time and date functions shall not be used,,Banned,Easy, -c,MISRA-C-2012,RULE-21-11,Yes,Required,,,The standard header file shall not be used,,Banned,Easy, +c,MISRA-C-2012,RULE-21-11,Yes,Advisory,,,The standard header file shall not be used,,Banned,Easy, c,MISRA-C-2012,RULE-21-12,Yes,Advisory,,,The exception handling features of should not be used,,Banned,Easy, c,MISRA-C-2012,RULE-21-13,Yes,Mandatory,,,Any value passed to a function in shall be representable as an unsigned char or be the value EOF,,StandardLibraryFunctionTypes,Medium, c,MISRA-C-2012,RULE-21-14,Yes,Required,,,The Standard Library function memcmp shall not be used to compare null terminated strings,,EssentialTypes,Hard, From 963ba5c41638ad33cc548f7ad2e3a1ade5463a1b Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 29 Jan 2025 15:59:33 -0800 Subject: [PATCH 219/628] Fix broken test expectation --- .../rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected | 2 ++ 1 file changed, 2 insertions(+) diff --git a/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected b/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected index 126e75bca7..dbee52ed58 100644 --- a/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected +++ b/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected @@ -1,3 +1,5 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MutexObjectsNotAlwaysUnlocked.ql:22,52-60) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (MutexObjectsNotAlwaysUnlocked.ql:30,42-50) | test.c:16:3:16:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | | test.c:21:3:21:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | | test.c:39:3:39:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | From a26959808c685f011b7356bafc778562b8e1dddb Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 29 Jan 2025 18:48:02 -0800 Subject: [PATCH 220/628] Fix another set of test expectations --- ...riateThreadObjectStorageDurations.expected | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected b/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected index 25cb74d7fa..085083228b 100644 --- a/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected +++ b/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected @@ -1,11 +1,16 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,29-37) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,54-62) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:35,62-70) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:40,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:40,30-38) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:41,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:41,30-38) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:28,3-16) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:31,14-22) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:33,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:35,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:38,45-53) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:48,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:48,58-66) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:49,42-50) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:52,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:52,34-42) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:53,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:53,34-42) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:38,9-22) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:48,7-20) | test.c:23:3:23:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:23:24:23:29 | & ... | Shared object | | test.c:74:3:74:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:74:24:74:24 | p | Shared object | | test.c:85:3:85:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:85:24:85:24 | p | Shared object | From 3a20ccca17259b3a5597f637cd9cce5156f5bd75 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Thu, 30 Jan 2025 22:43:18 +0000 Subject: [PATCH 221/628] Update cpp/autosar/test/rules/A7-1-1/test.cpp --- cpp/autosar/test/rules/A7-1-1/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/autosar/test/rules/A7-1-1/test.cpp b/cpp/autosar/test/rules/A7-1-1/test.cpp index 5e47b9c0bf..1fdc0d66eb 100644 --- a/cpp/autosar/test/rules/A7-1-1/test.cpp +++ b/cpp/autosar/test/rules/A7-1-1/test.cpp @@ -90,7 +90,7 @@ void fp_621() { recurse_var; } void variadic_forwarding() {} template -void variadic_forwarding(T &&first, Args &&... rest) { +void variadic_forwarding(T &&first, Args &&...rest) { first; variadic_forwarding(std::forward(rest)...); } From 638c083b3b55c790a3b588d9bc70ba02a0ced449 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 29 Oct 2024 14:48:44 -0700 Subject: [PATCH 222/628] save work for draft PR --- .../PossibleMisuseOfUndetectedInfinity.ql | 104 + .../DIR-4-15/PossibleMisuseOfUndetectedNaN.ql | 157 ++ .../PossibleUndetectedNaNorInfinity.ql | 223 ++ ...ossibleMisuseOfUndetectedInfinity.expected | 48 + .../PossibleMisuseOfUndetectedInfinity.qlref | 1 + .../PossibleMisuseOfUndetectedNaN.expected | 63 + .../PossibleMisuseOfUndetectedNaN.qlref | 1 + .../PossibleUndetectedNaNorInfinity.expected | 1 + .../PossibleUndetectedNaNorInfinity.qlref | 1 + c/misra/test/rules/DIR-4-15/test.c | 76 + .../src/codingstandards/cpp/FloatingPoint.qll | 61 + .../cpp/RestrictedRangeAnalysis.qll | 1903 +++++++++++++++++ .../cpp/SimpleRangeAnalysisCustomizations.qll | 39 + .../cpp/exclusions/c/FloatingTypes2.qll | 44 + .../cpp/exclusions/c/RuleMetadata.qll | 3 + rule_packages/c/FloatingTypes2.json | 36 + 16 files changed, 2761 insertions(+) create mode 100644 c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql create mode 100644 c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql create mode 100644 c/misra/src/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.ql create mode 100644 c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected create mode 100644 c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.qlref create mode 100644 c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected create mode 100644 c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.qlref create mode 100644 c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.expected create mode 100644 c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.qlref create mode 100644 c/misra/test/rules/DIR-4-15/test.c create mode 100644 cpp/common/src/codingstandards/cpp/FloatingPoint.qll create mode 100644 cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/FloatingTypes2.qll create mode 100644 rule_packages/c/FloatingTypes2.json diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql new file mode 100644 index 0000000000..84a3fbfd3c --- /dev/null +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql @@ -0,0 +1,104 @@ +/** + * @id c/misra/possible-misuse-of-undetected-infinity + * @name DIR-4-15: Evaluation of floating-point expressions shall not lead to the undetected generation of infinities + * @description Evaluation of floating-point expressions shall not lead to the undetected generation + * of infinities. + * @kind path-problem + * @precision high + * @problem.severity error + * @tags external/misra/id/dir-4-15 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codeql.util.Boolean +import codingstandards.c.misra +import codingstandards.cpp.RestrictedRangeAnalysis +import codingstandards.cpp.FloatingPoint +import codingstandards.cpp.AlertReporting +import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.dataflow.new.TaintTracking +import semmle.code.cpp.controlflow.Dominance + +module InvalidInfinityUsage implements DataFlow::ConfigSig { + /** + * An operation which does not have Infinity as an input, but may produce Infinity, according + * to the `RestrictedRangeAnalysis` module. + */ + predicate isSource(DataFlow::Node node) { + potentialSource(node) and + not exists(DataFlow::Node prior | + isAdditionalFlowStep(prior, node) and + potentialSource(prior) + ) + } + + /** + * An operation which may produce Infinity acconding to the `RestrictedRangeAnalysis` module. + */ + additional predicate potentialSource(DataFlow::Node node) { + node.asExpr() instanceof Operation and + exprMayEqualInfinity(node.asExpr(), _) + } + + /** + * An additional flow step to handle operations which propagate Infinity. + * + * This double checks that an Infinity may propagate by checking the `RestrictedRangeAnalysis` + * value estimate. This is conservative, since `RestrictedRangeAnalysis` is performed locally + * in scope with unanalyzable values in a finite range. However, this conservative approach + * leverages analysis of guards and other local conditions to avoid false positives. + */ + predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) { + exists(Operation o | + o.getAnOperand() = source.asExpr() and + o = sink.asExpr() and + potentialSource(sink) + ) + } + + predicate isSink(DataFlow::Node node) { + ( + // Require that range analysis finds this value potentially infinite, to avoid false positives + // in the presence of guards. This may induce false negatives. + exprMayEqualInfinity(node.asExpr(), _) or + // Unanalyzable expressions are not checked against range analysis, which assumes a finite + // range. + not RestrictedRangeAnalysis::analyzableExpr(node.asExpr()) + ) and + ( + // Case 2: NaNs and infinities shall not be cast to integers + exists(Conversion c | + node.asExpr() = c.getUnconverted() and + c.getExpr().getType() instanceof FloatingPointType and + c.getType() instanceof IntegralType + ) + or + // Case 3: Infinities shall not underflow or otherwise produce finite values + exists(BinaryOperation op | + node.asExpr() = op.getRightOperand() and + op.getOperator() = ["/", "%"] + ) + ) + } +} + +module InvalidInfinityFlow = DataFlow::Global; + +import InvalidInfinityFlow::PathGraph + +from + Element elem, InvalidInfinityFlow::PathNode source, InvalidInfinityFlow::PathNode sink, + string msg, string sourceString +where + elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and + not isExcluded(elem, FloatingTypes2Package::possibleMisuseOfUndetectedInfinityQuery()) and + ( + InvalidInfinityFlow::flow(source.getNode(), sink.getNode()) and + msg = "Invalid usage of possible $@." and + sourceString = "infinity" + ) +select elem, source, sink, msg, source, sourceString diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql new file mode 100644 index 0000000000..6962a1c36d --- /dev/null +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql @@ -0,0 +1,157 @@ +/** + * @id c/misra/possible-misuse-of-undetected-na-n + * @name DIR-4-15: Evaluation of floating-point expressions shall not lead to the undetected generation of NaNs + * @description Evaluation of floating-point expressions shall not lead to the undetected generation + * of NaNs. + * @kind path-problem + * @precision high + * @problem.severity error + * @tags external/misra/id/dir-4-15 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codeql.util.Boolean +import codingstandards.c.misra +import codingstandards.cpp.RestrictedRangeAnalysis +import codingstandards.cpp.FloatingPoint +import codingstandards.cpp.AlertReporting +import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.dataflow.new.TaintTracking +import semmle.code.cpp.controlflow.Dominance + +// IEEE 754-1985 Section 7.1 invalid operations +class InvalidOperationExpr extends BinaryOperation { + string reason; + + InvalidOperationExpr() { + // Usual arithmetic conversions in both languages mean that if either operand is a floating + // type, the other one is converted to a floating type as well. + getAnOperand().getFullyConverted().getType() instanceof FloatingPointType and + ( + // 7.1.1 propagates signaling NaNs, we rely on flow analysis and/or assume quiet NaNs, so we + // intentionally do not cover this case. + // 7.1.2: magnitude subtraction of infinities, such as +Inf + -Inf + getOperator() = "+" and + exists(Boolean sign | + exprMayEqualInfinity(getLeftOperand(), sign) and + exprMayEqualInfinity(getRightOperand(), sign.booleanNot()) + ) and + reason = "possible addition of infinity and negative infinity" + or + // 7.1.2 continued + getOperator() = "-" and + exists(Boolean sign | + exprMayEqualInfinity(getLeftOperand(), sign) and + exprMayEqualInfinity(getRightOperand(), sign) + ) and + reason = "possible subtraction of an infinity from itself" + or + // 7.1.3: multiplication of zero by infinity + getOperator() = "*" and + exprMayEqualZero(getAnOperand()) and + exprMayEqualInfinity(getAnOperand(), _) and + reason = "possible multiplication of zero by infinity" + or + // 7.1.4: Division of zero by zero, or infinity by infinity + getOperator() = "/" and + exprMayEqualZero(getLeftOperand()) and + exprMayEqualZero(getRightOperand()) and + reason = "possible division of zero by zero" + or + // 7.1.4 continued + getOperator() = "/" and + exprMayEqualInfinity(getLeftOperand(), _) and + exprMayEqualInfinity(getRightOperand(), _) and + reason = "possible division of infinity by infinity" + or + // 7.1.5: x % y where y is zero or x is infinite + getOperator() = "%" and + exprMayEqualInfinity(getLeftOperand(), _) and + reason = "possible modulus of infinity" + or + // 7.1.5 continued + getOperator() = "%" and + exprMayEqualZero(getRightOperand()) and + reason = "possible modulus by zero" + // 7.1.6 handles the sqrt function, not covered here. + // 7.1.7 declares exceptions during invalid conversions, which we catch as sinks in our flow + // analysis. + // 7.1.8 declares exceptions for unordered comparisons, which we catch as sinks in our flow + // analysis. + ) + } + + string getReason() { result = reason } +} + +module InvalidNaNUsage implements DataFlow::ConfigSig { + + /** + * An expression which has non-NaN inputs and may produce a NaN output. + */ + predicate isSource(DataFlow::Node node) { + potentialSource(node) and + not exists(DataFlow::Node prior | + isAdditionalFlowStep(prior, node) and + potentialSource(prior) + ) + } + + /** + * An expression which may produce a NaN output. + */ + additional predicate potentialSource(DataFlow::Node node) { + node.asExpr() instanceof InvalidOperationExpr + } + + /** + * Add an additional flow step to handle NaN propagation through floating point operations. + */ + predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) { + exists(Operation o | + o.getAnOperand() = source.asExpr() and + o = sink.asExpr() and + o.getType() instanceof FloatingPointType + ) + } + + predicate isSink(DataFlow::Node node) { + // Case 1: NaNs shall not be compared, except to themselves + exists(ComparisonOperation cmp | + node.asExpr() = cmp.getAnOperand() and + not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand()) + ) + or + // Case 2: NaNs and infinities shall not be cast to integers + exists(Conversion c | + node.asExpr() = c.getUnconverted() and + c.getExpr().getType() instanceof FloatingPointType and + c.getType() instanceof IntegralType + ) + //or + //// Case 4: Functions shall not return NaNs or infinities + //exists(ReturnStmt ret | node.asExpr() = ret.getExpr()) + } +} + +module InvalidNaNFlow = DataFlow::Global; + +import InvalidNaNFlow::PathGraph + +from + Element elem, InvalidNaNFlow::PathNode source, InvalidNaNFlow::PathNode sink, string msg, + string sourceString +where + elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and + not isExcluded(elem, FloatingTypes2Package::possibleMisuseOfUndetectedNaNQuery()) and + ( + InvalidNaNFlow::flow(source.getNode(), sink.getNode()) and + msg = "Invalid usage of possible $@." and + sourceString = + "NaN resulting from " + source.getNode().asExpr().(InvalidOperationExpr).getReason() + ) +select elem, source, sink, msg, source, sourceString diff --git a/c/misra/src/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.ql b/c/misra/src/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.ql new file mode 100644 index 0000000000..94888a95e6 --- /dev/null +++ b/c/misra/src/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.ql @@ -0,0 +1,223 @@ +/** + * @id c/misra/possible-undetected-na-nor-infinity + * @name DIR-4-15: Evaluation of floating-point expressions shall not lead to the undetected generation of infinities + * @description Evaluation of floating-point expressions shall not lead to the undetected generation + * of infinities and NaNs. + * @kind path-problem + * @precision high + * @problem.severity error + * @tags external/misra/id/dir-4-15 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codeql.util.Boolean +import codingstandards.c.misra +import codingstandards.cpp.RestrictedRangeAnalysis +import codingstandards.cpp.FloatingPoint +import codingstandards.cpp.AlertReporting +import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.dataflow.new.TaintTracking +import semmle.code.cpp.controlflow.Dominance + +class CantHandleInfinityFunction extends Function { + CantHandleInfinityFunction() { not hasDefinition() and not getName() = "__fpclassifyl" } +} + +class InfinityCheckedExpr extends Expr { + InfinityCheckedExpr() { + exists(MacroInvocation mi | + mi.getMacroName() = ["isfinite", "isinf"] and + mi.getExpr() = this + ) + } + + Expr getCheckedExpr() { + result = + this.(ConditionalExpr) + .getThen() + .(LTExpr) + .getLesserOperand() + .(BitwiseAndExpr) + .getLeftOperand() + .(FunctionCall) + .getArgument(0) + } +} + +/* +signature module ResourceLeakConfigSig { + predicate isResource(DataFlow::Node node); + + predicate isFree(DataFlow::Node node, DataFlow::Node resource); + + default ControlFlowNode outOfScope(DataFlow::Node resource) { + result = resource.asExpr().getEnclosingFunction().getBlock().getLastStmt() + } + + default predicate isAlias(DataFlow::Node alias, DataFlow::Node resource) { + isResource(resource) and + DataFlow::localFlow(resource, alias) + } +} + +module ResourceLeak { + predicate isLeaked(DataFlow::Node resource, ControlFlowNode cfgNode) { + resource.asExpr() = cfgNode + or + isLeaked(resource, cfgNode.getAPredecessor()) and + not exists(DataFlow::Node free, DataFlow::Node freed | + free.asExpr() = cfgNode and + Config::isFree(free, freed) and + Config::isAlias(freed, resource) + ) + } + + private ControlFlowNode getARawLeak(DataFlow::Node resource) { + Config::isResource(resource) and + result = Config::outOfScope(resource) and + isLeaked(resource, result) + } + + ControlFlowNode getALeak(DataFlow::Node resource) { + result = getARawLeak(resource) and + not exists(DataFlow::Node dealiased | + Config::isResource(dealiased) and + Config::isAlias(resource, dealiased) and + not resource = dealiased and + result = getARawLeak(dealiased) + ) and + not exists(ControlFlowNode dominator | + dominator = getARawLeak(resource) and + strictlyDominates(dominator, result) + ) + } +} + +module MissedInfinityConfig implements ResourceLeakConfigSig { + predicate isResource(DataFlow::Node node) { + //exists(BinaryOperation expr | + // expr = node.asExpr() and + // expr.getOperator() = "/" and + // RestrictedRangeAnalysis::upperBound(expr.getRightOperand()) <= 0 and + // RestrictedRangeAnalysis::lowerBound(expr.getRightOperand()) >= 0 + //) + [ + RestrictedRangeAnalysis::upperBound(node.asExpr()), + RestrictedRangeAnalysis::lowerBound(node.asExpr()) + ].toString() = "Infinity" + //and not node.asExpr() instanceof VariableAccess + //and not node.asExpr() instanceof ArrayExpr + } + + predicate test(Expr expr, string lowerBound, string upperBound) { + //expr.getType() instanceof FloatingPointType + //and + lowerBound = RestrictedRangeAnalysis::lowerBound(expr).toString() and + upperBound = RestrictedRangeAnalysis::upperBound(expr).toString() and + [lowerBound, upperBound] = "Infinity" + } + + additional predicate testDiv( + DivExpr div, string lbDiv, string ubDiv, string lbNum, string ubNum, string lbDenom, + string ubDenom + ) { + lbDiv = RestrictedRangeAnalysis::lowerBound(div).toString() and + ubDiv = RestrictedRangeAnalysis::upperBound(div).toString() and + lbNum = RestrictedRangeAnalysis::lowerBound(div.getLeftOperand()).toString() and + ubNum = RestrictedRangeAnalysis::upperBound(div.getLeftOperand()).toString() and + lbDenom = RestrictedRangeAnalysis::lowerBound(div.getRightOperand()).toString() and + ubDenom = RestrictedRangeAnalysis::upperBound(div.getRightOperand()).toString() and + not lbDiv = ubDiv and + InvalidNaNUsage::isSource(DataFlow::exprNode(div)) + } + + predicate isFree(DataFlow::Node node, DataFlow::Node resource) { + isResource(resource) and + ( + node.asExpr().(InfinityCheckedExpr).getCheckedExpr() = resource.asExpr() + or + not [ + RestrictedRangeAnalysis::lowerBound(node.asExpr()), + RestrictedRangeAnalysis::upperBound(node.asExpr()) + ].toString() = "Infinity" and + isMove(node, resource) + ) + } + + predicate isMove(DataFlow::Node node, DataFlow::Node moved) { + isResource(moved) and + isAlias(node, moved) and + not exists(DataFlow::Node laterUse, ControlFlowNode later | + later = laterUse.asExpr() and + later = node.asExpr().getASuccessor+() and + hashCons(laterUse.asExpr()) = hashCons(moved.asExpr()) + ) + } + + ControlFlowNode outOfScope(DataFlow::Node resource) { + result = resource.asExpr().getEnclosingFunction().getBlock().getLastStmt() + or + exists(AssignExpr assign, DataFlow::Node alias | + assign.getRValue() = alias.asExpr() and + isAlias(alias, resource) and + not assign.getRValue().(VariableAccess).getTarget() instanceof StackVariable and + result = assign + ) + or + exists(FunctionCall fc | + fc.getArgument(_) = resource.asExpr() and + result = fc + ) + } + + predicate isAlias(DataFlow::Node alias, DataFlow::Node resource) { + TaintTracking::localTaint(resource, alias) + } +} + +import ResourceLeak as MissedInfinity +*/ + +//from Expr value, FunctionCall fc +//where +// not isExcluded(value, FloatingTypes2Package::possibleUndetectedNaNorInfinityQuery()) and +// [RestrictedRangeAnalysis::lowerBound(value), RestrictedRangeAnalysis::upperBound(value)].toString() = "Infinity" and +// value = fc.getAnArgument() and +// fc.getTarget() instanceof CantHandleInfinityFunction and +// not value instanceof InfinityCheckedExpr and +// not exists (GuardCondition g | +// g.controls(fc.getBasicBlock(), true) and +// g instanceof InfinityCheckedExpr +// // TODO check we check the right expr +// ) +//select +// value, "possible use of unchecked infinity as arg to " + fc.getTarget().getName() +//from DataFlow::Node node, ControlFlowNode leakPoint +//where +// not isExcluded(node.asExpr(), FloatingTypes2Package::possibleUndetectedNaNorInfinityQuery()) and +// leakPoint = MissedInfinity::getALeak(node) +// select node, "Expression generates an infinity which is not checked before $@.", leakPoint, "external leak point" + + +//import InvalidNaNFlow::PathGraph +//from Element elem, DataFlow::Node source, DataFlow::Node sink, string msg, string sourceString +from + Element elem, InvalidInfinityFlow::PathNode source, InvalidInfinityFlow::PathNode sink, + string msg, string sourceString +where + elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and + not isExcluded(elem, FloatingTypes2Package::possibleUndetectedNaNorInfinityQuery()) and + ( + InvalidInfinityFlow::flow(source.getNode(), sink.getNode()) and + msg = "Invalid usage of possible $@." and + sourceString = "infinity" + //or + //InvalidNaNFlow::flow(source, sink) and + //msg = "Invalid usage of possible $@." and + //sourceString = "NaN resulting from " + source.asExpr().(InvalidOperationExpr).getReason() + ) +select elem, source, sink, msg, source, sourceString diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected new file mode 100644 index 0000000000..78f4c6baec --- /dev/null +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected @@ -0,0 +1,48 @@ +edges +| test.c:8:14:8:20 | ... / ... | test.c:8:14:8:20 | ... / ... | provenance | | +| test.c:8:14:8:20 | ... / ... | test.c:12:8:12:9 | l2 | provenance | | +| test.c:8:14:8:20 | ... / ... | test.c:18:3:18:9 | l2 | provenance | | +| test.c:8:14:8:20 | ... / ... | test.c:27:19:27:20 | l2 | provenance | | +| test.c:9:14:9:16 | - ... | test.c:9:14:9:16 | - ... | provenance | | +| test.c:9:14:9:16 | - ... | test.c:13:8:13:9 | l3 | provenance | | +| test.c:9:14:9:16 | - ... | test.c:19:3:19:9 | l3 | provenance | | +| test.c:9:14:9:16 | - ... | test.c:28:19:28:20 | l3 | provenance | | +| test.c:31:14:32:15 | ... / ... | test.c:31:14:32:15 | ... / ... | provenance | | +| test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | provenance | | +| test.c:33:14:33:22 | ... / ... | test.c:33:14:33:22 | ... / ... | provenance | | +| test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | provenance | | +nodes +| test.c:8:14:8:20 | ... / ... | semmle.label | ... / ... | +| test.c:8:14:8:20 | ... / ... | semmle.label | ... / ... | +| test.c:9:14:9:16 | - ... | semmle.label | - ... | +| test.c:9:14:9:16 | - ... | semmle.label | - ... | +| test.c:12:8:12:9 | l2 | semmle.label | l2 | +| test.c:13:8:13:9 | l3 | semmle.label | l3 | +| test.c:18:3:18:9 | l2 | semmle.label | l2 | +| test.c:19:3:19:9 | l3 | semmle.label | l3 | +| test.c:27:19:27:20 | l2 | semmle.label | l2 | +| test.c:28:19:28:20 | l3 | semmle.label | l3 | +| test.c:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.c:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.c:33:14:33:22 | ... / ... | semmle.label | ... / ... | +| test.c:33:14:33:22 | ... / ... | semmle.label | ... / ... | +| test.c:38:3:38:9 | l7 | semmle.label | l7 | +| test.c:39:3:39:9 | l8 | semmle.label | l8 | +| test.c:61:5:61:19 | ... / ... | semmle.label | ... / ... | +| test.c:66:5:66:21 | ... / ... | semmle.label | ... / ... | +| test.c:72:14:72:30 | ... / ... | semmle.label | ... / ... | +| test.c:75:18:75:34 | ... / ... | semmle.label | ... / ... | +subpaths +#select +| test.c:12:8:12:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:12:8:12:9 | l2 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | +| test.c:13:8:13:9 | l3 | test.c:9:14:9:16 | - ... | test.c:13:8:13:9 | l3 | Invalid usage of possible $@. | test.c:9:14:9:16 | - ... | infinity | +| test.c:18:8:18:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:18:3:18:9 | l2 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | +| test.c:19:8:19:9 | l3 | test.c:9:14:9:16 | - ... | test.c:19:3:19:9 | l3 | Invalid usage of possible $@. | test.c:9:14:9:16 | - ... | infinity | +| test.c:27:19:27:20 | l2 | test.c:8:14:8:20 | ... / ... | test.c:27:19:27:20 | l2 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | +| test.c:28:19:28:20 | l3 | test.c:9:14:9:16 | - ... | test.c:28:19:28:20 | l3 | Invalid usage of possible $@. | test.c:9:14:9:16 | - ... | infinity | +| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Invalid usage of possible $@. | test.c:31:14:32:15 | ... / ... | infinity | +| test.c:39:8:39:9 | l8 | test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | Invalid usage of possible $@. | test.c:33:14:33:22 | ... / ... | infinity | +| test.c:61:12:61:18 | ... / ... | test.c:61:5:61:19 | ... / ... | test.c:61:5:61:19 | ... / ... | Invalid usage of possible $@. | test.c:61:5:61:19 | ... / ... | infinity | +| test.c:66:12:66:20 | ... / ... | test.c:66:5:66:21 | ... / ... | test.c:66:5:66:21 | ... / ... | Invalid usage of possible $@. | test.c:66:5:66:21 | ... / ... | infinity | +| test.c:72:21:72:29 | ... / ... | test.c:72:14:72:30 | ... / ... | test.c:72:14:72:30 | ... / ... | Invalid usage of possible $@. | test.c:72:14:72:30 | ... / ... | infinity | +| test.c:75:25:75:33 | ... / ... | test.c:75:18:75:34 | ... / ... | test.c:75:18:75:34 | ... / ... | Invalid usage of possible $@. | test.c:75:18:75:34 | ... / ... | infinity | diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.qlref b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.qlref new file mode 100644 index 0000000000..dccac37c5f --- /dev/null +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.qlref @@ -0,0 +1 @@ +rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected new file mode 100644 index 0000000000..f317f236ef --- /dev/null +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected @@ -0,0 +1,63 @@ +edges +| test.c:27:14:27:20 | ... / ... | test.c:27:14:27:20 | ... / ... | provenance | | +| test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | provenance | | +| test.c:27:14:27:20 | ... / ... | test.c:46:3:46:4 | l5 | provenance | | +| test.c:27:14:27:20 | ... / ... | test.c:47:3:47:4 | l5 | provenance | | +| test.c:27:14:27:20 | ... / ... | test.c:48:3:48:4 | l5 | provenance | | +| test.c:27:14:27:20 | ... / ... | test.c:49:3:49:4 | l5 | provenance | | +| test.c:27:14:27:20 | ... / ... | test.c:50:3:50:4 | l5 | provenance | | +| test.c:27:14:27:20 | ... / ... | test.c:51:3:51:4 | l5 | provenance | | +| test.c:28:14:28:20 | ... / ... | test.c:28:14:28:20 | ... / ... | provenance | | +| test.c:28:14:28:20 | ... / ... | test.c:37:3:37:9 | l6 | provenance | | +| test.c:28:14:28:20 | ... / ... | test.c:52:3:52:4 | l6 | provenance | | +| test.c:31:14:32:15 | ... / ... | test.c:31:14:32:15 | ... / ... | provenance | | +| test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | provenance | | +| test.c:31:14:32:15 | ... / ... | test.c:53:3:53:4 | l7 | provenance | | +| test.c:33:14:33:22 | ... / ... | test.c:33:14:33:22 | ... / ... | provenance | | +| test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | provenance | | +| test.c:33:14:33:22 | ... / ... | test.c:54:3:54:4 | l8 | provenance | | +nodes +| test.c:27:14:27:20 | ... / ... | semmle.label | ... / ... | +| test.c:27:14:27:20 | ... / ... | semmle.label | ... / ... | +| test.c:28:14:28:20 | ... / ... | semmle.label | ... / ... | +| test.c:28:14:28:20 | ... / ... | semmle.label | ... / ... | +| test.c:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.c:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.c:33:14:33:22 | ... / ... | semmle.label | ... / ... | +| test.c:33:14:33:22 | ... / ... | semmle.label | ... / ... | +| test.c:36:3:36:9 | l5 | semmle.label | l5 | +| test.c:37:3:37:9 | l6 | semmle.label | l6 | +| test.c:38:3:38:9 | l7 | semmle.label | l7 | +| test.c:39:3:39:9 | l8 | semmle.label | l8 | +| test.c:46:3:46:4 | l5 | semmle.label | l5 | +| test.c:47:3:47:4 | l5 | semmle.label | l5 | +| test.c:48:3:48:4 | l5 | semmle.label | l5 | +| test.c:49:3:49:4 | l5 | semmle.label | l5 | +| test.c:50:3:50:4 | l5 | semmle.label | l5 | +| test.c:51:3:51:4 | l5 | semmle.label | l5 | +| test.c:52:3:52:4 | l6 | semmle.label | l6 | +| test.c:53:3:53:4 | l7 | semmle.label | l7 | +| test.c:54:3:54:4 | l8 | semmle.label | l8 | +| test.c:61:5:61:19 | ... / ... | semmle.label | ... / ... | +| test.c:66:5:66:21 | ... / ... | semmle.label | ... / ... | +| test.c:72:14:72:30 | ... / ... | semmle.label | ... / ... | +| test.c:75:18:75:34 | ... / ... | semmle.label | ... / ... | +subpaths +#select +| test.c:36:8:36:9 | l5 | test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | +| test.c:37:8:37:9 | l6 | test.c:28:14:28:20 | ... / ... | test.c:37:3:37:9 | l6 | Invalid usage of possible $@. | test.c:28:14:28:20 | ... / ... | NaN resulting from possible division of infinity by infinity | +| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Invalid usage of possible $@. | test.c:31:14:32:15 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:39:8:39:9 | l8 | test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | Invalid usage of possible $@. | test.c:33:14:33:22 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:46:3:46:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:46:3:46:4 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | +| test.c:47:3:47:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:47:3:47:4 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | +| test.c:48:3:48:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:48:3:48:4 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | +| test.c:49:3:49:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:49:3:49:4 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | +| test.c:50:3:50:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:50:3:50:4 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | +| test.c:51:3:51:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:51:3:51:4 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | +| test.c:52:3:52:4 | l6 | test.c:28:14:28:20 | ... / ... | test.c:52:3:52:4 | l6 | Invalid usage of possible $@. | test.c:28:14:28:20 | ... / ... | NaN resulting from possible division of infinity by infinity | +| test.c:53:3:53:4 | l7 | test.c:31:14:32:15 | ... / ... | test.c:53:3:53:4 | l7 | Invalid usage of possible $@. | test.c:31:14:32:15 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:54:3:54:4 | l8 | test.c:33:14:33:22 | ... / ... | test.c:54:3:54:4 | l8 | Invalid usage of possible $@. | test.c:33:14:33:22 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:61:12:61:18 | ... / ... | test.c:61:5:61:19 | ... / ... | test.c:61:5:61:19 | ... / ... | Invalid usage of possible $@. | test.c:61:5:61:19 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:66:12:66:20 | ... / ... | test.c:66:5:66:21 | ... / ... | test.c:66:5:66:21 | ... / ... | Invalid usage of possible $@. | test.c:66:5:66:21 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:72:21:72:29 | ... / ... | test.c:72:14:72:30 | ... / ... | test.c:72:14:72:30 | ... / ... | Invalid usage of possible $@. | test.c:72:14:72:30 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:75:25:75:33 | ... / ... | test.c:75:18:75:34 | ... / ... | test.c:75:18:75:34 | ... / ... | Invalid usage of possible $@. | test.c:75:18:75:34 | ... / ... | NaN resulting from possible division of zero by zero | diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.qlref b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.qlref new file mode 100644 index 0000000000..d88c172bd5 --- /dev/null +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.qlref @@ -0,0 +1 @@ +rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.expected b/c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.qlref b/c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.qlref new file mode 100644 index 0000000000..1ffb7ad071 --- /dev/null +++ b/c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.qlref @@ -0,0 +1 @@ +rules/DIR-4-15/PossibleUndetectedNaNorInfinity.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/test.c b/c/misra/test/rules/DIR-4-15/test.c new file mode 100644 index 0000000000..d634a6e594 --- /dev/null +++ b/c/misra/test/rules/DIR-4-15/test.c @@ -0,0 +1,76 @@ +#include "math.h" + +float getFloat() { return 1.0; } + +// Parameter could be infinity +void f1(float p1) { + float l1 = 1; + float l2 = 1.0 / 0; + float l3 = -l2; + + 10 / l1; // COMPLIANT + 10 / l2; // NON_COMPLIANT: Underflows to zero + 10 / l3; // NON_COMPLIANT: Underflow to negative zero + 10 / p1; // COMPLIANT: Reduce false positives by assuming not infinity + 10 / getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + (int)l1; // COMPLIANT + (int)l2; // NON_COMPLIANT + (int)l3; // NON_COMPLIANT + (int)p1; // COMPLIANT: Reduce false positives by assuming not infinity + (int)getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + // Not NaN: + float l4 = l1 / l1; // COMPLIANT + + // NaN because of infinity divided by itself: + float l5 = l2 / l2; // NON_COMPLIANT: Division by infinity not allowed. + float l6 = l3 / l3; // NON_COMPLIANT: Division by infinity not allowed. + + // NaN because of zero divided by itself: + float l7 = getFloat() / + p1; // COMPLIANT: Reduce false positives by assuming not infinity + float l8 = 0.0 / 0.0; + + (int)l4; // COMPLIANT + (int)l5; // NON_COMPLIANT: Casting NaN to int + (int)l6; // NON_COMPLIANT: Casting NaN to int + (int)l7; // NON_COMPLIANT: Casting NaN to int + (int)l8; // NON_COMPLIANT: Casting NaN to int + + l4 == 0; // COMPLIANT + l4 != 0; // COMPLIANT + l4 <= 0; // COMPLIANT + l4 < 0; // COMPLIANT + l4 >= 0; // COMPLIANT + l5 == 0; // NON_COMPLIANT: Comparison with NaN always false + l5 != 0; // NON_COMPLIANT: Comparison with NaN always false + l5 < 0; // NON_COMPLIANT: Comparison with NaN always false + l5 <= 0; // NON_COMPLIANT: Comparison with NaN always false + l5 > 0; // NON_COMPLIANT: Comparison with NaN always false + l5 >= 0; // NON_COMPLIANT: Comparison with NaN always false + l6 == 0; // NON_COMPLIANT: Comparison with NaN always false + l7 == 0; // NON_COMPLIANT: Comparison with NaN always false + l8 == 0; // NON_COMPLIANT: Comparison with NaN always false + + // Guards + float l9 = 0; + if (l9 != 0) { + (int) (l9 / l9); // COMPLIANT: l9 is not zero + } else { + (int) (l9 / l9); // NON_COMPLIANT: Casting NaN to integer + } + + float l10 = 0; + if (l10 == 0) { + (int) (l10 / l10); // NON_COMPLIANT: Casting NaN to integer + } else { + (int) (l10 / l10); // COMPLIANT: l10 is not zero + } + + float l11 = 0; + l11 == 0 ? (int) (l11 / l11) : 0; // NON_COMPLIANT + l11 == 0 ? 0 : (int) (l11 / l11); // COMPLIANT + l11 != 0 ? (int) (l11 / l11) : 0; // COMPLIANT + l11 != 0 ? 0 : (int) (l11 / l11); // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/FloatingPoint.qll b/cpp/common/src/codingstandards/cpp/FloatingPoint.qll new file mode 100644 index 0000000000..d143f81418 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/FloatingPoint.qll @@ -0,0 +1,61 @@ +import codeql.util.Boolean +import codingstandards.cpp.RestrictedRangeAnalysis + +predicate exprMayEqualZero(Expr e) { + RestrictedRangeAnalysis::upperBound(e) >= 0 and + RestrictedRangeAnalysis::lowerBound(e) <= 0 and + not guardedNotEqualZero(e) +} + +predicate guardedNotEqualZero(Expr e) { + /* Note Boolean cmpEq, false means cmpNeq */ + exists(Expr checked, GuardCondition guard, boolean cmpEq, BooleanValue value | + hashCons(checked) = hashCons(e) and + guard.controls(e.getBasicBlock(), cmpEq) and + value.getValue() = cmpEq and + guard.comparesEq(checked, 0, false, value) + ) + or + exists(Expr checked, Expr val, int valVal, GuardCondition guard, boolean cmpEq | + hashCons(checked) = hashCons(e) and + forex(float v | + v = [RestrictedRangeAnalysis::lowerBound(val), RestrictedRangeAnalysis::upperBound(val)] + | + valVal = v + ) and + guard.controls(e.getBasicBlock(), cmpEq) and + guard.comparesEq(checked, val, -valVal, false, cmpEq) + ) +} + +predicate guardedNotInfinite(Expr e) { + /* Note Boolean cmpEq, false means cmpNeq */ + exists(Expr c, GuardCondition guard, boolean cmpEq | + hashCons(c) = hashCons(e) and + guard.controls(e, cmpEq) and + guard.comparesEq(c, 0, cmpEq.booleanNot(), _) + ) +} + +predicate test(Expr e, Expr v, int k, boolean areEqual, Boolean value, Expr gce, BasicBlock bb) { + exists(GuardCondition gc | gce = gc | + gc.controls(bb, _) and + gc.comparesEq(e, v, k, areEqual, value) and + ( + //gc.getAChild+().toString().matches("%dfYRes%") or + e.getAChild*().toString().matches("%dfPseudoPanchro%") or + v.getAChild*().toString().matches("%dfPseudoPanchro%") + ) + ) +} + +predicate exprMayEqualInfinity(Expr e, Boolean positive) { + exists(float target | + positive = true and target = 1.0 / 0.0 + or + positive = false and target = -1.0 / 0.0 + | + RestrictedRangeAnalysis::upperBound(e.getUnconverted()) = target or + RestrictedRangeAnalysis::lowerBound(e.getUnconverted()) = target + ) +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll new file mode 100644 index 0000000000..79ae2f367a --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll @@ -0,0 +1,1903 @@ +import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.valuenumbering.HashCons +/** + * A fork of SimpleRangeAnalysis.qll, which is intended to only give + * results with a conservative basis. + * + * For instance, since range analysis is local, a function call (e.g. + * `f()`) is given the widest possible range in the original library. In + * this fork, we do not provide any result. + * + * Original library level doc comment from SimpleRangeAnalysis.qll: + * + * Simple range analysis library. Range analysis is usually done as an + * abstract interpretation over the lattice of range values. (A range is a + * pair, containing a lower and upper bound for the value.) The problem + * with this approach is that the lattice is very tall, which means it can + * take an extremely large number of iterations to find the least fixed + * point. This example illustrates the problem: + * + * int count = 0; + * for (; p; p = p->next) { + * count = count+1; + * } + * + * The range of 'count' is initially (0,0), then (0,1) on the second + * iteration, (0,2) on the third iteration, and so on until we eventually + * reach maxInt. + * + * This library uses a crude solution to the problem described above: if + * the upper (or lower) bound of an expression might depend recursively on + * itself then we round it up (down for lower bounds) to one of a fixed set + * of values, such as 0, 1, 2, 256, and +Inf. This limits the height of the + * lattice which ensures that the analysis will terminate in a reasonable + * amount of time. This solution is similar to the abstract interpretation + * technique known as 'widening', but it is less precise because we are + * unable to inspect the bounds from the previous iteration of the fixed + * point computation. For example, widening might be able to deduce that + * the lower bound is -11 but we would approximate it to -16. + * + * QL does not allow us to compute an aggregate over a recursive + * sub-expression, so we cannot compute the minimum lower bound and maximum + * upper bound during the recursive phase of the query. Instead, the + * recursive phase computes a set of lower bounds and a set of upper bounds + * for each expression. We compute the minimum lower bound and maximum + * upper bound after the recursion is finished. This is another reason why + * we need to limit the number of bounds per expression, because they will + * all be stored until the recursive phase is finished. + * + * The ranges are represented using a pair of floating point numbers. This + * is simpler than using integers because floating point numbers cannot + * overflow and wrap. It is also convenient because we can detect overflow + * and negative overflow by looking for bounds that are outside the range + * of the type. + */ +module RestrictedRangeAnalysis { + import cpp + private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils as Util + import semmle.code.cpp.rangeanalysis.RangeSSA + import SimpleRangeAnalysisCached + private import semmle.code.cpp.rangeanalysis.NanAnalysis + + float largeValue() { result = 1000000000000000.0 } + + /** + * This fixed set of lower bounds is used when the lower bounds of an + * expression are recursively defined. The inferred lower bound is rounded + * down to the nearest lower bound in the fixed set. This restricts the + * height of the lattice, which prevents the analysis from exploding. + * + * Note: these bounds were chosen fairly arbitrarily. Feel free to add more + * bounds to the set if it helps on specific examples and does not make + * performance dramatically worse on large codebases, such as libreoffice. + */ + private float wideningLowerBounds(ArithmeticType t) { + result = 2.0 or + result = 1.0 or + result = 0.0 or + result = -1.0 or + result = -2.0 or + result = -8.0 or + result = -16.0 or + result = -128.0 or + result = -256.0 or + result = -32768.0 or + result = -65536.0 or + result = max(float v | v = Util::typeLowerBound(t) or v = -largeValue()) + } + + /** See comment for `wideningLowerBounds`, above. */ + private float wideningUpperBounds(ArithmeticType t) { + result = -2.0 or + result = -1.0 or + result = 0.0 or + result = 1.0 or + result = 2.0 or + result = 7.0 or + result = 15.0 or + result = 127.0 or + result = 255.0 or + result = 32767.0 or + result = 65535.0 or + result = min(float v | v = Util::typeLowerBound(t) or v = largeValue()) + } + + /** + * Gets the value of the expression `e`, if it is a constant. + * This predicate also handles the case of constant variables initialized in different + * compilation units, which doesn't necessarily have a getValue() result from the extractor. + */ + private string getValue(Expr e) { + if exists(e.getValue()) + then result = e.getValue() + else + /* + * It should be safe to propagate the initialization value to a variable if: + * The type of v is const, and + * The type of v is not volatile, and + * Either: + * v is a local/global variable, or + * v is a static member variable + */ + + exists(VariableAccess access, StaticStorageDurationVariable v | + not v.getUnderlyingType().isVolatile() and + v.getUnderlyingType().isConst() and + e = access and + v = access.getTarget() and + result = getValue(v.getAnAssignedValue()) + ) + } + + private float varMaxVal(Variable v) { + result = min(float f | f = Util::varMaxVal(v) or f = largeValue()) + } + + private float varMinVal(Variable v) { + result = max(float f | f = Util::varMinVal(v) or f = -largeValue()) + } + + private float exprMaxVal(Expr e) { + result = min(float f | f = Util::exprMaxVal(e) or f = largeValue()) + } + + private float exprMinVal(Expr e) { + result = max(float f | f = Util::exprMinVal(e) or f = -largeValue()) + } + + /** + * A bitwise `&` expression in which both operands are unsigned, or are effectively + * unsigned due to being a non-negative constant. + */ + private class UnsignedBitwiseAndExpr extends BitwiseAndExpr { + UnsignedBitwiseAndExpr() { + ( + this.getLeftOperand() + .getFullyConverted() + .getType() + .getUnderlyingType() + .(IntegralType) + .isUnsigned() or + getValue(this.getLeftOperand().getFullyConverted()).toInt() >= 0 + ) and + ( + this.getRightOperand() + .getFullyConverted() + .getType() + .getUnderlyingType() + .(IntegralType) + .isUnsigned() or + getValue(this.getRightOperand().getFullyConverted()).toInt() >= 0 + ) + } + } + + /** + * Gets the floor of `v`, with additional logic to work around issues with + * large numbers. + */ + bindingset[v] + float safeFloor(float v) { + // return the floor of v + v.abs() < 2.pow(31) and + result = v.floor() + or + // `floor()` doesn't work correctly on large numbers (since it returns an integer), + // so fall back to unrounded numbers at this scale. + not v.abs() < 2.pow(31) and + result = v + } + + /** A `MulExpr` where exactly one operand is constant. */ + private class MulByConstantExpr extends MulExpr { + float constant; + Expr operand; + + MulByConstantExpr() { + exists(Expr constantExpr | + this.hasOperands(constantExpr, operand) and + constant = getValue(constantExpr.getFullyConverted()).toFloat() and + not exists(getValue(operand.getFullyConverted()).toFloat()) + ) + } + + /** Gets the value of the constant operand. */ + float getConstant() { result = constant } + + /** Gets the non-constant operand. */ + Expr getOperand() { result = operand } + } + + private class UnsignedMulExpr extends MulExpr { + UnsignedMulExpr() { + this.getType().(IntegralType).isUnsigned() and + // Avoid overlap. It should be slightly cheaper to analyze + // `MulByConstantExpr`. + not this instanceof MulByConstantExpr + } + } + + /** + * Holds if `expr` is effectively a multiplication of `operand` with the + * positive constant `positive`. + */ + private predicate effectivelyMultipliesByPositive(Expr expr, Expr operand, float positive) { + operand = expr.(MulByConstantExpr).getOperand() and + positive = expr.(MulByConstantExpr).getConstant() and + positive >= 0.0 // includes positive zero + or + operand = expr.(UnaryPlusExpr).getOperand() and + positive = 1.0 + or + operand = expr.(CommaExpr).getRightOperand() and + positive = 1.0 + or + operand = expr.(StmtExpr).getResultExpr() and + positive = 1.0 + } + + /** + * Holds if `expr` is effectively a multiplication of `operand` with the + * negative constant `negative`. + */ + private predicate effectivelyMultipliesByNegative(Expr expr, Expr operand, float negative) { + operand = expr.(MulByConstantExpr).getOperand() and + negative = expr.(MulByConstantExpr).getConstant() and + negative < 0.0 // includes negative zero + or + operand = expr.(UnaryMinusExpr).getOperand() and + negative = -1.0 + } + + private class AssignMulByConstantExpr extends AssignMulExpr { + float constant; + + AssignMulByConstantExpr() { + constant = getValue(this.getRValue().getFullyConverted()).toFloat() + } + + float getConstant() { result = constant } + } + + private class AssignMulByPositiveConstantExpr extends AssignMulByConstantExpr { + AssignMulByPositiveConstantExpr() { constant >= 0.0 } + } + + private class AssignMulByNegativeConstantExpr extends AssignMulByConstantExpr { + AssignMulByNegativeConstantExpr() { constant < 0.0 } + } + + private class UnsignedAssignMulExpr extends AssignMulExpr { + UnsignedAssignMulExpr() { + this.getType().(IntegralType).isUnsigned() and + // Avoid overlap. It should be slightly cheaper to analyze + // `AssignMulByConstantExpr`. + not this instanceof AssignMulByConstantExpr + } + } + + /** + * Holds if `expr` is effectively a division of `operand` with the + * positive constant `positive`. + */ + private predicate dividesByPositive(DivExpr expr, Expr operand, float positive) { + operand = expr.(DivExpr).getLeftOperand() and + positive = expr.(DivExpr).getRightOperand().getValue().toFloat() and + positive > 0.0 // doesn't include zero + } + + /** + * Holds if `expr` is effectively a division of `operand` with the + * negative constant `negative`. + */ + private predicate dividesByNegative(Expr expr, Expr operand, float negative) { + operand = expr.(DivExpr).getLeftOperand() and + negative = getValue(expr.(DivExpr).getRightOperand().getFullyConverted()).toFloat() and + negative < 0.0 // doesn't include zero + } + + /** + * Holds if `expr` may divide by zero. + */ + predicate dividesByZero(Expr expr) { + exists(Expr divisor | + divisor = expr.(DivExpr).getRightOperand() and + getTruncatedLowerBounds(divisor) <= 0.0 and + getTruncatedUpperBounds(divisor) >= 0.0 and + not isCheckedNotZero(divisor) + ) + } + + /** + * Holds if `expr` is checked with a guard to not be zero. + * + * Since our range analysis only tracks an upper and lower bound, that means if a variable has + * range [-10, 10], its range includes zero. In the body of an if statement that checks it's not + * equal to zero, we cannot update the range to reflect that as the upper and lower bounds are + * not changed. This problem is not the case for gt, lt, gte, lte, or ==, as these can be used to + * create a new subset range that does not include zero. + * + * It is important to know if an expr may be zero to avoid division by zero creating infinities. + */ + predicate isCheckedNotZero(Expr expr) { + exists(RangeSsaDefinition def, StackVariable v, VariableAccess guardVa, Expr guard | + // This is copied from getGuardedUpperBound, which says its only an approximation. This is + // indeed wrong in many cases. + def.isGuardPhi(v, guardVa, guard, _) and + exists(unique(BasicBlock b | b = def.(BasicBlock).getAPredecessor())) and + expr = def.getAUse(v) and + isNEPhi(v, def, guardVa, 0) + ) + or guardedHashConsNotEqualZero(expr) + } + + predicate guardedHashConsNotEqualZero(Expr e) { + /* Note Boolean cmpEq, false means cmpNeq */ + exists(Expr check, Expr val, int valVal, GuardCondition guard, boolean cmpEq | + hashCons(check) = hashCons(e) and + valVal = getValue(val).toFloat() and + guard.controls(e.getBasicBlock(), cmpEq) and + ( + guard.comparesEq(check, val, -valVal, false, cmpEq) or + guard.comparesEq(val, check, -valVal, false, cmpEq) + ) + ) + } + + /** Set of expressions which we know how to analyze. */ + predicate analyzableExpr(Expr e) { + // The type of the expression must be arithmetic. We reuse the logic in + // `exprMinVal` to check this. + exists(Util::exprMinVal(e)) and + ( + exists(getValue(e).toFloat()) + or + effectivelyMultipliesByPositive(e, _, _) + or + effectivelyMultipliesByNegative(e, _, _) + or + dividesByPositive(e, _, _) + or + dividesByNegative(e, _, _) + // Introduces non-monotonic recursion. However, analysis mostly works with this + // commented out. + // or + // dividesByZero(e) + or + e instanceof DivExpr // TODO: confirm this is OK + or + e instanceof MinExpr + or + e instanceof MaxExpr + or + e instanceof ConditionalExpr + or + e instanceof AddExpr + or + e instanceof SubExpr + or + e instanceof UnsignedMulExpr + or + e instanceof AssignExpr + or + e instanceof AssignAddExpr + or + e instanceof AssignSubExpr + or + e instanceof UnsignedAssignMulExpr + or + e instanceof AssignMulByConstantExpr + or + e instanceof CrementOperation + or + e instanceof RemExpr + or + // A conversion is analyzable, provided that its child has an arithmetic + // type. (Sometimes the child is a reference type, and so does not get + // any bounds.) Rather than checking whether the type of the child is + // arithmetic, we reuse the logic that is already encoded in + // `exprMinVal`. + exists(Util::exprMinVal(e.(Conversion).getExpr())) + or + // Also allow variable accesses, provided that they have SSA + // information. + exists(RangeSsaDefinition def | e = def.getAUse(_)) + or + e instanceof UnsignedBitwiseAndExpr + or + // `>>` by a constant + exists(getValue(e.(RShiftExpr).getRightOperand())) + ) + } + + /** + * Set of definitions that this definition depends on. The transitive + * closure of this relation is used to detect definitions which are + * recursively defined, so that we can prevent the analysis from exploding. + * + * The structure of `defDependsOnDef` and its helper predicates matches the + * structure of `getDefLowerBoundsImpl` and + * `getDefUpperBoundsImpl`. Therefore, if changes are made to the structure + * of the main analysis algorithm then matching changes need to be made + * here. + */ + private predicate defDependsOnDef( + RangeSsaDefinition def, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar + ) { + // Definitions with a defining value. + exists(Expr expr | assignmentDef(def, v, expr) | exprDependsOnDef(expr, srcDef, srcVar)) + or + // Assignment operations with a defining value + exists(AssignOperation assignOp | + analyzableExpr(assignOp) and + def = assignOp and + def.getAVariable() = v and + exprDependsOnDef(assignOp, srcDef, srcVar) + ) + or + exists(CrementOperation crem | + def = crem and + def.getAVariable() = v and + exprDependsOnDef(crem.getOperand(), srcDef, srcVar) + ) + or + // Phi nodes. + phiDependsOnDef(def, v, srcDef, srcVar) + } + + /** + * Helper predicate for `defDependsOnDef`. This predicate matches + * the structure of `getLowerBoundsImpl` and `getUpperBoundsImpl`. + */ + private predicate exprDependsOnDef(Expr e, RangeSsaDefinition srcDef, StackVariable srcVar) { + exists(Expr operand | + effectivelyMultipliesByNegative(e, operand, _) and + exprDependsOnDef(operand, srcDef, srcVar) + ) + or + exists(Expr operand | + effectivelyMultipliesByPositive(e, operand, _) and + exprDependsOnDef(operand, srcDef, srcVar) + ) + or + exists(Expr operand | + (dividesByPositive(e, operand, _) or dividesByNegative(e, operand, _)) and + exprDependsOnDef(operand, srcDef, srcVar) + ) + or + exists(MinExpr minExpr | e = minExpr | exprDependsOnDef(minExpr.getAnOperand(), srcDef, srcVar)) + or + exists(MaxExpr maxExpr | e = maxExpr | exprDependsOnDef(maxExpr.getAnOperand(), srcDef, srcVar)) + or + exists(ConditionalExpr condExpr | e = condExpr | + exprDependsOnDef(condExpr.getAnOperand(), srcDef, srcVar) + ) + or + exists(AddExpr addExpr | e = addExpr | exprDependsOnDef(addExpr.getAnOperand(), srcDef, srcVar)) + or + exists(SubExpr subExpr | e = subExpr | exprDependsOnDef(subExpr.getAnOperand(), srcDef, srcVar)) + or + exists(UnsignedMulExpr mulExpr | e = mulExpr | + exprDependsOnDef(mulExpr.getAnOperand(), srcDef, srcVar) + ) + or + exists(AssignExpr addExpr | e = addExpr | exprDependsOnDef(addExpr.getRValue(), srcDef, srcVar)) + or + exists(AssignAddExpr addExpr | e = addExpr | + exprDependsOnDef(addExpr.getAnOperand(), srcDef, srcVar) + ) + or + exists(AssignSubExpr subExpr | e = subExpr | + exprDependsOnDef(subExpr.getAnOperand(), srcDef, srcVar) + ) + or + exists(UnsignedAssignMulExpr mulExpr | e = mulExpr | + exprDependsOnDef(mulExpr.getAnOperand(), srcDef, srcVar) + ) + or + exists(AssignMulByConstantExpr mulExpr | e = mulExpr | + exprDependsOnDef(mulExpr.getLValue(), srcDef, srcVar) + ) + or + exists(CrementOperation crementExpr | e = crementExpr | + exprDependsOnDef(crementExpr.getOperand(), srcDef, srcVar) + ) + or + exists(RemExpr remExpr | e = remExpr | exprDependsOnDef(remExpr.getAnOperand(), srcDef, srcVar)) + or + exists(Conversion convExpr | e = convExpr | + exprDependsOnDef(convExpr.getExpr(), srcDef, srcVar) + ) + or + // unsigned `&` + exists(UnsignedBitwiseAndExpr andExpr | + andExpr = e and + exprDependsOnDef(andExpr.getAnOperand(), srcDef, srcVar) + ) + or + // `>>` by a constant + exists(RShiftExpr rs | + rs = e and + exists(getValue(rs.getRightOperand())) and + exprDependsOnDef(rs.getLeftOperand(), srcDef, srcVar) + ) + or + e = srcDef.getAUse(srcVar) + } + + /** + * Helper predicate for `defDependsOnDef`. This predicate matches + * the structure of `getPhiLowerBounds` and `getPhiUpperBounds`. + */ + private predicate phiDependsOnDef( + RangeSsaDefinition phi, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar + ) { + exists(VariableAccess access, Expr guard | phi.isGuardPhi(v, access, guard, _) | + exprDependsOnDef(guard.(ComparisonOperation).getAnOperand(), srcDef, srcVar) or + exprDependsOnDef(access, srcDef, srcVar) + ) + or + srcDef = phi.getAPhiInput(v) and srcVar = v + } + + /** The transitive closure of `defDependsOnDef`. */ + private predicate defDependsOnDefTransitively( + RangeSsaDefinition def, StackVariable v, RangeSsaDefinition srcDef, StackVariable srcVar + ) { + defDependsOnDef(def, v, srcDef, srcVar) + or + exists(RangeSsaDefinition midDef, StackVariable midVar | + defDependsOnDef(def, v, midDef, midVar) + | + defDependsOnDefTransitively(midDef, midVar, srcDef, srcVar) + ) + } + + /** The set of definitions that depend recursively on themselves. */ + private predicate isRecursiveDef(RangeSsaDefinition def, StackVariable v) { + defDependsOnDefTransitively(def, v, def, v) + } + + /** + * Holds if the bounds of `e` depend on a recursive definition, meaning that + * `e` is likely to have many candidate bounds during the main recursion. + */ + private predicate isRecursiveExpr(Expr e) { + exists(RangeSsaDefinition def, StackVariable v | exprDependsOnDef(e, def, v) | + isRecursiveDef(def, v) + ) + } + + /** + * Holds if `binop` is a binary operation that's likely to be assigned a + * quadratic (or more) number of candidate bounds during the analysis. This can + * happen when two conditions are satisfied: + * 1. It is likely there are many more candidate bounds for `binop` than for + * its operands. For example, the number of candidate bounds for `x + y`, + * denoted here nbounds(`x + y`), will be O(nbounds(`x`) * nbounds(`y`)). + * In contrast, nbounds(`b ? x : y`) is only O(nbounds(`x`) + nbounds(`y`)). + * 2. Both operands of `binop` are recursively determined and are therefore + * likely to have a large number of candidate bounds. + */ + private predicate isRecursiveBinary(BinaryOperation binop) { + ( + binop instanceof UnsignedMulExpr + or + binop instanceof AddExpr + or + binop instanceof SubExpr + ) and + isRecursiveExpr(binop.getLeftOperand()) and + isRecursiveExpr(binop.getRightOperand()) + } + + /** + * We distinguish 3 kinds of RangeSsaDefinition: + * + * 1. Definitions with a defining value. + * For example: x = y+3 is a definition of x with defining value y+3. + * + * 2. Phi nodes: x3 = phi(x0,x1,x2) + * + * 3. Unanalyzable definitions. + * For example: a parameter is unanalyzable because we know nothing + * about its value. We assign these range [-largeValue(), largeValue()] + * + * This predicate finds all the definitions in the first set. + */ + private predicate assignmentDef(RangeSsaDefinition def, StackVariable v, Expr expr) { + Util::getVariableRangeType(v) instanceof ArithmeticType and + ( + def = v.getInitializer().getExpr() and def = expr + or + exists(AssignExpr assign | + def = assign and + assign.getLValue() = v.getAnAccess() and + expr = assign.getRValue() + ) + ) + } + + /** See comment above assignmentDef. */ + private predicate analyzableDef(RangeSsaDefinition def, StackVariable v) { + assignmentDef(def, v, _) + or + analyzableExpr(def.(AssignOperation)) and + v = def.getAVariable() + or + analyzableExpr(def.(CrementOperation)) and + v = def.getAVariable() + or + phiDependsOnDef(def, v, _, _) + } + + /** + * Computes a normal form of `x` where -0.0 has changed to +0.0. This can be + * needed on the lesser side of a floating-point comparison or on both sides of + * a floating point equality because QL does not follow IEEE in floating-point + * comparisons but instead defines -0.0 to be less than and distinct from 0.0. + */ + bindingset[x] + private float normalizeFloatUp(float x) { result = x + 0.0 } + + /** + * Computes `x + y`, rounded towards +Inf. This is the general case where both + * `x` and `y` may be large numbers. + */ + bindingset[x, y] + private float addRoundingUp(float x, float y) { + if normalizeFloatUp((x + y) - x) < y or normalizeFloatUp((x + y) - y) < x + then result = (x + y).nextUp() + else result = (x + y) + } + + /** + * Computes `x + y`, rounded towards -Inf. This is the general case where both + * `x` and `y` may be large numbers. + */ + bindingset[x, y] + private float addRoundingDown(float x, float y) { + if (x + y) - x > normalizeFloatUp(y) or (x + y) - y > normalizeFloatUp(x) + then result = (x + y).nextDown() + else result = (x + y) + } + + /** + * Computes `x + small`, rounded towards +Inf, where `small` is a small + * constant. + */ + bindingset[x, small] + private float addRoundingUpSmall(float x, float small) { + if (x + small) - x < small then result = (x + small).nextUp() else result = (x + small) + } + + /** + * Computes `x + small`, rounded towards -Inf, where `small` is a small + * constant. + */ + bindingset[x, small] + private float addRoundingDownSmall(float x, float small) { + if (x + small) - x > small then result = (x + small).nextDown() else result = (x + small) + } + + private predicate lowerBoundableExpr(Expr expr) { + (analyzableExpr(expr) or dividesByZero(expr)) and + getUpperBoundsImpl(expr) <= Util::exprMaxVal(expr) and + not exists(getValue(expr).toFloat()) + } + + /** + * Gets the lower bounds of the expression. + * + * Most of the work of computing the lower bounds is done by + * `getLowerBoundsImpl`. However, the lower bounds computed by + * `getLowerBoundsImpl` may not be representable by the result type of the + * expression. For example, if `x` and `y` are of type `int32` and each + * have lower bound -2147483648, then getLowerBoundsImpl` will compute a + * lower bound -4294967296 for the expression `x+y`, even though + * -4294967296 cannot be represented as an `int32`. Such unrepresentable + * bounds are replaced with `exprMinVal(expr)`. This predicate also adds + * `exprMinVal(expr)` as a lower bound if the expression might overflow + * positively, or if it is unanalyzable. + * + * Note: most callers should use `getFullyConvertedLowerBounds` rather than + * this predicate. + */ + private float getTruncatedLowerBounds(Expr expr) { + // If the expression evaluates to a constant, then there is no + // need to call getLowerBoundsImpl. + analyzableExpr(expr) and + result = getValue(expr).toFloat() + or + // Some of the bounds computed by getLowerBoundsImpl might + // overflow, so we replace invalid bounds with exprMinVal. + exists(float newLB | newLB = normalizeFloatUp(getLowerBoundsImpl(expr)) | + if Util::exprMinVal(expr) <= newLB and newLB <= Util::exprMaxVal(expr) + then + // Apply widening where we might get a combinatorial explosion. + if isRecursiveBinary(expr) + then + result = + max(float widenLB | + widenLB = wideningLowerBounds(expr.getUnspecifiedType()) and + not widenLB > newLB + ) + else result = newLB + else result = Util::exprMinVal(expr) + ) and + lowerBoundableExpr(expr) + or + // The expression might overflow and wrap. If so, the + // lower bound is exprMinVal. + analyzableExpr(expr) and + exprMightOverflowPositively(expr) and + not result = getValue(expr).toFloat() and + result = Util::exprMinVal(expr) + or + // The expression is not analyzable, so its lower bound is + // unknown. Note that the call to exprMinVal restricts the + // expressions to just those with arithmetic types. There is no + // need to return results for non-arithmetic expressions. + not analyzableExpr(expr) and + result = exprMinVal(expr) + } + + /** + * Gets the upper bounds of the expression. + * + * Most of the work of computing the upper bounds is done by + * `getUpperBoundsImpl`. However, the upper bounds computed by + * `getUpperBoundsImpl` may not be representable by the result type of the + * expression. For example, if `x` and `y` are of type `int32` and each + * have upper bound 2147483647, then getUpperBoundsImpl` will compute an + * upper bound 4294967294 for the expression `x+y`, even though 4294967294 + * cannot be represented as an `int32`. Such unrepresentable bounds are + * replaced with `exprMaxVal(expr)`. This predicate also adds + * `exprMaxVal(expr)` as an upper bound if the expression might overflow + * negatively, or if it is unanalyzable. + * + * Note: most callers should use `getFullyConvertedUpperBounds` rather than + * this predicate. + */ + private float getTruncatedUpperBounds(Expr expr) { + (analyzableExpr(expr) or dividesByZero(expr)) + and ( + // If the expression evaluates to a constant, then there is no + // need to call getUpperBoundsImpl. + if exists(getValue(expr).toFloat()) + then result = getValue(expr).toFloat() + else ( + // Some of the bounds computed by `getUpperBoundsImpl` + // might overflow, so we replace invalid bounds with + // `exprMaxVal`. + exists(float newUB | newUB = normalizeFloatUp(getUpperBoundsImpl(expr)) | + if Util::exprMinVal(expr) <= newUB and newUB <= Util::exprMaxVal(expr) + then + // Apply widening where we might get a combinatorial explosion. + if isRecursiveBinary(expr) + then + result = + min(float widenUB | + widenUB = wideningUpperBounds(expr.getUnspecifiedType()) and + not widenUB < newUB + ) + else result = newUB + else result = Util::exprMaxVal(expr) + ) + or + // The expression might overflow negatively and wrap. If so, + // the upper bound is `exprMaxVal`. + exprMightOverflowNegatively(expr) and + result = Util::exprMaxVal(expr) + ) + ) or + not analyzableExpr(expr) and + // The expression is not analyzable, so its upper bound is + // unknown. Note that the call to exprMaxVal restricts the + // expressions to just those with arithmetic types. There is no + // need to return results for non-arithmetic expressions. + result = exprMaxVal(expr) + } + + /** Only to be called by `getTruncatedLowerBounds`. */ + private float getLowerBoundsImpl(Expr expr) { + ( + exists(Expr operand, float operandLow, float positive | + effectivelyMultipliesByPositive(expr, operand, positive) and + operandLow = getFullyConvertedLowerBounds(operand) and + result = positive * operandLow + ) + or + exists(Expr operand, float operandHigh, float negative | + effectivelyMultipliesByNegative(expr, operand, negative) and + operandHigh = getFullyConvertedUpperBounds(operand) and + result = negative * operandHigh + ) + or + exists(Expr operand, float operandLow, float positive | + dividesByPositive(expr, operand, positive) and + operandLow = getFullyConvertedLowerBounds(operand) and + result = operandLow / positive + ) + or + exists(Expr operand, float operandLow, float negative | + dividesByNegative(expr, operand, negative) and + operandLow = getFullyConvertedUpperBounds(operand) and + result = operandLow / negative + ) + or + exists(DivExpr div | expr = div | + dividesByZero(expr) and + result = getFullyConvertedLowerBounds(div.getLeftOperand()) / 0 + ) + or + exists(MinExpr minExpr | + expr = minExpr and + // Return the union of the lower bounds from both children. + result = getFullyConvertedLowerBounds(minExpr.getAnOperand()) + ) + or + exists(MaxExpr maxExpr | + expr = maxExpr and + // Compute the cross product of the bounds from both children. We are + // using this mathematical property: + // + // max (minimum{X}, minimum{Y}) + // = minimum { max(x,y) | x in X, y in Y } + exists(float x, float y | + x = getFullyConvertedLowerBounds(maxExpr.getLeftOperand()) and + y = getFullyConvertedLowerBounds(maxExpr.getRightOperand()) and + if x >= y then result = x else result = y + ) + ) + or + // ConditionalExpr (true branch) + exists(ConditionalExpr condExpr | + expr = condExpr and + // Use `boolConversionUpperBound` to determine whether the condition + // might evaluate to `true`. + boolConversionUpperBound(condExpr.getCondition().getFullyConverted()) = 1 and + result = getFullyConvertedLowerBounds(condExpr.getThen()) + ) + or + // ConditionalExpr (false branch) + exists(ConditionalExpr condExpr | + expr = condExpr and + // Use `boolConversionLowerBound` to determine whether the condition + // might evaluate to `false`. + boolConversionLowerBound(condExpr.getCondition().getFullyConverted()) = 0 and + result = getFullyConvertedLowerBounds(condExpr.getElse()) + ) + or + exists(AddExpr addExpr, float xLow, float yLow | + expr = addExpr and + xLow = getFullyConvertedLowerBounds(addExpr.getLeftOperand()) and + yLow = getFullyConvertedLowerBounds(addExpr.getRightOperand()) and + result = addRoundingDown(xLow, yLow) + ) + or + exists(SubExpr subExpr, float xLow, float yHigh | + expr = subExpr and + xLow = getFullyConvertedLowerBounds(subExpr.getLeftOperand()) and + yHigh = getFullyConvertedUpperBounds(subExpr.getRightOperand()) and + result = addRoundingDown(xLow, -yHigh) + ) + or + exists(UnsignedMulExpr mulExpr, float xLow, float yLow | + expr = mulExpr and + xLow = getFullyConvertedLowerBounds(mulExpr.getLeftOperand()) and + yLow = getFullyConvertedLowerBounds(mulExpr.getRightOperand()) and + result = xLow * yLow + ) + or + exists(AssignExpr assign | + expr = assign and + result = getFullyConvertedLowerBounds(assign.getRValue()) + ) + or + exists(AssignAddExpr addExpr, float xLow, float yLow | + expr = addExpr and + xLow = getFullyConvertedLowerBounds(addExpr.getLValue()) and + yLow = getFullyConvertedLowerBounds(addExpr.getRValue()) and + result = addRoundingDown(xLow, yLow) + ) + or + exists(AssignSubExpr subExpr, float xLow, float yHigh | + expr = subExpr and + xLow = getFullyConvertedLowerBounds(subExpr.getLValue()) and + yHigh = getFullyConvertedUpperBounds(subExpr.getRValue()) and + result = addRoundingDown(xLow, -yHigh) + ) + or + exists(UnsignedAssignMulExpr mulExpr, float xLow, float yLow | + expr = mulExpr and + xLow = getFullyConvertedLowerBounds(mulExpr.getLValue()) and + yLow = getFullyConvertedLowerBounds(mulExpr.getRValue()) and + result = xLow * yLow + ) + or + exists(AssignMulByPositiveConstantExpr mulExpr, float xLow | + expr = mulExpr and + xLow = getFullyConvertedLowerBounds(mulExpr.getLValue()) and + result = xLow * mulExpr.getConstant() + ) + or + exists(AssignMulByNegativeConstantExpr mulExpr, float xHigh | + expr = mulExpr and + xHigh = getFullyConvertedUpperBounds(mulExpr.getLValue()) and + result = xHigh * mulExpr.getConstant() + ) + or + exists(PrefixIncrExpr incrExpr, float xLow | + expr = incrExpr and + xLow = getFullyConvertedLowerBounds(incrExpr.getOperand()) and + result = xLow + 1 + ) + or + exists(PrefixDecrExpr decrExpr, float xLow | + expr = decrExpr and + xLow = getFullyConvertedLowerBounds(decrExpr.getOperand()) and + result = addRoundingDownSmall(xLow, -1) + ) + or + // `PostfixIncrExpr` and `PostfixDecrExpr` return the value of their + // operand. The incrementing/decrementing behavior is handled in + // `getDefLowerBoundsImpl`. + exists(PostfixIncrExpr incrExpr | + expr = incrExpr and + result = getFullyConvertedLowerBounds(incrExpr.getOperand()) + ) + or + exists(PostfixDecrExpr decrExpr | + expr = decrExpr and + result = getFullyConvertedLowerBounds(decrExpr.getOperand()) + ) + or + exists(RemExpr remExpr | expr = remExpr | + // If both inputs are positive then the lower bound is zero. + result = 0 + or + // If either input could be negative then the output could be + // negative. If so, the lower bound of `x%y` is `-abs(y) + 1`, which is + // equal to `min(-y + 1,y - 1)`. + exists(float childLB | + childLB = getFullyConvertedLowerBounds(remExpr.getAnOperand()) and + not childLB >= 0 + | + result = getFullyConvertedLowerBounds(remExpr.getRightOperand()) - 1 + or + exists(float rhsUB | rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand()) | + result = -rhsUB + 1 + ) + ) + ) + or + // If the conversion is to an arithmetic type then we just return the + // lower bound of the child. We do not need to handle truncation and + // overflow here, because that is done in `getTruncatedLowerBounds`. + // Conversions to `bool` need to be handled specially because they test + // whether the value of the expression is equal to 0. + exists(Conversion convExpr | expr = convExpr | + if convExpr.getUnspecifiedType() instanceof BoolType + then result = boolConversionLowerBound(convExpr.getExpr()) + else result = getTruncatedLowerBounds(convExpr.getExpr()) + ) + or + // Use SSA to get the lower bounds for a variable use. + exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | + result = getDefLowerBounds(def, v) + ) + or + // unsigned `&` (tighter bounds may exist) + exists(UnsignedBitwiseAndExpr andExpr | + andExpr = expr and + result = 0.0 + ) + or + // `>>` by a constant + exists(RShiftExpr rsExpr, float left, int right | + rsExpr = expr and + left = getFullyConvertedLowerBounds(rsExpr.getLeftOperand()) and + right = getValue(rsExpr.getRightOperand().getFullyConverted()).toInt() and + result = safeFloor(left / 2.pow(right)) + ) + ) + } + + /** Only to be called by `getTruncatedUpperBounds`. */ + private float getUpperBoundsImpl(Expr expr) { + ( + exists(Expr operand, float operandHigh, float positive | + effectivelyMultipliesByPositive(expr, operand, positive) and + operandHigh = getFullyConvertedUpperBounds(operand) and + result = positive * operandHigh + ) + or + exists(Expr operand, float operandLow, float negative | + effectivelyMultipliesByNegative(expr, operand, negative) and + operandLow = getFullyConvertedLowerBounds(operand) and + result = negative * operandLow + ) + or + exists(Expr operand, float operandHigh, float positive | + dividesByPositive(expr, operand, positive) and + operandHigh = getFullyConvertedUpperBounds(operand) and + result = operandHigh / positive + ) + or + exists(Expr operand, float operandHigh, float negative | + dividesByNegative(expr, operand, negative) and + operandHigh = getFullyConvertedLowerBounds(operand) and + result = operandHigh / negative + ) + or + exists(DivExpr div | expr = div | + dividesByZero(expr) and + result = getFullyConvertedUpperBounds(div.getLeftOperand()) / 0 + ) + or + exists(MaxExpr maxExpr | + expr = maxExpr and + // Return the union of the upper bounds from both children. + result = getFullyConvertedUpperBounds(maxExpr.getAnOperand()) + ) + or + exists(MinExpr minExpr | + expr = minExpr and + // Compute the cross product of the bounds from both children. We are + // using this mathematical property: + // + // min (maximum{X}, maximum{Y}) + // = maximum { min(x,y) | x in X, y in Y } + exists(float x, float y | + x = getFullyConvertedUpperBounds(minExpr.getLeftOperand()) and + y = getFullyConvertedUpperBounds(minExpr.getRightOperand()) and + if x <= y then result = x else result = y + ) + ) + or + // ConditionalExpr (true branch) + exists(ConditionalExpr condExpr | + expr = condExpr and + // Use `boolConversionUpperBound` to determine whether the condition + // might evaluate to `true`. + boolConversionUpperBound(condExpr.getCondition().getFullyConverted()) = 1 and + result = getFullyConvertedUpperBounds(condExpr.getThen()) + ) + or + // ConditionalExpr (false branch) + exists(ConditionalExpr condExpr | + expr = condExpr and + // Use `boolConversionLowerBound` to determine whether the condition + // might evaluate to `false`. + boolConversionLowerBound(condExpr.getCondition().getFullyConverted()) = 0 and + result = getFullyConvertedUpperBounds(condExpr.getElse()) + ) + or + exists(AddExpr addExpr, float xHigh, float yHigh | + expr = addExpr and + xHigh = getFullyConvertedUpperBounds(addExpr.getLeftOperand()) and + yHigh = getFullyConvertedUpperBounds(addExpr.getRightOperand()) and + result = addRoundingUp(xHigh, yHigh) + ) + or + exists(SubExpr subExpr, float xHigh, float yLow | + expr = subExpr and + xHigh = getFullyConvertedUpperBounds(subExpr.getLeftOperand()) and + yLow = getFullyConvertedLowerBounds(subExpr.getRightOperand()) and + result = addRoundingUp(xHigh, -yLow) + ) + or + exists(UnsignedMulExpr mulExpr, float xHigh, float yHigh | + expr = mulExpr and + xHigh = getFullyConvertedUpperBounds(mulExpr.getLeftOperand()) and + yHigh = getFullyConvertedUpperBounds(mulExpr.getRightOperand()) and + result = xHigh * yHigh + ) + or + exists(AssignExpr assign | + expr = assign and + result = getFullyConvertedUpperBounds(assign.getRValue()) + ) + or + exists(AssignAddExpr addExpr, float xHigh, float yHigh | + expr = addExpr and + xHigh = getFullyConvertedUpperBounds(addExpr.getLValue()) and + yHigh = getFullyConvertedUpperBounds(addExpr.getRValue()) and + result = addRoundingUp(xHigh, yHigh) + ) + or + exists(AssignSubExpr subExpr, float xHigh, float yLow | + expr = subExpr and + xHigh = getFullyConvertedUpperBounds(subExpr.getLValue()) and + yLow = getFullyConvertedLowerBounds(subExpr.getRValue()) and + result = addRoundingUp(xHigh, -yLow) + ) + or + exists(UnsignedAssignMulExpr mulExpr, float xHigh, float yHigh | + expr = mulExpr and + xHigh = getFullyConvertedUpperBounds(mulExpr.getLValue()) and + yHigh = getFullyConvertedUpperBounds(mulExpr.getRValue()) and + result = xHigh * yHigh + ) + or + exists(AssignMulByPositiveConstantExpr mulExpr, float xHigh | + expr = mulExpr and + xHigh = getFullyConvertedUpperBounds(mulExpr.getLValue()) and + result = xHigh * mulExpr.getConstant() + ) + or + exists(AssignMulByNegativeConstantExpr mulExpr, float xLow | + expr = mulExpr and + xLow = getFullyConvertedLowerBounds(mulExpr.getLValue()) and + result = xLow * mulExpr.getConstant() + ) + or + exists(PrefixIncrExpr incrExpr, float xHigh | + expr = incrExpr and + xHigh = getFullyConvertedUpperBounds(incrExpr.getOperand()) and + result = addRoundingUpSmall(xHigh, 1) + ) + or + exists(PrefixDecrExpr decrExpr, float xHigh | + expr = decrExpr and + xHigh = getFullyConvertedUpperBounds(decrExpr.getOperand()) and + result = xHigh - 1 + ) + or + // `PostfixIncrExpr` and `PostfixDecrExpr` return the value of their operand. + // The incrementing/decrementing behavior is handled in + // `getDefUpperBoundsImpl`. + exists(PostfixIncrExpr incrExpr | + expr = incrExpr and + result = getFullyConvertedUpperBounds(incrExpr.getOperand()) + ) + or + exists(PostfixDecrExpr decrExpr | + expr = decrExpr and + result = getFullyConvertedUpperBounds(decrExpr.getOperand()) + ) + or + exists(RemExpr remExpr, float rhsUB | + expr = remExpr and + rhsUB = getFullyConvertedUpperBounds(remExpr.getRightOperand()) + | + result = rhsUB - 1 + or + // If the right hand side could be negative then we need to take its + // absolute value. Since `abs(x) = max(-x,x)` this is equivalent to + // adding `-rhsLB` to the set of upper bounds. + exists(float rhsLB | + rhsLB = getFullyConvertedLowerBounds(remExpr.getRightOperand()) and + not rhsLB >= 0 + | + result = -rhsLB + 1 + ) + ) + or + // If the conversion is to an arithmetic type then we just return the + // upper bound of the child. We do not need to handle truncation and + // overflow here, because that is done in `getTruncatedUpperBounds`. + // Conversions to `bool` need to be handled specially because they test + // whether the value of the expression is equal to 0. + exists(Conversion convExpr | expr = convExpr | + if convExpr.getUnspecifiedType() instanceof BoolType + then result = boolConversionUpperBound(convExpr.getExpr()) + else result = getTruncatedUpperBounds(convExpr.getExpr()) + ) + or + // Use SSA to get the upper bounds for a variable use. + exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | + result = getDefUpperBounds(def, v) + ) + or + // unsigned `&` (tighter bounds may exist) + exists(UnsignedBitwiseAndExpr andExpr, float left, float right | + andExpr = expr and + left = getFullyConvertedUpperBounds(andExpr.getLeftOperand()) and + right = getFullyConvertedUpperBounds(andExpr.getRightOperand()) and + result = left.minimum(right) + ) + or + // `>>` by a constant + exists(RShiftExpr rsExpr, float left, int right | + rsExpr = expr and + left = getFullyConvertedUpperBounds(rsExpr.getLeftOperand()) and + right = getValue(rsExpr.getRightOperand().getFullyConverted()).toInt() and + result = safeFloor(left / 2.pow(right)) + ) + ) + } + + /** + * Holds if `expr` is converted to `bool` or if it is the child of a + * logical operation. + * + * The purpose of this predicate is to optimize `boolConversionLowerBound` + * and `boolConversionUpperBound` by preventing them from computing + * unnecessary results. In other words, `exprIsUsedAsBool(expr)` holds if + * `expr` is an expression that might be passed as an argument to + * `boolConversionLowerBound` or `boolConversionUpperBound`. + */ + private predicate exprIsUsedAsBool(Expr expr) { + expr = any(BinaryLogicalOperation op).getAnOperand().getFullyConverted() + or + expr = any(UnaryLogicalOperation op).getOperand().getFullyConverted() + or + expr = any(ConditionalExpr c).getCondition().getFullyConverted() + or + exists(Conversion cast | cast.getUnspecifiedType() instanceof BoolType | expr = cast.getExpr()) + } + + /** + * Gets the lower bound of the conversion `(bool)expr`. If we can prove that + * the value of `expr` is never 0 then `lb = 1`. Otherwise `lb = 0`. + */ + private float boolConversionLowerBound(Expr expr) { + // Case 1: if the range for `expr` includes the value 0, + // then `result = 0`. + exprIsUsedAsBool(expr) and + exists(float lb | lb = getTruncatedLowerBounds(expr) and not lb > 0) and + exists(float ub | ub = getTruncatedUpperBounds(expr) and not ub < 0) and + result = 0 + or + // Case 2a: if the range for `expr` does not include the value 0, + // then `result = 1`. + exprIsUsedAsBool(expr) and getTruncatedLowerBounds(expr) > 0 and result = 1 + or + // Case 2b: if the range for `expr` does not include the value 0, + // then `result = 1`. + exprIsUsedAsBool(expr) and getTruncatedUpperBounds(expr) < 0 and result = 1 + or + // Case 3: the type of `expr` is not arithmetic. For example, it might + // be a pointer. + exprIsUsedAsBool(expr) and not exists(Util::exprMinVal(expr)) and result = 0 + } + + /** + * Gets the upper bound of the conversion `(bool)expr`. If we can prove that + * the value of `expr` is always 0 then `ub = 0`. Otherwise `ub = 1`. + */ + private float boolConversionUpperBound(Expr expr) { + // Case 1a: if the upper bound of the operand is <= 0, then the upper + // bound might be 0. + exprIsUsedAsBool(expr) and getTruncatedUpperBounds(expr) <= 0 and result = 0 + or + // Case 1b: if the upper bound of the operand is not <= 0, then the upper + // bound is 1. + exprIsUsedAsBool(expr) and + exists(float ub | ub = getTruncatedUpperBounds(expr) and not ub <= 0) and + result = 1 + or + // Case 2a: if the lower bound of the operand is >= 0, then the upper + // bound might be 0. + exprIsUsedAsBool(expr) and getTruncatedLowerBounds(expr) >= 0 and result = 0 + or + // Case 2b: if the lower bound of the operand is not >= 0, then the upper + // bound is 1. + exprIsUsedAsBool(expr) and + exists(float lb | lb = getTruncatedLowerBounds(expr) and not lb >= 0) and + result = 1 + or + // Case 3: the type of `expr` is not arithmetic. For example, it might + // be a pointer. + exprIsUsedAsBool(expr) and not exists(Util::exprMaxVal(expr)) and result = 1 + } + + /** + * This predicate computes the lower bounds of a phi definition. If the + * phi definition corresponds to a guard, then the guard is used to + * deduce a better lower bound. + * For example: + * + * def: x = y % 10; + * guard: if (x >= 2) { + * block: f(x) + * } + * + * In this example, the lower bound of x is 0, but we can + * use the guard to deduce that the lower bound is 2 inside the block. + */ + private float getPhiLowerBounds(StackVariable v, RangeSsaDefinition phi) { + exists(VariableAccess access, Expr guard, boolean branch, float defLB, float guardLB | + phi.isGuardPhi(v, access, guard, branch) and + lowerBoundFromGuard(guard, access, guardLB, branch) and + defLB = getFullyConvertedLowerBounds(access) + | + // Compute the maximum of `guardLB` and `defLB`. + if guardLB > defLB then result = guardLB else result = defLB + ) + or + exists(VariableAccess access, float neConstant, float lower | + isNEPhi(v, phi, access, neConstant) and + lower = getTruncatedLowerBounds(access) and + if lower = neConstant then result = lower + 1 else result = lower + ) + or + exists(VariableAccess access | + isUnsupportedGuardPhi(v, phi, access) and + result = getTruncatedLowerBounds(access) + ) + or + result = getDefLowerBounds(phi.getAPhiInput(v), v) + } + + /** See comment for `getPhiLowerBounds`, above. */ + private float getPhiUpperBounds(StackVariable v, RangeSsaDefinition phi) { + exists(VariableAccess access, Expr guard, boolean branch, float defUB, float guardUB | + phi.isGuardPhi(v, access, guard, branch) and + upperBoundFromGuard(guard, access, guardUB, branch) and + defUB = getFullyConvertedUpperBounds(access) + | + // Compute the minimum of `guardUB` and `defUB`. + if guardUB < defUB then result = guardUB else result = defUB + ) + or + exists(VariableAccess access, float neConstant, float upper | + isNEPhi(v, phi, access, neConstant) and + upper = getTruncatedUpperBounds(access) and + if upper = neConstant then result = upper - 1 else result = upper + ) + or + exists(VariableAccess access | + isUnsupportedGuardPhi(v, phi, access) and + result = getTruncatedUpperBounds(access) + ) + or + result = getDefUpperBounds(phi.getAPhiInput(v), v) + } + + /** Only to be called by `getDefLowerBounds`. */ + private float getDefLowerBoundsImpl(RangeSsaDefinition def, StackVariable v) { + // Definitions with a defining value. + exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedLowerBounds(expr)) + or + // Assignment operations with a defining value + exists(AssignOperation assignOp | + def = assignOp and + assignOp.getLValue() = v.getAnAccess() and + result = getTruncatedLowerBounds(assignOp) + ) + or + exists(IncrementOperation incr, float newLB | + def = incr and + incr.getOperand() = v.getAnAccess() and + newLB = getFullyConvertedLowerBounds(incr.getOperand()) and + result = newLB + 1 + ) + or + exists(DecrementOperation decr, float newLB | + def = decr and + decr.getOperand() = v.getAnAccess() and + newLB = getFullyConvertedLowerBounds(decr.getOperand()) and + result = addRoundingDownSmall(newLB, -1) + ) + or + // Phi nodes. + result = getPhiLowerBounds(v, def) + or + // Unanalyzable definitions. + unanalyzableDefBounds(def, v, result, _) + } + + /** Only to be called by `getDefUpperBounds`. */ + private float getDefUpperBoundsImpl(RangeSsaDefinition def, StackVariable v) { + // Definitions with a defining value. + exists(Expr expr | assignmentDef(def, v, expr) | result = getFullyConvertedUpperBounds(expr)) + or + // Assignment operations with a defining value + exists(AssignOperation assignOp | + def = assignOp and + assignOp.getLValue() = v.getAnAccess() and + result = getTruncatedUpperBounds(assignOp) + ) + or + exists(IncrementOperation incr, float newUB | + def = incr and + incr.getOperand() = v.getAnAccess() and + newUB = getFullyConvertedUpperBounds(incr.getOperand()) and + result = addRoundingUpSmall(newUB, 1) + ) + or + exists(DecrementOperation decr, float newUB | + def = decr and + decr.getOperand() = v.getAnAccess() and + newUB = getFullyConvertedUpperBounds(decr.getOperand()) and + result = newUB - 1 + ) + or + // Phi nodes. + result = getPhiUpperBounds(v, def) + or + // Unanalyzable definitions. + unanalyzableDefBounds(def, v, _, result) + } + + /** + * Helper for `getDefLowerBounds` and `getDefUpperBounds`. Find the set of + * unanalyzable definitions (such as function parameters) and make their + * bounds unknown. + */ + private predicate unanalyzableDefBounds( + RangeSsaDefinition def, StackVariable v, float lb, float ub + ) { + v = def.getAVariable() and + not analyzableDef(def, v) and + lb = varMinVal(v) and + ub = varMaxVal(v) + } + + /** + * Holds if in the `branch` branch of a guard `guard` involving `v`, + * we know that `v` is not NaN, and therefore it is safe to make range + * inferences about `v`. + */ + bindingset[guard, v, branch] + predicate nonNanGuardedVariable(Expr guard, VariableAccess v, boolean branch) { + Util::getVariableRangeType(v.getTarget()) instanceof IntegralType + or + Util::getVariableRangeType(v.getTarget()) instanceof FloatingPointType and + v instanceof NonNanVariableAccess + or + // The reason the following case is here is to ensure that when we say + // `if (x > 5) { ...then... } else { ...else... }` + // it is ok to conclude that `x > 5` in the `then`, (though not safe + // to conclude that x <= 5 in `else`) even if we had no prior + // knowledge of `x` not being `NaN`. + nanExcludingComparison(guard, branch) + } + + /** + * If the guard is a comparison of the form `p*v + q r`, then this + * predicate uses the bounds information for `r` to compute a lower bound + * for `v`. + */ + private predicate lowerBoundFromGuard(Expr guard, VariableAccess v, float lb, boolean branch) { + exists(float childLB, Util::RelationStrictness strictness | + boundFromGuard(guard, v, childLB, true, strictness, branch) + | + if nonNanGuardedVariable(guard, v, branch) + then + if + strictness = Util::Nonstrict() or + not Util::getVariableRangeType(v.getTarget()) instanceof IntegralType + then lb = childLB + else lb = childLB + 1 + else lb = varMinVal(v.getTarget()) + ) + } + + /** + * If the guard is a comparison of the form `p*v + q r`, then this + * predicate uses the bounds information for `r` to compute a upper bound + * for `v`. + */ + private predicate upperBoundFromGuard(Expr guard, VariableAccess v, float ub, boolean branch) { + exists(float childUB, Util::RelationStrictness strictness | + boundFromGuard(guard, v, childUB, false, strictness, branch) + | + if nonNanGuardedVariable(guard, v, branch) + then + if + strictness = Util::Nonstrict() or + not Util::getVariableRangeType(v.getTarget()) instanceof IntegralType + then ub = childUB + else ub = childUB - 1 + else ub = varMaxVal(v.getTarget()) + ) + } + + /** + * This predicate simplifies the results returned by + * `linearBoundFromGuard`. + */ + private predicate boundFromGuard( + Expr guard, VariableAccess v, float boundValue, boolean isLowerBound, + Util::RelationStrictness strictness, boolean branch + ) { + exists(float p, float q, float r, boolean isLB | + linearBoundFromGuard(guard, v, p, q, r, isLB, strictness, branch) and + boundValue = (r - q) / p + | + // If the multiplier is negative then the direction of the comparison + // needs to be flipped. + p > 0 and isLowerBound = isLB + or + p < 0 and isLowerBound = isLB.booleanNot() + ) + or + // When `!e` is true, we know that `0 <= e <= 0` + exists(float p, float q, Expr e | + Util::linearAccess(e, v, p, q) and + Util::eqZeroWithNegate(guard, e, true, branch) and + boundValue = (0.0 - q) / p and + isLowerBound = [false, true] and + strictness = Util::Nonstrict() + ) + } + + /** + * This predicate finds guards of the form `p*v + q < r or p*v + q == r` + * and decomposes them into a tuple of values which can be used to deduce a + * lower or upper bound for `v`. + */ + private predicate linearBoundFromGuard( + ComparisonOperation guard, VariableAccess v, float p, float q, float boundValue, + boolean isLowerBound, // Is this a lower or an upper bound? + Util::RelationStrictness strictness, boolean branch // Which control-flow branch is this bound valid on? + ) { + // For the comparison x < RHS, we create two bounds: + // + // 1. x < upperbound(RHS) + // 2. x >= typeLowerBound(RHS.getUnspecifiedType()) + // + exists(Expr lhs, Expr rhs, Util::RelationDirection dir, Util::RelationStrictness st | + Util::linearAccess(lhs, v, p, q) and + Util::relOpWithSwapAndNegate(guard, lhs, rhs, dir, st, branch) + | + isLowerBound = Util::directionIsGreater(dir) and + strictness = st and + getBounds(rhs, boundValue, isLowerBound) + or + isLowerBound = Util::directionIsLesser(dir) and + strictness = Util::Nonstrict() and + exprTypeBounds(rhs, boundValue, isLowerBound) + ) + or + // For x == RHS, we create the following bounds: + // + // 1. x <= upperbound(RHS) + // 2. x >= lowerbound(RHS) + // + exists(Expr lhs, Expr rhs | + Util::linearAccess(lhs, v, p, q) and + Util::eqOpWithSwapAndNegate(guard, lhs, rhs, true, branch) and + getBounds(rhs, boundValue, isLowerBound) and + strictness = Util::Nonstrict() + ) + // x != RHS and !x are handled elsewhere + } + + /** Utility for `linearBoundFromGuard`. */ + private predicate getBounds(Expr expr, float boundValue, boolean isLowerBound) { + isLowerBound = true and boundValue = getFullyConvertedLowerBounds(expr) + or + isLowerBound = false and boundValue = getFullyConvertedUpperBounds(expr) + } + + /** Utility for `linearBoundFromGuard`. */ + private predicate exprTypeBounds(Expr expr, float boundValue, boolean isLowerBound) { + isLowerBound = true and boundValue = exprMinVal(expr.getFullyConverted()) + or + isLowerBound = false and boundValue = exprMaxVal(expr.getFullyConverted()) + } + + /** + * Holds if `(v, phi)` ensures that `access` is not equal to `neConstant`. For + * example, the condition `if (x + 1 != 3)` ensures that `x` is not equal to 2. + * Only integral types are supported. + */ + private predicate isNEPhi( + Variable v, RangeSsaDefinition phi, VariableAccess access, float neConstant + ) { + exists( + ComparisonOperation cmp, boolean branch, Expr linearExpr, Expr rExpr, float p, float q, + float r + | + phi.isGuardPhi(v, access, cmp, branch) and + Util::eqOpWithSwapAndNegate(cmp, linearExpr, rExpr, false, branch) and + v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!=` is too imprecise + r = getValue(rExpr).toFloat() and + Util::linearAccess(linearExpr, access, p, q) and + neConstant = (r - q) / p + ) + or + exists(Expr op, boolean branch, Expr linearExpr, float p, float q | + phi.isGuardPhi(v, access, op, branch) and + Util::eqZeroWithNegate(op, linearExpr, false, branch) and + v.getUnspecifiedType() instanceof IntegralOrEnumType and // Float `!` is too imprecise + Util::linearAccess(linearExpr, access, p, q) and + neConstant = (0.0 - q) / p + ) + } + + /** + * Holds if `(v, phi)` constrains the value of `access` but in a way that + * doesn't allow this library to constrain the upper or lower bounds of + * `access`. An example is `if (x != y)` if neither `x` nor `y` is a + * compile-time constant. + */ + private predicate isUnsupportedGuardPhi(Variable v, RangeSsaDefinition phi, VariableAccess access) { + exists(Expr cmp, boolean branch | + Util::eqOpWithSwapAndNegate(cmp, _, _, false, branch) + or + Util::eqZeroWithNegate(cmp, _, false, branch) + | + phi.isGuardPhi(v, access, cmp, branch) and + not isNEPhi(v, phi, access, _) + ) + } + + /** + * Gets the upper bound of the expression, if the expression is guarded. + * An upper bound can only be found, if a guard phi node can be found, and the + * expression has only one immediate predecessor. + */ + private float getGuardedUpperBound(VariableAccess guardedAccess) { + exists( + RangeSsaDefinition def, StackVariable v, VariableAccess guardVa, Expr guard, boolean branch + | + def.isGuardPhi(v, guardVa, guard, branch) and + // If the basic block for the variable access being examined has + // more than one predecessor, the guard phi node could originate + // from one of the predecessors. This is because the guard phi + // node is attached to the block at the end of the edge and not on + // the actual edge. It is therefore not possible to determine which + // edge the guard phi node belongs to. The predicate below ensures + // that there is one predecessor, albeit somewhat conservative. + exists(unique(BasicBlock b | b = def.(BasicBlock).getAPredecessor())) and + guardedAccess = def.getAUse(v) and + result = max(float ub | upperBoundFromGuard(guard, guardVa, ub, branch)) and + not convertedExprMightOverflow(guard.getAChild+()) + ) + } + + cached + private module SimpleRangeAnalysisCached { + /** + * Gets the lower bound of the expression. + * + * Note: expressions in C/C++ are often implicitly or explicitly cast to a + * different result type. Such casts can cause the value of the expression + * to overflow or to be truncated. This predicate computes the lower bound + * of the expression without including the effect of the casts. To compute + * the lower bound of the expression after all the casts have been applied, + * call `lowerBound` like this: + * + * `lowerBound(expr.getFullyConverted())` + */ + cached + float lowerBound(Expr expr) { + // Combine the lower bounds returned by getTruncatedLowerBounds into a + // single minimum value. + result = min(float lb | lb = getTruncatedLowerBounds(expr) | lb) + } + + /** + * Gets the upper bound of the expression. + * + * Note: expressions in C/C++ are often implicitly or explicitly cast to a + * different result type. Such casts can cause the value of the expression + * to overflow or to be truncated. This predicate computes the upper bound + * of the expression without including the effect of the casts. To compute + * the upper bound of the expression after all the casts have been applied, + * call `upperBound` like this: + * + * `upperBound(expr.getFullyConverted())` + */ + cached + float upperBound(Expr expr) { + // Combine the upper bounds returned by getTruncatedUpperBounds and + // getGuardedUpperBound into a single maximum value + result = min([max(getTruncatedUpperBounds(expr)), getGuardedUpperBound(expr)]) + } + + /** Holds if the upper bound of `expr` may have been widened. This means the upper bound is in practice likely to be overly wide. */ + cached + predicate upperBoundMayBeWidened(Expr e) { + isRecursiveExpr(e) and + // Widening is not a problem if the post-analysis in `getGuardedUpperBound` has overridden the widening. + // Note that the RHS of `<` may be multi-valued. + not getGuardedUpperBound(e) < getTruncatedUpperBounds(e) + } + + /** + * Holds if `expr` has a provably empty range. For example: + * + * 10 < expr and expr < 5 + * + * The range of an expression can only be empty if it can never be + * executed. For example: + * + * if (10 < x) { + * if (x < 5) { + * // Unreachable code + * return x; // x has an empty range: 10 < x && x < 5 + * } + * } + */ + cached + predicate exprWithEmptyRange(Expr expr) { + analyzableExpr(expr) and + ( + not exists(lowerBound(expr)) or + not exists(upperBound(expr)) or + lowerBound(expr) > upperBound(expr) + ) + } + + /** Holds if the definition might overflow negatively. */ + cached + predicate defMightOverflowNegatively(RangeSsaDefinition def, StackVariable v) { + getDefLowerBoundsImpl(def, v) < Util::varMinVal(v) + } + + /** Holds if the definition might overflow positively. */ + cached + predicate defMightOverflowPositively(RangeSsaDefinition def, StackVariable v) { + getDefUpperBoundsImpl(def, v) > Util::varMaxVal(v) + } + + /** + * Holds if the definition might overflow (either positively or + * negatively). + */ + cached + predicate defMightOverflow(RangeSsaDefinition def, StackVariable v) { + defMightOverflowNegatively(def, v) or + defMightOverflowPositively(def, v) + } + + /** + * Holds if `e` is an expression where the concept of overflow makes sense. + * This predicate is used to filter out some of the unanalyzable expressions + * from `exprMightOverflowPositively` and `exprMightOverflowNegatively`. + */ + pragma[inline] + private predicate exprThatCanOverflow(Expr e) { + e instanceof UnaryArithmeticOperation or + e instanceof BinaryArithmeticOperation or + e instanceof AssignArithmeticOperation or + e instanceof LShiftExpr or + e instanceof AssignLShiftExpr + } + + /** + * Holds if the expression might overflow negatively. This predicate + * does not consider the possibility that the expression might overflow + * due to a conversion. + */ + cached + predicate exprMightOverflowNegatively(Expr expr) { + getLowerBoundsImpl(expr) < Util::exprMinVal(expr) + or + // The lower bound of the expression `x--` is the same as the lower + // bound of `x`, so the standard logic (above) does not work for + // detecting whether it might overflow. + getLowerBoundsImpl(expr.(PostfixDecrExpr)) = Util::exprMinVal(expr) + or + // We can't conclude that any unanalyzable expression might overflow. This + // is because there are many expressions that the range analysis doesn't + // handle, but where the concept of overflow doesn't make sense. + exprThatCanOverflow(expr) and not analyzableExpr(expr) + } + + /** + * Holds if the expression might overflow negatively. Conversions + * are also taken into account. For example the expression + * `(int16)(x+y)` might overflow due to the `(int16)` cast, rather than + * due to the addition. + */ + cached + predicate convertedExprMightOverflowNegatively(Expr expr) { + exprMightOverflowNegatively(expr) or + convertedExprMightOverflowNegatively(expr.getConversion()) + } + + /** + * Holds if the expression might overflow positively. This predicate + * does not consider the possibility that the expression might overflow + * due to a conversion. + */ + cached + predicate exprMightOverflowPositively(Expr expr) { + getUpperBoundsImpl(expr) > Util::exprMaxVal(expr) + or + // The upper bound of the expression `x++` is the same as the upper + // bound of `x`, so the standard logic (above) does not work for + // detecting whether it might overflow. + getUpperBoundsImpl(expr.(PostfixIncrExpr)) = Util::exprMaxVal(expr) + } + + /** + * Holds if the expression might overflow positively. Conversions + * are also taken into account. For example the expression + * `(int16)(x+y)` might overflow due to the `(int16)` cast, rather than + * due to the addition. + */ + cached + predicate convertedExprMightOverflowPositively(Expr expr) { + exprMightOverflowPositively(expr) or + convertedExprMightOverflowPositively(expr.getConversion()) + } + + /** + * Holds if the expression might overflow (either positively or + * negatively). The possibility that the expression might overflow + * due to an implicit or explicit cast is also considered. + */ + cached + predicate convertedExprMightOverflow(Expr expr) { + convertedExprMightOverflowNegatively(expr) or + convertedExprMightOverflowPositively(expr) + } + } + + /** + * Gets the truncated lower bounds of the fully converted expression. + */ + float getFullyConvertedLowerBounds(Expr expr) { + result = getTruncatedLowerBounds(expr.getFullyConverted()) + } + + /** + * Gets the truncated upper bounds of the fully converted expression. + */ + float getFullyConvertedUpperBounds(Expr expr) { + result = getTruncatedUpperBounds(expr.getFullyConverted()) + } + + /** + * Get the lower bounds for a `RangeSsaDefinition`. Most of the work is + * done by `getDefLowerBoundsImpl`, but this is where widening is applied + * to prevent the analysis from exploding due to a recursive definition. + */ + float getDefLowerBounds(RangeSsaDefinition def, StackVariable v) { + exists(float newLB, float truncatedLB | + newLB = getDefLowerBoundsImpl(def, v) and + if Util::varMinVal(v) <= newLB and newLB <= Util::varMaxVal(v) + then truncatedLB = newLB + else truncatedLB = Util::varMinVal(v) + | + // Widening: check whether the new lower bound is from a source which + // depends recursively on the current definition. + if isRecursiveDef(def, v) + then + // The new lower bound is from a recursive source, so we round + // down to one of a limited set of values to prevent the + // recursion from exploding. + result = + max(float widenLB | + widenLB = wideningLowerBounds(Util::getVariableRangeType(v)) and + not widenLB > truncatedLB + | + widenLB + ) + else result = truncatedLB + ) + or + // The definition might overflow positively and wrap. If so, the lower + // bound is `typeLowerBound`. + defMightOverflowPositively(def, v) and result = Util::varMinVal(v) + } + + /** See comment for `getDefLowerBounds`, above. */ + float getDefUpperBounds(RangeSsaDefinition def, StackVariable v) { + exists(float newUB, float truncatedUB | + newUB = getDefUpperBoundsImpl(def, v) and + if Util::varMinVal(v) <= newUB and newUB <= Util::varMaxVal(v) + then truncatedUB = newUB + else truncatedUB = Util::varMaxVal(v) + | + // Widening: check whether the new upper bound is from a source which + // depends recursively on the current definition. + if isRecursiveDef(def, v) + then + // The new upper bound is from a recursive source, so we round + // up to one of a fixed set of values to prevent the recursion + // from exploding. + result = + min(float widenUB | + widenUB = wideningUpperBounds(Util::getVariableRangeType(v)) and + not widenUB < truncatedUB + | + widenUB + ) + else result = truncatedUB + ) + or + // The definition might overflow negatively and wrap. If so, the upper + // bound is `typeUpperBound`. + defMightOverflowNegatively(def, v) and result = Util::varMaxVal(v) + } +} diff --git a/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll b/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll index 5144f63dc2..2688452d28 100644 --- a/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll +++ b/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll @@ -14,6 +14,45 @@ import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils import experimental.semmle.code.cpp.rangeanalysis.extensions.ConstantBitwiseAndExprRange private import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisExpr +// Disabled, causing performance issues in grpc: +/* +private class DivByConstantExpr extends SimpleRangeAnalysisExpr, DivExpr { + float quotient; + + DivByConstantExpr() { + quotient = evaluateConstantExpr(getRightOperand()) + } + + override predicate dependsOnChild(Expr e) { + e = getLeftOperand() + } + + override float getLowerBounds() { + exists(float numerator | + result = numerator / quotient and + if (quotient > 0) then + // x / y where and y is positive scales the UB/LB. + numerator = getFullyConvertedLowerBounds(getLeftOperand()) + else + // x / -y where and -y is negative will invert and scale the UB/LB. + numerator = getFullyConvertedUpperBounds(getLeftOperand()) + ) + } + + override float getUpperBounds() { + exists(float numerator | + result = numerator / quotient and + if (quotient > 0) then + // x / y where and y is positive scales the UB/LB. + numerator = getFullyConvertedUpperBounds(getLeftOperand()) + else + // x / -y where and -y is negative will invert and scale the UB/LB. + numerator = getFullyConvertedLowerBounds(getLeftOperand()) + ) + } +} + */ + /** * A range analysis extension that support bitwise `|` and `|=` where at least one operand is a * non-negative constant. diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/FloatingTypes2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/FloatingTypes2.qll new file mode 100644 index 0000000000..7cdc6430a3 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/FloatingTypes2.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype FloatingTypes2Query = + TPossibleMisuseOfUndetectedInfinityQuery() or + TPossibleMisuseOfUndetectedNaNQuery() + +predicate isFloatingTypes2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `possibleMisuseOfUndetectedInfinity` query + FloatingTypes2Package::possibleMisuseOfUndetectedInfinityQuery() and + queryId = + // `@id` for the `possibleMisuseOfUndetectedInfinity` query + "c/misra/possible-misuse-of-undetected-infinity" and + ruleId = "DIR-4-15" and + category = "required" + or + query = + // `Query` instance for the `possibleMisuseOfUndetectedNaN` query + FloatingTypes2Package::possibleMisuseOfUndetectedNaNQuery() and + queryId = + // `@id` for the `possibleMisuseOfUndetectedNaN` query + "c/misra/possible-misuse-of-undetected-na-n" and + ruleId = "DIR-4-15" and + category = "required" +} + +module FloatingTypes2Package { + Query possibleMisuseOfUndetectedInfinityQuery() { + //autogenerate `Query` type + result = + // `Query` type for `possibleMisuseOfUndetectedInfinity` query + TQueryC(TFloatingTypes2PackageQuery(TPossibleMisuseOfUndetectedInfinityQuery())) + } + + Query possibleMisuseOfUndetectedNaNQuery() { + //autogenerate `Query` type + result = + // `Query` type for `possibleMisuseOfUndetectedNaN` query + TQueryC(TFloatingTypes2PackageQuery(TPossibleMisuseOfUndetectedNaNQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 6ab695fb99..41ae2931b1 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -32,6 +32,7 @@ import Declarations8 import EssentialTypes import Expressions import FloatingTypes +import FloatingTypes2 import FunctionTypes import IO1 import IO2 @@ -112,6 +113,7 @@ newtype TCQuery = TEssentialTypesPackageQuery(EssentialTypesQuery q) or TExpressionsPackageQuery(ExpressionsQuery q) or TFloatingTypesPackageQuery(FloatingTypesQuery q) or + TFloatingTypes2PackageQuery(FloatingTypes2Query q) or TFunctionTypesPackageQuery(FunctionTypesQuery q) or TIO1PackageQuery(IO1Query q) or TIO2PackageQuery(IO2Query q) or @@ -192,6 +194,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isEssentialTypesQueryMetadata(query, queryId, ruleId, category) or isExpressionsQueryMetadata(query, queryId, ruleId, category) or isFloatingTypesQueryMetadata(query, queryId, ruleId, category) or + isFloatingTypes2QueryMetadata(query, queryId, ruleId, category) or isFunctionTypesQueryMetadata(query, queryId, ruleId, category) or isIO1QueryMetadata(query, queryId, ruleId, category) or isIO2QueryMetadata(query, queryId, ruleId, category) or diff --git a/rule_packages/c/FloatingTypes2.json b/rule_packages/c/FloatingTypes2.json new file mode 100644 index 0000000000..152ead08d3 --- /dev/null +++ b/rule_packages/c/FloatingTypes2.json @@ -0,0 +1,36 @@ +{ + "MISRA-C-2012": { + "DIR-4-15": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Evaluation of floating-point expressions shall not lead to the undetected generation of infinities.", + "kind": "path-problem", + "name": "Evaluation of floating-point expressions shall not lead to the undetected generation of infinities", + "precision": "high", + "severity": "error", + "short_name": "PossibleMisuseOfUndetectedInfinity", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "Evaluation of floating-point expressions shall not lead to the undetected generation of NaNs.", + "kind": "path-problem", + "name": "Evaluation of floating-point expressions shall not lead to the undetected generation of NaNs", + "precision": "high", + "severity": "error", + "short_name": "PossibleMisuseOfUndetectedNaN", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "Evaluation of floating-point expressions shall not lead to the undetected generation of infinities and NaNs" + } + } +} \ No newline at end of file From 16d44f1ae793cbdcca2854bf610cd8f0d707776c Mon Sep 17 00:00:00 2001 From: MichaelRFairhurst <1627771+MichaelRFairhurst@users.noreply.github.com> Date: Sat, 1 Feb 2025 03:15:52 +0000 Subject: [PATCH 223/628] Upgrading `github/codeql` dependency to 2.19.4 --- c/cert/src/codeql-pack.lock.yml | 20 +++++++++---------- c/cert/src/qlpack.yml | 2 +- c/cert/test/codeql-pack.lock.yml | 20 +++++++++---------- c/common/src/codeql-pack.lock.yml | 20 +++++++++---------- c/common/src/qlpack.yml | 2 +- c/common/test/codeql-pack.lock.yml | 20 +++++++++---------- c/misra/src/codeql-pack.lock.yml | 20 +++++++++---------- c/misra/src/qlpack.yml | 2 +- c/misra/test/codeql-pack.lock.yml | 20 +++++++++---------- cpp/autosar/src/codeql-pack.lock.yml | 20 +++++++++---------- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/codeql-pack.lock.yml | 20 +++++++++---------- cpp/cert/src/codeql-pack.lock.yml | 20 +++++++++---------- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/codeql-pack.lock.yml | 20 +++++++++---------- cpp/common/src/codeql-pack.lock.yml | 20 +++++++++---------- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/codeql-pack.lock.yml | 20 +++++++++---------- cpp/misra/src/codeql-pack.lock.yml | 20 +++++++++---------- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/codeql-pack.lock.yml | 20 +++++++++---------- cpp/report/src/codeql-pack.lock.yml | 20 +++++++++---------- cpp/report/src/qlpack.yml | 2 +- .../queries/codeql-pack.lock.yml | 20 +++++++++---------- scripts/generate_modules/queries/qlpack.yml | 2 +- supported_codeql_configs.json | 6 +++--- 26 files changed, 172 insertions(+), 172 deletions(-) diff --git a/c/cert/src/codeql-pack.lock.yml b/c/cert/src/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/c/cert/src/codeql-pack.lock.yml +++ b/c/cert/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index d5ba524b14..6e023bc238 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -5,4 +5,4 @@ suites: codeql-suites license: MIT dependencies: codeql/common-c-coding-standards: '*' - codeql/cpp-all: 1.4.2 + codeql/cpp-all: 2.1.1 diff --git a/c/cert/test/codeql-pack.lock.yml b/c/cert/test/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/c/cert/test/codeql-pack.lock.yml +++ b/c/cert/test/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/c/common/src/codeql-pack.lock.yml b/c/common/src/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/c/common/src/codeql-pack.lock.yml +++ b/c/common/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index e775358108..9188ad8bda 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -3,4 +3,4 @@ version: 2.42.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' - codeql/cpp-all: 1.4.2 + codeql/cpp-all: 2.1.1 diff --git a/c/common/test/codeql-pack.lock.yml b/c/common/test/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/c/common/test/codeql-pack.lock.yml +++ b/c/common/test/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/c/misra/src/codeql-pack.lock.yml b/c/misra/src/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/c/misra/src/codeql-pack.lock.yml +++ b/c/misra/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 0ed5ef8b97..721a052e6b 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -6,4 +6,4 @@ license: MIT default-suite-file: codeql-suites/misra-c-default.qls dependencies: codeql/common-c-coding-standards: '*' - codeql/cpp-all: 1.4.2 + codeql/cpp-all: 2.1.1 diff --git a/c/misra/test/codeql-pack.lock.yml b/c/misra/test/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/c/misra/test/codeql-pack.lock.yml +++ b/c/misra/test/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/cpp/autosar/src/codeql-pack.lock.yml b/cpp/autosar/src/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/cpp/autosar/src/codeql-pack.lock.yml +++ b/cpp/autosar/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index 80f6d1b0d2..e4d17b7309 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -5,4 +5,4 @@ suites: codeql-suites license: MIT dependencies: codeql/common-cpp-coding-standards: '*' - codeql/cpp-all: 1.4.2 + codeql/cpp-all: 2.1.1 diff --git a/cpp/autosar/test/codeql-pack.lock.yml b/cpp/autosar/test/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/cpp/autosar/test/codeql-pack.lock.yml +++ b/cpp/autosar/test/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/cpp/cert/src/codeql-pack.lock.yml b/cpp/cert/src/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/cpp/cert/src/codeql-pack.lock.yml +++ b/cpp/cert/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 3005c15ec3..b0645353f6 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -4,5 +4,5 @@ description: CERT C++ 2016 suites: codeql-suites license: MIT dependencies: - codeql/cpp-all: 1.4.2 + codeql/cpp-all: 2.1.1 codeql/common-cpp-coding-standards: '*' diff --git a/cpp/cert/test/codeql-pack.lock.yml b/cpp/cert/test/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/cpp/cert/test/codeql-pack.lock.yml +++ b/cpp/cert/test/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/cpp/common/src/codeql-pack.lock.yml b/cpp/common/src/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/cpp/common/src/codeql-pack.lock.yml +++ b/cpp/common/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index d97b322120..4b4619e6b9 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -2,6 +2,6 @@ name: codeql/common-cpp-coding-standards version: 2.42.0-dev license: MIT dependencies: - codeql/cpp-all: 1.4.2 + codeql/cpp-all: 2.1.1 dataExtensions: - ext/*.model.yml diff --git a/cpp/common/test/codeql-pack.lock.yml b/cpp/common/test/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/cpp/common/test/codeql-pack.lock.yml +++ b/cpp/common/test/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/cpp/misra/src/codeql-pack.lock.yml b/cpp/misra/src/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/cpp/misra/src/codeql-pack.lock.yml +++ b/cpp/misra/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index fc3162ffb4..2c8f21a82f 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -5,4 +5,4 @@ default-suite: codeql-suites/misra-cpp-default.qls license: MIT dependencies: codeql/common-cpp-coding-standards: '*' - codeql/cpp-all: 1.4.2 + codeql/cpp-all: 2.1.1 diff --git a/cpp/misra/test/codeql-pack.lock.yml b/cpp/misra/test/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/cpp/misra/test/codeql-pack.lock.yml +++ b/cpp/misra/test/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/cpp/report/src/codeql-pack.lock.yml b/cpp/report/src/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/cpp/report/src/codeql-pack.lock.yml +++ b/cpp/report/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index 1a8ea75e77..3203133ffc 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -2,4 +2,4 @@ name: codeql/report-cpp-coding-standards version: 2.42.0-dev license: MIT dependencies: - codeql/cpp-all: 1.4.2 + codeql/cpp-all: 2.1.1 diff --git a/scripts/generate_modules/queries/codeql-pack.lock.yml b/scripts/generate_modules/queries/codeql-pack.lock.yml index 910a6e060e..ab9a39f9c1 100644 --- a/scripts/generate_modules/queries/codeql-pack.lock.yml +++ b/scripts/generate_modules/queries/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 1.4.2 + version: 2.1.1 codeql/dataflow: - version: 1.1.1 + version: 1.1.6 codeql/mad: - version: 1.0.7 + version: 1.0.12 codeql/rangeanalysis: - version: 1.0.7 + version: 1.0.12 codeql/ssa: - version: 1.0.7 + version: 1.0.12 codeql/tutorial: - version: 1.0.7 + version: 1.0.12 codeql/typeflow: - version: 1.0.7 + version: 1.0.12 codeql/typetracking: - version: 1.0.7 + version: 1.0.12 codeql/util: - version: 1.0.7 + version: 1.0.12 codeql/xml: - version: 1.0.7 + version: 1.0.12 compiled: false diff --git a/scripts/generate_modules/queries/qlpack.yml b/scripts/generate_modules/queries/qlpack.yml index 88a48269e7..d2c729dfb9 100644 --- a/scripts/generate_modules/queries/qlpack.yml +++ b/scripts/generate_modules/queries/qlpack.yml @@ -2,4 +2,4 @@ name: codeql/standard-library-extraction-cpp-coding-standards version: 0.0.0 license: MIT dependencies: - codeql/cpp-all: 1.4.2 + codeql/cpp-all: 2.1.1 diff --git a/supported_codeql_configs.json b/supported_codeql_configs.json index b143f67fe9..77534bd53d 100644 --- a/supported_codeql_configs.json +++ b/supported_codeql_configs.json @@ -1,9 +1,9 @@ { "supported_environment": [ { - "codeql_cli": "2.18.4", - "codeql_standard_library": "codeql-cli/v2.18.4", - "codeql_cli_bundle": "codeql-bundle-v2.18.4" + "codeql_cli": "2.19.4", + "codeql_standard_library": "codeql-cli/v2.19.4", + "codeql_cli_bundle": "codeql-bundle-v2.19.4" } ], "supported_language": [ From 59ebba0f3c52d090b1c07c0e732db7d740485870 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 3 Feb 2025 19:11:59 -0800 Subject: [PATCH 224/628] Support guards isinf(), isfinite(), isnan(), etc --- .../PossibleMisuseOfUndetectedInfinity.ql | 12 + .../DIR-4-15/PossibleMisuseOfUndetectedNaN.ql | 41 ++- ...ossibleMisuseOfUndetectedInfinity.expected | 59 +++- .../PossibleMisuseOfUndetectedNaN.expected | 43 ++- c/misra/test/rules/DIR-4-15/test.c | 99 +++++- .../src/codingstandards/cpp/FloatingPoint.qll | 317 +++++++++++++++++- .../cpp/RestrictedRangeAnalysis.qll | 22 +- 7 files changed, 521 insertions(+), 72 deletions(-) diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql index 84a3fbfd3c..97dd251083 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql @@ -44,6 +44,18 @@ module InvalidInfinityUsage implements DataFlow::ConfigSig { exprMayEqualInfinity(node.asExpr(), _) } + predicate isBarrierOut(DataFlow::Node node) { + guardedNotFPClass(node.asExpr(), TInfinite()) + or + exists(Expr e | + e.getType() instanceof IntegralType and + e = node.asConvertedExpr() + ) + or + // Sinks are places where Infinity produce a finite value + isSink(node) + } + /** * An additional flow step to handle operations which propagate Infinity. * diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql index 6962a1c36d..036d470247 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql @@ -89,7 +89,6 @@ class InvalidOperationExpr extends BinaryOperation { } module InvalidNaNUsage implements DataFlow::ConfigSig { - /** * An expression which has non-NaN inputs and may produce a NaN output. */ @@ -108,6 +107,15 @@ module InvalidNaNUsage implements DataFlow::ConfigSig { node.asExpr() instanceof InvalidOperationExpr } + predicate isBarrierOut(DataFlow::Node node) { + guardedNotFPClass(node.asExpr(), TNaN()) + or + exists(Expr e | + e.getType() instanceof IntegralType and + e = node.asConvertedExpr() + ) + } + /** * Add an additional flow step to handle NaN propagation through floating point operations. */ @@ -120,21 +128,24 @@ module InvalidNaNUsage implements DataFlow::ConfigSig { } predicate isSink(DataFlow::Node node) { - // Case 1: NaNs shall not be compared, except to themselves - exists(ComparisonOperation cmp | - node.asExpr() = cmp.getAnOperand() and - not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand()) - ) - or - // Case 2: NaNs and infinities shall not be cast to integers - exists(Conversion c | - node.asExpr() = c.getUnconverted() and - c.getExpr().getType() instanceof FloatingPointType and - c.getType() instanceof IntegralType + not guardedNotFPClass(node.asExpr(), TNaN()) and + ( + // Case 1: NaNs shall not be compared, except to themselves + exists(ComparisonOperation cmp | + node.asExpr() = cmp.getAnOperand() and + not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand()) + ) + or + // Case 2: NaNs and infinities shall not be cast to integers + exists(Conversion c | + node.asExpr() = c.getUnconverted() and + c.getExpr().getType() instanceof FloatingPointType and + c.getType() instanceof IntegralType + ) + //or + //// Case 4: Functions shall not return NaNs or infinities + //exists(ReturnStmt ret | node.asExpr() = ret.getExpr()) ) - //or - //// Case 4: Functions shall not return NaNs or infinities - //exists(ReturnStmt ret | node.asExpr() = ret.getExpr()) } } diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected index 78f4c6baec..75534df6a0 100644 --- a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected @@ -1,5 +1,6 @@ edges | test.c:8:14:8:20 | ... / ... | test.c:8:14:8:20 | ... / ... | provenance | | +| test.c:8:14:8:20 | ... / ... | test.c:9:14:9:16 | - ... | provenance | Config | | test.c:8:14:8:20 | ... / ... | test.c:12:8:12:9 | l2 | provenance | | | test.c:8:14:8:20 | ... / ... | test.c:18:3:18:9 | l2 | provenance | | | test.c:8:14:8:20 | ... / ... | test.c:27:19:27:20 | l2 | provenance | | @@ -9,8 +10,17 @@ edges | test.c:9:14:9:16 | - ... | test.c:28:19:28:20 | l3 | provenance | | | test.c:31:14:32:15 | ... / ... | test.c:31:14:32:15 | ... / ... | provenance | | | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | provenance | | -| test.c:33:14:33:22 | ... / ... | test.c:33:14:33:22 | ... / ... | provenance | | -| test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:77:15:77:21 | ... / ... | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:79:5:79:12 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:87:5:87:12 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:91:5:91:12 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:93:5:93:12 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:99:5:99:12 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:105:5:105:12 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:111:5:111:12 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:114:16:114:23 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:117:23:117:30 | l12 | provenance | | +| test.c:77:15:77:21 | ... / ... | test.c:120:20:120:27 | l12 | provenance | | nodes | test.c:8:14:8:20 | ... / ... | semmle.label | ... / ... | | test.c:8:14:8:20 | ... / ... | semmle.label | ... / ... | @@ -24,25 +34,46 @@ nodes | test.c:28:19:28:20 | l3 | semmle.label | l3 | | test.c:31:14:32:15 | ... / ... | semmle.label | ... / ... | | test.c:31:14:32:15 | ... / ... | semmle.label | ... / ... | -| test.c:33:14:33:22 | ... / ... | semmle.label | ... / ... | -| test.c:33:14:33:22 | ... / ... | semmle.label | ... / ... | | test.c:38:3:38:9 | l7 | semmle.label | l7 | -| test.c:39:3:39:9 | l8 | semmle.label | l8 | -| test.c:61:5:61:19 | ... / ... | semmle.label | ... / ... | -| test.c:66:5:66:21 | ... / ... | semmle.label | ... / ... | -| test.c:72:14:72:30 | ... / ... | semmle.label | ... / ... | -| test.c:75:18:75:34 | ... / ... | semmle.label | ... / ... | +| test.c:61:5:61:18 | ... / ... | semmle.label | ... / ... | +| test.c:66:5:66:20 | ... / ... | semmle.label | ... / ... | +| test.c:72:14:72:29 | ... / ... | semmle.label | ... / ... | +| test.c:75:18:75:33 | ... / ... | semmle.label | ... / ... | +| test.c:77:15:77:21 | ... / ... | semmle.label | ... / ... | +| test.c:77:15:77:21 | ... / ... | semmle.label | ... / ... | +| test.c:79:5:79:12 | l12 | semmle.label | l12 | +| test.c:87:5:87:12 | l12 | semmle.label | l12 | +| test.c:91:5:91:12 | l12 | semmle.label | l12 | +| test.c:93:5:93:12 | l12 | semmle.label | l12 | +| test.c:99:5:99:12 | l12 | semmle.label | l12 | +| test.c:105:5:105:12 | l12 | semmle.label | l12 | +| test.c:111:5:111:12 | l12 | semmle.label | l12 | +| test.c:114:16:114:23 | l12 | semmle.label | l12 | +| test.c:117:23:117:30 | l12 | semmle.label | l12 | +| test.c:120:20:120:27 | l12 | semmle.label | l12 | subpaths #select | test.c:12:8:12:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:12:8:12:9 | l2 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | +| test.c:13:8:13:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:13:8:13:9 | l3 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | | test.c:13:8:13:9 | l3 | test.c:9:14:9:16 | - ... | test.c:13:8:13:9 | l3 | Invalid usage of possible $@. | test.c:9:14:9:16 | - ... | infinity | | test.c:18:8:18:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:18:3:18:9 | l2 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | +| test.c:19:8:19:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:19:3:19:9 | l3 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | | test.c:19:8:19:9 | l3 | test.c:9:14:9:16 | - ... | test.c:19:3:19:9 | l3 | Invalid usage of possible $@. | test.c:9:14:9:16 | - ... | infinity | | test.c:27:19:27:20 | l2 | test.c:8:14:8:20 | ... / ... | test.c:27:19:27:20 | l2 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | +| test.c:28:19:28:20 | l3 | test.c:8:14:8:20 | ... / ... | test.c:28:19:28:20 | l3 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | | test.c:28:19:28:20 | l3 | test.c:9:14:9:16 | - ... | test.c:28:19:28:20 | l3 | Invalid usage of possible $@. | test.c:9:14:9:16 | - ... | infinity | | test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Invalid usage of possible $@. | test.c:31:14:32:15 | ... / ... | infinity | -| test.c:39:8:39:9 | l8 | test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | Invalid usage of possible $@. | test.c:33:14:33:22 | ... / ... | infinity | -| test.c:61:12:61:18 | ... / ... | test.c:61:5:61:19 | ... / ... | test.c:61:5:61:19 | ... / ... | Invalid usage of possible $@. | test.c:61:5:61:19 | ... / ... | infinity | -| test.c:66:12:66:20 | ... / ... | test.c:66:5:66:21 | ... / ... | test.c:66:5:66:21 | ... / ... | Invalid usage of possible $@. | test.c:66:5:66:21 | ... / ... | infinity | -| test.c:72:21:72:29 | ... / ... | test.c:72:14:72:30 | ... / ... | test.c:72:14:72:30 | ... / ... | Invalid usage of possible $@. | test.c:72:14:72:30 | ... / ... | infinity | -| test.c:75:25:75:33 | ... / ... | test.c:75:18:75:34 | ... / ... | test.c:75:18:75:34 | ... / ... | Invalid usage of possible $@. | test.c:75:18:75:34 | ... / ... | infinity | +| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Invalid usage of possible $@. | test.c:61:5:61:18 | ... / ... | infinity | +| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Invalid usage of possible $@. | test.c:66:5:66:20 | ... / ... | infinity | +| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Invalid usage of possible $@. | test.c:72:14:72:29 | ... / ... | infinity | +| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Invalid usage of possible $@. | test.c:75:18:75:33 | ... / ... | infinity | +| test.c:79:10:79:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:79:5:79:12 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | +| test.c:87:10:87:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:87:5:87:12 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | +| test.c:91:10:91:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:91:5:91:12 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | +| test.c:93:10:93:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:93:5:93:12 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | +| test.c:99:10:99:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:99:5:99:12 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | +| test.c:105:10:105:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:105:5:105:12 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | +| test.c:111:10:111:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:111:5:111:12 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | +| test.c:114:21:114:23 | l12 | test.c:77:15:77:21 | ... / ... | test.c:114:16:114:23 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | +| test.c:117:28:117:30 | l12 | test.c:77:15:77:21 | ... / ... | test.c:117:23:117:30 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | +| test.c:120:25:120:27 | l12 | test.c:77:15:77:21 | ... / ... | test.c:120:20:120:27 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected index f317f236ef..e59d43d867 100644 --- a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected @@ -16,6 +16,15 @@ edges | test.c:33:14:33:22 | ... / ... | test.c:33:14:33:22 | ... / ... | provenance | | | test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | provenance | | | test.c:33:14:33:22 | ... / ... | test.c:54:3:54:4 | l8 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:122:15:122:21 | ... / ... | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:126:5:126:12 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:132:5:132:12 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:138:5:138:12 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:144:5:144:12 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:148:5:148:12 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:154:20:154:27 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:156:23:156:30 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:157:16:157:23 | l13 | provenance | | nodes | test.c:27:14:27:20 | ... / ... | semmle.label | ... / ... | | test.c:27:14:27:20 | ... / ... | semmle.label | ... / ... | @@ -38,10 +47,20 @@ nodes | test.c:52:3:52:4 | l6 | semmle.label | l6 | | test.c:53:3:53:4 | l7 | semmle.label | l7 | | test.c:54:3:54:4 | l8 | semmle.label | l8 | -| test.c:61:5:61:19 | ... / ... | semmle.label | ... / ... | -| test.c:66:5:66:21 | ... / ... | semmle.label | ... / ... | -| test.c:72:14:72:30 | ... / ... | semmle.label | ... / ... | -| test.c:75:18:75:34 | ... / ... | semmle.label | ... / ... | +| test.c:61:5:61:18 | ... / ... | semmle.label | ... / ... | +| test.c:66:5:66:20 | ... / ... | semmle.label | ... / ... | +| test.c:72:14:72:29 | ... / ... | semmle.label | ... / ... | +| test.c:75:18:75:33 | ... / ... | semmle.label | ... / ... | +| test.c:122:15:122:21 | ... / ... | semmle.label | ... / ... | +| test.c:122:15:122:21 | ... / ... | semmle.label | ... / ... | +| test.c:126:5:126:12 | l13 | semmle.label | l13 | +| test.c:132:5:132:12 | l13 | semmle.label | l13 | +| test.c:138:5:138:12 | l13 | semmle.label | l13 | +| test.c:144:5:144:12 | l13 | semmle.label | l13 | +| test.c:148:5:148:12 | l13 | semmle.label | l13 | +| test.c:154:20:154:27 | l13 | semmle.label | l13 | +| test.c:156:23:156:30 | l13 | semmle.label | l13 | +| test.c:157:16:157:23 | l13 | semmle.label | l13 | subpaths #select | test.c:36:8:36:9 | l5 | test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | @@ -57,7 +76,15 @@ subpaths | test.c:52:3:52:4 | l6 | test.c:28:14:28:20 | ... / ... | test.c:52:3:52:4 | l6 | Invalid usage of possible $@. | test.c:28:14:28:20 | ... / ... | NaN resulting from possible division of infinity by infinity | | test.c:53:3:53:4 | l7 | test.c:31:14:32:15 | ... / ... | test.c:53:3:53:4 | l7 | Invalid usage of possible $@. | test.c:31:14:32:15 | ... / ... | NaN resulting from possible division of zero by zero | | test.c:54:3:54:4 | l8 | test.c:33:14:33:22 | ... / ... | test.c:54:3:54:4 | l8 | Invalid usage of possible $@. | test.c:33:14:33:22 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:61:12:61:18 | ... / ... | test.c:61:5:61:19 | ... / ... | test.c:61:5:61:19 | ... / ... | Invalid usage of possible $@. | test.c:61:5:61:19 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:66:12:66:20 | ... / ... | test.c:66:5:66:21 | ... / ... | test.c:66:5:66:21 | ... / ... | Invalid usage of possible $@. | test.c:66:5:66:21 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:72:21:72:29 | ... / ... | test.c:72:14:72:30 | ... / ... | test.c:72:14:72:30 | ... / ... | Invalid usage of possible $@. | test.c:72:14:72:30 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:75:25:75:33 | ... / ... | test.c:75:18:75:34 | ... / ... | test.c:75:18:75:34 | ... / ... | Invalid usage of possible $@. | test.c:75:18:75:34 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Invalid usage of possible $@. | test.c:61:5:61:18 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Invalid usage of possible $@. | test.c:66:5:66:20 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Invalid usage of possible $@. | test.c:72:14:72:29 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Invalid usage of possible $@. | test.c:75:18:75:33 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:126:10:126:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:126:5:126:12 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:132:10:132:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:132:5:132:12 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:138:10:138:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:138:5:138:12 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:144:10:144:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:144:5:144:12 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:148:10:148:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:148:5:148:12 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:154:25:154:27 | l13 | test.c:122:15:122:21 | ... / ... | test.c:154:20:154:27 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:156:28:156:30 | l13 | test.c:122:15:122:21 | ... / ... | test.c:156:23:156:30 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:157:21:157:23 | l13 | test.c:122:15:122:21 | ... / ... | test.c:157:16:157:23 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | diff --git a/c/misra/test/rules/DIR-4-15/test.c b/c/misra/test/rules/DIR-4-15/test.c index d634a6e594..d0f9ab5418 100644 --- a/c/misra/test/rules/DIR-4-15/test.c +++ b/c/misra/test/rules/DIR-4-15/test.c @@ -56,21 +56,104 @@ void f1(float p1) { // Guards float l9 = 0; if (l9 != 0) { - (int) (l9 / l9); // COMPLIANT: l9 is not zero + (int)(l9 / l9); // COMPLIANT: l9 is not zero } else { - (int) (l9 / l9); // NON_COMPLIANT: Casting NaN to integer + (int)(l9 / l9); // NON_COMPLIANT: Guarded to not be NaN } float l10 = 0; if (l10 == 0) { - (int) (l10 / l10); // NON_COMPLIANT: Casting NaN to integer + (int)(l10 / l10); // NON_COMPLIANT: Casting NaN to integer } else { - (int) (l10 / l10); // COMPLIANT: l10 is not zero + (int)(l10 / l10); // COMPLIANT: Guarded to not be NaN } float l11 = 0; - l11 == 0 ? (int) (l11 / l11) : 0; // NON_COMPLIANT - l11 == 0 ? 0 : (int) (l11 / l11); // COMPLIANT - l11 != 0 ? (int) (l11 / l11) : 0; // COMPLIANT - l11 != 0 ? 0 : (int) (l11 / l11); // NON_COMPLIANT + l11 == 0 ? (int)(l11 / l11) : 0; // NON_COMPLIANT + l11 == 0 ? 0 : (int)(l11 / l11); // COMPLIANT + l11 != 0 ? (int)(l11 / l11) : 0; // COMPLIANT + l11 != 0 ? 0 : (int)(l11 / l11); // NON_COMPLIANT + + float l12 = 1.0 / 0; + if (isinf(l12)) { + (int)l12; // NON_COMPLIANT: Casting Infinity to integer + } else { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } + + if (!isinf(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // NON_COMPLIANT: Casting Infinity to integer + } + + if (isinf(l12) == 1) { + (int)l12; // NON_COMPLIANT: Must be +Infinity + } else { + (int)l12; // NON_COMPLIANT: May be -Infinity + } + + if (isfinite(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // NON_COMPLIANT: Casting Infinity to integer + } + + if (isnormal(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // NON_COMPLIANT: Casting Infinity to integer + } + + if (isnan(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // NON_COMPLIANT: Casting Infinity to integer + } + + isinf(l12) ? (int)l12 : 0; // NON_COMPLIANT: Check on wrong branch + isinf(l12) ? 0 : (int)l12; // COMPLIANT: Checked not infinite before use + isfinite(l12) ? (int)l12 : 0; // COMPLIANT: Checked finite before use + isfinite(l12) ? 0 : (int)l12; // NON_COMPLIANT: Checked on wrong branch + isnan(l12) ? (int)l12 + : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use + isnan(l12) ? 0 : (int)l12; // NON_COMPLIANT: Check on wrong branch + + float l13 = 0.0 / 0; + if (isinf(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isinf(l13) == 1) { + (int)l13; // COMPLIANT: Guarded not to be NaN (must be +Infinity) + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isfinite(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isnormal(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isnan(l13)) { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } else { + (int)l13; // COMPLIANT: Guarded not to be NaN + } + + isinf(l13) ? (int)l13 : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use + isinf(l13) ? 0 : (int)l13; // COMPLIANT: Check on wrong branch + isfinite(l13) ? (int)l13 : 0; // COMPLIANT: Checked finite before use + isfinite(l13) ? 0 : (int)l13; // NON_COMPLIANT: Checked on wrong branch + isnan(l13) ? (int)l13 : 0; // NON_COMPLIANT: Check on wrong branch + isnan(l13) ? 0 : (int)l13; // COMPLIANT: Checked not NaN before use } \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/FloatingPoint.qll b/cpp/common/src/codingstandards/cpp/FloatingPoint.qll index d143f81418..f3ba8dba18 100644 --- a/cpp/common/src/codingstandards/cpp/FloatingPoint.qll +++ b/cpp/common/src/codingstandards/cpp/FloatingPoint.qll @@ -7,6 +7,294 @@ predicate exprMayEqualZero(Expr e) { not guardedNotEqualZero(e) } +newtype TFPClassification = + TFinite() or + TNaN() or + TInfinite() + +class FPClassification extends TFPClassification { + string toString() { + this = TFinite() and + result = "finite" + or + this = TNaN() and + result = "NaN" + or + this = TInfinite() and + result = "infinite" + } +} + +newtype TFPClassificationConstraint = + /* The value may be infinite, NaN, or finite. */ + TUnclassified() or + /** + * The value must be one of: infinite, NaN, or finite. + * + * If strict is `true` then this inverts naively. For example, `!isfinite(x)` means `x` must not + * be finite. However, `!iszero(x)` is true for some finite values, and inverts to + * `TUnclassified`. + */ + TExactFPClassification(TFPClassification cls, Boolean strict) or + /* The value must not be one of: infinite, NaN, or finite. */ + TExcludeFPClassification(TFPClassification cls1) + +class FPClassificationConstraint extends TFPClassificationConstraint { + string toString() { + this = TUnclassified() and + result = "unclassified" + or + exists(FPClassification cls, Boolean strict | + this = TExactFPClassification(cls, strict) and + result = "must be " + cls.toString() + ", strict: " + strict.toString() + or + this = TExcludeFPClassification(cls) and + result = "must NOT be " + cls.toString() + ) + } + + /** + * Invert the constraint, for instance, "must be finite" becomes "must not be finite". + * + * Non-strict exact constraints are inverted to the unclassified constraint. For example, + * `iszero(x)` guarantees `x` to be finite, however, `!iszero(x)` can be true for all three + * classes of floating point values. + * + * The unclassified constraint inverts to itself. + */ + FPClassificationConstraint invert() { + // Unclassified inverts to itself. + this = TUnclassified() and result = this + or + exists(FPClassification cls | + // `!isfinite()` implies is infinite or NaN. + this = TExactFPClassification(cls, true) and + result = TExcludeFPClassification(cls) + or + // `!iszero()` implies nothing. + this = TExactFPClassification(cls, false) and + result = TUnclassified() + or + // For completeness: `!isfinite(x) ? ... : x` would imply `isfinite(x)`. + this = TExcludeFPClassification(cls) and + result = TExactFPClassification(cls, true) + ) + } + + /** + * Naively invert the constraint, for instance, "must be finite" becomes "must not be finite". + * + * Word of caution: inverting a guard condition does not necessarily invert the constraint. For + * example, `iszero(x)` guarantees `x` to be finite, however, `isnotzero(x)` does not guarantee + * `x` not to be finite. + * + * The unclassified constraint is not inverted. + */ + FPClassificationConstraint naiveInversion() { + this = TUnclassified() and result = this + or + exists(FPClassification cls | + this = TExactFPClassification(cls, _) and + result = TExcludeFPClassification(cls) + or + this = TExcludeFPClassification(cls) and + result = TExactFPClassification(cls, true) + ) + } + + predicate mustBe(FPClassification cls) { this = TExactFPClassification(cls, _) } + + predicate mustNotBe(FPClassification cls) { + this = TExcludeFPClassification(cls) + or + this = TExactFPClassification(_, _) and + not this = TExactFPClassification(cls, _) + } + + predicate mayBe(FPClassification cls) { not mustNotBe(cls) } +} + +/** + * The names of the functions or macros that classify floating point values. + * + * These names reflect a check that a value is finite, or infinite, or NaN. Finite and NaN checks + * are either strict (return true for all values in the class) or not (return true for some + * values). + * + * The infinite check is always strict, and specially, returns 1 or -1 for positive or negative + * infinity. + */ +newtype TFPClassifierName = + TClassifiesFinite(string name, boolean strict) { + strict = true and + name = ["finite" + ["", "l", "f"], "isfinite"] + or + strict = false and + name = ["isnormal", "issubnormal", "iszero"] + } or + TClassifiesNaN(string name, boolean strict) { + strict = true and + name = "isnan" + ["", "f", "l"] + or + strict = false and + name = "issignaling" + } or + TClassifiesInfinite(string name) { name = "isinf" + ["", "f", "l"] } + +class FPClassifierName extends TFPClassifierName { + string name; + boolean strict; + + FPClassifierName() { + this = TClassifiesFinite(name, strict) + or + this = TClassifiesInfinite(name) and + strict = true + or + this = TClassifiesNaN(name, strict) + } + + string toString() { result = name } + + /** The classification name, for instance, "isfinite". */ + string getName() { result = name } + + /** + * Whether the check holds for all values in the class, or only some. + * + * For instance, "isfinite" is strict because it returns true for all finite values, but + * "isnormal" is not as it returns false for some finite values. + */ + predicate isStrict() { strict = true } + + FPClassificationConstraint getConstraint() { + this = TClassifiesFinite(_, strict) and + result = TExactFPClassification(any(TFinite t), strict) + or + this = TClassifiesNaN(_, strict) and + result = TExactFPClassification(any(TNaN t), strict) + or + this = TClassifiesInfinite(_) and + // TODO: isinf() is special + result = TExactFPClassification(any(TInfinite t), false) + } +} + +/** + * An invocation of a classification function, for instance, "isfinite(x)", implemented as a macro. + */ +class FPClassifierMacroInvocation extends MacroInvocation { + FPClassifierName classifier; + + FPClassifierMacroInvocation() { getMacroName() = classifier.getName() } + + Expr getCheckedExpr() { + // Getting the checked expr in a cross-platform way is extroardinarily difficult, as glibc has + // multiple conditional implementations of the same macro. Assume the checked expr is a + // variable access so we can search optimistically like so: + exists(VariableAccess va | + va.getTarget().getName() = getExpandedArgument(0) and + va = getAnExpandedElement() and + result = va + ) + } + + /** + * The classification name, for instance, "isfinite". + */ + FPClassifierName getFPClassifierName() { result = classifier } +} + +/** + * A classification function, for instance, "isfinite", when implemented as a function. + */ +class FPClassifierFunction extends Function { + FPClassifierName classifier; + + FPClassifierFunction() { getName() = classifier.getName() } + + FPClassifierName getFPClassifierName() { result = classifier } +} + +class FPClassificationGuard instanceof GuardCondition { + Expr floatExpr; + Expr checkResultExpr; + FPClassifierName classifier; + + FPClassificationGuard() { + super.comparesEq(checkResultExpr, _, _, _) and + ( + exists(FPClassifierMacroInvocation m | + floatExpr = m.getCheckedExpr() and + checkResultExpr = m.getExpr() and + classifier = m.getFPClassifierName() + ) + or + exists(FunctionCall fc, FPClassifierFunction f | + fc.getTarget() = f and + floatExpr = fc.getArgument(0) and + checkResultExpr = fc and + classifier = f.getFPClassifierName() + ) + ) + } + + string toString() { + result = + classifier.toString() + " guard on " + floatExpr.toString() + " via " + + checkResultExpr.toString() + } + + predicate constrainsFPClass(Expr e, FPClassificationConstraint constraint, Boolean testIsTrue) { + floatExpr = e and + exists(BooleanValue value, boolean areEqual, int testResult, FPClassificationConstraint base | + super.comparesEq(checkResultExpr, testResult, areEqual, value) and + base = getBaseConstraint(areEqual, testResult) and + if value.getValue() = testIsTrue then constraint = base else constraint = base.invert() + ) + } + + // Helper function, gets base constraint assuming `classifier() == value` or `classifier != value`. + private FPClassificationConstraint getBaseConstraint(Boolean areEqual, int testResult) { + exists(FPClassificationConstraint base | + testResult = 0 and + exists(Boolean strict | + // Handle isfinite() != 0: + classifier = TClassifiesFinite(_, strict) and + base = TExactFPClassification(TFinite(), strict) + or + // Handle isNaN() != 0: + classifier = TClassifiesNaN(_, strict) and + base = TExactFPClassification(TNaN(), strict) + or + // Handle isinf() != 0, which matches for +/- infinity: + classifier = TClassifiesInfinite(_) and + base = TExactFPClassification(TInfinite(), true) + ) and + // Invert the base constraint in the case of `classifier() == 0` + if areEqual = false then result = base else result = base.invert() + or + // Handle isinf() == 1 or isInf() == -1, which matches for one of +/- infinity: + testResult = 1 and + classifier = TClassifiesInfinite(_) and + base = TExactFPClassification(TInfinite(), false) and + // Invert the base constraint in the case of `classifier() != 1` + if areEqual = true then result = base else result = base.invert() + // TODO: handle fpclassify() == FP_INFINITE, FP_NAN, FP_NORMAL, FP_ZERO, etc. + ) + } + + predicate controls(Expr e, boolean testIsTrue) { + exists(IRGuardCondition irg, IRBlock irb, Instruction eir, BooleanValue bval | + irg.getUnconvertedResultExpression() = this and + bval.getValue() = testIsTrue and + irg.valueControls(irb, bval) and + eir.getAst().(ControlFlowNode).getBasicBlock() = e.getBasicBlock() and + eir.getBlock() = irb + ) + } +} + predicate guardedNotEqualZero(Expr e) { /* Note Boolean cmpEq, false means cmpNeq */ exists(Expr checked, GuardCondition guard, boolean cmpEq, BooleanValue value | @@ -28,24 +316,15 @@ predicate guardedNotEqualZero(Expr e) { ) } -predicate guardedNotInfinite(Expr e) { +predicate guardedNotFPClass(Expr e, FPClassification cls) { /* Note Boolean cmpEq, false means cmpNeq */ - exists(Expr c, GuardCondition guard, boolean cmpEq | - hashCons(c) = hashCons(e) and + exists( + Expr checked, FPClassificationGuard guard, FPClassificationConstraint constraint, boolean cmpEq + | + hashCons(checked) = hashCons(e) and guard.controls(e, cmpEq) and - guard.comparesEq(c, 0, cmpEq.booleanNot(), _) - ) -} - -predicate test(Expr e, Expr v, int k, boolean areEqual, Boolean value, Expr gce, BasicBlock bb) { - exists(GuardCondition gc | gce = gc | - gc.controls(bb, _) and - gc.comparesEq(e, v, k, areEqual, value) and - ( - //gc.getAChild+().toString().matches("%dfYRes%") or - e.getAChild*().toString().matches("%dfPseudoPanchro%") or - v.getAChild*().toString().matches("%dfPseudoPanchro%") - ) + guard.constrainsFPClass(checked, constraint, cmpEq) and + constraint.mustNotBe(cls) ) } @@ -57,5 +336,7 @@ predicate exprMayEqualInfinity(Expr e, Boolean positive) { | RestrictedRangeAnalysis::upperBound(e.getUnconverted()) = target or RestrictedRangeAnalysis::lowerBound(e.getUnconverted()) = target - ) -} \ No newline at end of file + ) and + not guardedNotFPClass(e, TInfinite()) and + not e.getType() instanceof IntegralType +} diff --git a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll index 79ae2f367a..9b4bba8980 100644 --- a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll +++ b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll @@ -297,17 +297,21 @@ module RestrictedRangeAnalysis { } /** - * Holds if `expr` may divide by zero. + * Holds if `expr` may divide by zero. Excludes dividing a constant zero divided by zero, + * which produces NaN instead of an infinite value. */ - predicate dividesByZero(Expr expr) { - exists(Expr divisor | + predicate dividesNonzeroByZero(Expr expr) { + exists(Expr divisor, Expr numerator | divisor = expr.(DivExpr).getRightOperand() and + numerator = expr.(DivExpr).getLeftOperand() and getTruncatedLowerBounds(divisor) <= 0.0 and getTruncatedUpperBounds(divisor) >= 0.0 and - not isCheckedNotZero(divisor) + not isCheckedNotZero(divisor) and + not getValue(numerator).toFloat() = 0.0 ) } + /** * Holds if `expr` is checked with a guard to not be zero. * @@ -362,7 +366,7 @@ module RestrictedRangeAnalysis { // Introduces non-monotonic recursion. However, analysis mostly works with this // commented out. // or - // dividesByZero(e) + // dividesNonzeroByZero(e) or e instanceof DivExpr // TODO: confirm this is OK or @@ -681,7 +685,7 @@ module RestrictedRangeAnalysis { } private predicate lowerBoundableExpr(Expr expr) { - (analyzableExpr(expr) or dividesByZero(expr)) and + (analyzableExpr(expr) or dividesNonzeroByZero(expr)) and getUpperBoundsImpl(expr) <= Util::exprMaxVal(expr) and not exists(getValue(expr).toFloat()) } @@ -760,7 +764,7 @@ module RestrictedRangeAnalysis { * this predicate. */ private float getTruncatedUpperBounds(Expr expr) { - (analyzableExpr(expr) or dividesByZero(expr)) + (analyzableExpr(expr) or dividesNonzeroByZero(expr)) and ( // If the expression evaluates to a constant, then there is no // need to call getUpperBoundsImpl. @@ -827,7 +831,7 @@ module RestrictedRangeAnalysis { ) or exists(DivExpr div | expr = div | - dividesByZero(expr) and + dividesNonzeroByZero(expr) and result = getFullyConvertedLowerBounds(div.getLeftOperand()) / 0 ) or @@ -1032,7 +1036,7 @@ module RestrictedRangeAnalysis { ) or exists(DivExpr div | expr = div | - dividesByZero(expr) and + dividesNonzeroByZero(expr) and result = getFullyConvertedUpperBounds(div.getLeftOperand()) / 0 ) or From 1af6957b71ed825ab1d76c92588e082e05a17ec7 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 6 Feb 2025 10:17:27 +0000 Subject: [PATCH 225/628] M5-3-1: Exclude unknown types This ensures we consistently exclude unknown results for unevaluated contexts in uninstantiated templates. --- .../2025-02-06-m5-3-1-exclude-unknown-type.md | 2 ++ ...ogicalAndOrTheLogicalOperatorsShallHaveTypeBool.ql | 5 +++++ cpp/autosar/test/rules/M5-3-1/test.cpp | 11 ++++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 change_notes/2025-02-06-m5-3-1-exclude-unknown-type.md diff --git a/change_notes/2025-02-06-m5-3-1-exclude-unknown-type.md b/change_notes/2025-02-06-m5-3-1-exclude-unknown-type.md new file mode 100644 index 0000000000..ba7f50af45 --- /dev/null +++ b/change_notes/2025-02-06-m5-3-1-exclude-unknown-type.md @@ -0,0 +1,2 @@ + - `M5-3-1` - `EachOperandOfTheOperatorOfTheLogicalAndOrTheLogicalOperatorsShallHaveTypeBool.ql`: + - Consistently exclude results in unevaluated contexts associated with uninstantiated templates, for example `noexcept` specifiers and `static_assert`s. \ No newline at end of file diff --git a/cpp/autosar/src/rules/M5-3-1/EachOperandOfTheOperatorTheLogicalAndOrTheLogicalOperatorsShallHaveTypeBool.ql b/cpp/autosar/src/rules/M5-3-1/EachOperandOfTheOperatorTheLogicalAndOrTheLogicalOperatorsShallHaveTypeBool.ql index 03b4ae7f1c..e4589a364a 100644 --- a/cpp/autosar/src/rules/M5-3-1/EachOperandOfTheOperatorTheLogicalAndOrTheLogicalOperatorsShallHaveTypeBool.ql +++ b/cpp/autosar/src/rules/M5-3-1/EachOperandOfTheOperatorTheLogicalAndOrTheLogicalOperatorsShallHaveTypeBool.ql @@ -25,6 +25,11 @@ where ) and t = operand.getType() and not t.getUnderlyingType().getUnspecifiedType() instanceof BoolType and + // Ignore cases where the type is unknown - this will typically be in unevaluated contexts + // within uninstantiated templates. It's necessary to check for this explicitly because + // not all unevaluated contexts are considered to be `isFromUninstantiatedTemplate(_)`, + // e.g. `noexcept` specifiers + not t instanceof UnknownType and not exists(ReferenceType rt | rt = t.getUnderlyingType().getUnspecifiedType() and rt.getBaseType() instanceof BoolType ) and diff --git a/cpp/autosar/test/rules/M5-3-1/test.cpp b/cpp/autosar/test/rules/M5-3-1/test.cpp index 9098e4e40e..4bda4c6682 100644 --- a/cpp/autosar/test/rules/M5-3-1/test.cpp +++ b/cpp/autosar/test/rules/M5-3-1/test.cpp @@ -25,4 +25,13 @@ template class A { void f() { A a; a.test1(); -} \ No newline at end of file +} + +template constexpr bool some_variable_template_v = false; +template <> constexpr bool some_variable_template_v = true; + +template +void template_with_no_except() noexcept(some_variable_template_v && + true) { // COMPLIANT +} +void test_template() { template_with_no_except(); } \ No newline at end of file From 879a6f27c9d29906e9b58e973574aba0360eccb3 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 6 Feb 2025 16:35:16 +0000 Subject: [PATCH 226/628] A3-1-5: Downgrade to an "audit" query This rule talks about developer intention in a way that is not possible to determine fully automatically with any confidence. We therefore downgrade this rule to an "audit" query. --- ...nTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql | 1 + rule_packages/cpp/Classes.json | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cpp/autosar/src/rules/A3-1-5/NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql b/cpp/autosar/src/rules/A3-1-5/NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql index 251f94d6eb..2edf73b6ee 100644 --- a/cpp/autosar/src/rules/A3-1-5/NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql +++ b/cpp/autosar/src/rules/A3-1-5/NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql @@ -7,6 +7,7 @@ * @precision very-high * @problem.severity recommendation * @tags external/autosar/id/a3-1-5 + * external/autosar/audit * external/autosar/allocated-target/design * external/autosar/enforcement/partially-automated * external/autosar/obligation/required diff --git a/rule_packages/cpp/Classes.json b/rule_packages/cpp/Classes.json index 6dd130a55b..d76a9b3bc5 100644 --- a/rule_packages/cpp/Classes.json +++ b/rule_packages/cpp/Classes.json @@ -185,7 +185,9 @@ "precision": "very-high", "severity": "recommendation", "short_name": "NonTrivialNonTemplateFunctionDefinedInsideClassDefinition", - "tags": [] + "tags": [ + "external/autosar/audit" + ] } ], "title": "A function definition shall only be placed in a class definition if (1) the function is intended to be inlined (2) it is a member function template (3) it is a member function of a class template." From 3f6235892f85ffbf1ff9e266fac003fcfeab1728 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 6 Feb 2025 16:39:14 +0000 Subject: [PATCH 227/628] Add change note --- change_notes/2025-02-06-a3-1-5-audit.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change_notes/2025-02-06-a3-1-5-audit.md diff --git a/change_notes/2025-02-06-a3-1-5-audit.md b/change_notes/2025-02-06-a3-1-5-audit.md new file mode 100644 index 0000000000..3aa0e6671b --- /dev/null +++ b/change_notes/2025-02-06-a3-1-5-audit.md @@ -0,0 +1,2 @@ + - `A3-1-5` - `NonTrivalNonTemplateFunctionDefinedInsideClassDefinition.ql`: + - Mark this as an `audit` query. As a consequence, it will no longer be run as part of the default query suite for AUTOSAR. It can still be run as part of the `autosar-audit.qls` query suite. The query has been downgraded because the rule allows for functions to be declared in the class body if they were "intended" to be inlined, and that developer intention cannot be determined automatically from the code. \ No newline at end of file From 4ee762909b228630ae6f7da1bcab8ba7922b2df5 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 6 Feb 2025 12:00:56 -0800 Subject: [PATCH 228/628] Deduplicate and filter results, improve messages, handle performance issue --- .../PossibleMisuseOfUndetectedInfinity.ql | 69 ++++-- .../DIR-4-15/PossibleMisuseOfUndetectedNaN.ql | 68 ++++-- .../PossibleUndetectedNaNorInfinity.ql | 223 ------------------ .../PossibleUndetectedNaNorInfinity.expected | 1 - .../PossibleUndetectedNaNorInfinity.qlref | 1 - .../cpp/RestrictedRangeAnalysis.qll | 126 ++++++++-- 6 files changed, 207 insertions(+), 281 deletions(-) delete mode 100644 c/misra/src/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.ql delete mode 100644 c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.expected delete mode 100644 c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.qlref diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql index 97dd251083..10c370690b 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql @@ -73,44 +73,73 @@ module InvalidInfinityUsage implements DataFlow::ConfigSig { } predicate isSink(DataFlow::Node node) { + node instanceof InvalidInfinityUsage and ( // Require that range analysis finds this value potentially infinite, to avoid false positives // in the presence of guards. This may induce false negatives. - exprMayEqualInfinity(node.asExpr(), _) or + exprMayEqualInfinity(node.asExpr(), _) + or // Unanalyzable expressions are not checked against range analysis, which assumes a finite // range. not RestrictedRangeAnalysis::analyzableExpr(node.asExpr()) - ) and - ( - // Case 2: NaNs and infinities shall not be cast to integers - exists(Conversion c | - node.asExpr() = c.getUnconverted() and - c.getExpr().getType() instanceof FloatingPointType and - c.getType() instanceof IntegralType - ) - or - // Case 3: Infinities shall not underflow or otherwise produce finite values - exists(BinaryOperation op | - node.asExpr() = op.getRightOperand() and - op.getOperator() = ["/", "%"] - ) ) } } +class InvalidInfinityUsage extends DataFlow::Node { + string description; + string infinityDescription; + + InvalidInfinityUsage() { + // Case 2: NaNs and infinities shall not be cast to integers + exists(Conversion c | + asExpr() = c.getUnconverted() and + c.getExpr().getType() instanceof FloatingPointType and + c.getType() instanceof IntegralType and + description = "$@ casted to integer." and + infinityDescription = "Possibly infinite float value" + ) + or + // Case 3: Infinities shall not underflow or otherwise produce finite values + exists(BinaryOperation op | + asExpr() = op.getRightOperand() and + op.getOperator() = "/" and + description = "Division operation may silently underflow and produce zero, as the divisor $@." and + infinityDescription = "may be an infinite float value" + ) + } + + string getDescription() { result = description } + + string getInfinityDescription() { result = infinityDescription } +} + module InvalidInfinityFlow = DataFlow::Global; import InvalidInfinityFlow::PathGraph from Element elem, InvalidInfinityFlow::PathNode source, InvalidInfinityFlow::PathNode sink, - string msg, string sourceString + InvalidInfinityUsage usage, Expr sourceExpr, Element extra, string extraString where elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and + not InvalidInfinityFlow::PathGraph::edges(_, source, _, _) and not isExcluded(elem, FloatingTypes2Package::possibleMisuseOfUndetectedInfinityQuery()) and + not sourceExpr.isFromTemplateInstantiation(_) and + not usage.asExpr().isFromTemplateInstantiation(_) and + usage = sink.getNode() and + sourceExpr = source.getNode().asExpr() and + InvalidInfinityFlow::flow(source.getNode(), usage) and ( - InvalidInfinityFlow::flow(source.getNode(), sink.getNode()) and - msg = "Invalid usage of possible $@." and - sourceString = "infinity" + if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() + then + extraString = usage.getInfinityDescription() + " computed in function " + sourceExpr.getEnclosingFunction().getName() + and extra = sourceExpr.getEnclosingFunction() + else ( + extra = sourceExpr and + if sourceExpr instanceof DivExpr + then extraString = usage.getInfinityDescription() + " from division by zero" + else extraString = usage.getInfinityDescription() + ) ) -select elem, source, sink, msg, source, sourceString +select elem, source, sink, usage.getDescription(), extra, extraString \ No newline at end of file diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql index 036d470247..942715fe2f 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql @@ -40,7 +40,7 @@ class InvalidOperationExpr extends BinaryOperation { exprMayEqualInfinity(getLeftOperand(), sign) and exprMayEqualInfinity(getRightOperand(), sign.booleanNot()) ) and - reason = "possible addition of infinity and negative infinity" + reason = "from addition of infinity and negative infinity" or // 7.1.2 continued getOperator() = "-" and @@ -48,35 +48,35 @@ class InvalidOperationExpr extends BinaryOperation { exprMayEqualInfinity(getLeftOperand(), sign) and exprMayEqualInfinity(getRightOperand(), sign) ) and - reason = "possible subtraction of an infinity from itself" + reason = "from subtraction of an infinity from itself" or // 7.1.3: multiplication of zero by infinity getOperator() = "*" and exprMayEqualZero(getAnOperand()) and exprMayEqualInfinity(getAnOperand(), _) and - reason = "possible multiplication of zero by infinity" + reason = "from multiplication of zero by infinity" or // 7.1.4: Division of zero by zero, or infinity by infinity getOperator() = "/" and exprMayEqualZero(getLeftOperand()) and exprMayEqualZero(getRightOperand()) and - reason = "possible division of zero by zero" + reason = "from division of zero by zero" or // 7.1.4 continued getOperator() = "/" and exprMayEqualInfinity(getLeftOperand(), _) and exprMayEqualInfinity(getRightOperand(), _) and - reason = "possible division of infinity by infinity" + reason = "from division of infinity by infinity" or // 7.1.5: x % y where y is zero or x is infinite getOperator() = "%" and exprMayEqualInfinity(getLeftOperand(), _) and - reason = "possible modulus of infinity" + reason = "from modulus of infinity" or // 7.1.5 continued getOperator() = "%" and exprMayEqualZero(getRightOperand()) and - reason = "possible modulus by zero" + reason = "from modulus by zero" // 7.1.6 handles the sqrt function, not covered here. // 7.1.7 declares exceptions during invalid conversions, which we catch as sinks in our flow // analysis. @@ -129,24 +129,39 @@ module InvalidNaNUsage implements DataFlow::ConfigSig { predicate isSink(DataFlow::Node node) { not guardedNotFPClass(node.asExpr(), TNaN()) and - ( + node instanceof InvalidNaNUsage + } +} + +class InvalidNaNUsage extends DataFlow::Node { + string description; + string nanDescription; + + InvalidNaNUsage() { // Case 1: NaNs shall not be compared, except to themselves exists(ComparisonOperation cmp | - node.asExpr() = cmp.getAnOperand() and - not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand()) + this.asExpr() = cmp.getAnOperand() and + not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand()) and + description = "Comparison involving a $@, which always evaluates to false." and + nanDescription = "possibly NaN float value" ) or // Case 2: NaNs and infinities shall not be cast to integers exists(Conversion c | - node.asExpr() = c.getUnconverted() and + this.asExpr() = c.getUnconverted() and c.getExpr().getType() instanceof FloatingPointType and - c.getType() instanceof IntegralType + c.getType() instanceof IntegralType and + description = "$@ casted to integer." and + nanDescription = "Possibly NaN float value" ) //or //// Case 4: Functions shall not return NaNs or infinities //exists(ReturnStmt ret | node.asExpr() = ret.getExpr()) - ) } + + string getDescription() { result = description } + + string getNaNDescription() { result = nanDescription } } module InvalidNaNFlow = DataFlow::Global; @@ -154,15 +169,26 @@ module InvalidNaNFlow = DataFlow::Global; import InvalidNaNFlow::PathGraph from - Element elem, InvalidNaNFlow::PathNode source, InvalidNaNFlow::PathNode sink, string msg, - string sourceString + Element elem, InvalidNaNFlow::PathNode source, InvalidNaNFlow::PathNode sink, + InvalidNaNUsage usage, Expr sourceExpr, string sourceString, Element extra, string extraString where + not InvalidNaNFlow::PathGraph::edges(_, source, _, _) and + not sourceExpr.isFromTemplateInstantiation(_) and + not usage.asExpr().isFromTemplateInstantiation(_) and elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and - not isExcluded(elem, FloatingTypes2Package::possibleMisuseOfUndetectedNaNQuery()) and - ( - InvalidNaNFlow::flow(source.getNode(), sink.getNode()) and - msg = "Invalid usage of possible $@." and + usage = sink.getNode() and + sourceExpr = source.getNode().asExpr() and sourceString = - "NaN resulting from " + source.getNode().asExpr().(InvalidOperationExpr).getReason() + " (" + source.getNode().asExpr().(InvalidOperationExpr).getReason() + ")" and + InvalidNaNFlow::flow(source.getNode(), usage) and + ( + if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() + then + extraString = usage.getNaNDescription() + sourceString + " computed in function " + sourceExpr.getEnclosingFunction().getName() + and extra = sourceExpr.getEnclosingFunction() + else ( + extra = sourceExpr and + extraString = usage.getNaNDescription() + sourceString + ) ) -select elem, source, sink, msg, source, sourceString +select elem, source, sink, usage.getDescription(), extra, extraString \ No newline at end of file diff --git a/c/misra/src/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.ql b/c/misra/src/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.ql deleted file mode 100644 index 94888a95e6..0000000000 --- a/c/misra/src/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.ql +++ /dev/null @@ -1,223 +0,0 @@ -/** - * @id c/misra/possible-undetected-na-nor-infinity - * @name DIR-4-15: Evaluation of floating-point expressions shall not lead to the undetected generation of infinities - * @description Evaluation of floating-point expressions shall not lead to the undetected generation - * of infinities and NaNs. - * @kind path-problem - * @precision high - * @problem.severity error - * @tags external/misra/id/dir-4-15 - * correctness - * external/misra/c/2012/amendment3 - * external/misra/obligation/required - */ - -import cpp -import codeql.util.Boolean -import codingstandards.c.misra -import codingstandards.cpp.RestrictedRangeAnalysis -import codingstandards.cpp.FloatingPoint -import codingstandards.cpp.AlertReporting -import semmle.code.cpp.controlflow.Guards -import semmle.code.cpp.dataflow.new.DataFlow -import semmle.code.cpp.dataflow.new.TaintTracking -import semmle.code.cpp.controlflow.Dominance - -class CantHandleInfinityFunction extends Function { - CantHandleInfinityFunction() { not hasDefinition() and not getName() = "__fpclassifyl" } -} - -class InfinityCheckedExpr extends Expr { - InfinityCheckedExpr() { - exists(MacroInvocation mi | - mi.getMacroName() = ["isfinite", "isinf"] and - mi.getExpr() = this - ) - } - - Expr getCheckedExpr() { - result = - this.(ConditionalExpr) - .getThen() - .(LTExpr) - .getLesserOperand() - .(BitwiseAndExpr) - .getLeftOperand() - .(FunctionCall) - .getArgument(0) - } -} - -/* -signature module ResourceLeakConfigSig { - predicate isResource(DataFlow::Node node); - - predicate isFree(DataFlow::Node node, DataFlow::Node resource); - - default ControlFlowNode outOfScope(DataFlow::Node resource) { - result = resource.asExpr().getEnclosingFunction().getBlock().getLastStmt() - } - - default predicate isAlias(DataFlow::Node alias, DataFlow::Node resource) { - isResource(resource) and - DataFlow::localFlow(resource, alias) - } -} - -module ResourceLeak { - predicate isLeaked(DataFlow::Node resource, ControlFlowNode cfgNode) { - resource.asExpr() = cfgNode - or - isLeaked(resource, cfgNode.getAPredecessor()) and - not exists(DataFlow::Node free, DataFlow::Node freed | - free.asExpr() = cfgNode and - Config::isFree(free, freed) and - Config::isAlias(freed, resource) - ) - } - - private ControlFlowNode getARawLeak(DataFlow::Node resource) { - Config::isResource(resource) and - result = Config::outOfScope(resource) and - isLeaked(resource, result) - } - - ControlFlowNode getALeak(DataFlow::Node resource) { - result = getARawLeak(resource) and - not exists(DataFlow::Node dealiased | - Config::isResource(dealiased) and - Config::isAlias(resource, dealiased) and - not resource = dealiased and - result = getARawLeak(dealiased) - ) and - not exists(ControlFlowNode dominator | - dominator = getARawLeak(resource) and - strictlyDominates(dominator, result) - ) - } -} - -module MissedInfinityConfig implements ResourceLeakConfigSig { - predicate isResource(DataFlow::Node node) { - //exists(BinaryOperation expr | - // expr = node.asExpr() and - // expr.getOperator() = "/" and - // RestrictedRangeAnalysis::upperBound(expr.getRightOperand()) <= 0 and - // RestrictedRangeAnalysis::lowerBound(expr.getRightOperand()) >= 0 - //) - [ - RestrictedRangeAnalysis::upperBound(node.asExpr()), - RestrictedRangeAnalysis::lowerBound(node.asExpr()) - ].toString() = "Infinity" - //and not node.asExpr() instanceof VariableAccess - //and not node.asExpr() instanceof ArrayExpr - } - - predicate test(Expr expr, string lowerBound, string upperBound) { - //expr.getType() instanceof FloatingPointType - //and - lowerBound = RestrictedRangeAnalysis::lowerBound(expr).toString() and - upperBound = RestrictedRangeAnalysis::upperBound(expr).toString() and - [lowerBound, upperBound] = "Infinity" - } - - additional predicate testDiv( - DivExpr div, string lbDiv, string ubDiv, string lbNum, string ubNum, string lbDenom, - string ubDenom - ) { - lbDiv = RestrictedRangeAnalysis::lowerBound(div).toString() and - ubDiv = RestrictedRangeAnalysis::upperBound(div).toString() and - lbNum = RestrictedRangeAnalysis::lowerBound(div.getLeftOperand()).toString() and - ubNum = RestrictedRangeAnalysis::upperBound(div.getLeftOperand()).toString() and - lbDenom = RestrictedRangeAnalysis::lowerBound(div.getRightOperand()).toString() and - ubDenom = RestrictedRangeAnalysis::upperBound(div.getRightOperand()).toString() and - not lbDiv = ubDiv and - InvalidNaNUsage::isSource(DataFlow::exprNode(div)) - } - - predicate isFree(DataFlow::Node node, DataFlow::Node resource) { - isResource(resource) and - ( - node.asExpr().(InfinityCheckedExpr).getCheckedExpr() = resource.asExpr() - or - not [ - RestrictedRangeAnalysis::lowerBound(node.asExpr()), - RestrictedRangeAnalysis::upperBound(node.asExpr()) - ].toString() = "Infinity" and - isMove(node, resource) - ) - } - - predicate isMove(DataFlow::Node node, DataFlow::Node moved) { - isResource(moved) and - isAlias(node, moved) and - not exists(DataFlow::Node laterUse, ControlFlowNode later | - later = laterUse.asExpr() and - later = node.asExpr().getASuccessor+() and - hashCons(laterUse.asExpr()) = hashCons(moved.asExpr()) - ) - } - - ControlFlowNode outOfScope(DataFlow::Node resource) { - result = resource.asExpr().getEnclosingFunction().getBlock().getLastStmt() - or - exists(AssignExpr assign, DataFlow::Node alias | - assign.getRValue() = alias.asExpr() and - isAlias(alias, resource) and - not assign.getRValue().(VariableAccess).getTarget() instanceof StackVariable and - result = assign - ) - or - exists(FunctionCall fc | - fc.getArgument(_) = resource.asExpr() and - result = fc - ) - } - - predicate isAlias(DataFlow::Node alias, DataFlow::Node resource) { - TaintTracking::localTaint(resource, alias) - } -} - -import ResourceLeak as MissedInfinity -*/ - -//from Expr value, FunctionCall fc -//where -// not isExcluded(value, FloatingTypes2Package::possibleUndetectedNaNorInfinityQuery()) and -// [RestrictedRangeAnalysis::lowerBound(value), RestrictedRangeAnalysis::upperBound(value)].toString() = "Infinity" and -// value = fc.getAnArgument() and -// fc.getTarget() instanceof CantHandleInfinityFunction and -// not value instanceof InfinityCheckedExpr and -// not exists (GuardCondition g | -// g.controls(fc.getBasicBlock(), true) and -// g instanceof InfinityCheckedExpr -// // TODO check we check the right expr -// ) -//select -// value, "possible use of unchecked infinity as arg to " + fc.getTarget().getName() -//from DataFlow::Node node, ControlFlowNode leakPoint -//where -// not isExcluded(node.asExpr(), FloatingTypes2Package::possibleUndetectedNaNorInfinityQuery()) and -// leakPoint = MissedInfinity::getALeak(node) -// select node, "Expression generates an infinity which is not checked before $@.", leakPoint, "external leak point" - - -//import InvalidNaNFlow::PathGraph -//from Element elem, DataFlow::Node source, DataFlow::Node sink, string msg, string sourceString -from - Element elem, InvalidInfinityFlow::PathNode source, InvalidInfinityFlow::PathNode sink, - string msg, string sourceString -where - elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and - not isExcluded(elem, FloatingTypes2Package::possibleUndetectedNaNorInfinityQuery()) and - ( - InvalidInfinityFlow::flow(source.getNode(), sink.getNode()) and - msg = "Invalid usage of possible $@." and - sourceString = "infinity" - //or - //InvalidNaNFlow::flow(source, sink) and - //msg = "Invalid usage of possible $@." and - //sourceString = "NaN resulting from " + source.asExpr().(InvalidOperationExpr).getReason() - ) -select elem, source, sink, msg, source, sourceString diff --git a/c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.expected b/c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.expected deleted file mode 100644 index 2ec1a0ac6c..0000000000 --- a/c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.expected +++ /dev/null @@ -1 +0,0 @@ -No expected results have yet been specified \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.qlref b/c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.qlref deleted file mode 100644 index 1ffb7ad071..0000000000 --- a/c/misra/test/rules/DIR-4-15/PossibleUndetectedNaNorInfinity.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/DIR-4-15/PossibleUndetectedNaNorInfinity.ql \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll index 9b4bba8980..8ae3c9c38b 100644 --- a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll +++ b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll @@ -1,5 +1,6 @@ import semmle.code.cpp.controlflow.Guards import semmle.code.cpp.valuenumbering.HashCons + /** * A fork of SimpleRangeAnalysis.qll, which is intended to only give * results with a conservative basis. @@ -311,7 +312,6 @@ module RestrictedRangeAnalysis { ) } - /** * Holds if `expr` is checked with a guard to not be zero. * @@ -332,7 +332,8 @@ module RestrictedRangeAnalysis { expr = def.getAUse(v) and isNEPhi(v, def, guardVa, 0) ) - or guardedHashConsNotEqualZero(expr) + or + guardedHashConsNotEqualZero(expr) } predicate guardedHashConsNotEqualZero(Expr e) { @@ -342,8 +343,8 @@ module RestrictedRangeAnalysis { valVal = getValue(val).toFloat() and guard.controls(e.getBasicBlock(), cmpEq) and ( - guard.comparesEq(check, val, -valVal, false, cmpEq) or - guard.comparesEq(val, check, -valVal, false, cmpEq) + guard.comparesEq(check, val, -valVal, false, cmpEq) or + guard.comparesEq(val, check, -valVal, false, cmpEq) ) ) } @@ -363,11 +364,11 @@ module RestrictedRangeAnalysis { dividesByPositive(e, _, _) or dividesByNegative(e, _, _) + or // Introduces non-monotonic recursion. However, analysis mostly works with this // commented out. // or // dividesNonzeroByZero(e) - or e instanceof DivExpr // TODO: confirm this is OK or e instanceof MinExpr @@ -469,6 +470,8 @@ module RestrictedRangeAnalysis { exprDependsOnDef(operand, srcDef, srcVar) ) or + exists(DivExpr div | div = e | exprDependsOnDef(div.getAnOperand(), srcDef, srcVar)) + or exists(MinExpr minExpr | e = minExpr | exprDependsOnDef(minExpr.getAnOperand(), srcDef, srcVar)) or exists(MaxExpr maxExpr | e = maxExpr | exprDependsOnDef(maxExpr.getAnOperand(), srcDef, srcVar)) @@ -595,6 +598,98 @@ module RestrictedRangeAnalysis { isRecursiveExpr(binop.getRightOperand()) } + private predicate applyWideningToBinary(BinaryOperation op) { + // Original behavior: + isRecursiveBinary(op) + or + // As we added support for DivExpr, we found cases of combinatorial explosion that are not + // caused by recursion. Given expr `x` that depends on a phi node that has evaluated y unique + // values, `x + x` will in the worst case evaluate to y^2 unique values, even if `x` is not + // recursive. By adding support for division, we have revealed certain pathological cases in + // open source code, for instance `posix_time_from_utc` from boringssl. We can reduce this + // greatly by widening, and targeting division effectively reduces the chains of evaluations + // that cause this issue while preserving the original behavior. + // + // There is also a set of functions intended to estimate the combinations of phi nodes each + // expression depends on, which could be used to accurately widen only expensive nodes. However, + // that estimation is more involved than it may seem, and hasn't yet resulted in a net + // improvement. See `estimatedPhiCombinationsExpr` and `estimatedPhiCombinationsDef`. + // + // This approach currently has the best performance. + op instanceof DivExpr + } + + /** + * Recursively scan this expr to see how many phi nodes it depends on. Binary expressions + * induce a combination effect, so `a + b` where `a` depends on 3 phi nodes and `b` depends on 4 + * will induce 3*4 = 12 phi node combinations. + * + * This currently requires additional optimization to be useful in practice. + */ + int estimatedPhiCombinationsExpr(Expr expr) { + if isRecursiveExpr(expr) + // Assume 10 values were computed to analyze recursive expressions. + then result = 10 + else ( + exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | + def.isPhiNode(v) and + result = estimatedPhiCombinationsDef(def, v) + ) + or + exists(BinaryOperation binop | + binop = expr and + result = + estimatedPhiCombinationsExpr(binop.getLeftOperand()) * + estimatedPhiCombinationsExpr(binop.getRightOperand()) + ) + or + not expr instanceof BinaryOperation and + exists(RangeSsaDefinition def, StackVariable v | exprDependsOnDef(expr, def, v) | + result = estimatedPhiCombinationsDef(def, v) + ) + or + not expr instanceof BinaryOperation and + not exprDependsOnDef(expr, _, _) and result = 1 + ) + } + + /** + * Recursively scan this def to see how many phi nodes it depends on. + * + * If this def is a phi node, it sums its downstream cost and adds one to account for itself, + * which is not exactly correct. + * + * This def may also be a crement expression (not currently supported), or an assign expr + * (currently not supported), or an unanalyzable expression which is the root of the recursion + * and given a value of 1. + */ + language[monotonicAggregates] + int estimatedPhiCombinationsDef(RangeSsaDefinition def, StackVariable v) { + if isRecursiveDef(def, v) + // Assume 10 values were computed to analyze recursive expressions. + then result = 10 + else ( + if def.isPhiNode(v) + then + exists(Expr e | e = def.getAUse(v) | + result = + 1 + + sum(RangeSsaDefinition srcDef | + srcDef = def.getAPhiInput(v) + | + estimatedPhiCombinationsDef(srcDef, v) + ) + ) + else ( + exists(Expr expr | assignmentDef(def, v, expr) | result = estimatedPhiCombinationsExpr(expr)) + or + v = def.getAVariable() and + not assignmentDef(def, v, _) and + result = 1 + ) + ) + } + /** * We distinguish 3 kinds of RangeSsaDefinition: * @@ -719,7 +814,7 @@ module RestrictedRangeAnalysis { if Util::exprMinVal(expr) <= newLB and newLB <= Util::exprMaxVal(expr) then // Apply widening where we might get a combinatorial explosion. - if isRecursiveBinary(expr) + if applyWideningToBinary(expr) then result = max(float widenLB | @@ -764,8 +859,8 @@ module RestrictedRangeAnalysis { * this predicate. */ private float getTruncatedUpperBounds(Expr expr) { - (analyzableExpr(expr) or dividesNonzeroByZero(expr)) - and ( + (analyzableExpr(expr) or dividesNonzeroByZero(expr)) and + ( // If the expression evaluates to a constant, then there is no // need to call getUpperBoundsImpl. if exists(getValue(expr).toFloat()) @@ -778,7 +873,7 @@ module RestrictedRangeAnalysis { if Util::exprMinVal(expr) <= newUB and newUB <= Util::exprMaxVal(expr) then // Apply widening where we might get a combinatorial explosion. - if isRecursiveBinary(expr) + if applyWideningToBinary(expr) then result = min(float widenUB | @@ -794,13 +889,14 @@ module RestrictedRangeAnalysis { exprMightOverflowNegatively(expr) and result = Util::exprMaxVal(expr) ) - ) or + ) + or not analyzableExpr(expr) and - // The expression is not analyzable, so its upper bound is - // unknown. Note that the call to exprMaxVal restricts the - // expressions to just those with arithmetic types. There is no - // need to return results for non-arithmetic expressions. - result = exprMaxVal(expr) + // The expression is not analyzable, so its upper bound is + // unknown. Note that the call to exprMaxVal restricts the + // expressions to just those with arithmetic types. There is no + // need to return results for non-arithmetic expressions. + result = exprMaxVal(expr) } /** Only to be called by `getTruncatedLowerBounds`. */ From dee226188f61262f5f5a02173c1545c7ad8783ca Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 7 Feb 2025 04:28:13 -0800 Subject: [PATCH 229/628] Widening/dedupe fixes, plus math lib support --- .../PossibleMisuseOfUndetectedInfinity.ql | 8 +- .../DIR-4-15/PossibleMisuseOfUndetectedNaN.ql | 74 +++++- ...ossibleMisuseOfUndetectedInfinity.expected | 82 ++++-- .../PossibleMisuseOfUndetectedNaN.expected | 108 +++++--- c/misra/test/rules/DIR-4-15/test.c | 59 ++++- .../cpp/RestrictedRangeAnalysis.qll | 242 +++++++++++++++++- 6 files changed, 496 insertions(+), 77 deletions(-) diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql index 10c370690b..357a8fce71 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql @@ -51,9 +51,6 @@ module InvalidInfinityUsage implements DataFlow::ConfigSig { e.getType() instanceof IntegralType and e = node.asConvertedExpr() ) - or - // Sinks are places where Infinity produce a finite value - isSink(node) } /** @@ -81,7 +78,9 @@ module InvalidInfinityUsage implements DataFlow::ConfigSig { or // Unanalyzable expressions are not checked against range analysis, which assumes a finite // range. - not RestrictedRangeAnalysis::analyzableExpr(node.asExpr()) + not RestrictedRangeAnalysis::canBoundExpr(node.asExpr()) + or + node.asExpr().(VariableAccess).getTarget() instanceof Parameter ) } } @@ -124,6 +123,7 @@ from where elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and not InvalidInfinityFlow::PathGraph::edges(_, source, _, _) and + not InvalidInfinityFlow::PathGraph::edges(sink, _, _, _) and not isExcluded(elem, FloatingTypes2Package::possibleMisuseOfUndetectedInfinityQuery()) and not sourceExpr.isFromTemplateInstantiation(_) and not usage.asExpr().isFromTemplateInstantiation(_) and diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql index 942715fe2f..f850cc3e55 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql @@ -23,8 +23,73 @@ import semmle.code.cpp.dataflow.new.DataFlow import semmle.code.cpp.dataflow.new.TaintTracking import semmle.code.cpp.controlflow.Dominance +bindingset[name] +Function getMathVariants(string name) { result.hasGlobalOrStdName([name, name + "f", name + "l"]) } + +predicate hasDomainError(FunctionCall fc, string description) { + exists(Function functionWithDomainError | fc.getTarget() = functionWithDomainError | + functionWithDomainError = [getMathVariants(["acos", "asin", "atanh"])] and + not ( + RestrictedRangeAnalysis::upperBound(fc.getArgument(0)) <= 1.0 and + RestrictedRangeAnalysis::lowerBound(fc.getArgument(0)) >= -1.0 + ) and + description = + "the argument has a range " + RestrictedRangeAnalysis::lowerBound(fc.getArgument(0)) + "..." + + RestrictedRangeAnalysis::upperBound(fc.getArgument(0)) + " which is outside the domain of this function (-1.0...1.0)" + or + functionWithDomainError = getMathVariants(["atan2", "pow"]) and + ( + exprMayEqualZero(fc.getArgument(0)) and + exprMayEqualZero(fc.getArgument(1)) and + description = "both arguments are equal to zero" + ) + or + functionWithDomainError = getMathVariants("pow") and + ( + RestrictedRangeAnalysis::upperBound(fc.getArgument(0)) < 0.0 and + RestrictedRangeAnalysis::upperBound(fc.getArgument(1)) < 0.0 and + description = "both arguments are less than zero" + ) + or + functionWithDomainError = getMathVariants("acosh") and + RestrictedRangeAnalysis::upperBound(fc.getArgument(0)) < 1.0 and + description = "argument is less than 1" + or + //pole error is the same as domain for logb and tgamma (but not ilogb - no pole error exists) + functionWithDomainError = getMathVariants(["ilogb", "logb", "tgamma"]) and + exprMayEqualZero(fc.getArgument(0)) and + description = "argument is equal to zero" + or + functionWithDomainError = getMathVariants(["log", "log10", "log2", "sqrt"]) and + RestrictedRangeAnalysis::upperBound(fc.getArgument(0)) < 0.0 and + description = "argument is negative" + or + functionWithDomainError = getMathVariants("log1p") and + RestrictedRangeAnalysis::upperBound(fc.getArgument(0)) < -1.0 and + description = "argument is less than 1" + or + functionWithDomainError = getMathVariants("fmod") and + exprMayEqualZero(fc.getArgument(1)) and + description = "y is 0" + ) +} + +abstract class PotentiallyNaNExpr extends Expr { + abstract string getReason(); +} + +class DomainErrorFunctionCall extends FunctionCall, PotentiallyNaNExpr { + string reason; + + DomainErrorFunctionCall() { + hasDomainError(this, reason) + } + + override string getReason() { result = reason } +} + // IEEE 754-1985 Section 7.1 invalid operations -class InvalidOperationExpr extends BinaryOperation { +class InvalidOperationExpr extends BinaryOperation, PotentiallyNaNExpr { string reason; InvalidOperationExpr() { @@ -85,7 +150,7 @@ class InvalidOperationExpr extends BinaryOperation { ) } - string getReason() { result = reason } + override string getReason() { result = reason } } module InvalidNaNUsage implements DataFlow::ConfigSig { @@ -104,7 +169,7 @@ module InvalidNaNUsage implements DataFlow::ConfigSig { * An expression which may produce a NaN output. */ additional predicate potentialSource(DataFlow::Node node) { - node.asExpr() instanceof InvalidOperationExpr + node.asExpr() instanceof PotentiallyNaNExpr } predicate isBarrierOut(DataFlow::Node node) { @@ -173,13 +238,14 @@ from InvalidNaNUsage usage, Expr sourceExpr, string sourceString, Element extra, string extraString where not InvalidNaNFlow::PathGraph::edges(_, source, _, _) and + not InvalidNaNFlow::PathGraph::edges(sink, _, _, _) and not sourceExpr.isFromTemplateInstantiation(_) and not usage.asExpr().isFromTemplateInstantiation(_) and elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and usage = sink.getNode() and sourceExpr = source.getNode().asExpr() and sourceString = - " (" + source.getNode().asExpr().(InvalidOperationExpr).getReason() + ")" and + " (" + source.getNode().asExpr().(PotentiallyNaNExpr).getReason() + ")" and InvalidNaNFlow::flow(source.getNode(), usage) and ( if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected index 75534df6a0..f1f08b5a51 100644 --- a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected @@ -21,6 +21,21 @@ edges | test.c:77:15:77:21 | ... / ... | test.c:114:16:114:23 | l12 | provenance | | | test.c:77:15:77:21 | ... / ... | test.c:117:23:117:30 | l12 | provenance | | | test.c:77:15:77:21 | ... / ... | test.c:120:20:120:27 | l12 | provenance | | +| test.c:175:22:175:22 | p | test.c:175:27:175:32 | p | provenance | | +| test.c:183:34:183:34 | p | test.c:185:13:185:18 | p | provenance | | +| test.c:189:32:189:32 | p | test.c:189:47:189:59 | ... + ... | provenance | Config | +| test.c:189:47:189:59 | ... + ... | test.c:175:22:175:22 | p | provenance | | +| test.c:189:47:189:59 | ... + ... | test.c:175:22:175:22 | p | provenance | | +| test.c:189:51:189:59 | ... / ... | test.c:189:47:189:59 | ... + ... | provenance | Config | +| test.c:193:13:194:15 | ... / ... | test.c:175:22:175:22 | p | provenance | | +| test.c:200:25:200:33 | ... / ... | test.c:183:34:183:34 | p | provenance | | +| test.c:204:19:204:27 | ... / ... | test.c:204:19:204:27 | ... / ... | provenance | | +| test.c:204:19:204:27 | ... / ... | test.c:206:21:206:31 | ... + ... | provenance | Config | +| test.c:206:21:206:31 | ... + ... | test.c:206:21:206:31 | ... + ... | provenance | | +| test.c:206:21:206:31 | ... + ... | test.c:208:13:208:21 | middleInf | provenance | | +| test.c:206:21:206:31 | ... + ... | test.c:210:23:210:31 | middleInf | provenance | | +| test.c:208:13:208:21 | middleInf | test.c:175:22:175:22 | p | provenance | | +| test.c:210:23:210:31 | middleInf | test.c:189:32:189:32 | p | provenance | | nodes | test.c:8:14:8:20 | ... / ... | semmle.label | ... / ... | | test.c:8:14:8:20 | ... / ... | semmle.label | ... / ... | @@ -51,29 +66,48 @@ nodes | test.c:114:16:114:23 | l12 | semmle.label | l12 | | test.c:117:23:117:30 | l12 | semmle.label | l12 | | test.c:120:20:120:27 | l12 | semmle.label | l12 | +| test.c:163:3:164:16 | ... / ... | semmle.label | ... / ... | +| test.c:175:22:175:22 | p | semmle.label | p | +| test.c:175:27:175:32 | p | semmle.label | p | +| test.c:183:34:183:34 | p | semmle.label | p | +| test.c:185:13:185:18 | p | semmle.label | p | +| test.c:189:32:189:32 | p | semmle.label | p | +| test.c:189:47:189:59 | ... + ... | semmle.label | ... + ... | +| test.c:189:47:189:59 | ... + ... | semmle.label | ... + ... | +| test.c:189:51:189:59 | ... / ... | semmle.label | ... / ... | +| test.c:193:13:194:15 | ... / ... | semmle.label | ... / ... | +| test.c:200:25:200:33 | ... / ... | semmle.label | ... / ... | +| test.c:204:19:204:27 | ... / ... | semmle.label | ... / ... | +| test.c:204:19:204:27 | ... / ... | semmle.label | ... / ... | +| test.c:206:21:206:31 | ... + ... | semmle.label | ... + ... | +| test.c:206:21:206:31 | ... + ... | semmle.label | ... + ... | +| test.c:208:13:208:21 | middleInf | semmle.label | middleInf | +| test.c:210:23:210:31 | middleInf | semmle.label | middleInf | subpaths #select -| test.c:12:8:12:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:12:8:12:9 | l2 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | -| test.c:13:8:13:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:13:8:13:9 | l3 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | -| test.c:13:8:13:9 | l3 | test.c:9:14:9:16 | - ... | test.c:13:8:13:9 | l3 | Invalid usage of possible $@. | test.c:9:14:9:16 | - ... | infinity | -| test.c:18:8:18:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:18:3:18:9 | l2 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | -| test.c:19:8:19:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:19:3:19:9 | l3 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | -| test.c:19:8:19:9 | l3 | test.c:9:14:9:16 | - ... | test.c:19:3:19:9 | l3 | Invalid usage of possible $@. | test.c:9:14:9:16 | - ... | infinity | -| test.c:27:19:27:20 | l2 | test.c:8:14:8:20 | ... / ... | test.c:27:19:27:20 | l2 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | -| test.c:28:19:28:20 | l3 | test.c:8:14:8:20 | ... / ... | test.c:28:19:28:20 | l3 | Invalid usage of possible $@. | test.c:8:14:8:20 | ... / ... | infinity | -| test.c:28:19:28:20 | l3 | test.c:9:14:9:16 | - ... | test.c:28:19:28:20 | l3 | Invalid usage of possible $@. | test.c:9:14:9:16 | - ... | infinity | -| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Invalid usage of possible $@. | test.c:31:14:32:15 | ... / ... | infinity | -| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Invalid usage of possible $@. | test.c:61:5:61:18 | ... / ... | infinity | -| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Invalid usage of possible $@. | test.c:66:5:66:20 | ... / ... | infinity | -| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Invalid usage of possible $@. | test.c:72:14:72:29 | ... / ... | infinity | -| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Invalid usage of possible $@. | test.c:75:18:75:33 | ... / ... | infinity | -| test.c:79:10:79:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:79:5:79:12 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | -| test.c:87:10:87:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:87:5:87:12 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | -| test.c:91:10:91:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:91:5:91:12 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | -| test.c:93:10:93:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:93:5:93:12 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | -| test.c:99:10:99:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:99:5:99:12 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | -| test.c:105:10:105:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:105:5:105:12 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | -| test.c:111:10:111:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:111:5:111:12 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | -| test.c:114:21:114:23 | l12 | test.c:77:15:77:21 | ... / ... | test.c:114:16:114:23 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | -| test.c:117:28:117:30 | l12 | test.c:77:15:77:21 | ... / ... | test.c:117:23:117:30 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | -| test.c:120:25:120:27 | l12 | test.c:77:15:77:21 | ... / ... | test.c:120:20:120:27 | l12 | Invalid usage of possible $@. | test.c:77:15:77:21 | ... / ... | infinity | +| test.c:12:8:12:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:12:8:12:9 | l2 | Division operation may silently underflow and produce zero, as the divisor $@. | test.c:8:14:8:20 | ... / ... | may be an infinite float value from division by zero | +| test.c:13:8:13:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:13:8:13:9 | l3 | Division operation may silently underflow and produce zero, as the divisor $@. | test.c:8:14:8:20 | ... / ... | may be an infinite float value from division by zero | +| test.c:18:8:18:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:18:3:18:9 | l2 | $@ casted to integer. | test.c:8:14:8:20 | ... / ... | Possibly infinite float value from division by zero | +| test.c:19:8:19:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:19:3:19:9 | l3 | $@ casted to integer. | test.c:8:14:8:20 | ... / ... | Possibly infinite float value from division by zero | +| test.c:27:19:27:20 | l2 | test.c:8:14:8:20 | ... / ... | test.c:27:19:27:20 | l2 | Division operation may silently underflow and produce zero, as the divisor $@. | test.c:8:14:8:20 | ... / ... | may be an infinite float value from division by zero | +| test.c:28:19:28:20 | l3 | test.c:8:14:8:20 | ... / ... | test.c:28:19:28:20 | l3 | Division operation may silently underflow and produce zero, as the divisor $@. | test.c:8:14:8:20 | ... / ... | may be an infinite float value from division by zero | +| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | $@ casted to integer. | test.c:31:14:32:15 | ... / ... | Possibly infinite float value from division by zero | +| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | $@ casted to integer. | test.c:61:11:61:17 | ... / ... | Possibly infinite float value from division by zero | +| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | $@ casted to integer. | test.c:66:11:66:19 | ... / ... | Possibly infinite float value from division by zero | +| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | $@ casted to integer. | test.c:72:20:72:28 | ... / ... | Possibly infinite float value from division by zero | +| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | $@ casted to integer. | test.c:75:24:75:32 | ... / ... | Possibly infinite float value from division by zero | +| test.c:79:10:79:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:79:5:79:12 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | +| test.c:87:10:87:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:87:5:87:12 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | +| test.c:91:10:91:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:91:5:91:12 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | +| test.c:93:10:93:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:93:5:93:12 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | +| test.c:99:10:99:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:99:5:99:12 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | +| test.c:105:10:105:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:105:5:105:12 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | +| test.c:111:10:111:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:111:5:111:12 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | +| test.c:114:21:114:23 | l12 | test.c:77:15:77:21 | ... / ... | test.c:114:16:114:23 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | +| test.c:117:28:117:30 | l12 | test.c:77:15:77:21 | ... / ... | test.c:117:23:117:30 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | +| test.c:120:25:120:27 | l12 | test.c:77:15:77:21 | ... / ... | test.c:120:20:120:27 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | +| test.c:163:9:164:15 | ... / ... | test.c:163:3:164:16 | ... / ... | test.c:163:3:164:16 | ... / ... | $@ casted to integer. | test.c:163:9:164:15 | ... / ... | Possibly infinite float value from division by zero | +| test.c:175:32:175:32 | p | test.c:189:51:189:59 | ... / ... | test.c:175:27:175:32 | p | $@ casted to integer. | test.c:189:6:189:24 | addInfThenCastToInt | Possibly infinite float value computed in function addInfThenCastToInt | +| test.c:175:32:175:32 | p | test.c:193:13:194:15 | ... / ... | test.c:175:27:175:32 | p | $@ casted to integer. | test.c:192:6:192:7 | f2 | Possibly infinite float value computed in function f2 | +| test.c:175:32:175:32 | p | test.c:204:19:204:27 | ... / ... | test.c:175:27:175:32 | p | $@ casted to integer. | test.c:192:6:192:7 | f2 | Possibly infinite float value computed in function f2 | +| test.c:185:18:185:18 | p | test.c:200:25:200:33 | ... / ... | test.c:185:13:185:18 | p | $@ casted to integer. | test.c:192:6:192:7 | f2 | Possibly infinite float value computed in function f2 | diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected index e59d43d867..e0047d9ef7 100644 --- a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected @@ -22,9 +22,27 @@ edges | test.c:122:15:122:21 | ... / ... | test.c:138:5:138:12 | l13 | provenance | | | test.c:122:15:122:21 | ... / ... | test.c:144:5:144:12 | l13 | provenance | | | test.c:122:15:122:21 | ... / ... | test.c:148:5:148:12 | l13 | provenance | | -| test.c:122:15:122:21 | ... / ... | test.c:154:20:154:27 | l13 | provenance | | -| test.c:122:15:122:21 | ... / ... | test.c:156:23:156:30 | l13 | provenance | | -| test.c:122:15:122:21 | ... / ... | test.c:157:16:157:23 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:155:20:155:27 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:157:23:157:30 | l13 | provenance | | +| test.c:122:15:122:21 | ... / ... | test.c:158:16:158:23 | l13 | provenance | | +| test.c:175:22:175:22 | p | test.c:175:27:175:32 | p | provenance | | +| test.c:183:34:183:34 | p | test.c:185:13:185:18 | p | provenance | | +| test.c:188:32:188:32 | p | test.c:188:47:188:51 | ... + ... | provenance | Config | +| test.c:188:47:188:51 | ... + ... | test.c:175:22:175:22 | p | provenance | | +| test.c:190:32:190:32 | p | test.c:190:47:190:59 | ... + ... | provenance | Config | +| test.c:190:47:190:59 | ... + ... | test.c:175:22:175:22 | p | provenance | | +| test.c:190:47:190:59 | ... + ... | test.c:175:22:175:22 | p | provenance | | +| test.c:190:51:190:59 | ... / ... | test.c:190:47:190:59 | ... + ... | provenance | Config | +| test.c:195:13:195:21 | ... / ... | test.c:175:22:175:22 | p | provenance | | +| test.c:199:23:199:31 | ... / ... | test.c:188:32:188:32 | p | provenance | | +| test.c:201:25:201:33 | ... / ... | test.c:183:34:183:34 | p | provenance | | +| test.c:205:19:205:27 | ... / ... | test.c:205:19:205:27 | ... / ... | provenance | | +| test.c:205:19:205:27 | ... / ... | test.c:207:21:207:31 | ... + ... | provenance | Config | +| test.c:207:21:207:31 | ... + ... | test.c:207:21:207:31 | ... + ... | provenance | | +| test.c:207:21:207:31 | ... + ... | test.c:209:13:209:21 | middleNaN | provenance | | +| test.c:207:21:207:31 | ... + ... | test.c:211:23:211:31 | middleNaN | provenance | | +| test.c:209:13:209:21 | middleNaN | test.c:175:22:175:22 | p | provenance | | +| test.c:211:23:211:31 | middleNaN | test.c:190:32:190:32 | p | provenance | | nodes | test.c:27:14:27:20 | ... / ... | semmle.label | ... / ... | | test.c:27:14:27:20 | ... / ... | semmle.label | ... / ... | @@ -58,33 +76,61 @@ nodes | test.c:138:5:138:12 | l13 | semmle.label | l13 | | test.c:144:5:144:12 | l13 | semmle.label | l13 | | test.c:148:5:148:12 | l13 | semmle.label | l13 | -| test.c:154:20:154:27 | l13 | semmle.label | l13 | -| test.c:156:23:156:30 | l13 | semmle.label | l13 | -| test.c:157:16:157:23 | l13 | semmle.label | l13 | +| test.c:155:20:155:27 | l13 | semmle.label | l13 | +| test.c:157:23:157:30 | l13 | semmle.label | l13 | +| test.c:158:16:158:23 | l13 | semmle.label | l13 | +| test.c:166:3:166:18 | call to pow | semmle.label | call to pow | +| test.c:171:3:171:15 | call to acos | semmle.label | call to acos | +| test.c:175:22:175:22 | p | semmle.label | p | +| test.c:175:27:175:32 | p | semmle.label | p | +| test.c:183:34:183:34 | p | semmle.label | p | +| test.c:185:13:185:18 | p | semmle.label | p | +| test.c:188:32:188:32 | p | semmle.label | p | +| test.c:188:47:188:51 | ... + ... | semmle.label | ... + ... | +| test.c:190:32:190:32 | p | semmle.label | p | +| test.c:190:47:190:59 | ... + ... | semmle.label | ... + ... | +| test.c:190:47:190:59 | ... + ... | semmle.label | ... + ... | +| test.c:190:51:190:59 | ... / ... | semmle.label | ... / ... | +| test.c:195:13:195:21 | ... / ... | semmle.label | ... / ... | +| test.c:199:23:199:31 | ... / ... | semmle.label | ... / ... | +| test.c:201:25:201:33 | ... / ... | semmle.label | ... / ... | +| test.c:205:19:205:27 | ... / ... | semmle.label | ... / ... | +| test.c:205:19:205:27 | ... / ... | semmle.label | ... / ... | +| test.c:207:21:207:31 | ... + ... | semmle.label | ... + ... | +| test.c:207:21:207:31 | ... + ... | semmle.label | ... + ... | +| test.c:209:13:209:21 | middleNaN | semmle.label | middleNaN | +| test.c:211:23:211:31 | middleNaN | semmle.label | middleNaN | subpaths #select -| test.c:36:8:36:9 | l5 | test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | -| test.c:37:8:37:9 | l6 | test.c:28:14:28:20 | ... / ... | test.c:37:3:37:9 | l6 | Invalid usage of possible $@. | test.c:28:14:28:20 | ... / ... | NaN resulting from possible division of infinity by infinity | -| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Invalid usage of possible $@. | test.c:31:14:32:15 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:39:8:39:9 | l8 | test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | Invalid usage of possible $@. | test.c:33:14:33:22 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:46:3:46:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:46:3:46:4 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | -| test.c:47:3:47:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:47:3:47:4 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | -| test.c:48:3:48:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:48:3:48:4 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | -| test.c:49:3:49:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:49:3:49:4 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | -| test.c:50:3:50:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:50:3:50:4 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | -| test.c:51:3:51:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:51:3:51:4 | l5 | Invalid usage of possible $@. | test.c:27:14:27:20 | ... / ... | NaN resulting from possible division of infinity by infinity | -| test.c:52:3:52:4 | l6 | test.c:28:14:28:20 | ... / ... | test.c:52:3:52:4 | l6 | Invalid usage of possible $@. | test.c:28:14:28:20 | ... / ... | NaN resulting from possible division of infinity by infinity | -| test.c:53:3:53:4 | l7 | test.c:31:14:32:15 | ... / ... | test.c:53:3:53:4 | l7 | Invalid usage of possible $@. | test.c:31:14:32:15 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:54:3:54:4 | l8 | test.c:33:14:33:22 | ... / ... | test.c:54:3:54:4 | l8 | Invalid usage of possible $@. | test.c:33:14:33:22 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Invalid usage of possible $@. | test.c:61:5:61:18 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Invalid usage of possible $@. | test.c:66:5:66:20 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Invalid usage of possible $@. | test.c:72:14:72:29 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Invalid usage of possible $@. | test.c:75:18:75:33 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:126:10:126:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:126:5:126:12 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:132:10:132:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:132:5:132:12 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:138:10:138:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:138:5:138:12 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:144:10:144:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:144:5:144:12 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:148:10:148:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:148:5:148:12 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:154:25:154:27 | l13 | test.c:122:15:122:21 | ... / ... | test.c:154:20:154:27 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:156:28:156:30 | l13 | test.c:122:15:122:21 | ... / ... | test.c:156:23:156:30 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | -| test.c:157:21:157:23 | l13 | test.c:122:15:122:21 | ... / ... | test.c:157:16:157:23 | l13 | Invalid usage of possible $@. | test.c:122:15:122:21 | ... / ... | NaN resulting from possible division of zero by zero | +| test.c:36:8:36:9 | l5 | test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | $@ casted to integer. | test.c:27:14:27:20 | ... / ... | Possibly NaN float value (from division of infinity by infinity) | +| test.c:37:8:37:9 | l6 | test.c:28:14:28:20 | ... / ... | test.c:37:3:37:9 | l6 | $@ casted to integer. | test.c:28:14:28:20 | ... / ... | Possibly NaN float value (from division of infinity by infinity) | +| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | $@ casted to integer. | test.c:31:14:32:15 | ... / ... | Possibly NaN float value (from division of zero by zero) | +| test.c:39:8:39:9 | l8 | test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | $@ casted to integer. | test.c:33:14:33:22 | ... / ... | Possibly NaN float value (from division of zero by zero) | +| test.c:46:3:46:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:46:3:46:4 | l5 | Comparison involving a $@, which always evaluates to false. | test.c:27:14:27:20 | ... / ... | possibly NaN float value (from division of infinity by infinity) | +| test.c:47:3:47:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:47:3:47:4 | l5 | Comparison involving a $@, which always evaluates to false. | test.c:27:14:27:20 | ... / ... | possibly NaN float value (from division of infinity by infinity) | +| test.c:48:3:48:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:48:3:48:4 | l5 | Comparison involving a $@, which always evaluates to false. | test.c:27:14:27:20 | ... / ... | possibly NaN float value (from division of infinity by infinity) | +| test.c:49:3:49:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:49:3:49:4 | l5 | Comparison involving a $@, which always evaluates to false. | test.c:27:14:27:20 | ... / ... | possibly NaN float value (from division of infinity by infinity) | +| test.c:50:3:50:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:50:3:50:4 | l5 | Comparison involving a $@, which always evaluates to false. | test.c:27:14:27:20 | ... / ... | possibly NaN float value (from division of infinity by infinity) | +| test.c:51:3:51:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:51:3:51:4 | l5 | Comparison involving a $@, which always evaluates to false. | test.c:27:14:27:20 | ... / ... | possibly NaN float value (from division of infinity by infinity) | +| test.c:52:3:52:4 | l6 | test.c:28:14:28:20 | ... / ... | test.c:52:3:52:4 | l6 | Comparison involving a $@, which always evaluates to false. | test.c:28:14:28:20 | ... / ... | possibly NaN float value (from division of infinity by infinity) | +| test.c:53:3:53:4 | l7 | test.c:31:14:32:15 | ... / ... | test.c:53:3:53:4 | l7 | Comparison involving a $@, which always evaluates to false. | test.c:31:14:32:15 | ... / ... | possibly NaN float value (from division of zero by zero) | +| test.c:54:3:54:4 | l8 | test.c:33:14:33:22 | ... / ... | test.c:54:3:54:4 | l8 | Comparison involving a $@, which always evaluates to false. | test.c:33:14:33:22 | ... / ... | possibly NaN float value (from division of zero by zero) | +| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | $@ casted to integer. | test.c:61:11:61:17 | ... / ... | Possibly NaN float value (from division of zero by zero) | +| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | $@ casted to integer. | test.c:66:11:66:19 | ... / ... | Possibly NaN float value (from division of zero by zero) | +| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | $@ casted to integer. | test.c:72:20:72:28 | ... / ... | Possibly NaN float value (from division of zero by zero) | +| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | $@ casted to integer. | test.c:75:24:75:32 | ... / ... | Possibly NaN float value (from division of zero by zero) | +| test.c:126:10:126:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:126:5:126:12 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | +| test.c:132:10:132:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:132:5:132:12 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | +| test.c:138:10:138:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:138:5:138:12 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | +| test.c:144:10:144:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:144:5:144:12 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | +| test.c:148:10:148:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:148:5:148:12 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | +| test.c:155:25:155:27 | l13 | test.c:122:15:122:21 | ... / ... | test.c:155:20:155:27 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | +| test.c:157:28:157:30 | l13 | test.c:122:15:122:21 | ... / ... | test.c:157:23:157:30 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | +| test.c:158:21:158:23 | l13 | test.c:122:15:122:21 | ... / ... | test.c:158:16:158:23 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | +| test.c:166:8:166:10 | call to pow | test.c:166:3:166:18 | call to pow | test.c:166:3:166:18 | call to pow | $@ casted to integer. | test.c:166:8:166:10 | call to pow | Possibly NaN float value (both arguments are equal to zero) | +| test.c:171:8:171:11 | call to acos | test.c:171:3:171:15 | call to acos | test.c:171:3:171:15 | call to acos | $@ casted to integer. | test.c:171:8:171:11 | call to acos | Possibly NaN float value (the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0)) | +| test.c:175:32:175:32 | p | test.c:190:51:190:59 | ... / ... | test.c:175:27:175:32 | p | $@ casted to integer. | test.c:190:6:190:24 | addNaNThenCastToInt | Possibly NaN float value (from division of zero by zero) computed in function addNaNThenCastToInt | +| test.c:175:32:175:32 | p | test.c:195:13:195:21 | ... / ... | test.c:175:27:175:32 | p | $@ casted to integer. | test.c:192:6:192:7 | f2 | Possibly NaN float value (from division of zero by zero) computed in function f2 | +| test.c:175:32:175:32 | p | test.c:199:23:199:31 | ... / ... | test.c:175:27:175:32 | p | $@ casted to integer. | test.c:192:6:192:7 | f2 | Possibly NaN float value (from division of zero by zero) computed in function f2 | +| test.c:175:32:175:32 | p | test.c:205:19:205:27 | ... / ... | test.c:175:27:175:32 | p | $@ casted to integer. | test.c:192:6:192:7 | f2 | Possibly NaN float value (from division of zero by zero) computed in function f2 | +| test.c:185:18:185:18 | p | test.c:201:25:201:33 | ... / ... | test.c:185:13:185:18 | p | $@ casted to integer. | test.c:192:6:192:7 | f2 | Possibly NaN float value (from division of zero by zero) computed in function f2 | diff --git a/c/misra/test/rules/DIR-4-15/test.c b/c/misra/test/rules/DIR-4-15/test.c index d0f9ab5418..e615d3447a 100644 --- a/c/misra/test/rules/DIR-4-15/test.c +++ b/c/misra/test/rules/DIR-4-15/test.c @@ -150,10 +150,63 @@ void f1(float p1) { (int)l13; // COMPLIANT: Guarded not to be NaN } - isinf(l13) ? (int)l13 : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use + isinf(l13) ? (int)l13 + : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use isinf(l13) ? 0 : (int)l13; // COMPLIANT: Check on wrong branch isfinite(l13) ? (int)l13 : 0; // COMPLIANT: Checked finite before use isfinite(l13) ? 0 : (int)l13; // NON_COMPLIANT: Checked on wrong branch - isnan(l13) ? (int)l13 : 0; // NON_COMPLIANT: Check on wrong branch - isnan(l13) ? 0 : (int)l13; // COMPLIANT: Checked not NaN before use + isnan(l13) ? (int)l13 : 0; // NON_COMPLIANT: Check on wrong branch + isnan(l13) ? 0 : (int)l13; // COMPLIANT: Checked not NaN before use + + (int)pow(2, p1); // NON_COMPLIANT: likely to be Infinity + (int)pow(2, sin(p1)); // COMPLIANT: not likely to be Infinity + (int)(1 / + sin(p1)); // NON_COMPLIANT: possible infinity from zero in denominator + (int)(1 / log(p1)); // COMPLIANT: not possibly zero in denominator + (int)pow(p1, p1); // NON_COMPLIANT: NaN if p1 is zero + if (p1 != 0) { + (int)pow(p1, p1); // COMPLIANT: p1 is not zero + } + + (int)acos(p1); // NON_COMPLIANT: NaN if p1 is not within -1..1 + (int)acos(cos(p1)); // COMPLIANT: cos(p1) is within -1..1 +} + +void castToInt(float p) { (int)p; } + +void checkBeforeCastToInt(float p) { + if (isfinite(p)) { + castToInt(p); + } +} + +void castToIntToFloatToInt(float p) { + // This should be reported as a violation, but not downstream from here. + castToInt((int)p); +} + +void addOneThenCastToInt(float p) { castToInt(p + 1); } +void addInfThenCastToInt(float p) { castToInt(p + 1.0 / 0.0); } +void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } + +void f2() { + castToInt(1.0 / + 0.0); // NON_COMPLIANT: Infinity flows to denominator in division + castToInt(0.0 / 0.0); // NON_COMPLIANT: NaN flows to denominator in division + checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT + addOneThenCastToInt(1.0 / 0.0); // NON_COMPLIANT[False negative] + addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(1.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(0.0 / 0.0); // NON_COMPLIANT + + // Check that during flow analysis, we only report the true root cause: + float rootInf = 1.0 / 0.0; + float rootNaN = 0.0 / 0.0; + float middleInf = rootInf + 1; + float middleNaN = rootNaN + 1; + castToInt(middleInf); // NON_COMPLIANT + castToInt(middleNaN); // NON_COMPLIANT + addInfThenCastToInt(middleInf); // NON_COMPLIANT + addNaNThenCastToInt(middleNaN); // NON_COMPLIANT } \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll index 8ae3c9c38b..0c98824dbf 100644 --- a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll +++ b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll @@ -84,7 +84,9 @@ module RestrictedRangeAnalysis { result = -256.0 or result = -32768.0 or result = -65536.0 or - result = max(float v | v = Util::typeLowerBound(t) or v = -largeValue()) + result = -largeValue() or + result = Util::typeLowerBound(t) + //result = max(float v | v = Util::typeLowerBound(t) or v = -largeValue()) } /** See comment for `wideningLowerBounds`, above. */ @@ -100,7 +102,9 @@ module RestrictedRangeAnalysis { result = 255.0 or result = 32767.0 or result = 65535.0 or - result = min(float v | v = Util::typeLowerBound(t) or v = largeValue()) + result = largeValue() or + result = Util::typeUpperBound(t) + //result = min(float v | v = Util::typeLowerBound(t) or v = largeValue()) } /** @@ -312,6 +316,196 @@ module RestrictedRangeAnalysis { ) } + bindingset[name] + Function getMathVariants(string name) { + result.hasGlobalOrStdName([name, name + "f", name + "l"]) + } + + /** + * New support added for mathematical functions that either monotonically increase, or decrease, + * or that have a known lower or upper bound. + * + * For instance, log(x) monotonically increases over x, and acos(x) monotonically decreases, + * while sin(x) has a known output range of -1 to 1. + * + * `pow` is especially common so minimal work is done to support that here as well. `pow(c, x)` + * monotonically increases or decreases over `x` if `c` is a constant, though the reverse is not + * true except in special cases. + */ + newtype TSupportedMathFunctionCall = + /* A monotonically increasing function call. `extra` is a constant for `pow(x, c)`. */ + TMonotonicIncrease(FunctionCall fc, Expr input, float extra) { + // Note: Codeql has no default implementation in codeql for exp2, atanh, acosh, asinh, or + // log1p so we haven't taken the time to support them yet. + fc.getTarget() = + getMathVariants(["log", "log2", "log10", "exp", "asin", "atan", "sinh", "sqrt"]) and + input = fc.getArgument(0) and + extra = 0.0 + or + // Notes: pow is monotonic if the base argument is constant, increasing if the base is greater + // than 1 or between -1 and 0, and decreasing otherwise. A constant power is monotonic over the + // base in the positive or negative domain, but distinguishing those separately can introduce + // non-monotonic recursion errors. + fc.getTarget() = getMathVariants("pow") and + extra = fc.getArgument(0).getValue().toFloat() and + ( + extra > 1.0 + or + extra < 0.0 and extra > -1.0 + ) and + input = fc.getArgument(1) + } or + /* A monotonically decreasing function call. `extra` is a constant for `pow(x, c)`. */ + TMonotonicDecrease(FunctionCall fc, Expr input, float extra) { + fc.getTarget() = getMathVariants(["acos"]) and + input = fc.getArgument(0) and + extra = 0.0 + or + fc.getTarget() = getMathVariants("pow") and + extra = fc.getArgument(0).getValue().toFloat() and + ( + extra < -1.0 + or + extra > 0.0 and extra < 1.0 + ) and + input = fc.getArgument(1) + } or + /* A non-mononotic function call with a known lower bound. */ + TNonMonotonicLowerBound(FunctionCall fc, float lb) { + fc.getTarget() = getMathVariants("cosh") and + lb = 1.0 + or + fc.getTarget() = getMathVariants(["cos", "sin"]) and + lb = -1.0 + } or + /* A non-mononotic function call with a known upper bound. */ + TNonMonotonicUpperBound(FunctionCall fc, float lb) { + fc.getTarget() = getMathVariants(["cos", "sin"]) and + lb = 1.0 + } + + /** + * A function call that is supported by range analysis. + */ + class SupportedFunctionCall extends TSupportedMathFunctionCall { + string toString() { + exists(FunctionCall fc | + this = TMonotonicIncrease(fc, _, _) and + result = "Monotonic increase " + fc.getTarget().getName() + or + this = TMonotonicDecrease(fc, _, _) and + result = "Monotonic decrease " + fc.getTarget().getName() + or + this = TNonMonotonicLowerBound(fc, _) and + result = "Nonmonotonic lower bound " + fc.getTarget().getName() + or + this = TNonMonotonicUpperBound(fc, _) and + result = "Nonmonotonic upper bound " + fc.getTarget().getName() + ) + } + + /** Get the function call node this algebraic type corresponds to. */ + FunctionCall getFunctionCall() { + this = TMonotonicIncrease(result, _, _) + or + this = TMonotonicDecrease(result, _, _) + or + this = TNonMonotonicLowerBound(result, _) + or + this = TNonMonotonicUpperBound(result, _) + } + + /** Get the function name (`sin`, `pow`, etc.) without the `l` or `f` suffix. */ + bindingset[this, result] + string getBaseFunctionName() { getMathVariants(result) = getFunctionCall().getTarget() } + + /** + * Compute a result bound based on an input value and an extra constant value. + * + * The functions `getUpperBound()` and `getLowerBound()` automatically handle the differences + * between monotonically increasing and decreasing functions, and provide the input value. The + * `extra` float exists to support `pow(x, c)` for the constant `c`, otherwise it is `0.0`. + */ + bindingset[value, extra, this] + float compute(float value, float extra) { + exists(string name | name = getBaseFunctionName() | + name = "log" and + result = value.log() + or + name = "log2" and + result = value.log2() + or + name = "log10" and + result = value.log10() + or + name = "exp" and + result = value.exp() + or + name = "asin" and + result = value.asin() + or + name = "atan" and + result = value.atan() + or + name = "acos" and + result = value.acos() + or + name = "sinh" and + result = value.sinh() + or + name = "sqrt" and + result = value.sqrt() + or + name = "pow" and + result = extra.pow(value) + ) + } + + /** + * Get the lower bound of this function, based on its fixed range (if it has one) or based on + * the lower or upper bound of its input, if it is a monotonically increasing or decreasing + * function. + */ + float getLowerBound() { + this = TNonMonotonicLowerBound(_, result) + or + exists(Expr expr, float bound, float extra | + ( + this = TMonotonicIncrease(_, expr, extra) and + bound = getFullyConvertedLowerBounds(expr) + or + this = TMonotonicDecrease(_, expr, extra) and + bound = getFullyConvertedUpperBounds(expr) + ) and + result = compute(bound, extra) + ) + } + + /** + * Get the lower bound of this function, based on its fixed range (if it has one) or based on + * the lower or upper bound of its input, if it is a monotonically increasing or decreasing + * function. + */ + float getUpperBound() { + this = TNonMonotonicUpperBound(_, result) + or + exists(Expr expr, float bound, float extra | + ( + this = TMonotonicIncrease(_, expr, extra) and + bound = getFullyConvertedUpperBounds(expr) + or + this = TMonotonicDecrease(_, expr, extra) and + bound = getFullyConvertedLowerBounds(expr) + ) and + result = compute(bound, extra) + ) + } + } + + predicate supportedMathFunction(FunctionCall fc) { + exists(SupportedFunctionCall sfc | sfc.getFunctionCall() = fc) + } + /** * Holds if `expr` is checked with a guard to not be zero. * @@ -371,6 +565,8 @@ module RestrictedRangeAnalysis { // dividesNonzeroByZero(e) e instanceof DivExpr // TODO: confirm this is OK or + supportedMathFunction(e) + or e instanceof MinExpr or e instanceof MaxExpr @@ -628,8 +824,9 @@ module RestrictedRangeAnalysis { */ int estimatedPhiCombinationsExpr(Expr expr) { if isRecursiveExpr(expr) - // Assume 10 values were computed to analyze recursive expressions. - then result = 10 + then + // Assume 10 values were computed to analyze recursive expressions. + result = 10 else ( exists(RangeSsaDefinition def, StackVariable v | expr = def.getAUse(v) | def.isPhiNode(v) and @@ -649,16 +846,17 @@ module RestrictedRangeAnalysis { ) or not expr instanceof BinaryOperation and - not exprDependsOnDef(expr, _, _) and result = 1 + not exprDependsOnDef(expr, _, _) and + result = 1 ) } /** * Recursively scan this def to see how many phi nodes it depends on. - * + * * If this def is a phi node, it sums its downstream cost and adds one to account for itself, - * which is not exactly correct. - * + * which is not exactly correct. + * * This def may also be a crement expression (not currently supported), or an assign expr * (currently not supported), or an unanalyzable expression which is the root of the recursion * and given a value of 1. @@ -666,8 +864,9 @@ module RestrictedRangeAnalysis { language[monotonicAggregates] int estimatedPhiCombinationsDef(RangeSsaDefinition def, StackVariable v) { if isRecursiveDef(def, v) - // Assume 10 values were computed to analyze recursive expressions. - then result = 10 + then + // Assume 10 values were computed to analyze recursive expressions. + result = 10 else ( if def.isPhiNode(v) then @@ -681,7 +880,9 @@ module RestrictedRangeAnalysis { ) ) else ( - exists(Expr expr | assignmentDef(def, v, expr) | result = estimatedPhiCombinationsExpr(expr)) + exists(Expr expr | assignmentDef(def, v, expr) | + result = estimatedPhiCombinationsExpr(expr) + ) or v = def.getAVariable() and not assignmentDef(def, v, _) and @@ -730,6 +931,17 @@ module RestrictedRangeAnalysis { phiDependsOnDef(def, v, _, _) } + predicate canBoundExpr(Expr e) { + exists(RangeSsaDefinition def, StackVariable v | e = def.getAUse(v) | + analyzableDef(def, v) + ) or + analyzableExpr(e) + or + exists(getGuardedUpperBound(e)) + or + lowerBoundFromGuard(e, _, _, _) + } + /** * Computes a normal form of `x` where -0.0 has changed to +0.0. This can be * needed on the lesser side of a floating-point comparison or on both sides of @@ -931,6 +1143,10 @@ module RestrictedRangeAnalysis { result = getFullyConvertedLowerBounds(div.getLeftOperand()) / 0 ) or + exists(SupportedFunctionCall sfc | sfc.getFunctionCall() = expr | + result = sfc.getLowerBound() + ) + or exists(MinExpr minExpr | expr = minExpr and // Return the union of the lower bounds from both children. @@ -1136,6 +1352,10 @@ module RestrictedRangeAnalysis { result = getFullyConvertedUpperBounds(div.getLeftOperand()) / 0 ) or + exists(SupportedFunctionCall sfc | sfc.getFunctionCall() = expr | + result = sfc.getUpperBound() + ) + or exists(MaxExpr maxExpr | expr = maxExpr and // Return the union of the upper bounds from both children. From 99e92cff45d595f15a033dd7e3559109050e436c Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 7 Feb 2025 04:31:30 -0800 Subject: [PATCH 230/628] formatting fixes --- .../PossibleMisuseOfUndetectedInfinity.ql | 14 +++-- .../DIR-4-15/PossibleMisuseOfUndetectedNaN.ql | 55 +++++++++---------- 2 files changed, 34 insertions(+), 35 deletions(-) diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql index 357a8fce71..61753c98a9 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql @@ -133,13 +133,15 @@ where ( if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() then - extraString = usage.getInfinityDescription() + " computed in function " + sourceExpr.getEnclosingFunction().getName() - and extra = sourceExpr.getEnclosingFunction() + extraString = + usage.getInfinityDescription() + " computed in function " + + sourceExpr.getEnclosingFunction().getName() and + extra = sourceExpr.getEnclosingFunction() else ( extra = sourceExpr and - if sourceExpr instanceof DivExpr - then extraString = usage.getInfinityDescription() + " from division by zero" - else extraString = usage.getInfinityDescription() + if sourceExpr instanceof DivExpr + then extraString = usage.getInfinityDescription() + " from division by zero" + else extraString = usage.getInfinityDescription() ) ) -select elem, source, sink, usage.getDescription(), extra, extraString \ No newline at end of file +select elem, source, sink, usage.getDescription(), extra, extraString diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql index f850cc3e55..701834ca3f 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql @@ -35,7 +35,8 @@ predicate hasDomainError(FunctionCall fc, string description) { ) and description = "the argument has a range " + RestrictedRangeAnalysis::lowerBound(fc.getArgument(0)) + "..." + - RestrictedRangeAnalysis::upperBound(fc.getArgument(0)) + " which is outside the domain of this function (-1.0...1.0)" + RestrictedRangeAnalysis::upperBound(fc.getArgument(0)) + + " which is outside the domain of this function (-1.0...1.0)" or functionWithDomainError = getMathVariants(["atan2", "pow"]) and ( @@ -81,9 +82,7 @@ abstract class PotentiallyNaNExpr extends Expr { class DomainErrorFunctionCall extends FunctionCall, PotentiallyNaNExpr { string reason; - DomainErrorFunctionCall() { - hasDomainError(this, reason) - } + DomainErrorFunctionCall() { hasDomainError(this, reason) } override string getReason() { result = reason } } @@ -203,25 +202,22 @@ class InvalidNaNUsage extends DataFlow::Node { string nanDescription; InvalidNaNUsage() { - // Case 1: NaNs shall not be compared, except to themselves - exists(ComparisonOperation cmp | - this.asExpr() = cmp.getAnOperand() and - not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand()) and - description = "Comparison involving a $@, which always evaluates to false." and - nanDescription = "possibly NaN float value" - ) - or - // Case 2: NaNs and infinities shall not be cast to integers - exists(Conversion c | - this.asExpr() = c.getUnconverted() and - c.getExpr().getType() instanceof FloatingPointType and - c.getType() instanceof IntegralType and - description = "$@ casted to integer." and - nanDescription = "Possibly NaN float value" - ) - //or - //// Case 4: Functions shall not return NaNs or infinities - //exists(ReturnStmt ret | node.asExpr() = ret.getExpr()) + // Case 1: NaNs shall not be compared, except to themselves + exists(ComparisonOperation cmp | + this.asExpr() = cmp.getAnOperand() and + not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand()) and + description = "Comparison involving a $@, which always evaluates to false." and + nanDescription = "possibly NaN float value" + ) + or + // Case 2: NaNs and infinities shall not be cast to integers + exists(Conversion c | + this.asExpr() = c.getUnconverted() and + c.getExpr().getType() instanceof FloatingPointType and + c.getType() instanceof IntegralType and + description = "$@ casted to integer." and + nanDescription = "Possibly NaN float value" + ) } string getDescription() { result = description } @@ -244,17 +240,18 @@ where elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and usage = sink.getNode() and sourceExpr = source.getNode().asExpr() and - sourceString = - " (" + source.getNode().asExpr().(PotentiallyNaNExpr).getReason() + ")" and + sourceString = " (" + source.getNode().asExpr().(PotentiallyNaNExpr).getReason() + ")" and InvalidNaNFlow::flow(source.getNode(), usage) and ( if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() then - extraString = usage.getNaNDescription() + sourceString + " computed in function " + sourceExpr.getEnclosingFunction().getName() - and extra = sourceExpr.getEnclosingFunction() + extraString = + usage.getNaNDescription() + sourceString + " computed in function " + + sourceExpr.getEnclosingFunction().getName() and + extra = sourceExpr.getEnclosingFunction() else ( extra = sourceExpr and - extraString = usage.getNaNDescription() + sourceString + extraString = usage.getNaNDescription() + sourceString ) ) -select elem, source, sink, usage.getDescription(), extra, extraString \ No newline at end of file +select elem, source, sink, usage.getDescription(), extra, extraString From c473ea0a98848fad8d40e2b292322decfdd4f755 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 7 Feb 2025 04:33:16 -0800 Subject: [PATCH 231/628] C formatting fix --- c/misra/test/rules/DIR-4-15/test.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/c/misra/test/rules/DIR-4-15/test.c b/c/misra/test/rules/DIR-4-15/test.c index e615d3447a..a827a7df97 100644 --- a/c/misra/test/rules/DIR-4-15/test.c +++ b/c/misra/test/rules/DIR-4-15/test.c @@ -162,8 +162,8 @@ void f1(float p1) { (int)pow(2, sin(p1)); // COMPLIANT: not likely to be Infinity (int)(1 / sin(p1)); // NON_COMPLIANT: possible infinity from zero in denominator - (int)(1 / log(p1)); // COMPLIANT: not possibly zero in denominator - (int)pow(p1, p1); // NON_COMPLIANT: NaN if p1 is zero + (int)(1 / log(p1)); // COMPLIANT: not possibly zero in denominator + (int)pow(p1, p1); // NON_COMPLIANT: NaN if p1 is zero if (p1 != 0) { (int)pow(p1, p1); // COMPLIANT: p1 is not zero } @@ -193,10 +193,10 @@ void f2() { castToInt(1.0 / 0.0); // NON_COMPLIANT: Infinity flows to denominator in division castToInt(0.0 / 0.0); // NON_COMPLIANT: NaN flows to denominator in division - checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT - checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT - addOneThenCastToInt(1.0 / 0.0); // NON_COMPLIANT[False negative] - addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT + checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT + addOneThenCastToInt(1.0 / 0.0); // NON_COMPLIANT[False negative] + addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT castToIntToFloatToInt(1.0 / 0.0); // NON_COMPLIANT castToIntToFloatToInt(0.0 / 0.0); // NON_COMPLIANT From c0e2020d70840f1f558ec567ef056cedb7687f7d Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 7 Feb 2025 04:34:58 -0800 Subject: [PATCH 232/628] Format range analysis qll --- .../src/codingstandards/cpp/RestrictedRangeAnalysis.qll | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll index 0c98824dbf..b81f113281 100644 --- a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll +++ b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll @@ -932,9 +932,8 @@ module RestrictedRangeAnalysis { } predicate canBoundExpr(Expr e) { - exists(RangeSsaDefinition def, StackVariable v | e = def.getAUse(v) | - analyzableDef(def, v) - ) or + exists(RangeSsaDefinition def, StackVariable v | e = def.getAUse(v) | analyzableDef(def, v)) + or analyzableExpr(e) or exists(getGuardedUpperBound(e)) From 09891b09d71ff26c6ac2a7e65bdc3442c6ec1f6a Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 7 Feb 2025 04:37:25 -0800 Subject: [PATCH 233/628] Remove changes to SimpleRangeAnalysisCustomizations.qll --- .../cpp/SimpleRangeAnalysisCustomizations.qll | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll b/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll index 2688452d28..5144f63dc2 100644 --- a/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll +++ b/cpp/common/src/codingstandards/cpp/SimpleRangeAnalysisCustomizations.qll @@ -14,45 +14,6 @@ import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils import experimental.semmle.code.cpp.rangeanalysis.extensions.ConstantBitwiseAndExprRange private import experimental.semmle.code.cpp.models.interfaces.SimpleRangeAnalysisExpr -// Disabled, causing performance issues in grpc: -/* -private class DivByConstantExpr extends SimpleRangeAnalysisExpr, DivExpr { - float quotient; - - DivByConstantExpr() { - quotient = evaluateConstantExpr(getRightOperand()) - } - - override predicate dependsOnChild(Expr e) { - e = getLeftOperand() - } - - override float getLowerBounds() { - exists(float numerator | - result = numerator / quotient and - if (quotient > 0) then - // x / y where and y is positive scales the UB/LB. - numerator = getFullyConvertedLowerBounds(getLeftOperand()) - else - // x / -y where and -y is negative will invert and scale the UB/LB. - numerator = getFullyConvertedUpperBounds(getLeftOperand()) - ) - } - - override float getUpperBounds() { - exists(float numerator | - result = numerator / quotient and - if (quotient > 0) then - // x / y where and y is positive scales the UB/LB. - numerator = getFullyConvertedUpperBounds(getLeftOperand()) - else - // x / -y where and -y is negative will invert and scale the UB/LB. - numerator = getFullyConvertedLowerBounds(getLeftOperand()) - ) - } -} - */ - /** * A range analysis extension that support bitwise `|` and `|=` where at least one operand is a * non-negative constant. From 2a0d6cb36c45deef89434d05eb942aabb21e62a4 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 7 Feb 2025 04:41:16 -0800 Subject: [PATCH 234/628] Set more accurate query metadata --- .../rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql | 4 ++-- .../src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql | 4 ++-- rule_packages/c/FloatingTypes2.json | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql index 61753c98a9..3d54b4f829 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql @@ -4,8 +4,8 @@ * @description Evaluation of floating-point expressions shall not lead to the undetected generation * of infinities. * @kind path-problem - * @precision high - * @problem.severity error + * @precision medium + * @problem.severity warning * @tags external/misra/id/dir-4-15 * correctness * external/misra/c/2012/amendment3 diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql index 701834ca3f..2835a454d9 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql @@ -4,8 +4,8 @@ * @description Evaluation of floating-point expressions shall not lead to the undetected generation * of NaNs. * @kind path-problem - * @precision high - * @problem.severity error + * @precision low + * @problem.severity warning * @tags external/misra/id/dir-4-15 * correctness * external/misra/c/2012/amendment3 diff --git a/rule_packages/c/FloatingTypes2.json b/rule_packages/c/FloatingTypes2.json index 152ead08d3..3f4771dcc6 100644 --- a/rule_packages/c/FloatingTypes2.json +++ b/rule_packages/c/FloatingTypes2.json @@ -9,8 +9,8 @@ "description": "Evaluation of floating-point expressions shall not lead to the undetected generation of infinities.", "kind": "path-problem", "name": "Evaluation of floating-point expressions shall not lead to the undetected generation of infinities", - "precision": "high", - "severity": "error", + "precision": "medium", + "severity": "warning", "short_name": "PossibleMisuseOfUndetectedInfinity", "tags": [ "correctness", @@ -21,8 +21,8 @@ "description": "Evaluation of floating-point expressions shall not lead to the undetected generation of NaNs.", "kind": "path-problem", "name": "Evaluation of floating-point expressions shall not lead to the undetected generation of NaNs", - "precision": "high", - "severity": "error", + "precision": "low", + "severity": "warning", "short_name": "PossibleMisuseOfUndetectedNaN", "tags": [ "correctness", From 4920e9ce6c8e18f1559715f46a9a812b8a91bea9 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Sat, 8 Feb 2025 23:02:59 +0000 Subject: [PATCH 235/628] Update change_notes/2025-02-06-a3-1-5-audit.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- change_notes/2025-02-06-a3-1-5-audit.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change_notes/2025-02-06-a3-1-5-audit.md b/change_notes/2025-02-06-a3-1-5-audit.md index 3aa0e6671b..1f56a25236 100644 --- a/change_notes/2025-02-06-a3-1-5-audit.md +++ b/change_notes/2025-02-06-a3-1-5-audit.md @@ -1,2 +1,2 @@ - - `A3-1-5` - `NonTrivalNonTemplateFunctionDefinedInsideClassDefinition.ql`: + - `A3-1-5` - `NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql`: - Mark this as an `audit` query. As a consequence, it will no longer be run as part of the default query suite for AUTOSAR. It can still be run as part of the `autosar-audit.qls` query suite. The query has been downgraded because the rule allows for functions to be declared in the class body if they were "intended" to be inlined, and that developer intention cannot be determined automatically from the code. \ No newline at end of file From 939ab7930b082d15900bfb823493be8923ceb6f5 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sat, 8 Feb 2025 23:07:59 +0000 Subject: [PATCH 236/628] A3-1-5: Move precision to low --- ...NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql | 2 +- cpp/autosar/test/rules/A3-1-5/test.cpp | 2 +- rule_packages/cpp/Classes.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/autosar/src/rules/A3-1-5/NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql b/cpp/autosar/src/rules/A3-1-5/NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql index 2edf73b6ee..9b250e487a 100644 --- a/cpp/autosar/src/rules/A3-1-5/NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql +++ b/cpp/autosar/src/rules/A3-1-5/NonTrivialNonTemplateFunctionDefinedInsideClassDefinition.ql @@ -4,7 +4,7 @@ * @description A function that is not either trivial, a template function, or a member of a * template class may not be defined within a class body. * @kind problem - * @precision very-high + * @precision low * @problem.severity recommendation * @tags external/autosar/id/a3-1-5 * external/autosar/audit diff --git a/cpp/autosar/test/rules/A3-1-5/test.cpp b/cpp/autosar/test/rules/A3-1-5/test.cpp index 1b2898bf63..e6db0d1190 100644 --- a/cpp/autosar/test/rules/A3-1-5/test.cpp +++ b/cpp/autosar/test/rules/A3-1-5/test.cpp @@ -188,4 +188,4 @@ int FooBar::f1(int a, int b) { // COMPLIANT not a trivial function ; ; } -} +} \ No newline at end of file diff --git a/rule_packages/cpp/Classes.json b/rule_packages/cpp/Classes.json index d76a9b3bc5..59eb9a0418 100644 --- a/rule_packages/cpp/Classes.json +++ b/rule_packages/cpp/Classes.json @@ -182,7 +182,7 @@ "description": "A function that is not either trivial, a template function, or a member of a template class may not be defined within a class body.", "kind": "problem", "name": "A function shall be defined with a class body if and only if it is intended to be inlined", - "precision": "very-high", + "precision": "low", "severity": "recommendation", "short_name": "NonTrivialNonTemplateFunctionDefinedInsideClassDefinition", "tags": [ From 80edc11f6fd64b48849d07a2674e342ffea12f63 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 9 Feb 2025 00:15:22 -0800 Subject: [PATCH 237/628] Address feedback on emergent language features --- amendments.csv | 2 +- ...024-12-12-lessen-emergent-language-feature-restrictions.md | 2 ++ cpp/common/src/codingstandards/cpp/Emergent.qll | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 change_notes/2024-12-12-lessen-emergent-language-feature-restrictions.md diff --git a/amendments.csv b/amendments.csv index 0f588b0e05..f153e68216 100644 --- a/amendments.csv +++ b/amendments.csv @@ -2,7 +2,7 @@ language,standard,amendment,rule_id,supportable,implementation_category,implemen c,MISRA-C-2012,Amendment3,DIR-4-6,Yes,Expand,Yes,Easy c,MISRA-C-2012,Amendment3,DIR-4-9,Yes,Refine,No,Easy c,MISRA-C-2012,Amendment3,DIR-4-11,Yes,Refine,No,Import -c,MISRA-C-2012,Amendment3,RULE-1-4,Yes,Replace,Yes,Easy +c,MISRA-C-2012,Amendment3,RULE-1-4,Yes,Replace,No,Easy c,MISRA-C-2012,Amendment3,RULE-10-1,Yes,Replace,Yes,Easy c,MISRA-C-2012,Amendment3,RULE-10-3,Yes,Refine,Yes,Easy c,MISRA-C-2012,Amendment3,RULE-10-4,Yes,Refine,Yes,Import diff --git a/change_notes/2024-12-12-lessen-emergent-language-feature-restrictions.md b/change_notes/2024-12-12-lessen-emergent-language-feature-restrictions.md new file mode 100644 index 0000000000..2893ba620b --- /dev/null +++ b/change_notes/2024-12-12-lessen-emergent-language-feature-restrictions.md @@ -0,0 +1,2 @@ + - `RULE-1-4` - `EmergentLanguageFeaturesUsed.ql`: + - Remove restrictions on `stdnoreturn.h`, `stdalign.h`. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Emergent.qll b/cpp/common/src/codingstandards/cpp/Emergent.qll index 30f1df58e4..f976da5f62 100644 --- a/cpp/common/src/codingstandards/cpp/Emergent.qll +++ b/cpp/common/src/codingstandards/cpp/Emergent.qll @@ -12,4 +12,8 @@ module C11 { getBody() = "1" } } + + class GenericMacro extends EmergentLanguageFeature, Macro { + GenericMacro() { getBody().indexOf("_Generic") = 0 } + } } From 57b4292b71fb46b76f239363ecc9eb9f35e54f96 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 9 Feb 2025 00:30:17 -0800 Subject: [PATCH 238/628] Revert deletion of stdatomic, threads, as emergent lanugage features --- amendments.csv | 2 +- .../src/codingstandards/cpp/Emergent.qll | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/amendments.csv b/amendments.csv index b64bb98f21..6049525515 100644 --- a/amendments.csv +++ b/amendments.csv @@ -24,7 +24,7 @@ c,MISRA-C-2012,Amendment4,RULE-8-9,Yes,Clarification,Yes,Import c,MISRA-C-2012,Amendment4,RULE-9-4,Yes,Clarification,Yes,Import c,MISRA-C-2012,Amendment4,RULE-10-1,Yes,Clarification,Yes,Import c,MISRA-C-2012,Amendment4,RULE-18-3,Yes,Clarification,Yes,Import -c,MISRA-C-2012,Amendment4,RULE-1-4,Yes,Replace,Yes,Easy +c,MISRA-C-2012,Amendment4,RULE-1-4,Yes,Replace,No,Easy c,MISRA-C-2012,Amendment4,RULE-9-1,Yes,Refine,No,Easy c,MISRA-C-2012,Amendment4,RULE-9-2,Yes,Refine,No,Import c,MISRA-C-2012,Corrigendum2,DIR-4-10,Yes,Clarification,Yes,Import diff --git a/cpp/common/src/codingstandards/cpp/Emergent.qll b/cpp/common/src/codingstandards/cpp/Emergent.qll index f976da5f62..506d024bc9 100644 --- a/cpp/common/src/codingstandards/cpp/Emergent.qll +++ b/cpp/common/src/codingstandards/cpp/Emergent.qll @@ -6,6 +6,24 @@ import cpp module C11 { abstract class EmergentLanguageFeature extends Element { } + class AtomicVariableSpecifier extends EmergentLanguageFeature, Variable { + AtomicVariableSpecifier() { + getType().(DerivedType).getBaseType*().getASpecifier().getName() = "atomic" + } + } + + class AtomicDeclaration extends EmergentLanguageFeature, Declaration { + AtomicDeclaration() { getASpecifier().getName() = "atomic" } + } + + class ThreadLocalDeclaration extends EmergentLanguageFeature, Declaration { + ThreadLocalDeclaration() { getASpecifier().getName() = "is_thread_local" } + } + + class EmergentHeader extends EmergentLanguageFeature, Include { + EmergentHeader() { getIncludedFile().getBaseName() = ["stdatomic.h", "threads.h"] } + } + class LibExt1Macro extends EmergentLanguageFeature, Macro { LibExt1Macro() { getName() = "__STDC_WANT_LIB_EXT1__" and From f473520127921c17de346387f921879ef39eb498 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 9 Feb 2025 00:36:56 -0800 Subject: [PATCH 239/628] Fix tests for rule-1-4 --- .../RULE-1-4/EmergentLanguageFeaturesUsed.expected | 7 +++++++ c/misra/test/rules/RULE-1-4/test.c | 14 +++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected b/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected index 3f63a6c26c..04c0e1bbd6 100644 --- a/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected +++ b/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected @@ -1 +1,8 @@ +| test.c:2:1:2:22 | #include | Usage of emergent language feature. | +| test.c:4:1:4:20 | #include | Usage of emergent language feature. | +| test.c:6:1:6:49 | #define MACRO(x) _Generic((x), int : 0, long : 1) | Usage of emergent language feature. | | test.c:7:1:7:32 | #define __STDC_WANT_LIB_EXT1__ 1 | Usage of emergent language feature. | +| test.c:12:26:12:40 | atomic_new_type | Usage of emergent language feature. | +| test.c:17:15:17:15 | i | Usage of emergent language feature. | +| test.c:24:27:24:28 | i3 | Usage of emergent language feature. | +| test.c:25:28:25:29 | i4 | Usage of emergent language feature. | diff --git a/c/misra/test/rules/RULE-1-4/test.c b/c/misra/test/rules/RULE-1-4/test.c index 8c1e44e6bd..106b29ef61 100644 --- a/c/misra/test/rules/RULE-1-4/test.c +++ b/c/misra/test/rules/RULE-1-4/test.c @@ -1,26 +1,26 @@ #include //COMPLIANT -#include //COMPLIANT +#include //NON-COMPLIANT #include //COMPLIANT -#include //COMPLIANT +#include //NON-COMPLIANT -#define MACRO(x) _Generic((x), int : 0, long : 1) // COMPLIANT +#define MACRO(x) _Generic((x), int : 0, long : 1) // NON-COMPLIANT #define __STDC_WANT_LIB_EXT1__ 1 // NON-COMPLIANT _Noreturn void f0(); // COMPLIANT typedef int new_type; // COMPLIANT -typedef _Atomic new_type atomic_new_type; // COMPLIANT +typedef _Atomic new_type atomic_new_type; // NON-COMPLIANT void f(int p) { int i0 = _Generic(p, int : 0, long : 1); // COMPLIANT - _Atomic int i; // COMPLIANT + _Atomic int i; // NON-COMPLIANT _Alignas(4) int i1; // COMPLIANT alignas(4) int i2; // COMPLIANT int a = _Alignof(int); // COMPLIANT int a1 = alignof(int); // COMPLIANT - static thread_local int i3; // COMPLIANT - static _Thread_local int i4; // COMPLIANT + static thread_local int i3; // NON-COMPLIANT + static _Thread_local int i4; // NON-COMPLIANT } \ No newline at end of file From 137329219c0e1c200f94f2bfe19e8c851636d24a Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 9 Feb 2025 00:38:27 -0800 Subject: [PATCH 240/628] s/NON-COMPLIANT/NON_COMPLIANT in rule-1-4 test.c --- c/misra/test/rules/RULE-1-4/test.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/c/misra/test/rules/RULE-1-4/test.c b/c/misra/test/rules/RULE-1-4/test.c index 106b29ef61..81d609f052 100644 --- a/c/misra/test/rules/RULE-1-4/test.c +++ b/c/misra/test/rules/RULE-1-4/test.c @@ -1,15 +1,15 @@ #include //COMPLIANT -#include //NON-COMPLIANT +#include //NON_COMPLIANT #include //COMPLIANT -#include //NON-COMPLIANT +#include //NON_COMPLIANT -#define MACRO(x) _Generic((x), int : 0, long : 1) // NON-COMPLIANT -#define __STDC_WANT_LIB_EXT1__ 1 // NON-COMPLIANT +#define MACRO(x) _Generic((x), int : 0, long : 1) // NON_COMPLIANT +#define __STDC_WANT_LIB_EXT1__ 1 // NON_COMPLIANT _Noreturn void f0(); // COMPLIANT typedef int new_type; // COMPLIANT -typedef _Atomic new_type atomic_new_type; // NON-COMPLIANT +typedef _Atomic new_type atomic_new_type; // NON_COMPLIANT void f(int p) { int i0 = _Generic(p, int : 0, long : 1); // COMPLIANT @@ -21,6 +21,6 @@ void f(int p) { int a = _Alignof(int); // COMPLIANT int a1 = alignof(int); // COMPLIANT - static thread_local int i3; // NON-COMPLIANT - static _Thread_local int i4; // NON-COMPLIANT + static thread_local int i3; // NON_COMPLIANT + static _Thread_local int i4; // NON_COMPLIANT } \ No newline at end of file From 42836526bb9953e0fb539f805988823612bc608d Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 10 Feb 2025 16:22:57 +0000 Subject: [PATCH 241/628] Deviations: Switch to new deviations format --- .../deviations/CodeIdentifierDeviation.qll | 37 ++++++++++++------ .../TypeLongDoubleUsed.expected | 6 +-- .../UnusedReturnValue.expected | 12 +++--- .../attribute_syntax.cpp | 17 ++++---- .../deviations/deviations_basic_test/main.cpp | 12 +++--- docs/user_manual.md | 39 ++++++++++--------- 6 files changed, 71 insertions(+), 52 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll index bd7100021a..731a04cfc7 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -1,14 +1,24 @@ /** - * A module for identifying comment markers in code that trigger deviations. + * A module for identifying in code markers in code that trigger deviations. * - * Each comment marker consists of a `code-identifier` with some optional annotations. A deviation will be applied to + * This module supports two different code identifier markers: + * - A C/C++ attribute based syntax + * - A comment-based format + * + * The C/C++ attribute based syntax uses the following format: + * ``` + * [[codeql::_deviation("code-identifier")]] + * ``` + * The deviation will be applied to the selected program element, and any syntactically nested children of that program element. + * + * For the comment format the marker consists of a `code-identifier` with some optional annotations. A deviation will be applied to * some range of lines in the file containing the comment based on the annotation. The supported marker annotation * formats are: * - `` - the deviation applies to results on the current line. - * - `[[codingstandards::deviation()]]` - same as above. - * - `[[codingstandards::deviation_next_line()]]` - this deviation applies to results on the next line. - * - `[[codingstandards::deviation_begin()]]` - marks the beginning of a range of lines where the deviation applies. - * - `[[codingstandards::deviation_end()]]` - marks the end of a range of lines where the deviation applies. + * - `codeql::_deviation()` - same as above. + * - `codeql::_deviation_next_line()` - this deviation applies to results on the next line. + * - `codeql::_deviation_begin()` - marks the beginning of a range of lines where the deviation applies. + * - `codeql::_deviation_end()` - marks the end of a range of lines where the deviation applies. * * The valid `code-identifier`s are specified in deviation records, which also specify the query whose results are * suppressed by the deviation. @@ -23,6 +33,8 @@ import cpp import Deviations +string supportedStandard() { result = ["misra", "autosar", "cert"] } + /** * Holds if the given comment contains the code identifier. */ @@ -67,7 +79,8 @@ abstract class CommentDeviationMarker extends Comment { */ class DeviationEndOfLineMarker extends CommentDeviationMarker { DeviationEndOfLineMarker() { - commentMatches(this, "[[codingstandards::deviation(" + record.getCodeIdentifier() + ")]]") + commentMatches(this, + "codeql::" + supportedStandard() + "_deviation(" + record.getCodeIdentifier() + ")") } } @@ -77,7 +90,7 @@ class DeviationEndOfLineMarker extends CommentDeviationMarker { class DeviationNextLineMarker extends CommentDeviationMarker { DeviationNextLineMarker() { commentMatches(this, - "[[codingstandards::deviation_next_line(" + record.getCodeIdentifier() + ")]]") + "codeql::" + supportedStandard() + "_deviation_next_line(" + record.getCodeIdentifier() + ")") } } @@ -91,7 +104,8 @@ abstract class CommentDeviationRangeMarker extends CommentDeviationMarker { } */ class DeviationBegin extends CommentDeviationRangeMarker { DeviationBegin() { - commentMatches(this, "[[codingstandards::deviation_begin(" + record.getCodeIdentifier() + ")]]") + commentMatches(this, + "codeql::" + supportedStandard() + "_deviation_begin(" + record.getCodeIdentifier() + ")") } } @@ -100,7 +114,8 @@ class DeviationBegin extends CommentDeviationRangeMarker { */ class DeviationEnd extends CommentDeviationRangeMarker { DeviationEnd() { - commentMatches(this, "[[codingstandards::deviation_end(" + record.getCodeIdentifier() + ")]]") + commentMatches(this, + "codeql::" + supportedStandard() + "_deviation_end(" + record.getCodeIdentifier() + ")") } } @@ -184,7 +199,7 @@ class DeviationAttribute extends StdAttribute { DeviationRecord record; DeviationAttribute() { - this.hasQualifiedName("codingstandards", "deviation") and + this.hasQualifiedName("codeql", supportedStandard() + "_deviation") and // Support multiple argument deviations "\"" + record.getCodeIdentifier() + "\"" = this.getAnArgument().getValueText() } diff --git a/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected b/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected index 99b3c89bfb..1786c4ce9e 100644 --- a/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected +++ b/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected @@ -1,7 +1,7 @@ | attribute_syntax.cpp:6:15:6:17 | dd1 | Use of long double type. | -| attribute_syntax.cpp:22:15:22:17 | d10 | Use of long double type. | -| attribute_syntax.cpp:30:15:30:17 | d14 | Use of long double type. | -| attribute_syntax.cpp:34:20:34:22 | d16 | Use of long double type. | +| attribute_syntax.cpp:21:15:21:17 | d10 | Use of long double type. | +| attribute_syntax.cpp:29:15:29:17 | d14 | Use of long double type. | +| attribute_syntax.cpp:33:20:33:22 | d16 | Use of long double type. | | main.cpp:13:15:13:16 | d1 | Use of long double type. | | main.cpp:18:15:18:16 | d4 | Use of long double type. | | main.cpp:21:15:21:16 | d6 | Use of long double type. | diff --git a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected index 7538df2195..8b258328ab 100644 --- a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected +++ b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected @@ -1,10 +1,10 @@ | attribute_syntax.cpp:5:3:5:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | -| attribute_syntax.cpp:17:5:17:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | -| attribute_syntax.cpp:19:5:19:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | -| attribute_syntax.cpp:25:5:25:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | -| attribute_syntax.cpp:27:5:27:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | -| attribute_syntax.cpp:31:3:31:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | -| attribute_syntax.cpp:42:3:42:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:16:5:16:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:18:5:18:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:24:5:24:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:26:5:26:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:30:3:30:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:41:3:41:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | | main.cpp:12:3:12:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | | main.cpp:25:3:25:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | | main.cpp:27:3:27:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | diff --git a/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp b/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp index 97b4ba987d..30acac3bfb 100644 --- a/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp +++ b/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp @@ -5,14 +5,13 @@ int alt() { getZ(); // NON_COMPLIANT long double dd1; // NON_COMPLIANT (A0-4-2) - long double [[codingstandards::deviation( - "a-0-4-2-deviation")]] dd3; // COMPLIANT[DEVIATED] - long double [[codingstandards::deviation("a")]] dd3a; // NON_COMPLIAT + long double [[codeql::autosar_deviation( + "a-0-4-2-deviation")]] dd3; // COMPLIANT[DEVIATED] - [[codingstandards::deviation( + [[codeql::autosar_deviation( "a-0-4-2-deviation")]] long double dd4; // COMPLIANT[DEVIATED] - [[codingstandards::deviation("a-0-4-2-deviation")]] { + [[codeql::autosar_deviation("a-0-4-2-deviation")]] { long double d7; // COMPLIANT[DEVIATED] getZ(); // NON_COMPLIANT (A0-1-2) long double d8; // COMPLIANT[DEVIATED] @@ -20,7 +19,7 @@ int alt() { long double d9; // COMPLIANT[DEVIATED] } long double d10; // NON_COMPLIANT (A0-4-2) - [[codingstandards::deviation("a-0-4-2-deviation")]] { + [[codeql::autosar_deviation("a-0-4-2-deviation")]] { long double d11; // COMPLIANT[DEVIATED] getZ(); // NON_COMPLIANT (A0-1-2) long double d12; // COMPLIANT[DEVIATED] @@ -29,16 +28,18 @@ int alt() { } long double d14; // NON_COMPLIANT (A0-4-2) getZ(); // NON_COMPLIANT (A0-1-2) - [[codingstandards::deviation("a-0-4-2-deviation")]] + [[codeql::autosar_deviation("a-0-4-2-deviation")]] for (long double d15 = 0.0; true;) {} // COMPLIANT[DEVIATED] for (long double d16 = 0.0; true;) { // NON_COMPLIANT (A0-4-2) } return 0; } -[[codingstandards::deviation("a-0-4-2-deviation")]] +[[codeql::autosar_deviation("a-0-4-2-deviation")]] int alt2() { int x = 0; // COMPLIANT[DEVIATED] getZ(); // NON_COMPLIANT long double dd1; // COMPLIANT[DEVIATED] + [[codeql::autosar_deviation( + "a-0-4-2-deviation")]] long double dd2; // COMPLIANT[DEVIATED] } \ No newline at end of file diff --git a/cpp/common/test/deviations/deviations_basic_test/main.cpp b/cpp/common/test/deviations/deviations_basic_test/main.cpp index e1faaec68c..aa389ed0ad 100644 --- a/cpp/common/test/deviations/deviations_basic_test/main.cpp +++ b/cpp/common/test/deviations/deviations_basic_test/main.cpp @@ -13,28 +13,28 @@ int main(int argc, char **argv) { long double d1; // NON_COMPLIANT (A0-4-2) long double d2; // a-0-4-2-deviation COMPLIANT[DEVIATED] - long double d3; // [[codingstandards::deviation(a-0-4-2-deviation)]] + long double d3; // codeql::autosar_deviation(a-0-4-2-deviation) // COMPLIANT[DEVIATED] long double d4; // NON_COMPLIANT (A0-4-2) - // [[codingstandards::deviation_next_line(a-0-4-2-deviation)]] + // codeql::autosar_deviation_next_line(a-0-4-2-deviation) long double d5; // COMPLIANT[DEVIATED] long double d6; // NON_COMPLIANT (A0-4-2) - // [[codingstandards::deviation_begin(a-0-4-2-deviation)]] + // codeql::autosar_deviation_begin(a-0-4-2-deviation) long double d7; // COMPLIANT[DEVIATED] getX(); // NON_COMPLIANT (A0-1-2) long double d8; // COMPLIANT[DEVIATED] getX(); // NON_COMPLIANT (A0-1-2) long double d9; // COMPLIANT[DEVIATED] - // [[codingstandards::deviation_end(a-0-4-2-deviation)]] + // codeql::autosar_deviation_end(a-0-4-2-deviation) long double d10; // NON_COMPLIANT (A0-4-2) - // [[codingstandards::deviation_begin(a-0-4-2-deviation)]] + // codeql::autosar_deviation_begin(a-0-4-2-deviation) long double d11; // COMPLIANT[DEVIATED] getX(); // NON_COMPLIANT (A0-1-2) long double d12; // COMPLIANT[DEVIATED] getX(); // NON_COMPLIANT (A0-1-2) long double d13; // COMPLIANT[DEVIATED] - // [[codingstandards::deviation_end(a-0-4-2-deviation)]] + // codeql::autosar_deviation_end(a-0-4-2-deviation) long double d14; // NON_COMPLIANT (A0-4-2) getX(); // NON_COMPLIANT (A0-1-2) return 0; diff --git a/docs/user_manual.md b/docs/user_manual.md index 5d2236ed10..34c675c4bc 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -426,10 +426,13 @@ The `process_coding_standards_config.py` has a dependency on the package `pyyaml A code identifier specified in a deviation record can be applied to certain results in the code by adding a C or C++ attribute of the following format: ``` -[[codingstandards::deviation("code-identifier")]] +[[codeql::_deviation("code-identifier")]] ``` +For example `[[codeql::misra_deviation("a1-2-4")]]` would apply a deviation of a rule in a MISRA standard, using the code identifier `a1-2-4`. The supported standard names are `misra`, `autosar` and `cert`. + This attribute may be added to the following program elements: + * Functions * Statements * Variables @@ -440,7 +443,7 @@ Deviation attributes are inherited from parents in the code structure. For examp Multiple code identifiers may be passed in a single attribute to apply multiple deviations, for example: ``` -[[codingstandards::deviation("code-identifier-1", "code-identifier-2")]] +[[codeql::misra_deviation("code-identifier-1", "code-identifier-2")]] ``` Note - considation should be taken to ensure the use of custom attributes for deviations is compatible with your chosen language version, compiler, compiler configuration and coding standard. @@ -461,10 +464,10 @@ If you cannot satisfy these condition, please use the deviation code identifier As an alternative to attributes, a code identifier specified in a deviation record can be applied to certain results in the code by adding a comment marker consisting of a `code-identifier` with some optional annotations. The supported marker annotation formats are: - `` - the deviation applies to results on the current line. - - `codingstandards::deviation()` - the deviation applies to results on the current line. - - `codingstandards::deviation_next_line()` - this deviation applies to results on the next line. - - `codingstandards::deviation_begin()` - marks the beginning of a range of lines where the deviation applies. - - `codingstandards::deviation_end()` - marks the end of a range of lines where the deviation applies. + - `codeql::_deviation()` - the deviation applies to results on the current line. + - `codeql::_deviation_next_line()` - this deviation applies to results on the next line. + - `codeql::_deviation_begin()` - marks the beginning of a range of lines where the deviation applies. + - `codeql::_deviation_end()` - marks the end of a range of lines where the deviation applies. Here are some examples, using the deviation record with the `a-0-4-2-deviation` code-identifier specified above: ```cpp @@ -473,32 +476,32 @@ Here are some examples, using the deviation record with the `a-0-4-2-deviation` long double x2; // a-0-4-2-deviation - COMPLIANT long double x3; // COMPLIANT - a-0-4-2-deviation - long double x4; // [[codingstandards::deviation(a-0-4-2-deviation)]] - COMPLIANT - long double x5; // COMPLIANT - [[codingstandards::deviation(a-0-4-2-deviation)]] + long double x4; // codeql::_deviation(a-0-4-2-deviation) - COMPLIANT + long double x5; // COMPLIANT - codeql::_deviation(a-0-4-2-deviation) - // [[codingstandards::deviation_next_line(a-0-4-2-deviation)]] + // codeql::_deviation_next_line(a-0-4-2-deviation) long double x6; // COMPLIANT - // [[codingstandards::deviation_begin(a-0-4-2-deviation)]] + // codeql::_deviation_begin(a-0-4-2-deviation) long double x7; // COMPLIANT - // [[codingstandards::deviation_end(a-0-4-2-deviation)]] + // codeql::_deviation_end(a-0-4-2-deviation) ``` -`codingstandards::deviation_end` markers will pair with the closest unmatched `codingstandards::deviation_begin` for the same `code-identifier`. Consider this example: +`codeql::_deviation_end` markers will pair with the closest unmatched `codeql::_deviation_begin` for the same `code-identifier`. Consider this example: ```cpp -1 | // [[codingstandards::deviation_begin(a-0-4-2-deviation)]] +1 | // codeql::_deviation_begin(a-0-4-2-deviation) 2 | -3 | // [[codingstandards::deviation_begin(a-0-4-2-deviation)]] +3 | // codeql::_deviation_begin(a-0-4-2-deviation) 4 | -5 | // [[codingstandards::deviation_end(a-0-4-2-deviation)]] +5 | // codeql::_deviation_end(a-0-4-2-deviation) 6 | -7 | // [[codingstandards::deviation_end(a-0-4-2-deviation)]] +7 | // codeql::_deviation_end(a-0-4-2-deviation) ``` Here, Line 1 will pair with Line 7, and Line 3 will pair with Line 8. -A `codingstandards::deviation_end` without a matching `codingstandards::deviation_begin`, or `codingstandards::deviation_begin` without a matching `codingstandards::deviation_end` is invalid and will be ignored. +A `codeql::_deviation_end` without a matching `codeql::_deviation_begin`, or `codeql::_deviation_begin` without a matching `codeql::_deviation_end` is invalid and will be ignored. -`codingstandards::deviation_begin` and `codingstandards::deviation_end` markers only apply within a single file. Markers cannot be paired across files, and deviations do not apply to included files. +`codeql::_deviation_begin` and `ccodeql::_deviation_end` markers only apply within a single file. Markers cannot be paired across files, and deviations do not apply to included files. Note: deviation markers cannot be applied to the body of a macro. Please apply the deviation to macro expansion, or use the attribute deviation format. From c65f635fc0740f45987f58a02dae5583b6bef2d3 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 10 Feb 2025 18:23:59 +0000 Subject: [PATCH 242/628] Remove deviation suppression query tests --- .../DeviationsSuppression.expected | 7 ------- .../deviations_report_deviated/DeviationsSuppression.qlref | 1 - 2 files changed, 8 deletions(-) delete mode 100644 cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected delete mode 100644 cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.qlref diff --git a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected deleted file mode 100644 index 50ceb35b9d..0000000000 --- a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected +++ /dev/null @@ -1,7 +0,0 @@ -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:12:1:12:58 | Deviation of cpp/autosar/type-long-double-used for comment // a-0-4-2-deviation COMPLIANT[DEVIATED]. | -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/unused-return-value] | lgtm[cpp/autosar/unused-return-value] | nested/nested2/test2.h:1:1:6:1 | Deviation of cpp/autosar/unused-return-value for nested/nested2/test2.h. | -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | coding-standards.xml:1:1:17:19 | Deviation of cpp/autosar/useless-assignment for coding-standards.xml. | -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | main.cpp:1:1:14:1 | Deviation of cpp/autosar/useless-assignment for main.cpp. | -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/coding-standards.xml:1:1:13:19 | Deviation of cpp/autosar/useless-assignment for nested/coding-standards.xml. | -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/nested2/test2.h:1:1:6:1 | Deviation of cpp/autosar/useless-assignment for nested/nested2/test2.h. | -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/test.h:1:1:6:1 | Deviation of cpp/autosar/useless-assignment for nested/test.h. | diff --git a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.qlref b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.qlref deleted file mode 100644 index 6268ee7342..0000000000 --- a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.qlref +++ /dev/null @@ -1 +0,0 @@ -codingstandards/cpp/deviations/DeviationsSuppression.ql \ No newline at end of file From e176bb10607c5321edf5facc6f99056d7164fe40 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 10 Feb 2025 21:19:34 +0000 Subject: [PATCH 243/628] Remove redundant import --- c/cert/src/rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql | 1 - 1 file changed, 1 deletion(-) diff --git a/c/cert/src/rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql b/c/cert/src/rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql index 4ae6619227..7974c4d601 100644 --- a/c/cert/src/rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql +++ b/c/cert/src/rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql @@ -15,7 +15,6 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Macro import codingstandards.cpp.SideEffect -import codingstandards.cpp.StructuralEquivalence import codingstandards.cpp.sideeffect.DefaultEffects import codingstandards.cpp.sideeffect.Customizations import semmle.code.cpp.valuenumbering.HashCons From 92f5d5b8ea4d37141200dc6b563c197e2bb1c5d4 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 10 Feb 2025 22:32:50 +0000 Subject: [PATCH 244/628] A5-1-9: Address param confusion The hash cons value for parameters was incorrectly calculated with parameter uses (e.g accesses to the parameter). The correct approach is to use the variable name and type. This caused performance issues, because the hash cons for a function was made up of all combinations of the accesses to the parameters. For lambdas with many parameters and many accesses, this was problematic. --- .../src/rules/A5-1-9/LambdaEquivalence.qll | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/cpp/autosar/src/rules/A5-1-9/LambdaEquivalence.qll b/cpp/autosar/src/rules/A5-1-9/LambdaEquivalence.qll index 040777e321..c9ea4a0fd8 100644 --- a/cpp/autosar/src/rules/A5-1-9/LambdaEquivalence.qll +++ b/cpp/autosar/src/rules/A5-1-9/LambdaEquivalence.qll @@ -211,7 +211,7 @@ private module HashCons { private newtype HC_Params = HC_NoParams() or - HC_ParamCons(HashConsExpr hc, int i, HC_Params list) { mk_ParamCons(hc, i, list, _) } + HC_ParamCons(Type t, string name, int i, HC_Params list) { mk_ParamCons(t, name, i, list, _) } /** * HashConsExpr is the hash-cons of an expression. The relationship between `Expr` @@ -1275,13 +1275,14 @@ private module HashCons { mk_DeclConsInner(_, _, s.getNumDeclarations() - 1, hc, s) } - private predicate mk_ParamCons(HashConsExpr hc, int i, HC_Params list, Function f) { - hc = hashConsExpr(f.getParameter(i).getAnAccess()) and - ( - exists(HashConsExpr head, HC_Params tail | - mk_ParamConsInner(head, tail, i - 1, list, f) and - i > 0 - ) + private predicate mk_ParamCons(Type t, string name, int i, HC_Params list, Function f) { + exists(Parameter p | + p = f.getParameter(i) and + t = p.getType() and + name = p.getName() + | + mk_ParamConsInner(_, _, _, i - 1, list, f) and + i > 0 or i = 0 and list = HC_NoParams() @@ -1289,10 +1290,10 @@ private module HashCons { } private predicate mk_ParamConsInner( - HashConsExpr head, HC_Params tail, int i, HC_Params list, Function f + Type t, string name, HC_Params tail, int i, HC_Params list, Function f ) { - list = HC_ParamCons(head, i, tail) and - mk_ParamCons(head, i, tail, f) + list = HC_ParamCons(t, name, i, tail) and + mk_ParamCons(t, name, i, tail, f) } private predicate mk_FunctionCons( @@ -1302,7 +1303,7 @@ private module HashCons { name = f.getName() and body = hashConsStmt(f.getBlock()) and if f.getNumberOfParameters() > 0 - then mk_ParamConsInner(_, _, f.getNumberOfParameters() - 1, params, f) + then mk_ParamConsInner(_, _, _, f.getNumberOfParameters() - 1, params, f) else params = HC_NoParams() } From a568b887fda9945a2f40984a2034a23e9438f829 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 10 Feb 2025 23:09:05 +0000 Subject: [PATCH 245/628] A5-1-9: Filter blocks to lambdas in hash cons calc Move the exclusion of non-lambda blocks to the calculation of HC_BlockStmt, to avoid generating newtype instances for non-lambda instances. --- .../src/rules/A5-1-9/LambdaEquivalence.qll | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/cpp/autosar/src/rules/A5-1-9/LambdaEquivalence.qll b/cpp/autosar/src/rules/A5-1-9/LambdaEquivalence.qll index c9ea4a0fd8..cab93608c5 100644 --- a/cpp/autosar/src/rules/A5-1-9/LambdaEquivalence.qll +++ b/cpp/autosar/src/rules/A5-1-9/LambdaEquivalence.qll @@ -624,11 +624,21 @@ private module HashCons { strictcount(access.getTarget()) = 1 } + /** + * Gets the name of a variable. + * + * Extracted for performance reasons, to avoid magic, which was causing performance issues in getParameter(int i). + */ + pragma[nomagic] + private string getVariableName(Variable v) { result = v.getName() } + /* Note: This changed from the original HashCons module to be able to find structural equivalent expression. */ private predicate mk_Variable(Type t, string name, VariableAccess access) { analyzableVariable(access) and exists(Variable v | - v = access.getTarget() and t = v.getUnspecifiedType() and name = v.getName() + v = access.getTarget() and + t = v.getUnspecifiedType() and + name = getVariableName(v) ) } @@ -1104,7 +1114,14 @@ private module HashCons { nee.getExpr().getFullyConverted() = child.getAnExpr() } - private predicate mk_StmtCons(HashConsStmt hc, int i, HC_Stmts list, BlockStmt block) { + private class LambdaBlockStmt extends BlockStmt { + LambdaBlockStmt() { + // Restricting to statements inside a lambda expressions. + this.getParentScope*() = any(LambdaExpression le).getLambdaFunction() + } + } + + private predicate mk_StmtCons(HashConsStmt hc, int i, HC_Stmts list, LambdaBlockStmt block) { hc = hashConsStmt(block.getStmt(i)) and ( exists(HashConsStmt head, HC_Stmts tail | @@ -1118,13 +1135,13 @@ private module HashCons { } private predicate mk_StmtConsInner( - HashConsStmt head, HC_Stmts tail, int i, HC_Stmts list, BlockStmt block + HashConsStmt head, HC_Stmts tail, int i, HC_Stmts list, LambdaBlockStmt block ) { list = HC_StmtCons(head, i, tail) and mk_StmtCons(head, i, tail, block) } - private predicate mk_BlockStmtCons(HC_Stmts hc, BlockStmt s) { + private predicate mk_BlockStmtCons(HC_Stmts hc, LambdaBlockStmt s) { if s.getNumStmt() > 0 then exists(HashConsStmt head, HC_Stmts tail | @@ -1487,8 +1504,6 @@ private module HashCons { cached HashConsStmt hashConsStmt(Stmt s) { - // Restricting to statements inside a lambda expressions. - s.getParentScope*() = any(LambdaExpression le).getLambdaFunction() and exists(HC_Stmts list | mk_BlockStmtCons(list, s) and result = HC_BlockStmt(list) From c1d45c3411d23501c205bea8c6a521426187b4b9 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 10 Feb 2025 23:49:13 +0000 Subject: [PATCH 246/628] A5-1-9: Exclude duplication through macros --- .../src/rules/A5-1-9/IdenticalLambdaExpressions.ql | 10 +++++++++- cpp/autosar/test/rules/A5-1-9/test.cpp | 8 +++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cpp/autosar/src/rules/A5-1-9/IdenticalLambdaExpressions.ql b/cpp/autosar/src/rules/A5-1-9/IdenticalLambdaExpressions.ql index 8717fd000e..1520955716 100644 --- a/cpp/autosar/src/rules/A5-1-9/IdenticalLambdaExpressions.ql +++ b/cpp/autosar/src/rules/A5-1-9/IdenticalLambdaExpressions.ql @@ -24,6 +24,14 @@ where not lambdaExpression = otherLambdaExpression and not lambdaExpression.isFromTemplateInstantiation(_) and not otherLambdaExpression.isFromTemplateInstantiation(_) and - getLambdaHashCons(lambdaExpression) = getLambdaHashCons(otherLambdaExpression) + getLambdaHashCons(lambdaExpression) = getLambdaHashCons(otherLambdaExpression) and + // Do not report lambdas produced by the same macro in different invocations + not exists(Macro m, MacroInvocation m1, MacroInvocation m2 | + m1 = m.getAnInvocation() and + m2 = m.getAnInvocation() and + not m1 = m2 and // Lambdas in the same macro can be reported + m1.getAnExpandedElement() = lambdaExpression and + m2.getAnExpandedElement() = otherLambdaExpression + ) select lambdaExpression, "Lambda expression is identical to $@ lambda expression.", otherLambdaExpression, "this" diff --git a/cpp/autosar/test/rules/A5-1-9/test.cpp b/cpp/autosar/test/rules/A5-1-9/test.cpp index 466cf14dfa..511be302a0 100644 --- a/cpp/autosar/test/rules/A5-1-9/test.cpp +++ b/cpp/autosar/test/rules/A5-1-9/test.cpp @@ -104,4 +104,10 @@ class Test_issue468 { LogError("Error"); LogFatal("Fatal"); } -}; \ No newline at end of file +}; + +#define MACRO() [](int i) -> int { return i + 3; } +void test_macros() { + MACRO(); // COMPLIANT + MACRO(); // COMPLIANT - no duplication +} \ No newline at end of file From 2d8beac88da84e404bddf654f53867934088b305 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 10 Feb 2025 23:52:18 +0000 Subject: [PATCH 247/628] Add change note --- change_notes/2025-02-10-improve-perf-a5-1-9.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change_notes/2025-02-10-improve-perf-a5-1-9.md diff --git a/change_notes/2025-02-10-improve-perf-a5-1-9.md b/change_notes/2025-02-10-improve-perf-a5-1-9.md new file mode 100644 index 0000000000..ae7ea6f240 --- /dev/null +++ b/change_notes/2025-02-10-improve-perf-a5-1-9.md @@ -0,0 +1,2 @@ + - `A5-1-9` - `IdenticalLambdaExpressions.ql`: + - Performance has been improved. \ No newline at end of file From 1bd7dab926f5c94f13c3685e240af3e41385d01c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 10 Feb 2025 23:53:26 +0000 Subject: [PATCH 248/628] Include fp update in change note --- change_notes/2025-02-10-improve-perf-a5-1-9.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/change_notes/2025-02-10-improve-perf-a5-1-9.md b/change_notes/2025-02-10-improve-perf-a5-1-9.md index ae7ea6f240..5d355bab49 100644 --- a/change_notes/2025-02-10-improve-perf-a5-1-9.md +++ b/change_notes/2025-02-10-improve-perf-a5-1-9.md @@ -1,2 +1,3 @@ - `A5-1-9` - `IdenticalLambdaExpressions.ql`: - - Performance has been improved. \ No newline at end of file + - Performance has been improved. + - False positives due to repeated invocation of macros containing lambdas have been excluded. \ No newline at end of file From 1ee79ac71f1858b054c65dd037c8cf9732ff1305 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 11 Feb 2025 23:45:03 +0000 Subject: [PATCH 249/628] A2-3-1: Address performance issue Address issue introduced in upgrade to 2.19.4. --- .../cpp/HardwareOrProtocolInterface.qll | 14 ++++++----- .../rules/A2-3-1/InvalidCharacterInComment.ql | 24 ++++++++++--------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/cpp/autosar/src/codingstandards/cpp/HardwareOrProtocolInterface.qll b/cpp/autosar/src/codingstandards/cpp/HardwareOrProtocolInterface.qll index d92a28e477..410fa1292f 100644 --- a/cpp/autosar/src/codingstandards/cpp/HardwareOrProtocolInterface.qll +++ b/cpp/autosar/src/codingstandards/cpp/HardwareOrProtocolInterface.qll @@ -3,14 +3,16 @@ import codingstandards.cpp.CommonTypes as CommonTypes abstract class HardwareOrProtocolInterfaceClass extends Class { } +class HardwareOrProtocolInterfaceComment extends Comment { + HardwareOrProtocolInterfaceComment() { + getContents().regexpMatch("(?m)^\\s*(//|\\*)\\s*@HardwareOrProtocolInterface\\s*$") + } +} + class AnnotatedHardwareOrProtocolInterfaceClass extends HardwareOrProtocolInterfaceClass { AnnotatedHardwareOrProtocolInterfaceClass() { - exists(Comment c, string contents | - c.getCommentedElement() = this.getADeclarationEntry() and - contents = - c.getContents() - .splitAt("\n") - .regexpFind("^\\s*(//|\\*)\\s*@HardwareOrProtocolInterface\\s*$", _, _) + exists(HardwareOrProtocolInterfaceComment c | + c.getCommentedElement() = this.getADeclarationEntry() ) } } diff --git a/cpp/autosar/src/rules/A2-3-1/InvalidCharacterInComment.ql b/cpp/autosar/src/rules/A2-3-1/InvalidCharacterInComment.ql index a3090003d3..fdcc74b115 100644 --- a/cpp/autosar/src/rules/A2-3-1/InvalidCharacterInComment.ql +++ b/cpp/autosar/src/rules/A2-3-1/InvalidCharacterInComment.ql @@ -18,21 +18,23 @@ import cpp import codingstandards.cpp.autosar -bindingset[s] -string getCharOutsideBasicSourceCharSet(string s) { - result = s.regexpFind("[\\u0000-\\u007f]", _, _) and - not result.regexpMatch("[\\p{Alnum}\\p{Space}_{}\\[\\]#()<>%:;.?*+-/^&|~!=,\\\\\"'@]") - or - result = s.regexpFind("[\\u00c0-\\u00df][\\u0080-\\u00bf]", _, _) - or - result = s.regexpFind("[\\u00e0-\\u00ef][\\u0080-\\u00bf]{2}", _, _) - or - result = s.regexpFind("[\\u00f0-\\u00f7][\\u0080-\\u00bf]{3}", _, _) +string getCharOutsideBasicSourceCharSet(Comment c) { + exists(string s | s = c.getContents() | + result = + s.regexpFind("(?![\\p{Alnum}\\p{Space}_{}\\[\\]#()<>%:;.?*+-/^&|~!=,\\\\\"'@])[\\u0000-\\u007f]", + _, _) + or + result = s.regexpFind("[\\u00c0-\\u00df][\\u0080-\\u00bf]", _, _) + or + result = s.regexpFind("[\\u00e0-\\u00ef][\\u0080-\\u00bf]{2}", _, _) + or + result = s.regexpFind("[\\u00f0-\\u00f7][\\u0080-\\u00bf]{3}", _, _) + ) } from Comment c, string ch where not isExcluded(c, NamingPackage::invalidCharacterInCommentQuery()) and - ch = getCharOutsideBasicSourceCharSet(c.getContents()) + ch = getCharOutsideBasicSourceCharSet(c) select c, "Comment uses the character '" + ch + "' that is outside the language basic character set." From cb4be0ff7e5b170556c4e0127828421861b9b1f4 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 11 Feb 2025 23:49:27 +0000 Subject: [PATCH 250/628] IsStrictlyWeak: Address performance issue --- .../OrderingPredicateMustBeStrictlyWeak.qll | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/orderingpredicatemustbestrictlyweak/OrderingPredicateMustBeStrictlyWeak.qll b/cpp/common/src/codingstandards/cpp/rules/orderingpredicatemustbestrictlyweak/OrderingPredicateMustBeStrictlyWeak.qll index aa4b646ec6..66563bb9ff 100644 --- a/cpp/common/src/codingstandards/cpp/rules/orderingpredicatemustbestrictlyweak/OrderingPredicateMustBeStrictlyWeak.qll +++ b/cpp/common/src/codingstandards/cpp/rules/orderingpredicatemustbestrictlyweak/OrderingPredicateMustBeStrictlyWeak.qll @@ -14,19 +14,19 @@ abstract class OrderingPredicateMustBeStrictlyWeakSharedQuery extends Query { } Query getQuery() { result instanceof OrderingPredicateMustBeStrictlyWeakSharedQuery } +class IsStrictlyWeaklyOrderedComment extends Comment { + IsStrictlyWeaklyOrderedComment() { + getContents().regexpMatch("(?m)^\\s*(//|\\*)\\s*@IsStrictlyWeaklyOrdered\\s*$") + } +} + /** * User annotated class indicating a comparator is axiomatically strictly weakly * ordering. */ class UserDefinedStrictlyWeakOrderingComparator extends Class { UserDefinedStrictlyWeakOrderingComparator() { - exists(Comment c, string contents | - c.getCommentedElement() = this.getADeclarationEntry() and - contents = - c.getContents() - .splitAt("\n") - .regexpFind("^\\s*(//|\\*)\\s*@IsStrictlyWeaklyOrdered\\s*$", _, _) - ) + exists(IsStrictlyWeaklyOrderedComment c | c.getCommentedElement() = this.getADeclarationEntry()) } } From f56fa0f05bac0c78f1816a6cee4948eeea5b2bb5 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 12 Feb 2025 23:48:55 +0000 Subject: [PATCH 251/628] Detect invalid deviation markers --- .../deviations/CodeIdentifierDeviation.qll | 29 +++++++++++++-- .../InvalidDeviationCodeIdentifier.md | 19 ++++++++++ .../InvalidDeviationCodeIdentifier.ql | 35 +++++++++++++++++++ .../InvalidDeviationCodeIdentifier.expected | 10 ++++++ .../InvalidDeviationCodeIdentifier.qlref | 1 + .../invalid_deviations/coding-standards.xml | 5 +++ .../invalid_deviations/coding-standards.yml | 3 ++ .../deviations/invalid_deviations/dummy.cpp | 1 - .../invalidcodeidentifiers.cpp | 22 ++++++++++++ 9 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.md create mode 100644 cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.ql create mode 100644 cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.expected create mode 100644 cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.qlref delete mode 100644 cpp/common/test/deviations/invalid_deviations/dummy.cpp create mode 100644 cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll index 731a04cfc7..8c55cc9428 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -74,6 +74,16 @@ abstract class CommentDeviationMarker extends Comment { DeviationRecord getRecord() { result = record } } +/** + * A deviation marker in a comment that is not a valid deviation marker. + */ +class InvalidCommentDeviationMarker extends Comment { + InvalidCommentDeviationMarker() { + not this instanceof CommentDeviationMarker and + commentMatches(this, "codeql::" + supportedStandard() + "_deviation") + } +} + /** * A deviation marker for a deviation that applies to the current line. */ @@ -182,9 +192,7 @@ private class BeginStack extends TBeginStack { } } -private predicate isDeviationRangePaired( - DeviationRecord record, DeviationBegin begin, DeviationEnd end -) { +predicate isDeviationRangePaired(DeviationRecord record, DeviationBegin begin, DeviationEnd end) { exists(File file, int index | record = end.getRecord() and hasDeviationCommentFileOrdering(record, end, file, index) and @@ -226,6 +234,21 @@ class DeviationAttribute extends StdAttribute { } } +/** + * A deviation attribute that is not associated with any deviation record. + */ +class InvalidDeviationAttribute extends StdAttribute { + string unknownCodeIdentifier; + + InvalidDeviationAttribute() { + this.hasQualifiedName("codeql", supportedStandard() + "_deviation") and + "\"" + unknownCodeIdentifier + "\"" = this.getAnArgument().getValueText() and + not exists(DeviationRecord record | record.getCodeIdentifier() = unknownCodeIdentifier) + } + + string getAnUnknownCodeIdentifier() { result = unknownCodeIdentifier } +} + newtype TCodeIndentifierDeviation = TSingleLineDeviation(DeviationRecord record, Comment comment, string filepath, int suppressedLine) { ( diff --git a/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.md b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.md new file mode 100644 index 0000000000..9c128bab2d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.md @@ -0,0 +1,19 @@ +# Invalid deviation dode identifier + +## Overview + +Invalid deviation markers in code have no effect on the results but may indicate confusion over which results will be suppressed. + +Deviation code markers are used to suppress CodeQL Coding Standards results, following the process specified in the "MISRA Compliance 2020" document. There are a range of different deviation markers, with specific syntactic requirements. If those syntactic requirements are not met, the marker is invalid and will not be applied, which is likely contrary to developer expectations. + +## Recommendation + +Ensure the following requirements are met: + + * All `codeql::_deviation_begin(..)` markers are paired with a matching `codeql::_deviation_end(..)` marker. + * All instances of `codeql::_deviation` in comments are correctly formatted comment markers, and reference a `code-identifier`s that is specified in a deviation record included in the analysis. + * All deviation attributes reference `code-identifier`s that are specified in a deviation record included in the analysis. + +## References + +* [MISRA Compliance 2020 document - Chapter 4.2 (page 12) - Deviations](https://www.misra.org.uk/app/uploads/2021/06/MISRA-Compliance-2020.pdf) \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.ql b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.ql new file mode 100644 index 0000000000..03e1ffc2b0 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.ql @@ -0,0 +1,35 @@ +/** + * @id cpp/coding-standards/invalid-deviation-code-identifiers + * @name Invalid deviation code identifiers + * @description Deviation code identifiers must be valid. + * @kind problem + * @problem.severity error + */ + +import cpp +import CodeIdentifierDeviation + +predicate deviationCodeIdentifierError(Element e, string message) { + exists(DeviationEnd end | + e = end and + not isDeviationRangePaired(_, _, end) and + message = "Deviation end block is unmatched." + ) + or + exists(InvalidDeviationAttribute b | + e = b and + message = + "Deviation attribute references unknown code identifier " + b.getAnUnknownCodeIdentifier() + + "." + ) + or + exists(InvalidCommentDeviationMarker m | + e = m and + message = + "Deviation marker does not match an expected format, or references an unknown code identifier." + ) +} + +from Element e, string message +where deviationCodeIdentifierError(e, message) +select e, message diff --git a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.expected b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.expected new file mode 100644 index 0000000000..eb81658007 --- /dev/null +++ b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.expected @@ -0,0 +1,10 @@ +| invalidcodeidentifiers.cpp:1:1:1:45 | // codeql::misra_deviation(x) - invalid, no x | Deviation marker does not match an expected format, or references an unknown code identifier. | +| invalidcodeidentifiers.cpp:2:1:2:47 | // codeql::autosar_deviation(x) - invalid, no x | Deviation marker does not match an expected format, or references an unknown code identifier. | +| invalidcodeidentifiers.cpp:3:1:3:44 | // codeql::cert_deviation(x) - invalid, no x | Deviation marker does not match an expected format, or references an unknown code identifier. | +| invalidcodeidentifiers.cpp:4:1:4:71 | // codeql::misra_deviation_next(a-0-4-2-deviation) - invalid, next_line | Deviation marker does not match an expected format, or references an unknown code identifier. | +| invalidcodeidentifiers.cpp:5:1:5:73 | // codeql::autosar_deviation_next(a-0-4-2-deviation) - invalid, next_line | Deviation marker does not match an expected format, or references an unknown code identifier. | +| invalidcodeidentifiers.cpp:6:1:6:70 | // codeql::cert_deviation_next(a-0-4-2-deviation) - invalid, next_line | Deviation marker does not match an expected format, or references an unknown code identifier. | +| invalidcodeidentifiers.cpp:14:1:14:74 | // codeql::misra_deviation_end(a-0-4-2-deviation) - invalid, unmatched end | Deviation end block is unmatched. | +| invalidcodeidentifiers.cpp:15:1:15:76 | // codeql::autosar_deviation_end(a-0-4-2-deviation) - invalid, unmatched end | Deviation end block is unmatched. | +| invalidcodeidentifiers.cpp:16:1:16:73 | // codeql::cert_deviation_end(a-0-4-2-deviation) - invalid, unmatched end | Deviation end block is unmatched. | +| invalidcodeidentifiers.cpp:18:3:18:25 | misra_deviation | Deviation attribute references unknown code identifier x. | diff --git a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.qlref b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.qlref new file mode 100644 index 0000000000..c70989966f --- /dev/null +++ b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.qlref @@ -0,0 +1 @@ +codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.ql \ No newline at end of file diff --git a/cpp/common/test/deviations/invalid_deviations/coding-standards.xml b/cpp/common/test/deviations/invalid_deviations/coding-standards.xml index 179227a13d..2b5d798b35 100644 --- a/cpp/common/test/deviations/invalid_deviations/coding-standards.xml +++ b/cpp/common/test/deviations/invalid_deviations/coding-standards.xml @@ -86,6 +86,11 @@ RULE-13-6 c/misra/sizeof-operand-with-side-effect + + A0-4-2 + long double is required for interaction with third-party libraries. + a-0-4-2-deviation + diff --git a/cpp/common/test/deviations/invalid_deviations/coding-standards.yml b/cpp/common/test/deviations/invalid_deviations/coding-standards.yml index 7b12c7a8c2..679ef8a31e 100644 --- a/cpp/common/test/deviations/invalid_deviations/coding-standards.yml +++ b/cpp/common/test/deviations/invalid_deviations/coding-standards.yml @@ -46,6 +46,9 @@ deviations: - permit-id: DP2 - rule-id: RULE-13-6 query-id: c/misra/sizeof-operand-with-side-effect + - rule-id: A0-4-2 + justification: long double is required for interaction with third-party libraries. + code-identifier: a-0-4-2-deviation deviation-permits: - permit-id: DP1 justification: foo bar baz diff --git a/cpp/common/test/deviations/invalid_deviations/dummy.cpp b/cpp/common/test/deviations/invalid_deviations/dummy.cpp deleted file mode 100644 index 4a3cb36e40..0000000000 --- a/cpp/common/test/deviations/invalid_deviations/dummy.cpp +++ /dev/null @@ -1 +0,0 @@ -// Deliberately blank \ No newline at end of file diff --git a/cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp b/cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp new file mode 100644 index 0000000000..714c83d264 --- /dev/null +++ b/cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp @@ -0,0 +1,22 @@ +// codeql::misra_deviation(x) - invalid, no x +// codeql::autosar_deviation(x) - invalid, no x +// codeql::cert_deviation(x) - invalid, no x +// codeql::misra_deviation_next(a-0-4-2-deviation) - invalid, next_line +// codeql::autosar_deviation_next(a-0-4-2-deviation) - invalid, next_line +// codeql::cert_deviation_next(a-0-4-2-deviation) - invalid, next_line + +// codeql::misra_deviation_begin(a-0-4-2-deviation) +// codeql::autosar_deviation_begin(a-0-4-2-deviation) +// codeql::cert_deviation_begin(a-0-4-2-deviation) +// codeql::misra_deviation_end(a-0-4-2-deviation) +// codeql::autosar_deviation_end(a-0-4-2-deviation) +// codeql::cert_deviation_end(a-0-4-2-deviation) +// codeql::misra_deviation_end(a-0-4-2-deviation) - invalid, unmatched end +// codeql::autosar_deviation_end(a-0-4-2-deviation) - invalid, unmatched end +// codeql::cert_deviation_end(a-0-4-2-deviation) - invalid, unmatched end + +[[codeql::misra_deviation("x")]] // invalid +void test() {} + +[[codeql::autosar_deviation("a-0-4-2-deviation")]] +void test2() {} From ef3104aa1dc91dadf938ffd0c01944df347dec89 Mon Sep 17 00:00:00 2001 From: Fernando Jose Date: Thu, 13 Feb 2025 18:11:51 +0900 Subject: [PATCH 252/628] Fix #718. Use % in string::matches to accept any sequence of characters after the group comment ending ///@}. --- change_notes/2025-02-13-fix-issue-718.md | 2 ++ .../src/rules/A2-7-3/UndocumentedUserDefinedType.ql | 2 +- cpp/autosar/test/rules/A2-7-3/test.cpp | 10 ++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 change_notes/2025-02-13-fix-issue-718.md diff --git a/change_notes/2025-02-13-fix-issue-718.md b/change_notes/2025-02-13-fix-issue-718.md new file mode 100644 index 0000000000..39e499d583 --- /dev/null +++ b/change_notes/2025-02-13-fix-issue-718.md @@ -0,0 +1,2 @@ +- `A2-7-3` - `UndocumentedUserDefinedType.ql` + - Fixes #718. Include trailing characters after group comment endings with ///@{ ... ///@}. diff --git a/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql b/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql index b38cf7d02c..f2dd0dc8bc 100644 --- a/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql +++ b/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql @@ -28,7 +28,7 @@ private predicate isInFunctionScope(Declaration d) { private string doxygenCommentGroupStrings(boolean opening) { opening = true and result = ["///@{", "/**@{*/"] or - opening = false and result = ["///@}", "/**@}*/"] + opening = false and result = ["///@}%", "/**@}*/"] } pragma[inline] diff --git a/cpp/autosar/test/rules/A2-7-3/test.cpp b/cpp/autosar/test/rules/A2-7-3/test.cpp index 01f7bad611..c062da4ee9 100644 --- a/cpp/autosar/test/rules/A2-7-3/test.cpp +++ b/cpp/autosar/test/rules/A2-7-3/test.cpp @@ -225,4 +225,14 @@ class ClassG2 { // COMPLIANT class ClassG3 { // COMPLIANT public: friend int foo3() { return 1; } // NON_COMPLIANT +}; + +/// @brief A Doxygen comment. +class ClassH { // COMPLIANT +public: + /// @brief Group with comment at the end. + ///@{ + void m(); // COMPLIANT + void n(); // COMPLIANT + ///@} End of group }; \ No newline at end of file From 5a6d7ca84f2dd1f00be7380d1800c095bc4a7439 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 13 Feb 2025 11:24:29 +0000 Subject: [PATCH 253/628] Deviations: Support attribute inheritence Attributes are inherited from their parent. Includes support for features which are not currently enabled, due to lack of support in CodeQL itself. --- .../deviations/CodeIdentifierDeviation.qll | 15 +++++++ .../TypeLongDoubleUsed.expected | 3 ++ .../UnusedReturnValue.expected | 2 + .../attribute_syntax.cpp | 39 +++++++++++++++++-- docs/user_manual.md | 5 +-- 5 files changed, 57 insertions(+), 7 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll index 8c55cc9428..2a2d0eec15 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -231,6 +231,21 @@ class DeviationAttribute extends StdAttribute { result.(Stmt).getEnclosingFunction() = this.getASuppressedElement() or result.(LocalVariable) = this.getASuppressedElement().(DeclStmt).getADeclaration() + or + result.(Function).getDeclaringType() = this.getASuppressedElement() + or + result.(Variable).getDeclaringType() = this.getASuppressedElement() + or + exists(LambdaExpression expr | + expr = this.getASuppressedElement() and + result = expr.getLambdaFunction() + ) + or + exists(Function f | + f = this.getASuppressedElement() and + // A suppression on the function should apply to the noexcept expression + result = f.getADeclarationEntry().getNoExceptExpr() + ) } } diff --git a/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected b/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected index 1786c4ce9e..172b623195 100644 --- a/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected +++ b/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected @@ -2,6 +2,9 @@ | attribute_syntax.cpp:21:15:21:17 | d10 | Use of long double type. | | attribute_syntax.cpp:29:15:29:17 | d14 | Use of long double type. | | attribute_syntax.cpp:33:20:33:22 | d16 | Use of long double type. | +| attribute_syntax.cpp:55:15:55:16 | d1 | Use of long double type. | +| attribute_syntax.cpp:57:17:57:18 | d2 | Use of long double type. | +| attribute_syntax.cpp:60:17:60:18 | d3 | Use of long double type. | | main.cpp:13:15:13:16 | d1 | Use of long double type. | | main.cpp:18:15:18:16 | d4 | Use of long double type. | | main.cpp:21:15:21:16 | d6 | Use of long double type. | diff --git a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected index 8b258328ab..120337ffdc 100644 --- a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected +++ b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected @@ -5,6 +5,8 @@ | attribute_syntax.cpp:26:5:26:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | | attribute_syntax.cpp:30:3:30:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | | attribute_syntax.cpp:41:3:41:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:49:5:49:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:61:5:61:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | | main.cpp:12:3:12:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | | main.cpp:25:3:25:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | | main.cpp:27:3:27:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | diff --git a/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp b/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp index 30acac3bfb..12a21e9673 100644 --- a/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp +++ b/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp @@ -36,10 +36,41 @@ int alt() { } [[codeql::autosar_deviation("a-0-4-2-deviation")]] -int alt2() { +int test_function_deviation() { int x = 0; // COMPLIANT[DEVIATED] getZ(); // NON_COMPLIANT long double dd1; // COMPLIANT[DEVIATED] - [[codeql::autosar_deviation( - "a-0-4-2-deviation")]] long double dd2; // COMPLIANT[DEVIATED] -} \ No newline at end of file +} + +[[codeql::autosar_deviation("a-0-4-2-deviation")]] +void test_lambdas() { + auto l = []() { + long double d4; // COMPLIANT[DEVIATED] + getZ(); // NON_COMPLIANT + }; +} + +// Attributes are not supported on a class level at the moment +[[codeql::autosar_deviation("a-0-4-2-deviation")]] class ClassA { + long double d1; // COMPLIANT[DEVIATED - false positive] + class ClassNested { + long double d2; // COMPLIANT[DEVIATED - false positive] + }; + void test() { + long double d3; // COMPLIANT[DEVIATED - false positive] + getZ(); // NON_COMPLIANT + } +}; + +// static_assert, templates, noexcept, multiple declarations + +// Namespaces not currently supported by attributes +// [[codeql::autosar_deviation("a-0-4-2-deviation")]] namespace NS { +// long double d1; // COMPLIANT[DEVIATED] +// class ClassA { +// long double d1; // COMPLIANT[DEVIATED] +// }; +// void test() { +// long double d1; // COMPLIANT[DEVIATED] +// } +// } \ No newline at end of file diff --git a/docs/user_manual.md b/docs/user_manual.md index 9b58764eb8..a9b119f0da 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -446,9 +446,8 @@ This attribute may be added to the following program elements: * Functions * Statements * Variables - * Type declarations -Deviation attributes are inherited from parents in the code structure. For example, a deviation attribute applied to a function will apply the deviation to all code within the function. Note: deviations are not inherited by lambda expressions. +Deviation attributes are inherited from parents in the code structure. For example, a deviation attribute applied to a function will apply the deviation to all code within the function. Multiple code identifiers may be passed in a single attribute to apply multiple deviations, for example: @@ -507,7 +506,7 @@ Here are some examples, using the deviation record with the `a-0-4-2-deviation` 6 | 7 | // codeql::_deviation_end(a-0-4-2-deviation) ``` -Here, Line 1 will pair with Line 7, and Line 3 will pair with Line 8. +Here, Line 1 will pair with Line 7, and Line 3 will pair with Line 5. A `codeql::_deviation_end` without a matching `codeql::_deviation_begin`, or `codeql::_deviation_begin` without a matching `codeql::_deviation_end` is invalid and will be ignored. From e38e416dc60edcd4093146984c777f58fdfa7ffe Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 13 Feb 2025 11:30:50 +0000 Subject: [PATCH 254/628] Reformatting test file --- .../deviations_basic_test/attribute_syntax.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp b/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp index 12a21e9673..e363de55af 100644 --- a/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp +++ b/cpp/common/test/deviations/deviations_basic_test/attribute_syntax.cpp @@ -28,22 +28,22 @@ int alt() { } long double d14; // NON_COMPLIANT (A0-4-2) getZ(); // NON_COMPLIANT (A0-1-2) - [[codeql::autosar_deviation("a-0-4-2-deviation")]] - for (long double d15 = 0.0; true;) {} // COMPLIANT[DEVIATED] - for (long double d16 = 0.0; true;) { // NON_COMPLIANT (A0-4-2) + [[codeql::autosar_deviation("a-0-4-2-deviation")]] for (long double d15 = 0.0; + true;) { + } // COMPLIANT[DEVIATED] + for (long double d16 = 0.0; true;) { // NON_COMPLIANT (A0-4-2) } return 0; } -[[codeql::autosar_deviation("a-0-4-2-deviation")]] -int test_function_deviation() { +[[codeql::autosar_deviation("a-0-4-2-deviation")]] int +test_function_deviation() { int x = 0; // COMPLIANT[DEVIATED] getZ(); // NON_COMPLIANT long double dd1; // COMPLIANT[DEVIATED] } -[[codeql::autosar_deviation("a-0-4-2-deviation")]] -void test_lambdas() { +[[codeql::autosar_deviation("a-0-4-2-deviation")]] void test_lambdas() { auto l = []() { long double d4; // COMPLIANT[DEVIATED] getZ(); // NON_COMPLIANT From 9f35565b83aae672819b16a30b709de7a11de89d Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 13 Feb 2025 11:37:36 +0000 Subject: [PATCH 255/628] Add change note, update manual. --- change_notes/2025-02-13-deviations.md | 13 +++++++++++++ docs/user_manual.md | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 change_notes/2025-02-13-deviations.md diff --git a/change_notes/2025-02-13-deviations.md b/change_notes/2025-02-13-deviations.md new file mode 100644 index 0000000000..fb01cdf596 --- /dev/null +++ b/change_notes/2025-02-13-deviations.md @@ -0,0 +1,13 @@ + - A new in code deviation format has been introduced, using the C/C++ attribute syntax: + ``` + [[codeql::_deviation("")]] + ``` + This can be applied to functions, statements and variables to apply a deviation from the Coding Standards configuration file. The user manual has been updated to describe the new format. + - For those codebases that cannot use standard attributes, we have also introduced a comment based syntax + ``` + // codeql::_deviation() + // codeql::_deviation_next_line() + // codeql::_deviation_begin() + // codeql::_deviation_end() + ``` + Further information is available in the user manual. \ No newline at end of file diff --git a/docs/user_manual.md b/docs/user_manual.md index a9b119f0da..8bbb900682 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -439,7 +439,7 @@ A code identifier specified in a deviation record can be applied to certain resu [[codeql::_deviation("code-identifier")]] ``` -For example `[[codeql::misra_deviation("a1-2-4")]]` would apply a deviation of a rule in a MISRA standard, using the code identifier `a1-2-4`. The supported standard names are `misra`, `autosar` and `cert`. +For example `[[codeql::autosar_deviation("a1-2-4")]]` would apply a deviation of a rule in the AUTOSAR standard, using the code identifier `a1-2-4`. The supported standard names are `misra`, `autosar` and `cert`. This attribute may be added to the following program elements: From d2f8670f4e2ae6d1e625a19dd867b3f2be876765 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 13 Feb 2025 11:40:56 +0000 Subject: [PATCH 256/628] Reformat file --- .../deviations/invalid_deviations/invalidcodeidentifiers.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp b/cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp index 714c83d264..07a12eb713 100644 --- a/cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp +++ b/cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp @@ -18,5 +18,4 @@ [[codeql::misra_deviation("x")]] // invalid void test() {} -[[codeql::autosar_deviation("a-0-4-2-deviation")]] -void test2() {} +[[codeql::autosar_deviation("a-0-4-2-deviation")]] void test2() {} From 0de32d39b093d59e6f3c857cd39cdb5cd91224bd Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 13 Feb 2025 15:15:35 +0000 Subject: [PATCH 257/628] Update expected results --- .../invalid_deviations/InvalidDeviationPermits.expected | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationPermits.expected b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationPermits.expected index 609d517c05..4378fdf11d 100644 --- a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationPermits.expected +++ b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationPermits.expected @@ -1,2 +1,2 @@ -| coding-standards.xml:100:7:103:33 | deviation-permits-entry | coding-standards.xml: Deviation permit does not specify a permit identifier. | -| coding-standards.xml:104:7:107:33 | deviation-permits-entry | coding-standards.xml: Deviation permit specifies unknown property `invalid-property`. | +| coding-standards.xml:105:7:108:33 | deviation-permits-entry | coding-standards.xml: Deviation permit does not specify a permit identifier. | +| coding-standards.xml:109:7:112:33 | deviation-permits-entry | coding-standards.xml: Deviation permit specifies unknown property `invalid-property`. | From 3b1ee2edb14d8e8a4eb6dc2ea30a2ec29c8a9b8d Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 14 Feb 2025 18:55:46 -0800 Subject: [PATCH 258/628] Fix test expectations --- ...riateThreadObjectStorageDurations.expected | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected b/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected index 085083228b..503a01bdad 100644 --- a/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected +++ b/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected @@ -1,16 +1,16 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:31,14-22) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:33,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:35,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:38,45-53) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:48,33-41) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:48,58-66) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:49,42-50) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:30,14-22) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:32,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:34,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:37,45-53) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:47,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:47,58-66) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:48,42-50) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:51,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:51,34-42) WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:52,9-17) WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:52,34-42) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:53,9-17) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:53,34-42) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:38,9-22) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:48,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:37,9-22) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:47,7-20) | test.c:23:3:23:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:23:24:23:29 | & ... | Shared object | | test.c:74:3:74:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:74:24:74:24 | p | Shared object | | test.c:85:3:85:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:85:24:85:24 | p | Shared object | From 3882e8754fc578874b1c77cd524f580807d1d179 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 14 Feb 2025 21:29:38 -0800 Subject: [PATCH 259/628] Address feedback --- .../TimedlockOnInappropriateMutexType.ql | 4 +- .../RULE-9-7/UninitializedAtomicObject.ql | 21 ++-- ...TimedlockOnInappropriateMutexType.expected | 16 +-- .../UninitializedAtomicObject.expected | 7 +- c/misra/test/rules/RULE-9-7/test.c | 12 ++ .../cpp/StdFunctionOrMacro.qll | 111 ++++++++++++++++++ rule_packages/c/Concurrency7.json | 6 +- 7 files changed, 155 insertions(+), 22 deletions(-) create mode 100644 cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll diff --git a/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql b/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql index e6dda61d79..4401d06e2c 100644 --- a/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql +++ b/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql @@ -71,4 +71,6 @@ where not isExcluded(sink.getNode().asExpr(), Concurrency7Package::timedlockOnInappropriateMutexTypeQuery()) and Flow::flowPath(source, sink) -select sink.getNode(), source, sink, "Call to mtx_timedlock with mutex not of type 'mtx_timed'." +select sink.getNode(), source, sink, + "Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'.", + source.getNode(), "initialized" diff --git a/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql b/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql index 006e8e8178..b6e8bc82bc 100644 --- a/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql +++ b/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql @@ -14,6 +14,7 @@ import cpp import codingstandards.c.misra +import codingstandards.cpp.StdFunctionOrMacro import semmle.code.cpp.controlflow.Dominance class ThreadSpawningFunction extends Function { @@ -29,18 +30,14 @@ class ThreadSpawningFunction extends Function { } } -class AtomicInitAddressOfExpr extends FunctionCall { - Expr addressedExpr; +private string atomicInit() { result = "atomic_init" } +class AtomicInitAddressOfExpr extends AddressOfExpr { AtomicInitAddressOfExpr() { - exists(AddressOfExpr addrOf | - getArgument(0) = addrOf and - addrOf.getOperand() = addressedExpr and - getTarget().getName() = "__c11_atomic_init" + exists(StdFunctionOrMacro::Call c | + this = c.getArgument(0) ) } - - Expr getAddressedExpr() { result = addressedExpr } } ControlFlowNode getARequiredInitializationPoint(LocalScopeVariable v) { @@ -66,9 +63,15 @@ where not exists(v.getInitializer()) and exists(ControlFlowNode missingInitPoint | missingInitPoint = getARequiredInitializationPoint(v) and + // Check for `atomic_init(&v)` not exists(AtomicInitAddressOfExpr initialization | - initialization.getAddressedExpr().(VariableAccess).getTarget() = v and + initialization.getOperand().(VariableAccess).getTarget() = v and dominates(initialization, missingInitPoint) + ) and + // Check for `unknown_func(&v)` which may call `atomic_init` on `v`. + not exists(FunctionCall fc | + fc.getAnArgument().(AddressOfExpr).getOperand().(VariableAccess).getTarget() = v and + dominates(fc, missingInitPoint) ) ) select decl, diff --git a/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.expected b/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.expected index 442f20bf73..0a4c0a496a 100644 --- a/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.expected +++ b/c/misra/test/rules/RULE-21-26/TimedlockOnInappropriateMutexType.expected @@ -35,11 +35,11 @@ nodes | test.c:44:15:44:16 | *l3 [m] | semmle.label | *l3 [m] | subpaths #select -| test.c:10:43:10:43 | *m | test.c:13:12:13:14 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | -| test.c:10:43:10:43 | *m | test.c:17:12:17:14 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | -| test.c:10:43:10:43 | *m | test.c:30:12:30:14 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | -| test.c:10:43:10:43 | *m | test.c:42:12:42:16 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | -| test.c:14:17:14:19 | *& ... | test.c:13:12:13:14 | mtx_init output argument | test.c:14:17:14:19 | *& ... | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | -| test.c:18:17:18:19 | *& ... | test.c:17:12:17:14 | mtx_init output argument | test.c:18:17:18:19 | *& ... | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | -| test.c:31:17:31:19 | *& ... | test.c:30:12:30:14 | mtx_init output argument | test.c:31:17:31:19 | *& ... | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | -| test.c:43:17:43:21 | *& ... | test.c:42:12:42:16 | mtx_init output argument | test.c:43:17:43:21 | *& ... | Call to mtx_timedlock with mutex not of type 'mtx_timed'. | +| test.c:10:43:10:43 | *m | test.c:13:12:13:14 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:13:12:13:14 | mtx_init output argument | initialized | +| test.c:10:43:10:43 | *m | test.c:17:12:17:14 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:17:12:17:14 | mtx_init output argument | initialized | +| test.c:10:43:10:43 | *m | test.c:30:12:30:14 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:30:12:30:14 | mtx_init output argument | initialized | +| test.c:10:43:10:43 | *m | test.c:42:12:42:16 | mtx_init output argument | test.c:10:43:10:43 | *m | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:42:12:42:16 | mtx_init output argument | initialized | +| test.c:14:17:14:19 | *& ... | test.c:13:12:13:14 | mtx_init output argument | test.c:14:17:14:19 | *& ... | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:13:12:13:14 | mtx_init output argument | initialized | +| test.c:18:17:18:19 | *& ... | test.c:17:12:17:14 | mtx_init output argument | test.c:18:17:18:19 | *& ... | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:17:12:17:14 | mtx_init output argument | initialized | +| test.c:31:17:31:19 | *& ... | test.c:30:12:30:14 | mtx_init output argument | test.c:31:17:31:19 | *& ... | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:30:12:30:14 | mtx_init output argument | initialized | +| test.c:43:17:43:21 | *& ... | test.c:42:12:42:16 | mtx_init output argument | test.c:43:17:43:21 | *& ... | Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'. | test.c:42:12:42:16 | mtx_init output argument | initialized | diff --git a/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.expected b/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.expected index 89facda9bb..f96fc6aa13 100644 --- a/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.expected +++ b/c/misra/test/rules/RULE-9-7/UninitializedAtomicObject.expected @@ -1,3 +1,4 @@ -| test.c:22:15:22:16 | definition of l3 | Atomic object 'l3' has no initializer or corresponding use of 'atomic_init()'. | -| test.c:25:15:25:16 | definition of l4 | Atomic object 'l4' has no initializer or corresponding use of 'atomic_init()'. | -| test.c:29:15:29:16 | definition of l5 | Atomic object 'l5' has no initializer or corresponding use of 'atomic_init()'. | +| test.c:24:15:24:16 | definition of l3 | Atomic object 'l3' has no initializer or corresponding use of 'atomic_init()'. | +| test.c:27:15:27:16 | definition of l4 | Atomic object 'l4' has no initializer or corresponding use of 'atomic_init()'. | +| test.c:31:15:31:16 | definition of l5 | Atomic object 'l5' has no initializer or corresponding use of 'atomic_init()'. | +| test.c:41:15:41:16 | definition of l7 | Atomic object 'l7' has no initializer or corresponding use of 'atomic_init()'. | diff --git a/c/misra/test/rules/RULE-9-7/test.c b/c/misra/test/rules/RULE-9-7/test.c index 5b3d8e36ec..da367c0bd1 100644 --- a/c/misra/test/rules/RULE-9-7/test.c +++ b/c/misra/test/rules/RULE-9-7/test.c @@ -11,6 +11,8 @@ void f_starts_thread() { thrd_create(&t, f_thread, 0); } +void f_may_initialize_argument(void *p1) {} + void main() { _Atomic int l1 = 1; // COMPLIANT f_starts_thread(); @@ -31,4 +33,14 @@ void main() { atomic_init(&l5, 0); } f_starts_thread(); + + _Atomic int l6; // COMPLIANT + f_may_initialize_argument(&l6); + f_starts_thread(); + + _Atomic int l7; // NON_COMPLIANT + if (g1 == 0) { + f_may_initialize_argument(&l7); + } + f_starts_thread(); } \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll b/cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll new file mode 100644 index 0000000000..5ae370183d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll @@ -0,0 +1,111 @@ +/** + * This module intends to reduce the difficulty of handling the pattern where implementations + * implement a function as a macro: the class `StdFunctionOrMacro<...>::Call` matches both std + * function calls as well as std function macro expansions. + * + * For instance, `atomic_init` may be implemented as a function, but is also implemented as + * `#DEFINE atomic_init(x) __c11_atomic_init(x)` on some platforms. This module aids in finding + * calls to any standard function which may be a macro, and has predefined behavior for + * handling `__c11_*` macros. + * + * Since a macro can be defined to expand to any expression, we cannot know generally which + * expanded expressions in `f(x, y)` correspond to arguments `x` or `y`. To handle this, the + * following inference options are available: + * - `NoMacroExpansionInference`: Assume any expression in the macro expansion could correspond to + * any macro argument. + * - `C11FunctionWrapperMacro`: Check if the macro expands to a function call prefixed with + * `__c11_` and if so, return the corresponding argument. Otherwise, fall back to + * `NoMacroExpansionInference`. + * - `InferMacroExpansionArguments`: Implement your own logic for inferring the argument. + * + * To use this module, pick one of the above inference strategies, and then create a predicate for + * the name you wish to match. For instance: + * + * ```codeql + * private string atomicInit() { result = "atomic_init" } + * + * from StdFunctionOrMacro::Call c + * select c.getArgument(0) + * ``` + */ + +import cpp as cpp + +/** Specify the name of your function as a predicate */ +signature string getName(); + +/** Signature module to implement custom argument resolution behavior in expanded macros */ +signature module InferMacroExpansionArguments { + bindingset[mi, argumentIdx] + cpp::Expr inferArgument(cpp::MacroInvocation mi, int argumentIdx); +} + +/** Assume all subexpressions of an expanded macro may be the result of any ith argument */ +module NoMacroExpansionInference implements InferMacroExpansionArguments { + bindingset[mi, argumentIdx] + cpp::Expr inferArgument(cpp::MacroInvocation mi, int argumentIdx) { + result.getParent*() = mi.getExpr() + } +} + +/** Assume macro `f(x, y, ...)` expands to `__c11_f(x, y, ...)`. */ +module C11FunctionWrapperMacro implements InferMacroExpansionArguments { + bindingset[mi, argumentIdx] + cpp::Expr inferArgument(cpp::MacroInvocation mi, int argumentIdx) { + if mi.getExpr().(cpp::FunctionCall).getTarget().hasName("__c11_" + mi.getMacroName()) + then result = mi.getExpr().(cpp::FunctionCall).getArgument(argumentIdx) + else result = NoMacroExpansionInference::inferArgument(mi, argumentIdx) + } +} + +/** + * A module to find calls to standard functions, or expansions of macros with the same name. + * + * To use this module, specify a name predicate and an inference strategy for correlating macro + * expansions to macro arguments. + * + * For example: + * + * ```codeql + * private string atomicInit() { result = "atomic_init" } + * from StdFunctionOrMacro::Call c + * select c.getArgument(0) + * ``` + */ +module StdFunctionOrMacro { + final private class Expr = cpp::Expr; + + final private class FunctionCall = cpp::FunctionCall; + + final private class MacroInvocation = cpp::MacroInvocation; + + private newtype TStdCall = + TStdFunctionCall(FunctionCall fc) { fc.getTarget().hasName(getStdName()) } or + TStdMacroInvocation(MacroInvocation mi) { mi.getMacro().hasName(getStdName()) } + + /** + * A call to a standard function or an expansion of a macro with the same name. + */ + class Call extends TStdCall { + bindingset[this, argumentIdx] + Expr getArgument(int argumentIdx) { + exists(FunctionCall fc | + this = TStdFunctionCall(fc) and + result = fc.getArgument(argumentIdx) + ) + or + exists(MacroInvocation mi | + this = TStdMacroInvocation(mi) and + result = InferExpansion::inferArgument(mi, argumentIdx) + ) + } + + string toString() { + this = TStdFunctionCall(_) and + result = "Standard function call" + or + this = TStdMacroInvocation(_) and + result = "Invocation of a standard function implemented as a macro" + } + } +} diff --git a/rule_packages/c/Concurrency7.json b/rule_packages/c/Concurrency7.json index 6fdc49984b..bda8881934 100644 --- a/rule_packages/c/Concurrency7.json +++ b/rule_packages/c/Concurrency7.json @@ -15,7 +15,11 @@ "tags": [ "concurrency", "external/misra/c/2012/amendment4" - ] + ], + "implementation_scope": { + "description": "This query tracks which functions may start threads, either indirectly or directly (\"thread spawning functions\"), and checks for local atomic variables that are not passed by address into `atomic_init` or other function calls, before such a thread spawning function is called.", + "items": [] + } } ], "title": "Atomic objects shall be appropriately initialized before being accessed" From b294477a2c2b79cf8242e8f12c0bc8e5a7689f3b Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 14 Feb 2025 21:37:26 -0800 Subject: [PATCH 260/628] CI/CD fixes: format, rules.csv package -> Concurrency8 for unhandled rules --- .../TimedlockOnInappropriateMutexType.ql | 4 ++-- rules.csv | 20 +++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql b/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql index 4401d06e2c..929eb5bd0a 100644 --- a/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql +++ b/c/misra/src/rules/RULE-21-26/TimedlockOnInappropriateMutexType.ql @@ -72,5 +72,5 @@ where Concurrency7Package::timedlockOnInappropriateMutexTypeQuery()) and Flow::flowPath(source, sink) select sink.getNode(), source, sink, - "Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'.", - source.getNode(), "initialized" + "Call to mtx_timedlock with mutex which is $@ without flag 'mtx_timed'.", source.getNode(), + "initialized" diff --git a/rules.csv b/rules.csv index 10478a3da8..3f959542a7 100644 --- a/rules.csv +++ b/rules.csv @@ -617,7 +617,7 @@ c,MISRA-C-2012,DIR-4-12,Yes,Required,,,Dynamic memory allocation shall not be us c,MISRA-C-2012,DIR-4-13,No,Advisory,,,Functions which are designed to provide operations on a resource should be called in an appropriate sequence,,,,"Rule 22.1, 22.2 and 22.6 cover aspects of this rule. In other cases this is a design issue and needs to be checked manually." c,MISRA-C-2012,DIR-4-14,Yes,Required,,,The validity of values received from external sources shall be checked,,Contracts8,Hard,This is supported by CodeQLs default C security queries. c,MISRA-C-2012,DIR-4-15,Yes,Required,,,Evaluation of floating-point expressions shall not lead to the undetected generation of infinities and NaNs,FLP32-C and FLP04-C,FloatingTypes2,Medium, -c,MISRA-C-2012,DIR-5-1,Yes,Required,,,There shall be no data races between threads,CON43-C and CON32-C,Concurrency7,Very Hard, +c,MISRA-C-2012,DIR-5-1,Yes,Required,,,There shall be no data races between threads,CON43-C and CON32-C,Concurrency8,Very Hard, c,MISRA-C-2012,DIR-5-2,Yes,Required,,,There shall be no deadlocks between threads,CON35-C,Concurrency6,Import, c,MISRA-C-2012,DIR-5-3,Yes,Required,,,There shall be no dynamic thread creation,,Concurrency6,Easy, c,MISRA-C-2012,RULE-1-1,No,Required,,,"The program shall contain no violations of the standard C syntax and constraints, and shall not exceed the implementation's translation limits",,,Easy,"This should be checked via the compiler output, rather than CodeQL, which adds unnecessary steps." @@ -803,15 +803,15 @@ c,MISRA-C-2012,RULE-22-8,Yes,Required,,,The value of errno shall be set to zero c,MISRA-C-2012,RULE-22-9,Yes,Required,,,The value of errno shall be tested against zero after calling an errno-setting-function,,Contracts3,Medium, c,MISRA-C-2012,RULE-22-10,Yes,Required,,,The value of errno shall only be tested when the last function to be called was an errno-setting-function,,Contracts3,Medium, c,MISRA-C-2012,RULE-22-11,Yes,Required,,,A thread that was previously either joined or detached shall not be subsequently joined nor detached,CON39-C,Concurrency6,Import, -c,MISRA-C-2012,RULE-22-12,Yes,Mandatory,,,"Thread objects, thread synchronization objects, and thread-specific storage pointers shall only be accessed by the appropriate Standard Library functions",,Concurrency7,Medium, -c,MISRA-C-2012,RULE-22-13,Yes,Required,,,"Thread objects, thread synchronization objects, and thread specific storage pointers shall have appropriate storage duration",EXP54-CPP and CON34-C,Concurrency7,Medium, -c,MISRA-C-2012,RULE-22-14,Yes,Mandatory,,,Thread synchronization objects shall be initialized before being accessed,EXP53-CPP,Concurrency7,Hard, -c,MISRA-C-2012,RULE-22-15,Yes,Required,,,Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated,,Concurrency7,Hard, -c,MISRA-C-2012,RULE-22-16,Yes,Required,,,All mutex objects locked by a thread shall be explicitly unlocked by the same thread,MEM51-CPP,Concurrency7,Hard, -c,MISRA-C-2012,RULE-22-17,Yes,Required,,,No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked before,Rule 22.2,Concurrency7,Medium, -c,MISRA-C-2012,RULE-22-18,Yes,Required,,,Non-recursive mutexes shall not be recursively locked,CON56-CPP,Concurrency7,Medium, -c,MISRA-C-2012,RULE-22-19,Yes,Required,,,A condition variable shall be associated with at most one mutex object,,Concurrency7,Medium, -c,MISRA-C-2012,RULE-22-20,Yes,Mandatory,,,Thread-specific storage pointers shall be created before being accessed,,Concurrency7,Hard, +c,MISRA-C-2012,RULE-22-12,Yes,Mandatory,,,"Thread objects, thread synchronization objects, and thread-specific storage pointers shall only be accessed by the appropriate Standard Library functions",,Concurrency8,Medium, +c,MISRA-C-2012,RULE-22-13,Yes,Required,,,"Thread objects, thread synchronization objects, and thread specific storage pointers shall have appropriate storage duration",EXP54-CPP and CON34-C,Concurrency8,Medium, +c,MISRA-C-2012,RULE-22-14,Yes,Mandatory,,,Thread synchronization objects shall be initialized before being accessed,EXP53-CPP,Concurrency8,Hard, +c,MISRA-C-2012,RULE-22-15,Yes,Required,,,Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated,,Concurrency8,Hard, +c,MISRA-C-2012,RULE-22-16,Yes,Required,,,All mutex objects locked by a thread shall be explicitly unlocked by the same thread,MEM51-CPP,Concurrency8,Hard, +c,MISRA-C-2012,RULE-22-17,Yes,Required,,,No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked before,Rule 22.2,Concurrency8,Medium, +c,MISRA-C-2012,RULE-22-18,Yes,Required,,,Non-recursive mutexes shall not be recursively locked,CON56-CPP,Concurrency8,Medium, +c,MISRA-C-2012,RULE-22-19,Yes,Required,,,A condition variable shall be associated with at most one mutex object,,Concurrency8,Medium, +c,MISRA-C-2012,RULE-22-20,Yes,Mandatory,,,Thread-specific storage pointers shall be created before being accessed,,Concurrency8,Hard, c,MISRA-C-2012,RULE-23-1,Yes,Advisory,,,A generic selection should only be expanded from a macro,,Generics,Medium, c,MISRA-C-2012,RULE-23-2,Yes,Required,,,A generic selection that is not expanded from a macro shall not contain potential side effects in the controlling expression,,Generics,Hard, c,MISRA-C-2012,RULE-23-3,Yes,Advisory,,,A generic selection should contain at least one non-default association,,Generics,Easy, From 0b59317e33dd4f2512017f74950fa474c87319ff Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 17 Feb 2025 17:51:34 +0000 Subject: [PATCH 261/628] A27-0-3: Improve performance oppositeDirection was a performance problem, because it was not restricted to read write calls with the same source. --- change_notes/2025-02-17-iofstream-performance.md | 2 ++ .../IOFstreamMissingPositioning.qll | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 change_notes/2025-02-17-iofstream-performance.md diff --git a/change_notes/2025-02-17-iofstream-performance.md b/change_notes/2025-02-17-iofstream-performance.md new file mode 100644 index 0000000000..8a0be4c3ac --- /dev/null +++ b/change_notes/2025-02-17-iofstream-performance.md @@ -0,0 +1,2 @@ + - `A27-0-3`, `FIO309-C` `FIO50-CPP`, `RULE-30-0-2` - `InterleavedInputOutputWithoutFlush.ql`, `DoNotAlternatelyIOFromStreamWithoutPositioning.ql`,`InterleavedInputOutputWithoutPosition.ql`, `ReadsAndWritesOnStreamNotSeparatedByPositioning.ql`: + - Reduce evaluation time on complex codebases. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll b/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll index 89f847c5aa..547c90daf5 100644 --- a/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll +++ b/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll @@ -57,17 +57,19 @@ predicate sameSource(FunctionCall a, FunctionCall b) { sameFileSource(a, b) } +bindingset[a, b] predicate sameAccessDirection(ReadWriteCall a, ReadWriteCall b) { a.getAccessDirection() = b.getAccessDirection() } +bindingset[a, b] predicate oppositeAccessDirection(ReadWriteCall a, ReadWriteCall b) { not sameAccessDirection(a, b) } /** * A write operation reaching a read and vice versa - * without intervening filepositioning + * without intervening file positioning calls. */ ControlFlowNode reachesInExOperator(ReadWriteCall op) { result = op From 029537df335fc3cd8dda1ec7a1d123a4f036114e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 18 Feb 2025 13:36:22 +0000 Subject: [PATCH 262/628] Fix typos --- .../InvalidDeviationCodeIdentifier.md | 2 +- docs/user_manual.md | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.md b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.md index 9c128bab2d..364e1ae915 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.md +++ b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.md @@ -1,4 +1,4 @@ -# Invalid deviation dode identifier +# Invalid deviation code identifier ## Overview diff --git a/docs/user_manual.md b/docs/user_manual.md index 8bbb900682..fb36d30fb7 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -485,26 +485,26 @@ Here are some examples, using the deviation record with the `a-0-4-2-deviation` long double x2; // a-0-4-2-deviation - COMPLIANT long double x3; // COMPLIANT - a-0-4-2-deviation - long double x4; // codeql::_deviation(a-0-4-2-deviation) - COMPLIANT - long double x5; // COMPLIANT - codeql::_deviation(a-0-4-2-deviation) + long double x4; // codeql::autosar_deviation(a-0-4-2-deviation) - COMPLIANT + long double x5; // COMPLIANT - codeql::autosar_deviation(a-0-4-2-deviation) - // codeql::_deviation_next_line(a-0-4-2-deviation) + // codeql::autosar_deviation_next_line(a-0-4-2-deviation) long double x6; // COMPLIANT - // codeql::_deviation_begin(a-0-4-2-deviation) + // codeql::autosar_deviation_begin(a-0-4-2-deviation) long double x7; // COMPLIANT - // codeql::_deviation_end(a-0-4-2-deviation) + // codeql::autosar_deviation_end(a-0-4-2-deviation) ``` `codeql::_deviation_end` markers will pair with the closest unmatched `codeql::_deviation_begin` for the same `code-identifier`. Consider this example: ```cpp -1 | // codeql::_deviation_begin(a-0-4-2-deviation) +1 | // codeql::autosar_deviation_begin(a-0-4-2-deviation) 2 | -3 | // codeql::_deviation_begin(a-0-4-2-deviation) +3 | // codeql::autosar_deviation_begin(a-0-4-2-deviation) 4 | -5 | // codeql::_deviation_end(a-0-4-2-deviation) +5 | // codeql::autosar_deviation_end(a-0-4-2-deviation) 6 | -7 | // codeql::_deviation_end(a-0-4-2-deviation) +7 | // codeql::autosar_deviation_end(a-0-4-2-deviation) ``` Here, Line 1 will pair with Line 7, and Line 3 will pair with Line 5. From 3f1997b6ce3bac8e2c42d0d5f93f8f12430ed5e3 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 18 Feb 2025 13:36:40 +0000 Subject: [PATCH 263/628] Deviations: Highlight invalid starts --- .../cpp/deviations/InvalidDeviationCodeIdentifier.ql | 6 ++++++ .../InvalidDeviationCodeIdentifier.expected | 5 ++++- .../invalid_deviations/invalidcodeidentifiers.cpp | 3 +++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.ql b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.ql index 03e1ffc2b0..87dafbba13 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.ql +++ b/cpp/common/src/codingstandards/cpp/deviations/InvalidDeviationCodeIdentifier.ql @@ -16,6 +16,12 @@ predicate deviationCodeIdentifierError(Element e, string message) { message = "Deviation end block is unmatched." ) or + exists(DeviationBegin begin | + e = begin and + not isDeviationRangePaired(_, begin, _) and + message = "Deviation start block is unmatched." + ) + or exists(InvalidDeviationAttribute b | e = b and message = diff --git a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.expected b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.expected index eb81658007..1d7153bafd 100644 --- a/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.expected +++ b/cpp/common/test/deviations/invalid_deviations/InvalidDeviationCodeIdentifier.expected @@ -7,4 +7,7 @@ | invalidcodeidentifiers.cpp:14:1:14:74 | // codeql::misra_deviation_end(a-0-4-2-deviation) - invalid, unmatched end | Deviation end block is unmatched. | | invalidcodeidentifiers.cpp:15:1:15:76 | // codeql::autosar_deviation_end(a-0-4-2-deviation) - invalid, unmatched end | Deviation end block is unmatched. | | invalidcodeidentifiers.cpp:16:1:16:73 | // codeql::cert_deviation_end(a-0-4-2-deviation) - invalid, unmatched end | Deviation end block is unmatched. | -| invalidcodeidentifiers.cpp:18:3:18:25 | misra_deviation | Deviation attribute references unknown code identifier x. | +| invalidcodeidentifiers.cpp:17:1:17:78 | // codeql::misra_deviation_begin(a-0-4-2-deviation) - invalid, unmatched begin | Deviation start block is unmatched. | +| invalidcodeidentifiers.cpp:18:1:18:80 | // codeql::autosar_deviation_begin(a-0-4-2-deviation) - invalid, unmatched begin | Deviation start block is unmatched. | +| invalidcodeidentifiers.cpp:19:1:19:77 | // codeql::cert_deviation_begin(a-0-4-2-deviation) - invalid, unmatched begin | Deviation start block is unmatched. | +| invalidcodeidentifiers.cpp:21:3:21:25 | misra_deviation | Deviation attribute references unknown code identifier x. | diff --git a/cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp b/cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp index 07a12eb713..a4da098dcb 100644 --- a/cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp +++ b/cpp/common/test/deviations/invalid_deviations/invalidcodeidentifiers.cpp @@ -14,6 +14,9 @@ // codeql::misra_deviation_end(a-0-4-2-deviation) - invalid, unmatched end // codeql::autosar_deviation_end(a-0-4-2-deviation) - invalid, unmatched end // codeql::cert_deviation_end(a-0-4-2-deviation) - invalid, unmatched end +// codeql::misra_deviation_begin(a-0-4-2-deviation) - invalid, unmatched begin +// codeql::autosar_deviation_begin(a-0-4-2-deviation) - invalid, unmatched begin +// codeql::cert_deviation_begin(a-0-4-2-deviation) - invalid, unmatched begin [[codeql::misra_deviation("x")]] // invalid void test() {} From 665a7d16c8c0f2339075c3097b40405bb393fc97 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 18 Feb 2025 16:50:33 +0000 Subject: [PATCH 264/628] Improve documentation --- .../codingstandards/cpp/deviations/CodeIdentifierDeviation.qll | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll index 2a2d0eec15..ab121f6095 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -145,6 +145,8 @@ private predicate mkBeginStack(DeviationRecord record, File file, BeginStack sta // Stack is empty at the start index = 0 and stack = TEmptyBeginStack() and + // Only initialize when there is at least one such comment marker for this file and record + // pairing exists(CommentDeviationRangeMarker marker | marker.getRecord() = record and marker.getLocation().getFile() = file ) From 8437c7cc76d011455580810501ccd7de2ce26190 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 18 Feb 2025 17:34:51 +0000 Subject: [PATCH 265/628] Deviation: Refactor begin/end for clarity. --- .../deviations/CodeIdentifierDeviation.qll | 36 ++++++++++++------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll index ab121f6095..9a694ccc8f 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -141,10 +141,14 @@ private predicate hasDeviationCommentFileOrdering( ) } -private predicate mkBeginStack(DeviationRecord record, File file, BeginStack stack, int index) { +/** + * Calculate the stack of deviation begin markers related to the given deviation record, in the given file, + * at the given `markerRecordFileIndex` into the list of deviation markers for that record in that file. + */ +private BeginStack calculateBeginStack(DeviationRecord record, File file, int markerRecordFileIndex) { // Stack is empty at the start - index = 0 and - stack = TEmptyBeginStack() and + markerRecordFileIndex = 0 and + result = TEmptyBeginStack() and // Only initialize when there is at least one such comment marker for this file and record // pairing exists(CommentDeviationRangeMarker marker | @@ -154,23 +158,23 @@ private predicate mkBeginStack(DeviationRecord record, File file, BeginStack sta // Next token is begin, so push it to the stack exists(DeviationBegin begin, BeginStack prev | record = begin.getRecord() and - hasDeviationCommentFileOrdering(record, begin, file, index) and - mkBeginStack(record, file, prev, index - 1) and - stack = TConsBeginStack(begin, prev) + hasDeviationCommentFileOrdering(record, begin, file, markerRecordFileIndex) and + prev = calculateBeginStack(record, file, markerRecordFileIndex - 1) and + result = TConsBeginStack(begin, prev) ) or // Next token is end exists(DeviationEnd end, BeginStack prevStack | record = end.getRecord() and - hasDeviationCommentFileOrdering(record, end, file, index) and - mkBeginStack(record, file, prevStack, index - 1) + hasDeviationCommentFileOrdering(record, end, file, markerRecordFileIndex) and + prevStack = calculateBeginStack(record, file, markerRecordFileIndex - 1) | // There is, so pop the most recent begin off the stack - prevStack = TConsBeginStack(_, stack) + prevStack = TConsBeginStack(_, result) or - // Error, no begin on the stack, ignore and continue + // Error, no begin on the stack, ignore the end and continue prevStack = TEmptyBeginStack() and - stack = TEmptyBeginStack() + result = TEmptyBeginStack() ) } @@ -178,12 +182,18 @@ newtype TBeginStack = TConsBeginStack(DeviationBegin begin, TBeginStack prev) { exists(File file, int index | hasDeviationCommentFileOrdering(begin.getRecord(), begin, file, index) and - mkBeginStack(begin.getRecord(), file, prev, index - 1) + prev = calculateBeginStack(begin.getRecord(), file, index - 1) ) } or TEmptyBeginStack() +/** + * A stack of begin markers that occur in the same file, referring to the same record. + */ private class BeginStack extends TBeginStack { + /** Gets the top begin marker on the stack. */ + DeviationBegin peek() { this = TConsBeginStack(result, _) } + string toString() { exists(DeviationBegin begin, BeginStack prev | this = TConsBeginStack(begin, prev) | result = "(" + begin + ", " + prev.toString() + ")" @@ -198,7 +208,7 @@ predicate isDeviationRangePaired(DeviationRecord record, DeviationBegin begin, D exists(File file, int index | record = end.getRecord() and hasDeviationCommentFileOrdering(record, end, file, index) and - mkBeginStack(record, file, TConsBeginStack(begin, _), index - 1) + begin = calculateBeginStack(record, file, index - 1).peek() ) } From 20669c7cc43e2c5fb2b6ab6cb2e76a6196ad2102 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 18 Feb 2025 17:35:08 +0000 Subject: [PATCH 266/628] Deviation: Clarification in user manual. --- docs/user_manual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/user_manual.md b/docs/user_manual.md index fb36d30fb7..a04ba0814e 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -512,7 +512,7 @@ A `codeql::_deviation_end` without a matching `codeql::_devi `codeql::_deviation_begin` and `ccodeql::_deviation_end` markers only apply within a single file. Markers cannot be paired across files, and deviations do not apply to included files. -Note: deviation markers cannot be applied to the body of a macro. Please apply the deviation to macro expansion, or use the attribute deviation format. +Note: deviation comment markers cannot be applied to the body of a macro. Please apply the deviation to macro expansion, or use the attribute deviation format. ##### Deviation permits From 713c6756671b01ef8fec7acb3f03d940dc859ed4 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 9 Dec 2024 14:47:29 -0800 Subject: [PATCH 267/628] Implement Concurrency9 package on top of Concurrency8 work --- c/common/src/codingstandards/c/SubObjects.qll | 94 ++ .../GlobalInitializationAnalysis.qll | 93 ++ .../test/includes/standard-library/stdlib.h | 1 + .../DIR-5-1/PossibleDataRaceBetweenThreads.ql | 158 +++ .../MutexNotInitializedBeforeUse.ql | 128 +- ...readResourceDisposedBeforeThreadsJoined.ql | 113 ++ .../InvalidOperationOnUnlockedMutex.ql | 68 ++ .../NonRecursiveMutexRecursivelyLocked.ql | 37 + ...NonRecursiveMutexRecursivelyLockedAudit.ql | 60 + ...onditionVariableUsedWithMultipleMutexes.ql | 69 ++ .../ThreadStorageNotInitializedBeforeUse.ql | 44 + ...adStoragePointerInitializedInsideThread.ql | 27 + .../PossibleDataRaceBetweenThreads.expected | 24 + .../PossibleDataRaceBetweenThreads.qlref | 1 + c/misra/test/rules/DIR-5-1/test.c | 132 +++ ...sourceDisposedBeforeThreadsJoined.expected | 12 + ...dResourceDisposedBeforeThreadsJoined.qlref | 1 + c/misra/test/rules/RULE-22-15/test.c | 113 ++ .../InvalidOperationOnUnlockedMutex.expected | 16 + .../InvalidOperationOnUnlockedMutex.qlref | 1 + c/misra/test/rules/RULE-22-17/test.c | 70 ++ ...onRecursiveMutexRecursivelyLocked.expected | 2 + .../NonRecursiveMutexRecursivelyLocked.qlref | 1 + ...ursiveMutexRecursivelyLockedAudit.expected | 6 + ...RecursiveMutexRecursivelyLockedAudit.qlref | 1 + c/misra/test/rules/RULE-22-18/test.c | 122 ++ ...onVariableUsedWithMultipleMutexes.expected | 2 + ...itionVariableUsedWithMultipleMutexes.qlref | 1 + c/misra/test/rules/RULE-22-19/test.c | 46 + ...eadStorageNotInitializedBeforeUse.expected | 5 + ...ThreadStorageNotInitializedBeforeUse.qlref | 1 + ...agePointerInitializedInsideThread.expected | 1 + ...toragePointerInitializedInsideThread.qlref | 1 + c/misra/test/rules/RULE-22-20/test.c | 70 ++ ...2024-12-10-refactor-concurrency-library.md | 2 + .../src/codingstandards/cpp/Concurrency.qll | 1026 +---------------- .../cpp/concurrency/Atomic.qll | 43 + .../cpp/concurrency/CConditionOperation.qll | 31 + .../cpp/concurrency/ConditionalWait.qll | 26 + .../cpp/concurrency/ControlFlow.qll | 101 ++ .../concurrency/LockProtectedControlFlow.qll | 49 + .../cpp/concurrency/LockingOperation.qll | 240 ++++ .../cpp/concurrency/MutexDestroyer.qll | 73 ++ .../cpp/concurrency/ThreadCreation.qll | 62 + .../cpp/concurrency/ThreadDependentMutex.qll | 246 ++++ .../cpp/concurrency/ThreadSpecificStorage.qll | 59 + .../cpp/concurrency/ThreadWaitDetach.qll | 41 + .../cpp/concurrency/ThreadedFunction.qll | 37 + .../codingstandards/cpp/concurrency/Types.qll | 29 + .../cpp/dominance/BehavioralSet.qll | 47 + .../cpp/exclusions/c/Concurrency9.qll | 146 +++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + rule_packages/c/Concurrency9.json | 158 +++ rules.csv | 12 +- 54 files changed, 2843 insertions(+), 1109 deletions(-) create mode 100644 c/common/src/codingstandards/c/SubObjects.qll create mode 100644 c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll create mode 100644 c/misra/src/rules/DIR-5-1/PossibleDataRaceBetweenThreads.ql create mode 100644 c/misra/src/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.ql create mode 100644 c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql create mode 100644 c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.ql create mode 100644 c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql create mode 100644 c/misra/src/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.ql create mode 100644 c/misra/src/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.ql create mode 100644 c/misra/src/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.ql create mode 100644 c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.expected create mode 100644 c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.qlref create mode 100644 c/misra/test/rules/DIR-5-1/test.c create mode 100644 c/misra/test/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.expected create mode 100644 c/misra/test/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.qlref create mode 100644 c/misra/test/rules/RULE-22-15/test.c create mode 100644 c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.expected create mode 100644 c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.qlref create mode 100644 c/misra/test/rules/RULE-22-17/test.c create mode 100644 c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.expected create mode 100644 c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.qlref create mode 100644 c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.expected create mode 100644 c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.qlref create mode 100644 c/misra/test/rules/RULE-22-18/test.c create mode 100644 c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.expected create mode 100644 c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.qlref create mode 100644 c/misra/test/rules/RULE-22-19/test.c create mode 100644 c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.expected create mode 100644 c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.qlref create mode 100644 c/misra/test/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.expected create mode 100644 c/misra/test/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.qlref create mode 100644 c/misra/test/rules/RULE-22-20/test.c create mode 100644 change_notes/2024-12-10-refactor-concurrency-library.md create mode 100644 cpp/common/src/codingstandards/cpp/concurrency/Atomic.qll create mode 100644 cpp/common/src/codingstandards/cpp/concurrency/CConditionOperation.qll create mode 100644 cpp/common/src/codingstandards/cpp/concurrency/ConditionalWait.qll create mode 100644 cpp/common/src/codingstandards/cpp/concurrency/ControlFlow.qll create mode 100644 cpp/common/src/codingstandards/cpp/concurrency/LockProtectedControlFlow.qll create mode 100644 cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll create mode 100644 cpp/common/src/codingstandards/cpp/concurrency/MutexDestroyer.qll create mode 100644 cpp/common/src/codingstandards/cpp/concurrency/ThreadCreation.qll create mode 100644 cpp/common/src/codingstandards/cpp/concurrency/ThreadDependentMutex.qll create mode 100644 cpp/common/src/codingstandards/cpp/concurrency/ThreadSpecificStorage.qll create mode 100644 cpp/common/src/codingstandards/cpp/concurrency/ThreadWaitDetach.qll create mode 100644 cpp/common/src/codingstandards/cpp/concurrency/ThreadedFunction.qll create mode 100644 cpp/common/src/codingstandards/cpp/concurrency/Types.qll create mode 100644 cpp/common/src/codingstandards/cpp/dominance/BehavioralSet.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency9.qll create mode 100644 rule_packages/c/Concurrency9.json diff --git a/c/common/src/codingstandards/c/SubObjects.qll b/c/common/src/codingstandards/c/SubObjects.qll new file mode 100644 index 0000000000..d7aa1e976b --- /dev/null +++ b/c/common/src/codingstandards/c/SubObjects.qll @@ -0,0 +1,94 @@ +import codingstandards.c.Objects + +newtype TSubObject = + TObjectRoot(ObjectIdentity i) or + TObjectMember(SubObject struct, MemberVariable m) { + m = struct.getType().(Struct).getAMemberVariable() + } or + TObjectIndex(SubObject array) { array.getType() instanceof ArrayType } + +class SubObject extends TSubObject { + string toString() { + exists(ObjectIdentity i | + this = TObjectRoot(i) and + result = i.toString() + ) + or + exists(SubObject struct, Variable m | + this = TObjectMember(struct, m) and + result = struct.toString() + "." + m.getName() + ) + or + exists(SubObject array | + this = TObjectIndex(array) and + result = array.toString() + ) + } + + Type getType() { + exists(ObjectIdentity i | + this = TObjectRoot(i) and + result = i.getType() + ) + or + exists(Variable m | + this = TObjectMember(_, m) and + result = m.getType() + ) + or + exists(SubObject array | + this = TObjectIndex(array) and + result = array.getType().(ArrayType).getBaseType() + ) + } + + /** + * Holds for object roots and for member accesses on that root, not for array accesses. + * + * This is useful for cases where we do not wish to treat `x[y]` and `x[z]` as the same object. + */ + predicate isPrecise() { + not getParent*() = TObjectIndex(_) + } + + SubObject getParent() { + exists(SubObject struct, MemberVariable m | + this = TObjectMember(struct, m) and + result = struct + ) + or + exists(SubObject array | + this = TObjectIndex(array) and + result = array + ) + } + + Expr getAnAccess() { + exists(ObjectIdentity i | + this = TObjectRoot(i) and + result = i.getAnAccess() + ) + or + exists(MemberVariable m | + this = TObjectMember(_, m) and + result = m.getAnAccess() and + result.(DotFieldAccess).getQualifier() = getParent().getAnAccess() + ) + or + this = TObjectIndex(_) and + result.(ArrayExpr).getArrayBase() = getParent().getAnAccess() + } + + AddressOfExpr getAnAddressOfExpr() { + result.getOperand() = this.getAnAccess() + } + + ObjectIdentity getRootIdentity() { + exists(ObjectIdentity i | + this = TObjectRoot(i) and + result = i + ) + or + result = getParent().getRootIdentity() + } +} diff --git a/c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll b/c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll new file mode 100644 index 0000000000..d2974f9924 --- /dev/null +++ b/c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll @@ -0,0 +1,93 @@ +import cpp +import codingstandards.c.Objects +import codingstandards.cpp.Concurrency +import codingstandards.cpp.Type + +signature module GlobalInitializationAnalysisConfigSig { + /** A function which is not called or started as a thread */ + default predicate isRootFunction(Function f) { + not exists(Function f2 | f2.calls(f)) and + not f instanceof ThreadedFunction + } + + ObjectIdentity getAnInitializedObject(Expr e); + + ObjectIdentity getAUsedObject(Expr e); +} + +module GlobalInitalizationAnalysis { + final class FinalFunction = Function; + + final class FinalExpr = Expr; + + class RootFunction extends FinalFunction { + RootFunction() { Config::isRootFunction(this) } + } + + /** A function call which initializes a mutex or a condition */ + class ObjectInit extends FinalExpr { + ObjectIdentity owningObject; + + ObjectInit() { owningObject = Config::getAnInitializedObject(this) } + + ObjectIdentity getOwningObject() { result = owningObject } + } + + /** + * A function argument where that argument is used as a mutex or condition object. + */ + class ObjectUse extends FinalExpr { + ObjectIdentity owningObject; + + ObjectUse() { owningObject = Config::getAUsedObject(this) } + + ObjectIdentity getOwningObject() { result = owningObject } + } + + predicate requiresInitializedMutexObject( + Function func, ObjectUse mutexUse, ObjectIdentity owningObject + ) { + mutexUse.getEnclosingFunction() = func and + owningObject = mutexUse.getOwningObject() and + not exists(ObjectInit init | + init.getEnclosingFunction() = func and + init.getOwningObject() = owningObject and + mutexUse.getAPredecessor+() = init + ) + or + exists(FunctionCall call | + func = call.getEnclosingFunction() and + requiresInitializedMutexObject(call.getTarget(), mutexUse, owningObject) and + not exists(ObjectInit init | + call.getAPredecessor*() = init and + init.getOwningObject() = owningObject + ) + ) + or + exists(C11ThreadCreateCall call | + func = call.getEnclosingFunction() and + not owningObject.getStorageDuration().isThread() and + requiresInitializedMutexObject(call.getFunction(), mutexUse, owningObject) and + not exists(ObjectInit init | + call.getAPredecessor*() = init and + init.getOwningObject() = owningObject + ) + ) + } + + predicate uninitializedFrom(Expr e, ObjectIdentity obj, Function callRoot) { + exists(ObjectUse use | use = e | + obj = use.getOwningObject() and + requiresInitializedMutexObject(callRoot, use, obj) and + ( + if obj.getStorageDuration().isAutomatic() + then obj.getEnclosingElement+() = callRoot + else ( + obj.getStorageDuration().isThread() and callRoot instanceof ThreadedFunction + or + callRoot instanceof RootFunction + ) + ) + ) + } +} diff --git a/c/common/test/includes/standard-library/stdlib.h b/c/common/test/includes/standard-library/stdlib.h index b54a051fe9..1af95223d1 100644 --- a/c/common/test/includes/standard-library/stdlib.h +++ b/c/common/test/includes/standard-library/stdlib.h @@ -49,6 +49,7 @@ int at_quick_exit (void (*) (void)); _Noreturn void quick_exit (int); char *getenv (const char *); +char *getenv_s (size_t *restrict len, char *restrict value, size_t valuesz, const char *restrict name); int system (const char *); diff --git a/c/misra/src/rules/DIR-5-1/PossibleDataRaceBetweenThreads.ql b/c/misra/src/rules/DIR-5-1/PossibleDataRaceBetweenThreads.ql new file mode 100644 index 0000000000..443dc284fd --- /dev/null +++ b/c/misra/src/rules/DIR-5-1/PossibleDataRaceBetweenThreads.ql @@ -0,0 +1,158 @@ +/** + * @id c/misra/possible-data-race-between-threads + * @name DIR-5-1: There shall be no data races between threads + * @description Threads shall not access the same memory location concurrently without utilization + * of thread synchronization objects. + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/misra/id/dir-5-1 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Objects +import codingstandards.c.SubObjects +import codingstandards.cpp.Concurrency + +newtype TNonReentrantOperation = + TReadWrite(SubObject object) { + object.getRootIdentity().getStorageDuration().isStatic() + or + object.getRootIdentity().getStorageDuration().isAllocated() + } or + TStdFunctionCall(FunctionCall call) { + call.getTarget() + .hasName([ + "setlocale", "tmpnam", "rand", "srand", "getenv", "getenv_s", "strok", "strerror", + "asctime", "ctime", "gmtime", "localtime", "mbrtoc16", "c16rtomb", "mbrtoc32", + "c32rtomb", "mbrlen", "mbrtowc", "wcrtomb", "mbsrtowcs", "wcsrtombs" + ]) + } + +class NonReentrantOperation extends TNonReentrantOperation { + string toString() { + exists(SubObject object | + this = TReadWrite(object) and + result = object.toString() + ) + or + exists(FunctionCall call | + this = TStdFunctionCall(call) and + result = call.getTarget().getName() + ) + } + + Expr getARead() { + exists(SubObject object | + this = TReadWrite(object) and + result = object.getAnAccess() + ) + or + this = TStdFunctionCall(result) + } + + Expr getAWrite() { + exists(SubObject object, Assignment assignment | + this = TReadWrite(object) and + result = assignment and + assignment.getLValue() = object.getAnAccess() + ) + or + this = TStdFunctionCall(result) + } + + string getReadString() { + this = TReadWrite(_) and + result = "read operation" + or + this = TStdFunctionCall(_) and + result = "call to non-reentrant function" + } + + string getWriteString() { + this = TReadWrite(_) and + result = "write to object" + or + this = TStdFunctionCall(_) and + result = "call to non-reentrant function" + } + + Element getSourceElement() { + exists(SubObject object | + this = TReadWrite(object) and + result = object.getRootIdentity() + ) + or + this = TStdFunctionCall(result) + } +} + +class WritingThread extends ThreadedFunction { + NonReentrantOperation aWriteObject; + Expr aWrite; + + WritingThread() { + aWrite = aWriteObject.getAWrite() and + this.calls*(aWrite.getEnclosingFunction()) and + not aWrite instanceof LockProtectedControlFlowNode and + not aWrite.getEnclosingFunction().getName().matches(["%init%", "%boot%", "%start%"]) + } + + Expr getAWrite() { result = aWrite } +} + +class ReadingThread extends ThreadedFunction { + Expr aReadExpr; + + ReadingThread() { + exists(NonReentrantOperation op | + aReadExpr = op.getARead() and + this.calls*(aReadExpr.getEnclosingFunction()) and + not aReadExpr instanceof LockProtectedControlFlowNode + ) + } + + Expr getARead() { result = aReadExpr } +} + +predicate mayBeDataRace(Expr write, Expr read, NonReentrantOperation operation) { + exists(WritingThread wt | + wt.getAWrite() = write and + write = operation.getAWrite() and + exists(ReadingThread rt | + read = rt.getARead() and + read = operation.getARead() and + ( + wt.isMultiplySpawned() or + not wt = rt + ) + ) + ) +} + +from + WritingThread wt, ReadingThread rt, Expr write, Expr read, NonReentrantOperation operation, + string message, string writeString, string readString +where + not isExcluded(write, Concurrency9Package::possibleDataRaceBetweenThreadsQuery()) and + mayBeDataRace(write, read, operation) and + wt = min(WritingThread f | f.getAWrite() = write | f order by f.getName()) and + rt = min(ReadingThread f | f.getARead() = read | f order by f.getName()) and + writeString = operation.getWriteString() and + readString = operation.getReadString() and + if wt.isMultiplySpawned() + then + message = + "Threaded " + writeString + + " $@ not synchronized, for example from thread function $@ spawned from a loop." + else + message = + "Threaded " + writeString + + " $@, for example from thread function $@, not synchronized with $@, for example from thread function $@." +select write, message, operation.getSourceElement(), operation.toString(), wt, wt.getName(), read, + "concurrent " + readString, rt, rt.getName() diff --git a/c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql b/c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql index f02891d5d0..f78c25f981 100644 --- a/c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql +++ b/c/misra/src/rules/RULE-22-14/MutexNotInitializedBeforeUse.ql @@ -18,113 +18,61 @@ import codingstandards.c.misra import codingstandards.c.Objects import codingstandards.cpp.Concurrency import codingstandards.cpp.Type +import codingstandards.c.initialization.GlobalInitializationAnalysis -/** A function which is not called or started as a thread */ -class RootFunction extends Function { - RootFunction() { - not exists(Function f | f.calls(this)) and - not this instanceof ThreadedFunction +module MutexInitializationConfig implements GlobalInitializationAnalysisConfigSig { + ObjectIdentity getAnInitializedObject(Expr e) { + e.(C11MutexSource).getMutexExpr() = result.getASubobjectAddressExpr() } -} - -/** A function call which initializes a mutex or a condition */ -class ThreadObjectInitialization extends FunctionCall { - ObjectIdentity owningObject; - ThreadObjectInitialization() { - this.(C11MutexSource).getMutexExpr() = owningObject.getASubobjectAddressExpr() - or - exists(CConditionOperation condOp | - this = condOp and - condOp.isInit() and - condOp.getConditionExpr() = owningObject.getASubobjectAddressExpr() + ObjectIdentity getAUsedObject(Expr e) { + result.getASubobjectAddressExpr() = e and + ( + exists(CMutexFunctionCall mutexUse | e = mutexUse.getLockExpr()) + or + exists(CConditionOperation condOp | e = condOp.getMutexExpr()) ) } - - ObjectIdentity getOwningObject() { result = owningObject } } -/** - * A function argument where that argument is used as a mutex or condition object. - */ -class ThreadObjectUse extends Expr { - ObjectIdentity owningObject; - string typeString; - - ThreadObjectUse() { - owningObject.getASubobjectAddressExpr() = this and - ( - exists(CMutexFunctionCall mutexUse | this = mutexUse.getLockExpr()) and - typeString = "Mutex" - or - exists(CConditionOperation condOp | this = condOp.getMutexExpr()) and - typeString = "Mutex" - or - exists(CConditionOperation condOp | - condOp.isUse() and - this = condOp.getConditionExpr() and - typeString = "Condition" - ) +module ConditionInitializationConfig implements GlobalInitializationAnalysisConfigSig { + ObjectIdentity getAnInitializedObject(Expr e) { + exists(CConditionOperation condOp | + e = condOp and + condOp.isInit() and + condOp.getConditionExpr() = result.getASubobjectAddressExpr() ) } - ObjectIdentity getOwningObject() { result = owningObject } - - string getDescription() { - if - getOwningObject().getType() instanceof PossiblySpecified::Type or - getOwningObject().getType() instanceof PossiblySpecified::Type - then result = typeString - else result = typeString + " in object" + ObjectIdentity getAUsedObject(Expr e) { + result.getASubobjectAddressExpr() = e and + exists(CConditionOperation condOp | + condOp.isUse() and + e = condOp.getConditionExpr() + ) } } -predicate requiresInitializedMutexObject( - Function func, ThreadObjectUse mutexUse, ObjectIdentity owningObject -) { - mutexUse.getEnclosingFunction() = func and - owningObject = mutexUse.getOwningObject() and - not exists(ThreadObjectInitialization init | - init.getEnclosingFunction() = func and - init.getOwningObject() = owningObject and - mutexUse.getAPredecessor+() = init - ) - or - exists(FunctionCall call | - func = call.getEnclosingFunction() and - requiresInitializedMutexObject(call.getTarget(), mutexUse, owningObject) and - not exists(ThreadObjectInitialization init | - call.getAPredecessor*() = init and - init.getOwningObject() = owningObject - ) - ) - or - exists(C11ThreadCreateCall call | - func = call.getEnclosingFunction() and - not owningObject.getStorageDuration().isThread() and - requiresInitializedMutexObject(call.getFunction(), mutexUse, owningObject) and - not exists(ThreadObjectInitialization init | - call.getAPredecessor*() = init and - init.getOwningObject() = owningObject - ) - ) -} +import GlobalInitalizationAnalysis as MutexInitAnalysis +import GlobalInitalizationAnalysis as CondInitAnalysis -from ThreadObjectUse objUse, ObjectIdentity obj, Function callRoot +from Expr objUse, ObjectIdentity obj, Function callRoot, string typeString, string description where not isExcluded(objUse, Concurrency8Package::mutexNotInitializedBeforeUseQuery()) and - obj = objUse.getOwningObject() and - requiresInitializedMutexObject(callRoot, objUse, obj) and ( - if obj.getStorageDuration().isAutomatic() - then obj.getEnclosingElement+() = callRoot - else ( - obj.getStorageDuration().isThread() and callRoot instanceof ThreadedFunction - or - callRoot instanceof RootFunction - ) + MutexInitAnalysis::uninitializedFrom(objUse, obj, callRoot) and + typeString = "Mutex" + or + CondInitAnalysis::uninitializedFrom(objUse, obj, callRoot) and + typeString = "Condition" + ) and + ( + if + obj.getType() instanceof PossiblySpecified::Type or + obj.getType() instanceof PossiblySpecified::Type + then description = typeString + else description = typeString + " in object" ) select objUse, - objUse.getDescription() + - " '$@' possibly used before initialization, from entry point function '$@'.", obj, + description + " '$@' possibly used before initialization, from entry point function '$@'.", obj, obj.toString(), callRoot, callRoot.getName() diff --git a/c/misra/src/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.ql b/c/misra/src/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.ql new file mode 100644 index 0000000000..966b948d81 --- /dev/null +++ b/c/misra/src/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.ql @@ -0,0 +1,113 @@ +/** + * @id c/misra/thread-resource-disposed-before-threads-joined + * @name RULE-22-15: Thread synchronization objects and thread-specific storage pointers shall not be disposed unsafely + * @description Thread synchronization objects and thread-specific storage pointers shall not be + * destroyed until after all threads accessing them have terminated + * @kind problem + * @precision medium + * @problem.severity error + * @tags external/misra/id/rule-22-15 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.SubObjects +import codingstandards.cpp.Concurrency + +newtype TThreadKind = + TSpawned(C11ThreadCreateCall tcc) or + TMainThread() + +TThreadKind getThreadKind(FunctionCall operation) { + if + not exists(C11ThreadCreateCall tcc | + getAThreadContextAwareSuccessor(tcc.getFunction().getEntryPoint()) = operation + ) + then result = TMainThread() + else + exists(C11ThreadCreateCall tcc | + getAThreadContextAwareSuccessor(tcc.getFunction().getEntryPoint()) = operation and + result = TSpawned(tcc) + ) +} + +bindingset[tcc, thread] +predicate followsMainThreadTcc(C11ThreadCreateCall tcc, TThreadKind thread) { + thread = TMainThread() + or + exists(C11ThreadCreateCall tcc2 | + getAThreadContextAwareSuccessor(tcc) = tcc2 and + thread = TSpawned(tcc2) + ) +} + +string describeThread(TThreadKind thread) { + thread = TMainThread() and + result = "main thread" + or + exists(C11ThreadCreateCall tcc2 | + thread = TSpawned(tcc2) and + result = tcc2.getFunction().getName() + ) +} + +bindingset[alternative] +Element elementOr(TThreadKind thread, Element alternative) { + thread = TMainThread() and + result = alternative + or + exists(C11ThreadCreateCall tcc2 | + thread = TSpawned(tcc2) and + result = tcc2 + ) +} + +from + FunctionCall dispose, FunctionCall use, C11ThreadCreateCall tcc, TThreadKind disposeThread, + TThreadKind useThread, SubObject usedAndDestroyed +where + not isExcluded(dispose, Concurrency9Package::threadResourceDisposedBeforeThreadsJoinedQuery()) and + // `tcc` may be the thread that uses the resource, or the thread that disposes it. What matters + // for the query is that `tcc` is before the use and the dispose. + dispose = getAThreadContextAwareSuccessor(tcc) and + ( + // Lock and dispose of mtx_t: + exists(CMutexFunctionCall mfc, C11MutexDestroyer md | dispose = md and use = mfc | + mfc = getAThreadContextAwareSuccessor(tcc) and + mfc.getLockExpr() = usedAndDestroyed.getAnAddressOfExpr() and + md.getMutexExpr() = usedAndDestroyed.getAnAddressOfExpr() + ) + or + // Read/store and dispose of tss_t: + exists(ThreadSpecificStorageFunctionCall tssfc, TSSDeleteFunctionCall td | + dispose = td and use = tssfc + | + tssfc = getAThreadContextAwareSuccessor(tcc) and + tssfc.getKey() = usedAndDestroyed.getAnAddressOfExpr() and + td.getKey() = usedAndDestroyed.getAnAddressOfExpr() + ) + or + // Wait and dispose of cnd_t: + exists(CConditionOperation cndop, C11ConditionDestroyer cd | dispose = cd and use = cndop | + cndop = getAThreadContextAwareSuccessor(tcc) and + cndop.getConditionExpr() = usedAndDestroyed.getAnAddressOfExpr() and + cd.getConditionExpr() = usedAndDestroyed.getAnAddressOfExpr() + ) + ) and + // Dispose could be in the main thread or in a spawned thread. + disposeThread = getThreadKind(dispose) and + // Dispose could be in the main thread or in a spawned thread. + useThread = getThreadKind(use) and + // Exclude a thread that does not concurrently share the resource it disposed (unlikely). + not useThread = disposeThread and + followsMainThreadTcc(tcc, useThread) and + followsMainThreadTcc(tcc, disposeThread) and + // If there is a join between the use and the dispose, the code is compliant. + not getAThreadContextAwarePredecessor(elementOr(useThread, use), dispose) instanceof C11ThreadWait +select dispose, "Thread resource $@ disposed before joining thread $@ which uses it.", + usedAndDestroyed.getRootIdentity(), usedAndDestroyed.toString(), elementOr(useThread, use), + describeThread(useThread) diff --git a/c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql b/c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql new file mode 100644 index 0000000000..7c0b86f145 --- /dev/null +++ b/c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql @@ -0,0 +1,68 @@ +/** + * @id c/misra/invalid-operation-on-unlocked-mutex + * @name RULE-22-17: No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked + * @description No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it + * has not locked before. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-17 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.SubObjects +import codingstandards.cpp.Concurrency +import codingstandards.cpp.dominance.BehavioralSet +import semmle.code.cpp.dataflow.new.DataFlow::DataFlow as NewDF + +/* A call to mtx_unlock() or cnd_wait() or cnd_timedwait(), which require a locked mutex */ +class RequiresLockOperation extends FunctionCall { + SubObject mutex; + + RequiresLockOperation() { + exists(CMutexFunctionCall mutexCall | this = mutexCall | + mutexCall.isUnlock() and + mutex.getAnAddressOfExpr() = mutexCall.getLockExpr() + ) + or + exists(CConditionOperation condOp | this = condOp | + mutex.getAnAddressOfExpr() = condOp.getMutexExpr() + ) + } + + SubObject getMutex() { result = mutex } +} + +/* A config to search for a dominating set that locks the mutex before the operation */ +module LockDominatingSetConfig implements DominatingSetConfigSig { + predicate isTargetBehavior(ControlFlowNode node, RequiresLockOperation op) { + exists(CMutexFunctionCall mutexCall | node = mutexCall | + mutexCall.isLock() and + mutexCall.getLockExpr() = op.getMutex().getAnAddressOfExpr() + ) + } + + predicate isBlockingBehavior(ControlFlowNode node, RequiresLockOperation op) { + // If we find a branch that explicitly unlocks the mutex, we should not look for an earlier + // call to lock that mutex. + exists(CMutexFunctionCall mutexCall | node = mutexCall | + mutexCall.isUnlock() and + mutexCall.getLockExpr() = op.getMutex().getAnAddressOfExpr() + ) + } +} + +import DominatingBehavioralSet as DominatingSet + +from RequiresLockOperation operation, SubObject mutex +where + not isExcluded(operation, Concurrency9Package::invalidOperationOnUnlockedMutexQuery()) and + mutex = operation.getMutex() and + not DominatingSet::isDominatedByBehavior(operation) +select operation, "Invalid operation on mutex '$@' not locked by the current thread", + mutex.getRootIdentity(), mutex.toString() diff --git a/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.ql b/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.ql new file mode 100644 index 0000000000..17762b3eee --- /dev/null +++ b/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.ql @@ -0,0 +1,37 @@ +/** + * @id c/misra/non-recursive-mutex-recursively-locked + * @name RULE-22-18: Non-recursive mutexes shall not be recursively locked + * @description Mutexes initialized with mtx_init() without mtx_recursive shall not be locked by a + * thread that has previously locked it. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-22-18 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.SubObjects +import codingstandards.cpp.Concurrency +import codingstandards.cpp.Type + +from + LockProtectedControlFlowNode n, CMutexFunctionCall lockCall, SubObject mutex, + CMutexFunctionCall coveredByLock +where + not isExcluded(n, Concurrency9Package::nonRecursiveMutexRecursivelyLockedQuery()) and + lockCall = n and + coveredByLock = n.coveredByLock() and + not coveredByLock = lockCall and + mutex.isPrecise() and + coveredByLock.getLockExpr() = mutex.getAnAddressOfExpr() and + lockCall.getLockExpr() = mutex.getAnAddressOfExpr() and + forex(C11MutexSource init | init.getMutexExpr() = mutex.getAnAddressOfExpr() | + not init.isRecursive() + ) +select n, "Non-recursive mutex " + mutex.toString() + " locked after it is $@.", coveredByLock, + "already locked" diff --git a/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql b/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql new file mode 100644 index 0000000000..5b848f9e1e --- /dev/null +++ b/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql @@ -0,0 +1,60 @@ +/** + * @id c/misra/non-recursive-mutex-recursively-locked-audit + * @name RULE-22-18: (Audit) Non-recursive mutexes shall not be recursively locked + * @description Mutex that may be initialized without mtx_recursive shall not be locked by a thread + * that has previous may havec locked it. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-18 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * audit + * external/misra/obligation/required + */ + +import cpp +import codeql.util.Boolean +import codingstandards.c.misra +import codingstandards.c.SubObjects +import codingstandards.cpp.Concurrency +import codingstandards.cpp.Type + +predicate isTrackableMutex(CMutexFunctionCall lockCall, Boolean recursive) { + exists(SubObject mutex | + lockCall.getLockExpr() = mutex.getAnAddressOfExpr() and + mutex.isPrecise() and + forex(C11MutexSource init | init.getMutexExpr() = mutex.getAnAddressOfExpr() | + if init.isRecursive() then recursive = true else recursive = false + ) + ) +} + +predicate definitelyDifferentMutexes(CMutexFunctionCall lockCall, CMutexFunctionCall coveredByLock) { + exists(SubObject a, SubObject b | + lockCall.getLockExpr() = a.getAnAddressOfExpr() and + coveredByLock.getLockExpr() = b.getAnAddressOfExpr() and + not a = b + ) +} + +from LockProtectedControlFlowNode n, CMutexFunctionCall lockCall, CMutexFunctionCall coveredByLock +where + not isExcluded(n, Concurrency9Package::nonRecursiveMutexRecursivelyLockedAuditQuery()) and + lockCall = n and + coveredByLock = n.coveredByLock() and + not coveredByLock = lockCall and + // If mutexes are provably different objects, they do not need to be audited + not definitelyDifferentMutexes(lockCall, coveredByLock) and + ( + // If either mutex is not trackable, it should be audited + not isTrackableMutex(lockCall, _) or + not isTrackableMutex(coveredByLock, _) + ) and + not ( + // If either mutex is definitely recursive, it does not need to be audited + isTrackableMutex(lockCall, true) or + isTrackableMutex(coveredByLock, true) + ) +select n, "Mutex locked after previous $@.", coveredByLock, "already locked" diff --git a/c/misra/src/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.ql b/c/misra/src/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.ql new file mode 100644 index 0000000000..afa2556646 --- /dev/null +++ b/c/misra/src/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.ql @@ -0,0 +1,69 @@ +/** + * @id c/misra/condition-variable-used-with-multiple-mutexes + * @name RULE-22-19: A condition variable shall be associated with at most one mutex object + * @description Standard library functions cnd_wait() and cnd_timedwait() shall specify the same + * mutex object for each condition object in all calls. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-22-19 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.SubObjects +import codingstandards.cpp.Concurrency + +bindingset[cond, mutex] +int countMutexesForConditionVariable(SubObject cond, SubObject mutex) { + result = + count(CConditionOperation call | + call.getConditionExpr() = cond.getAnAddressOfExpr() and + call.getMutexExpr() = mutex.getAnAddressOfExpr() + ) +} + +bindingset[cond, mutex] +predicate conditionVariableUsesMutex(SubObject cond, SubObject mutex) { + countMutexesForConditionVariable(cond, mutex) > 0 +} + +bindingset[cond, n] +SubObject nthMutexForConditionVariable(SubObject cond, int n) { + result = + rank[n](SubObject mutex | + conditionVariableUsesMutex(cond, mutex) + | + mutex order by countMutexesForConditionVariable(cond, mutex), mutex.toString() + ) +} + +bindingset[cond, mutex] +CConditionOperation firstCallForConditionMutex(SubObject cond, SubObject mutex) { + result = + rank[1](CConditionOperation call | + call.getConditionExpr() = cond.getAnAddressOfExpr() and + call.getMutexExpr() = mutex.getAnAddressOfExpr() + | + call order by call.getFile().getAbsolutePath(), call.getLocation().getStartLine() + ) +} + +from + SubObject cond, CConditionOperation useOne, SubObject mutexOne, CConditionOperation useTwo, + SubObject mutexTwo +where + not isExcluded(cond.getRootIdentity(), + Concurrency9Package::conditionVariableUsedWithMultipleMutexesQuery()) and + mutexOne = nthMutexForConditionVariable(cond, 1) and + mutexTwo = nthMutexForConditionVariable(cond, 2) and + useOne = firstCallForConditionMutex(cond, mutexOne) and + useTwo = firstCallForConditionMutex(cond, mutexOne) +select useOne, + "Condition variable $@ associated with multiple mutexes, operation uses mutex $@ while $@ uses other mutex $@", + cond.getRootIdentity(), cond.toString(), mutexOne.getRootIdentity(), mutexOne.toString(), useTwo, + "another operation", mutexTwo.getRootIdentity(), mutexTwo.toString() diff --git a/c/misra/src/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.ql b/c/misra/src/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.ql new file mode 100644 index 0000000000..652b5d1f8c --- /dev/null +++ b/c/misra/src/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.ql @@ -0,0 +1,44 @@ +/** + * @id c/misra/thread-storage-not-initialized-before-use + * @name RULE-22-20: Thread-specific storage pointers shall be created before being accessed + * @description Thread specific storage pointers shall be initialized with the standard library + * functions before using them. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-22-20 + * correctness + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Objects +import codingstandards.cpp.Concurrency +import codingstandards.cpp.Type +import codingstandards.c.initialization.GlobalInitializationAnalysis + +module ThreadStoreInitializationConfig implements GlobalInitializationAnalysisConfigSig { + ObjectIdentity getAnInitializedObject(Expr e) { + e.(TSSCreateFunctionCall).getKey() = result.getASubobjectAddressExpr() + } + + ObjectIdentity getAUsedObject(Expr e) { + result.getASubobjectAddressExpr() = e and + exists(ThreadSpecificStorageFunctionCall use | + not use instanceof TSSCreateFunctionCall and e = use.getKey() + ) + } +} + +import GlobalInitalizationAnalysis as InitAnalysis + +from Expr objUse, ObjectIdentity obj, Function callRoot +where + not isExcluded(objUse, Concurrency9Package::threadStorageNotInitializedBeforeUseQuery()) and + InitAnalysis::uninitializedFrom(objUse, obj, callRoot) +select objUse, + "Thread specific storage pointer '$@' possibly used before initialization, from entry point function '$@'.", + obj, obj.toString(), callRoot, callRoot.getName() diff --git a/c/misra/src/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.ql b/c/misra/src/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.ql new file mode 100644 index 0000000000..3c40ea7116 --- /dev/null +++ b/c/misra/src/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.ql @@ -0,0 +1,27 @@ +/** + * @id c/misra/thread-storage-pointer-initialized-inside-thread + * @name RULE-22-20: Thread specific storage pointers shall be initialized deterministically + * @description Thread specific storage pointers initialized inside of threads may result in + * indeterministic state. + * @kind problem + * @precision very-high + * @problem.severity recommendation + * @tags external/misra/id/rule-22-20 + * readability + * maintainability + * concurrency + * external/misra/c/2012/amendment4 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.Concurrency + +from TSSCreateFunctionCall tssCreate, ThreadedFunction thread +where + not isExcluded(tssCreate, Concurrency8Package::mutexInitializedInsideThreadQuery()) and + thread.calls*(tssCreate.getEnclosingFunction()) +select tssCreate, + "Thread specific storage object initialization reachable from threaded function '$@'.", thread, + thread.getName() diff --git a/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.expected b/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.expected new file mode 100644 index 0000000000..3f32b09d5c --- /dev/null +++ b/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.expected @@ -0,0 +1,24 @@ +| test.c:31:3:31:8 | ... = ... | Threaded write to object $@, for example from thread function $@, not synchronized with $@, for example from thread function $@. | test.c:11:5:11:6 | g2 | g2 | test.c:30:6:30:29 | single_thread4_writes_g2 | single_thread4_writes_g2 | test.c:27:3:27:4 | g2 | concurrent read operation | test.c:26:6:26:28 | single_thread3_reads_g2 | single_thread3_reads_g2 | +| test.c:35:3:35:8 | ... = ... | Threaded write to object $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:12:5:12:6 | g3 | g3 | test.c:34:6:34:27 | many_thread5_writes_g3 | many_thread5_writes_g3 | test.c:35:3:35:4 | g3 | concurrent read operation | test.c:34:6:34:27 | many_thread5_writes_g3 | many_thread5_writes_g3 | +| test.c:71:3:71:11 | ... = ... | Threaded write to object $@, for example from thread function $@, not synchronized with $@, for example from thread function $@. | test.c:68:3:68:4 | g7 | g7.m1 | test.c:70:6:70:33 | single_thread11_writes_g7_m1 | single_thread11_writes_g7_m1 | test.c:75:6:75:7 | m1 | concurrent read operation | test.c:74:6:74:33 | single_thread12_writes_g7_m1 | single_thread12_writes_g7_m1 | +| test.c:75:3:75:11 | ... = ... | Threaded write to object $@, for example from thread function $@, not synchronized with $@, for example from thread function $@. | test.c:68:3:68:4 | g7 | g7.m1 | test.c:74:6:74:33 | single_thread12_writes_g7_m1 | single_thread12_writes_g7_m1 | test.c:71:6:71:7 | m1 | concurrent read operation | test.c:70:6:70:33 | single_thread11_writes_g7_m1 | single_thread11_writes_g7_m1 | +| test.c:79:3:79:11 | call to setlocale | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:79:3:79:11 | call to setlocale | setlocale | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:79:3:79:11 | call to setlocale | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:80:3:80:8 | call to tmpnam | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:80:3:80:8 | call to tmpnam | tmpnam | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:80:3:80:8 | call to tmpnam | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:81:3:81:6 | call to rand | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:81:3:81:6 | call to rand | rand | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:81:3:81:6 | call to rand | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:82:3:82:7 | call to srand | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:82:3:82:7 | call to srand | srand | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:82:3:82:7 | call to srand | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:83:3:83:8 | call to getenv | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:83:3:83:8 | call to getenv | getenv | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:83:3:83:8 | call to getenv | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:84:3:84:10 | call to getenv_s | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:84:3:84:10 | call to getenv_s | getenv_s | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:84:3:84:10 | call to getenv_s | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:86:3:86:10 | call to strerror | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:86:3:86:10 | call to strerror | strerror | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:86:3:86:10 | call to strerror | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:87:3:87:9 | call to asctime | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:87:3:87:9 | call to asctime | asctime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:87:3:87:9 | call to asctime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:88:3:88:7 | call to ctime | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:88:3:88:7 | call to ctime | ctime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:88:3:88:7 | call to ctime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:89:3:89:8 | call to gmtime | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:89:3:89:8 | call to gmtime | gmtime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:89:3:89:8 | call to gmtime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:90:3:90:11 | call to localtime | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:90:3:90:11 | call to localtime | localtime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:90:3:90:11 | call to localtime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:91:3:91:10 | call to mbrtoc16 | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:91:3:91:10 | call to mbrtoc16 | mbrtoc16 | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:91:3:91:10 | call to mbrtoc16 | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:92:3:92:10 | call to mbrtoc32 | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:92:3:92:10 | call to mbrtoc32 | mbrtoc32 | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:92:3:92:10 | call to mbrtoc32 | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:93:3:93:10 | call to c16rtomb | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:93:3:93:10 | call to c16rtomb | c16rtomb | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:93:3:93:10 | call to c16rtomb | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:94:3:94:10 | call to c32rtomb | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:94:3:94:10 | call to c32rtomb | c32rtomb | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:94:3:94:10 | call to c32rtomb | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:95:3:95:8 | call to mbrlen | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:95:3:95:8 | call to mbrlen | mbrlen | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:95:3:95:8 | call to mbrlen | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:96:3:96:9 | call to mbrtowc | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:96:3:96:9 | call to mbrtowc | mbrtowc | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:96:3:96:9 | call to mbrtowc | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:97:3:97:9 | call to wcrtomb | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:97:3:97:9 | call to wcrtomb | wcrtomb | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:97:3:97:9 | call to wcrtomb | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:98:3:98:11 | call to mbsrtowcs | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:98:3:98:11 | call to mbsrtowcs | mbsrtowcs | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:98:3:98:11 | call to mbsrtowcs | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:99:3:99:11 | call to wcsrtombs | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:99:3:99:11 | call to wcsrtombs | wcsrtombs | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:99:3:99:11 | call to wcsrtombs | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | diff --git a/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.qlref b/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.qlref new file mode 100644 index 0000000000..737cf79505 --- /dev/null +++ b/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.qlref @@ -0,0 +1 @@ +rules/DIR-5-1/PossibleDataRaceBetweenThreads.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-5-1/test.c b/c/misra/test/rules/DIR-5-1/test.c new file mode 100644 index 0000000000..5e568cc95c --- /dev/null +++ b/c/misra/test/rules/DIR-5-1/test.c @@ -0,0 +1,132 @@ +#include "locale.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "threads.h" +#include "time.h" +#include "uchar.h" +#include "wchar.h" + +int g1; +int g2; +int g3; +int g4; +mtx_t g4_lock; +int g5; +mtx_t g5_lock; + +void single_thread1_reads_g1(void *p) { + g1; // COMPLIANT +} + +void many_thread2_reads_g1(void *p) { + g1; // COMPLIANT +} + +void single_thread3_reads_g2(void *p) { + g2; // COMPLIANT +} + +void single_thread4_writes_g2(void *p) { + g2 = 1; // NON-COMPLIANT +} + +void many_thread5_writes_g3(void *p) { + g3 = 1; // NON-COMPLIANT +} + +void single_thread6_reads_g4_locked(void *p) { + mtx_lock(&g4_lock); + g4; // COMPLIANT +} + +void single_thread7_writes_g4_locked(void *p) { + mtx_lock(&g4_lock); + g4 = 1; // COMPLIANT +} + +void many_thread8_writes_g5_locked(void *p) { + mtx_lock(&g5_lock); + g5 = 1; // COMPLIANT +} + +struct { + int m1; + int m2; +} g6; + +void single_thread9_writes_g6_m1(void *p) { + g6.m1 = 1; // COMPLIANT +} + +void single_thread10_writes_g6_m2(void *p) { + g6.m2 = 1; // COMPLIANT +} + +struct { + int m1; +} g7; + +void single_thread11_writes_g7_m1(void *p) { + g7.m1 = 1; // NON-COMPLIANT +} + +void single_thread12_writes_g7_m1(void *p) { + g7.m1 = 1; // NON-COMPLIANT +} + +void many_thread13_calls_nonreentrant_funcs(void *p) { + setlocale(LC_ALL, "C"); // NON-COMPLIANT + tmpnam(""); // NON-COMPLIANT + rand(); // NON-COMPLIANT + srand(0); // NON-COMPLIANT + getenv("PATH"); // NON-COMPLIANT + getenv_s(NULL, NULL, 0, NULL); // NON-COMPLIANT + strtok("a", "b"); // NON-COMPLIANT + strerror(0); // NON-COMPLIANT + asctime(NULL); // NON-COMPLIANT + ctime(NULL); // NON-COMPLIANT + gmtime(NULL); // NON-COMPLIANT + localtime(NULL); // NON-COMPLIANT + mbrtoc16(NULL, NULL, 0, NULL); // NON-COMPLIANT + mbrtoc32(NULL, NULL, 0, NULL); // NON-COMPLIANT + c16rtomb(NULL, 0, NULL); // NON-COMPLIANT + c32rtomb(NULL, 0, NULL); // NON-COMPLIANT + mbrlen(NULL, 0, NULL); // NON-COMPLIANT + mbrtowc(NULL, NULL, 0, NULL); // NON-COMPLIANT + wcrtomb(NULL, 0, NULL); // NON-COMPLIANT + mbsrtowcs(NULL, NULL, 0, NULL); // NON-COMPLIANT + wcsrtombs(NULL, NULL, 0, NULL); // NON-COMPLIANT +} + +void main() { + thrd_t single_thread1; + thrd_t many_thread2; + thrd_t single_thread3; + thrd_t single_thread4; + thrd_t many_thread5; + thrd_t single_thread6; + thrd_t single_thread7; + thrd_t many_thread8; + thrd_t single_thread9; + thrd_t single_thread10; + thrd_t single_thread11; + thrd_t single_thread12; + thrd_t many_thread13; + + thrd_create(&single_thread1, single_thread1_reads_g1, NULL); + thrd_create(&single_thread3, single_thread3_reads_g2, NULL); + thrd_create(&single_thread4, single_thread4_writes_g2, NULL); + thrd_create(&single_thread6, single_thread6_reads_g4_locked, NULL); + thrd_create(&single_thread7, single_thread7_writes_g4_locked, NULL); + thrd_create(&single_thread9, single_thread9_writes_g6_m1, NULL); + thrd_create(&single_thread10, single_thread10_writes_g6_m2, NULL); + thrd_create(&single_thread11, single_thread11_writes_g7_m1, NULL); + thrd_create(&single_thread12, single_thread12_writes_g7_m1, NULL); + for (;;) { + thrd_create(&many_thread2, many_thread2_reads_g1, NULL); + thrd_create(&many_thread5, many_thread5_writes_g3, NULL); + thrd_create(&many_thread8, many_thread8_writes_g5_locked, NULL); + thrd_create(&many_thread13, many_thread13_calls_nonreentrant_funcs, NULL); + } +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.expected b/c/misra/test/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.expected new file mode 100644 index 0000000000..49f1b74c15 --- /dev/null +++ b/c/misra/test/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.expected @@ -0,0 +1,12 @@ +| test.c:16:3:16:13 | call to mtx_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:3:7:3:8 | g1 | g1 | test.c:64:3:64:13 | call to thrd_create | t2_use_all | +| test.c:16:3:16:13 | call to mtx_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:3:7:3:8 | g1 | g1 | test.c:72:3:72:13 | call to thrd_create | t2_use_all | +| test.c:16:3:16:13 | call to mtx_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:3:7:3:8 | g1 | g1 | test.c:91:3:91:10 | call to mtx_lock | main thread | +| test.c:17:3:17:12 | call to tss_delete | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:4:7:4:8 | g2 | g2 | test.c:64:3:64:13 | call to thrd_create | t2_use_all | +| test.c:17:3:17:12 | call to tss_delete | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:4:7:4:8 | g2 | g2 | test.c:72:3:72:13 | call to thrd_create | t2_use_all | +| test.c:17:3:17:12 | call to tss_delete | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:4:7:4:8 | g2 | g2 | test.c:92:3:92:9 | call to tss_get | main thread | +| test.c:18:3:18:13 | call to cnd_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:5:7:5:8 | g3 | g3 | test.c:64:3:64:13 | call to thrd_create | t2_use_all | +| test.c:18:3:18:13 | call to cnd_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:5:7:5:8 | g3 | g3 | test.c:72:3:72:13 | call to thrd_create | t2_use_all | +| test.c:18:3:18:13 | call to cnd_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:5:7:5:8 | g3 | g3 | test.c:93:3:93:10 | call to cnd_wait | main thread | +| test.c:42:3:42:13 | call to mtx_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:3:7:3:8 | g1 | g1 | test.c:41:3:41:13 | call to thrd_create | t2_use_all | +| test.c:43:3:43:12 | call to tss_delete | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:4:7:4:8 | g2 | g2 | test.c:41:3:41:13 | call to thrd_create | t2_use_all | +| test.c:44:3:44:13 | call to cnd_destroy | Thread resource $@ disposed before joining thread $@ which uses it. | test.c:5:7:5:8 | g3 | g3 | test.c:41:3:41:13 | call to thrd_create | t2_use_all | diff --git a/c/misra/test/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.qlref b/c/misra/test/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.qlref new file mode 100644 index 0000000000..809eae6faf --- /dev/null +++ b/c/misra/test/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.qlref @@ -0,0 +1 @@ +rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-15/test.c b/c/misra/test/rules/RULE-22-15/test.c new file mode 100644 index 0000000000..7679730fc9 --- /dev/null +++ b/c/misra/test/rules/RULE-22-15/test.c @@ -0,0 +1,113 @@ +#include "threads.h" + +mtx_t g1; +tss_t g2; +cnd_t g3; + +int t1_use_none(void *p) { return 0; } + +int t2_use_all(void *p) { + mtx_lock(&g1); + tss_get(&g2); + cnd_wait(&g3, &g1); +} + +int t3_dispose_all(void *p) { + mtx_destroy(&g1); + tss_delete(&g2); + cnd_destroy(&g3); +} + +int t4_use_then_dispose(void *p) { + mtx_lock(&g1); + tss_get(&g2); + cnd_wait(&g3, &g1); + + mtx_destroy(&g1); + tss_delete(&g2); + cnd_destroy(&g3); +} + +void f1() { + thrd_t t; + thrd_create(&t, t1_use_none, NULL); + mtx_destroy(&g1); + tss_delete(&g2); + cnd_destroy(&g3); +} + +void f2() { + thrd_t t; + thrd_create(&t, t2_use_all, NULL); + mtx_destroy(&g1); // NON-COMPLIANT + tss_delete(&g2); // NON-COMPLIANT + cnd_destroy(&g3); // NON-COMPLIANT +} + +void f3() { + thrd_t t; + thrd_create(&t, t2_use_all, NULL); // COMPLIANT +} + +void f4() { + thrd_t t; + thrd_create(&t, t2_use_all, NULL); // COMPLIANT + thrd_join(&t, NULL); + mtx_destroy(&g1); // COMPLIANT + tss_delete(&g2); // COMPLIANT + cnd_destroy(&g3); // COMPLIANT +} + +void f5() { + thrd_t t1; + thrd_t t2; + thrd_create(&t1, t2_use_all, NULL); // COMPLIANT + thrd_create(&t2, t3_dispose_all, NULL); // NON-COMPLIANT +} + +void f6() { + thrd_t t1; + thrd_t t2; + thrd_create(&t1, t3_dispose_all, NULL); // NON-COMPLIANT + thrd_create(&t2, t2_use_all, NULL); // COMPLIANT +} + +void f7() { + thrd_t t1; + thrd_t t2; + thrd_create(&t1, t2_use_all, NULL); // COMPLIANT + thrd_join(&t1, NULL); + thrd_create(&t2, t3_dispose_all, NULL); // COMPLIANT +} + +void f8() { + thrd_t t; + thrd_create(&t, t4_use_then_dispose, NULL); // COMPLIANT +} + +void f9() { + thrd_t t; + thrd_create(&t, t3_dispose_all, NULL); // NON-COMPLIANT + mtx_lock(&g1); + tss_get(&g2); + cnd_wait(&g3, &g1); +} + +void f10() { + thrd_t t; + mtx_lock(&g1); + tss_get(&g2); + cnd_wait(&g3, &g1); + thrd_create(&t, t3_dispose_all, NULL); // COMPLIANT +} + +void f11() { + thrd_t t; + thrd_create(&t, t1_use_none, NULL); + mtx_lock(&g1); + tss_get(&g2); + cnd_wait(&g3, &g1); + mtx_destroy(&g1); // COMPLIANT + tss_delete(&g2); // COMPLIANT + cnd_destroy(&g3); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.expected b/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.expected new file mode 100644 index 0000000000..76d3ac1ba1 --- /dev/null +++ b/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.expected @@ -0,0 +1,16 @@ +| test.c:19:3:19:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:11:9:11:10 | l1 | l1 | +| test.c:20:3:20:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:11:9:11:10 | l1 | l1 | +| test.c:25:3:25:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:14:5:14:6 | l2 | l2.m1 | +| test.c:26:3:26:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:14:5:14:6 | l2 | l2.m1 | +| test.c:31:3:31:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:3:7:3:8 | g1 | g1 | +| test.c:32:3:32:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:3:7:3:8 | g1 | g1 | +| test.c:37:3:37:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:6:3:6:4 | g2 | g2.m1 | +| test.c:38:3:38:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:6:3:6:4 | g2 | g2.m1 | +| test.c:47:3:47:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:11:9:11:10 | l1 | l1 | +| test.c:48:3:48:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:14:5:14:6 | l2 | l2.m1 | +| test.c:49:3:49:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:3:7:3:8 | g1 | g1 | +| test.c:50:3:50:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:6:3:6:4 | g2 | g2.m1 | +| test.c:51:3:51:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:11:9:11:10 | l1 | l1 | +| test.c:52:3:52:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:14:5:14:6 | l2 | l2.m1 | +| test.c:53:3:53:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:3:7:3:8 | g1 | g1 | +| test.c:54:3:54:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:6:3:6:4 | g2 | g2.m1 | diff --git a/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.qlref b/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.qlref new file mode 100644 index 0000000000..4ac06f10ed --- /dev/null +++ b/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.qlref @@ -0,0 +1 @@ +rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-17/test.c b/c/misra/test/rules/RULE-22-17/test.c new file mode 100644 index 0000000000..fc841bb3e1 --- /dev/null +++ b/c/misra/test/rules/RULE-22-17/test.c @@ -0,0 +1,70 @@ +#include "threads.h" + +mtx_t g1; +struct { + mtx_t m1; +} g2; + +cnd_t cnd; + +void f1(int p) { + mtx_t l1; + struct { + mtx_t m1; + } l2; + + mtx_lock(&l1); + cnd_wait(&cnd, &l1); // COMPLIANT + mtx_unlock(&l1); // COMPLIANT + cnd_wait(&cnd, &l1); // NON-COMPLIANT + mtx_unlock(&l1); // NON-COMPLIANT + + mtx_lock(&l2.m1); + cnd_wait(&cnd, &l2.m1); // COMPLIANT + mtx_unlock(&l2.m1); // COMPLIANT + cnd_wait(&cnd, &l2.m1); // NON-COMPLIANT + mtx_unlock(&l2.m1); // NON-COMPLIANT + + mtx_lock(&g1); + cnd_wait(&cnd, &g1); // COMPLIANT + mtx_unlock(&g1); // COMPLIANT + cnd_wait(&cnd, &g1); // NON-COMPLIANT + mtx_unlock(&g1); // NON-COMPLIANT + + mtx_lock(&g2.m1); + cnd_wait(&cnd, &g2.m1); // COMPLIANT + mtx_unlock(&g2.m1); // COMPLIANT + cnd_wait(&cnd, &g2.m1); // NON-COMPLIANT + mtx_unlock(&g2.m1); // NON-COMPLIANT + + // We should report when a mutex is unlocked in the wrong block: + if (p) { + mtx_lock(&l1); + mtx_lock(&l2.m1); + mtx_lock(&g1); + mtx_lock(&g2.m1); + } + cnd_wait(&cnd, &l1); // NON-COMPLIANT + cnd_wait(&cnd, &l2.m1); // NON-COMPLIANT + cnd_wait(&cnd, &g1); // NON-COMPLIANT + cnd_wait(&cnd, &g2.m1); // NON-COMPLIANT + mtx_unlock(&l1); // NON-COMPLIANT + mtx_unlock(&l2.m1); // NON-COMPLIANT + mtx_unlock(&g1); // NON-COMPLIANT + mtx_unlock(&g2.m1); // NON-COMPLIANT + + // The above requires dominance analysis. Check dominator sets don't cause + // false positives: + if (p) { + mtx_lock(&l1); + } else { + mtx_lock(&l1); + } + mtx_unlock(&l1); // COMPLIANT + + // Invalid but satisfies the rule: + mtx_lock(&l1); + if (p) { + mtx_unlock(&l1); // COMPLIANT + } +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.expected b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.expected new file mode 100644 index 0000000000..fd947dee51 --- /dev/null +++ b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.expected @@ -0,0 +1,2 @@ +| test.c:19:3:19:10 | call to mtx_lock | Non-recursive mutex nonrec locked after it is $@. | test.c:18:3:18:10 | call to mtx_lock | already locked | +| test.c:22:3:22:10 | call to mtx_lock | Non-recursive mutex s.m locked after it is $@. | test.c:21:3:21:10 | call to mtx_lock | already locked | diff --git a/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.qlref b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.qlref new file mode 100644 index 0000000000..131e0476bf --- /dev/null +++ b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.qlref @@ -0,0 +1 @@ +rules/RULE-22-18/NonRecursiveMutexRecursivelyLocked.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.expected b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.expected new file mode 100644 index 0000000000..8f359c90f8 --- /dev/null +++ b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.expected @@ -0,0 +1,6 @@ +| test.c:44:3:44:10 | call to mtx_lock | Mutex locked after previous $@. | test.c:43:3:43:10 | call to mtx_lock | already locked | +| test.c:49:3:49:10 | call to mtx_lock | Mutex locked after previous $@. | test.c:48:3:48:10 | call to mtx_lock | already locked | +| test.c:54:3:54:10 | call to mtx_lock | Mutex locked after previous $@. | test.c:53:3:53:10 | call to mtx_lock | already locked | +| test.c:59:3:59:10 | call to mtx_lock | Mutex locked after previous $@. | test.c:58:3:58:10 | call to mtx_lock | already locked | +| test.c:76:3:76:10 | call to mtx_lock | Mutex locked after previous $@. | test.c:75:3:75:10 | call to mtx_lock | already locked | +| test.c:81:3:81:10 | call to mtx_lock | Mutex locked after previous $@. | test.c:80:3:80:10 | call to mtx_lock | already locked | diff --git a/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.qlref b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.qlref new file mode 100644 index 0000000000..77a81deb69 --- /dev/null +++ b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.qlref @@ -0,0 +1 @@ +rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-18/test.c b/c/misra/test/rules/RULE-22-18/test.c new file mode 100644 index 0000000000..f71066b1bc --- /dev/null +++ b/c/misra/test/rules/RULE-22-18/test.c @@ -0,0 +1,122 @@ +#include "threads.h" + +mtx_t rec; +mtx_t nonrec; +mtx_t both; +mtx_t unknown; + +struct { + mtx_t m; +} s; + +mtx_t arr[2]; + +int t1(void *arg) { + mtx_lock(&rec); // COMPLIANT + mtx_lock(&rec); // COMPLIANT + + mtx_lock(&nonrec); // COMPLIANT + mtx_lock(&nonrec); // NON-COMPLIANT + + mtx_lock(&s.m); // COMPLIANT + mtx_lock(&s.m); // NON-COMPLIANT +} + +void f1() { + mtx_init(&rec, mtx_plain | mtx_recursive); + mtx_init(&nonrec, mtx_plain); + mtx_init(&both, mtx_plain); + mtx_init(&both, mtx_plain | mtx_recursive); + // Do not initialize `unknown`. + mtx_init(&s.m, mtx_plain); + mtx_init(&arr[0], mtx_plain); + mtx_init(&arr[1], mtx_plain); + + thrd_t t; + thrd_create(t, t1, NULL); +} + +mtx_t *p; + +// Results for the audit query: +void t2(void *arg) { + mtx_lock(&arr[0]); + mtx_lock(&arr[(int)arg]); // NON-COMPLIANT +} + +void t3(void *arg) { + mtx_lock(arg); + mtx_lock(p); // NON-COMPLIANT +} + +void t4() { + mtx_lock(&both); + mtx_lock(&both); // NON-COMPLIANT +} + +void t5() { + mtx_lock(&unknown); + mtx_lock(&unknown); // NON-COMPLIANT +} + +void t6() { + // Cannot be locks of the same mutex: + mtx_lock(&nonrec); + mtx_lock(&unknown); // COMPLIANT +} + +void t7() { + mtx_lock(p); + // Definitely a recursive mutex: + mtx_lock(&rec); // COMPLIANT +} + +void t8() { + mtx_lock(p); + mtx_lock(&nonrec); // NON-COMPLIANT +} + +void t9() { + mtx_lock(&nonrec); + mtx_lock(p); // NON-COMPLIANT +} + +void f2() { + thrd_t t; + thrd_create(t, t2, NULL); +} + +void f3() { + thrd_t t; + thrd_create(t, t3, &rec); +} + +void f4() { + thrd_t t; + thrd_create(t, t4, NULL); +} + +void f5() { + thrd_t t; + thrd_create(t, t5, NULL); +} + +void f6() { + thrd_t t; + thrd_create(t, t6, NULL); +} + +void f7() { + thrd_t t; + thrd_create(t, t7, NULL); +} + +void f8() { + thrd_t t; + thrd_create(t, t8, NULL); +} + +void f9() { + thrd_t t; + thrd_create(t, t9, NULL); +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.expected b/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.expected new file mode 100644 index 0000000000..ee9dff0be2 --- /dev/null +++ b/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.expected @@ -0,0 +1,2 @@ +| test.c:19:3:19:10 | call to cnd_wait | Condition variable $@ associated with multiple mutexes, operation uses mutex $@ while $@ uses other mutex $@ | test.c:16:9:16:12 | cnd1 | cnd1 | test.c:17:9:17:12 | mtx1 | mtx1 | test.c:19:3:19:10 | call to cnd_wait | another operation | test.c:18:9:18:12 | mtx2 | mtx2 | +| test.c:41:3:41:10 | call to cnd_wait | Condition variable $@ associated with multiple mutexes, operation uses mutex $@ while $@ uses other mutex $@ | test.c:37:7:37:11 | gcnd1 | gcnd1 | test.c:38:7:38:11 | gmtx1 | gmtx1 | test.c:41:3:41:10 | call to cnd_wait | another operation | test.c:39:7:39:11 | gmtx2 | gmtx2 | diff --git a/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.qlref b/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.qlref new file mode 100644 index 0000000000..d43a824ec8 --- /dev/null +++ b/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.qlref @@ -0,0 +1 @@ +rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-19/test.c b/c/misra/test/rules/RULE-22-19/test.c new file mode 100644 index 0000000000..f4b46d4077 --- /dev/null +++ b/c/misra/test/rules/RULE-22-19/test.c @@ -0,0 +1,46 @@ +#include "threads.h" + +void f1(void) { + cnd_t cnd1; + mtx_t mtx1; + cnd_wait(&cnd1, &mtx1); // COMPLIANT + cnd_wait(&cnd1, &mtx1); // COMPLIANT + + cnd_t cnd2; + mtx_t mtx2; + cnd_wait(&cnd2, &mtx2); // COMPLIANT + cnd_wait(&cnd2, &mtx2); // COMPLIANT +} + +void f2(void) { + cnd_t cnd1; + mtx_t mtx1; + mtx_t mtx2; + cnd_wait(&cnd1, &mtx1); // NON-COMPLIANT + cnd_wait(&cnd1, &mtx2); // NON-COMPLIANT +} + +void f3(void) { + cnd_t cnd1; + cnd_t cnd2; + mtx_t mtx1; + cnd_wait(&cnd1, &mtx1); // COMPLIANT + cnd_wait(&cnd2, &mtx1); // COMPLIANT +} + +void f4(cnd_t *cnd1, mtx_t *mtx1, mtx_t *mtx2) { + cnd_wait(cnd1, mtx1); // COMPLIANT + // Compliant, mtx1 and mtx2 may point to the same object + cnd_wait(cnd1, mtx2); // COMPLIANT +} + +cnd_t gcnd1; +mtx_t gmtx1; +mtx_t gmtx2; +void f5(void) { + cnd_wait(&gcnd1, &gmtx1); // NON-COMPLIANT +} + +void f6(void) { + cnd_wait(&gcnd1, &gmtx2); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.expected b/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.expected new file mode 100644 index 0000000000..9a9b86dfa2 --- /dev/null +++ b/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.expected @@ -0,0 +1,5 @@ +| test.c:6:11:6:13 | & ... | Thread specific storage pointer '$@' possibly used before initialization, from entry point function '$@'. | test.c:5:9:5:10 | l1 | l1 | test.c:4:6:4:19 | use_local_mtxs | use_local_mtxs | +| test.c:11:11:11:12 | l4 | Thread specific storage pointer '$@' possibly used before initialization, from entry point function '$@'. | test.c:10:15:10:20 | call to malloc | call to malloc | test.c:16:6:16:31 | root1_calls_use_local_mtxs | root1_calls_use_local_mtxs | +| test.c:25:11:25:13 | & ... | Thread specific storage pointer '$@' possibly used before initialization, from entry point function '$@'. | test.c:22:7:22:8 | g1 | g1 | test.c:24:6:24:28 | root2_uses_global_tss_t | root2_uses_global_tss_t | +| test.c:38:11:38:13 | & ... | Thread specific storage pointer '$@' possibly used before initialization, from entry point function '$@'. | test.c:22:7:22:8 | g1 | g1 | test.c:41:6:41:45 | root4_call_thread_without_initialization | root4_call_thread_without_initialization | +| test.c:58:11:58:13 | & ... | Thread specific storage pointer '$@' possibly used before initialization, from entry point function '$@'. | test.c:56:7:56:8 | g5 | g5 | test.c:67:6:67:50 | root6_spawn_thread_uninitialized_thread_local | root6_spawn_thread_uninitialized_thread_local | diff --git a/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.qlref b/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.qlref new file mode 100644 index 0000000000..10d9aadf1b --- /dev/null +++ b/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.qlref @@ -0,0 +1 @@ +rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.expected b/c/misra/test/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.expected new file mode 100644 index 0000000000..75e9825074 --- /dev/null +++ b/c/misra/test/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.expected @@ -0,0 +1 @@ +| test.c:61:3:61:12 | call to tss_create | Thread specific storage object initialization reachable from threaded function '$@'. | test.c:57:6:57:41 | from_root6_init_and_use_thread_local | from_root6_init_and_use_thread_local | diff --git a/c/misra/test/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.qlref b/c/misra/test/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.qlref new file mode 100644 index 0000000000..d299808814 --- /dev/null +++ b/c/misra/test/rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.qlref @@ -0,0 +1 @@ +rules/RULE-22-20/ThreadStoragePointerInitializedInsideThread.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-20/test.c b/c/misra/test/rules/RULE-22-20/test.c new file mode 100644 index 0000000000..0fe58abdcd --- /dev/null +++ b/c/misra/test/rules/RULE-22-20/test.c @@ -0,0 +1,70 @@ +#include "stdlib.h" +#include "threads.h" + +void use_local_mtxs(int x, int y) { + tss_t l1; + tss_get(&l1); // NON-COMPLIANT + tss_create(&l1, NULL); + tss_get(&l1); // COMPLIANT + + tss_t *l4 = malloc(sizeof(tss_t)); + tss_get(l4); // NON-COMPLIANT + tss_create(l4, NULL); + tss_get(l4); // COMPLIANT +} + +void root1_calls_use_local_mtxs() { + // Since a function exists which calls use_local_mtxs(), that function is not + // a root function. The query should still report unused locals in this case. + use_local_mtxs(1, 2); +} + +tss_t g1; + +void root2_uses_global_tss_t() { + tss_get(&g1); // NON-COMPLIANT +} + +void from_root3_use_global_tss_t() { + tss_get(&g1); // COMPLIANT +} + +void root3_initializes_and_uses_global_tss_t() { + tss_create(&g1, NULL); + from_root3_use_global_tss_t(); +} + +void from_root4_use_global_tss_t(void *arg) { + tss_get(&g1); // NON-COMPLIANT +} + +void root4_call_thread_without_initialization() { + thrd_t t; + thrd_create(&t, &from_root4_use_global_tss_t, NULL); +} + +void from_root5_use_global_tss_t(void *arg) { + tss_get(&g1); // COMPLIANT +} + +void root5_thread_with_initialization() { + tss_create(&g1, NULL); + thrd_t t; + thrd_create(&t, &from_root5_use_global_tss_t, NULL); +} + +mtx_t g5; +void from_root6_init_and_use_thread_local() { + tss_get(&g5); // NON-COMPLIANT + + // Violates recommendation, tss_t initialized within a thread. + tss_create(&g5, NULL); // NON-COMPLIANT + + // Valid if we except the above initialization. + tss_get(&g5); // COMPLIANT +} + +void root6_spawn_thread_uninitialized_thread_local() { + thrd_t t; + thrd_create(&t, &from_root6_init_and_use_thread_local, NULL); +} \ No newline at end of file diff --git a/change_notes/2024-12-10-refactor-concurrency-library.md b/change_notes/2024-12-10-refactor-concurrency-library.md new file mode 100644 index 0000000000..ccefe85f19 --- /dev/null +++ b/change_notes/2024-12-10-refactor-concurrency-library.md @@ -0,0 +1,2 @@ + - `Concurrency.qll` - for all queries using this library + - This has been refactored into a set of smaller utility files. No impact on query results or performance expected. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Concurrency.qll b/cpp/common/src/codingstandards/cpp/Concurrency.qll index cfb0f03f72..0e2afb8ece 100644 --- a/cpp/common/src/codingstandards/cpp/Concurrency.qll +++ b/cpp/common/src/codingstandards/cpp/Concurrency.qll @@ -1,1015 +1,15 @@ import cpp import semmle.code.cpp.dataflow.TaintTracking - -/** - * Models CFG nodes which should be added to a thread context. - */ -abstract class ThreadedCFGPathExtension extends ControlFlowNode { - /** - * Returns the next `ControlFlowNode` in this thread context. - */ - abstract ControlFlowNode getNext(); -} - -/** - * Models a `FunctionCall` invoked from a threaded context. - */ -class ThreadContextFunctionCall extends FunctionCall, ThreadedCFGPathExtension { - override ControlFlowNode getNext() { getTarget().getEntryPoint() = result } -} - -/** - * Models a specialized `FunctionCall` that may create a thread. - */ -abstract class ThreadCreationFunction extends FunctionCall, ThreadedCFGPathExtension { - /** - * Returns the function that will be invoked. - */ - abstract Function getFunction(); -} - -/** - * Models a call to a thread constructor via `std::thread`. - */ -class ThreadConstructorCall extends ConstructorCall, ThreadCreationFunction { - Function f; - - ThreadConstructorCall() { - getTarget().getDeclaringType().hasQualifiedName("std", "thread") and - f = getArgument(0).(FunctionAccess).getTarget() - } - - /** - * Returns the function that will be invoked by this `std::thread`. - */ - override Function getFunction() { result = f } - - override ControlFlowNode getNext() { result = getFunction().getEntryPoint() } -} - -/** - * Models a call to a thread creation via `thrd_create` or `pthread_create`. - */ -class CThreadCreateCall extends FunctionCall { - Function f; - int fArgIdx; - - CThreadCreateCall() { - ( - getTarget().getName() = "thrd_create" and - fArgIdx = 1 - or - getTarget().getName() = "pthread_create" and - fArgIdx = 2 - ) and - ( - f = getArgument(fArgIdx).(FunctionAccess).getTarget() or - f = getArgument(fArgIdx).(AddressOfExpr).getOperand().(FunctionAccess).getTarget() - ) - } - - /** - * Returns the function that will be invoked by this thread. - */ - Function getFunction() { result = f } -} - -/** - * Models a call to a thread constructor via `thrd_create`. - */ -class C11ThreadCreateCall extends ThreadCreationFunction, CThreadCreateCall { - C11ThreadCreateCall() { getTarget().getName() = "thrd_create" } - - /** - * Returns the function that will be invoked by this thread. - */ - override Function getFunction() { result = f } - - override ControlFlowNode getNext() { result = getFunction().getEntryPoint() } -} - -class C11MutexType extends TypedefType { - C11MutexType() { this.hasName("mtx_t") } -} - -class C11ThreadType extends TypedefType { - C11ThreadType() { this.hasName("thrd_t") } -} - -class C11ConditionType extends TypedefType { - C11ConditionType() { this.hasName("cnd_t") } -} - -class C11ThreadStorageType extends TypedefType { - C11ThreadStorageType() { this.hasName("tss_t") } -} - -class C11ThreadingObjectType extends TypedefType { - C11ThreadingObjectType() { - this instanceof C11MutexType - or - this instanceof C11ThreadType - or - this instanceof C11ConditionType - or - this instanceof C11ThreadStorageType - } -} - -/** - * Common base class providing an interface into function call - * based mutex locks. - */ -abstract class MutexFunctionCall extends LockingOperation { - abstract predicate isRecursive(); - - abstract predicate isSpeculativeLock(); - - abstract predicate unlocks(MutexFunctionCall fc); -} - -/** - * Models calls to various mutex types found in CPP. - */ -class CPPMutexFunctionCall extends MutexFunctionCall { - VariableAccess var; - - CPPMutexFunctionCall() { - ( - // the non recursive kinds - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "mutex") or - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "timed_mutex") or - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "shared_timed_mutex") or - // the recursive ones - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_mutex") or - getTarget() - .(MemberFunction) - .getDeclaringType() - .hasQualifiedName("std", "recursive_timed_mutex") - ) and - var = getQualifier() - } - - /** - * Holds if this mutex is a recursive mutex. - */ - override predicate isRecursive() { - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_mutex") or - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_timed_mutex") - } - - /** - * Holds if this `CPPMutexFunctionCall` is a lock. - */ - override predicate isLock() { - not isLockingOperationWithinLockingOperation(this) and - getTarget().getName() = "lock" - } - - /** - * Holds if this `CPPMutexFunctionCall` is a speculative lock, defined as calling - * one of the speculative locking functions such as `try_lock`. - */ - override predicate isSpeculativeLock() { - getTarget().getName() in [ - "try_lock", "try_lock_for", "try_lock_until", "try_lock_shared_for", "try_lock_shared_until" - ] - } - - /** - * Returns the lock to which this `CPPMutexFunctionCall` refers to. - */ - override Variable getLock() { result = getQualifier().(VariableAccess).getTarget() } - - /** - * Returns the qualifier for this `CPPMutexFunctionCall`. - */ - override Expr getLockExpr() { result = var } - - /** - * Holds if this is a `unlock` and *may* unlock the previously locked `MutexFunctionCall`. - * This predicate does not check that the mutex is currently locked. - */ - override predicate unlocks(MutexFunctionCall fc) { - isUnlock() and - fc.getQualifier().(VariableAccess).getTarget() = getQualifier().(VariableAccess).getTarget() - } - - /** - * Holds if this is an unlock call. - */ - override predicate isUnlock() { getTarget().getName() = "unlock" } -} - -/** - * Models calls to various mutex types specialized to C code. - */ -class CMutexFunctionCall extends MutexFunctionCall { - Expr arg; - - CMutexFunctionCall() { - // the non recursive kinds - getTarget().getName() = ["mtx_lock", "mtx_unlock", "mtx_timedlock", "mtx_trylock"] and - arg = getArgument(0) - } - - /** - * Holds if this mutex is a recursive mutex. - */ - override predicate isRecursive() { none() } - - /** - * Holds if this `CMutexFunctionCall` is a lock. - */ - override predicate isLock() { - not isLockingOperationWithinLockingOperation(this) and - getTarget().getName() = ["mtx_lock", "mtx_timedlock", "mtx_trylock"] - } - - /** - * Holds if this `CMutexFunctionCall` is a speculative lock, defined as calling - * one of the speculative locking functions such as `try_lock`. - */ - override predicate isSpeculativeLock() { - getTarget().getName() in ["mtx_timedlock", "mtx_trylock"] - } - - /** - * Returns the `Variable` to which this `CMutexFunctionCall` refers to. For this - * style of lock it can reference a number of different variables. - */ - override Variable getLock() { - exists(VariableAccess va | - TaintTracking::localTaint(DataFlow::exprNode(va), DataFlow::exprNode(getLockExpr())) and - result = va.getTarget() - ) - } - - /** - * Returns the expression for this `CMutexFunctionCall`. - */ - override Expr getLockExpr() { result = arg } - - /** - * Holds if this is a `unlock` and *may* unlock the previously locked `CMutexFunctionCall`. - * This predicate does not check that the mutex is currently locked. - */ - override predicate unlocks(MutexFunctionCall fc) { - isUnlock() and - fc.getLock() = getLock() - } - - /** - * Holds if this is an unlock call. - */ - override predicate isUnlock() { getTarget().getName() = "mtx_unlock" } -} - -/** - * The thread-aware predecessor function is defined in terms of the thread aware - * successor function. This is because it is simpler to construct the forward - * paths of a thread's execution than the backwards paths. For this reason we - * require a `start` and `end` node. - * - * The logic of this function is that a thread aware predecessor is one that - * follows a `start` node, is not equal to the ending node, and does not follow - * the `end` node. Such nodes can only be predecessors of `end`. - * - * For this reason this function requires a `start` node from which to start - * considering something a predecessor of `end`. - */ -pragma[inline] -ControlFlowNode getAThreadContextAwarePredecessor(ControlFlowNode start, ControlFlowNode end) { - result = getAThreadContextAwareSuccessor(start) and - not result = getAThreadContextAwareSuccessor(end) and - not result = end -} - -/** - * A predicate for finding successors of `ControlFlowNode`s that are aware of - * the objects that my flow into a thread's context. This is achieved by adding - * additional edges to thread entry points and function calls. - */ -ControlFlowNode getAThreadContextAwareSuccessorR(ControlFlowNode cfn) { - result = cfn.getASuccessor() - or - result = cfn.(ThreadedCFGPathExtension).getNext() -} - -ControlFlowNode getAThreadContextAwareSuccessor(ControlFlowNode m) { - result = getAThreadContextAwareSuccessorR*(m) and - // for performance reasons we handle back edges by enforcing a lexical - // ordering restriction on these nodes if they are both in - // the same loop. One way of doing this is as follows: - // - // ````and ( - // exists(Loop loop | - // loop.getAChild*() = m and - // loop.getAChild*() = result - // ) - // implies - // not result.getLocation().isBefore(m.getLocation()) - // )``` - // In this implementation we opt for the more generic form below - // which seems to have reasonable performance. - ( - m.getEnclosingStmt().getParentStmt*() = result.getEnclosingStmt().getParentStmt*() - implies - not exists(Location l1, Location l2 | - l1 = result.getLocation() and - l2 = m.getLocation() - | - l1.getEndLine() < l2.getStartLine() - or - l1.getStartLine() = l2.getEndLine() and - l1.getEndColumn() < l2.getStartColumn() - ) - ) -} - -abstract class LockingOperation extends FunctionCall { - /** - * Returns the target of the lock underlying this RAII-style lock. - */ - abstract Variable getLock(); - - /** - * Returns the lock underlying this RAII-style lock. - */ - abstract Expr getLockExpr(); - - /** - * Holds if this is a lock operation - */ - abstract predicate isLock(); - - /** - * Holds if this is an unlock operation - */ - abstract predicate isUnlock(); - - /** - * Holds if this locking operation is really a locking operation within a - * designated locking operation. This library assumes the underlying locking - * operations are implemented correctly in that calling a `LockingOperation` - * results in the creation of a singular lock. - */ - predicate isLockingOperationWithinLockingOperation(LockingOperation inner) { - exists(LockingOperation outer | outer.getTarget() = inner.getEnclosingFunction()) - } -} - -/** - * Models a RAII-Style lock. - */ -class RAIIStyleLock extends LockingOperation { - VariableAccess lock; - - RAIIStyleLock() { - ( - getTarget().getDeclaringType().hasQualifiedName("std", "lock_guard") or - getTarget().getDeclaringType().hasQualifiedName("std", "unique_lock") or - getTarget().getDeclaringType().hasQualifiedName("std", "scoped_lock") - ) and - ( - lock = getArgument(0).getAChild*() - or - this instanceof DestructorCall and - exists(RAIIStyleLock constructor | - constructor = getQualifier().(VariableAccess).getTarget().getInitializer().getExpr() and - lock = constructor.getArgument(0).getAChild*() - ) - ) - } - - /** - * Holds if this is a lock operation - */ - override predicate isLock() { - not isLockingOperationWithinLockingOperation(this) and - this instanceof ConstructorCall and - lock = getArgument(0).getAChild*() and - // defer_locks don't cause a lock - not exists(Expr exp | - exp = getArgument(1) and - exp.(VariableAccess) - .getTarget() - .getUnderlyingType() - .(Class) - .hasQualifiedName("std", "defer_lock_t") - ) - } - - /** - * Holds if this is an unlock operation - */ - override predicate isUnlock() { this instanceof DestructorCall } - - /** - * Returns the target of the lock underlying this RAII-style lock. - */ - override Variable getLock() { result = lock.getTarget() } - - /** - * Returns the lock underlying this RAII-style lock. - */ - override Expr getLockExpr() { result = lock } -} - -/** - * Models a function that may be executed by some thread. - */ -abstract class ThreadedFunction extends Function { } - -/** - * Models a function that may be executed by some thread via - * C++ standard classes. - */ -class CPPThreadedFunction extends ThreadedFunction { - CPPThreadedFunction() { exists(ThreadConstructorCall tcc | tcc.getFunction() = this) } -} - -/** - * Models a function that may be executed by some thread via - * C11 standard functions. - */ -class C11ThreadedFunction extends ThreadedFunction { - C11ThreadedFunction() { exists(C11ThreadCreateCall cc | cc.getFunction() = this) } -} - -/** - * Models a control flow node within a function that may be executed by some - * thread. - */ -class ThreadedCFN extends ControlFlowNode { - ThreadedCFN() { - exists(ThreadedFunction tf | this = getAThreadContextAwareSuccessor(tf.getEntryPoint())) - } -} - -/** - * Models a `ControlFlowNode` that is protected by some sort of lock. - */ -class LockProtectedControlFlowNode extends ThreadedCFN { - FunctionCall lockingFunction; - - LockProtectedControlFlowNode() { - exists(LockingOperation lock | - // there is a node that is a lock - lockingFunction = lock and - lock.isLock() and - // this node should be a successor of this lock - this = getAThreadContextAwareSuccessor(lock) and - // and there should not exist a predecessor of this - // node that is an unlock. Since we are doing thread context - // aware tracking it is easier to go forwards than backwards - // in constructing the call graph. Thus we can define predecessor - // in terms of a node that is a successor of the lock but NOT a - // successor of the current node. - not exists(ControlFlowNode unlock | - // it's an unlock - unlock = getAThreadContextAwarePredecessor(lock, this) and - unlock.(MutexFunctionCall).isUnlock() and - // note that we don't check that it's the same lock -- this is left - // to the caller to enforce this condition. - // Because of the way that `getAThreadContextAwarePredecessor` works, it is possible - // for operations PAST it to be technically part of the predecessors. - // Thus, we need to make sure that this node is a - // successor of the unlock in the CFG - getAThreadContextAwareSuccessor(unlock) = this - ) and - (lock instanceof MutexFunctionCall implies not this.(MutexFunctionCall).isUnlock()) - ) - } - - /** - * The `MutexFunctionCall` holding the lock that locks this node. - */ - FunctionCall coveredByLock() { result = lockingFunction } - - /** - * The lock underlying this `LockProtectedControlFlowNode`. - */ - Variable getAProtectingLock() { result = lockingFunction.(LockingOperation).getLock() } -} - -/** - * Models a function that conditionally waits. - */ -abstract class ConditionalWait extends FunctionCall { } - -/** - * Models a function in CPP that will conditionally wait. - */ -class CPPConditionalWait extends ConditionalWait { - CPPConditionalWait() { - exists(MemberFunction mf | - mf = getTarget() and - mf.getDeclaringType().hasQualifiedName("std", "condition_variable") and - mf.getName() in ["wait", "wait_for", "wait_until"] - ) - } -} - -/** - * Models a function in C that will conditionally wait. - */ -class CConditionalWait extends ConditionalWait { - CConditionalWait() { getTarget().getName() in ["cnd_wait"] } -} - -/** - * Models a function which uses a c condition variable. Not integrated into the thread aware CFG. - */ -class CConditionOperation extends FunctionCall { - CConditionOperation() { - getTarget().hasName(["cnd_broadcast", "cnd_signal", "cnd_timedwait", "cnd_wait", "cnd_init"]) - } - - predicate isInit() { getTarget().hasName("cnd_init") } - - predicate isUse() { not isInit() } - - Expr getConditionExpr() { result = getArgument(0) } - - /* Note: only holds for `cnd_wait()` and `cnd_timedwait()` */ - Expr getMutexExpr() { result = getArgument(1) } -} - -/** - * Models a call to a `std::thread` constructor that depends on a mutex. - */ -class MutexDependentThreadConstructor extends ThreadConstructorCall { - Expr mutexExpr; - - MutexDependentThreadConstructor() { - mutexExpr = getAnArgument() and - mutexExpr.getUnderlyingType().stripType() instanceof MutexType - } - - Expr dependentMutex() { result = mutexExpr } -} - -/** - * Models thread waiting functions. - */ -abstract class ThreadWait extends FunctionCall { } - -/** - * Models a call to a `std::thread` join. - */ -class CPPThreadWait extends ThreadWait { - VariableAccess var; - - CPPThreadWait() { - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "thread") and - getTarget().getName() = "join" - } -} - -/** - * Models a call to `thrd_join` in C11. - */ -class C11ThreadWait extends ThreadWait { - VariableAccess var; - - C11ThreadWait() { getTarget().getName() = "thrd_join" } -} - -/** - * Models thread detach functions. - */ -abstract class ThreadDetach extends FunctionCall { } - -/** - * Models a call to `thrd_detach` in C11. - */ -class C11ThreadDetach extends ThreadWait { - VariableAccess var; - - C11ThreadDetach() { getTarget().getName() = "thrd_detach" } -} - -abstract class MutexSource extends FunctionCall { } - -/** - * Models a C++ style mutex. - */ -class CPPMutexSource extends MutexSource, ConstructorCall { - CPPMutexSource() { getTarget().getDeclaringType().hasQualifiedName("std", "mutex") } -} - -/** - * Models a C11 style mutex. - */ -class C11MutexSource extends MutexSource, FunctionCall { - C11MutexSource() { getTarget().hasName("mtx_init") } - - Expr getMutexExpr() { result = getArgument(0) } - - Expr getMutexTypeExpr() { result = getArgument(1) } -} - -/** - * Models a thread dependent mutex. A thread dependent mutex is a mutex - * that is used by a thread. This dependency is established either by directly - * passing in a mutex or by referencing a mutex that is in the local scope. The utility - * of this class is it captures the `DataFlow::Node` source at which the mutex - * came from. For example, if it is passed in from a local function to a thread. - * This functionality is critical, since it allows one to inspect how the thread - * behaves with respect to the owner of a resource. - * - * To model the myriad ways this can happen, the subclasses of this class are - * responsible for implementing the various usage patterns. - */ -abstract class ThreadDependentMutex extends DataFlow::Node { - DataFlow::Node sink; - - DataFlow::Node getASource() { - // the source is either the thing that declared - // the mutex - result = this - or - // or the thread we are using it in - result = getAThreadSource() - } - - /** - * Gets the dataflow nodes corresponding to thread local usages of the - * dependent mutex. - */ - DataFlow::Node getAThreadSource() { - // here we line up the actual parameter at the thread creation - // site with the formal parameter in the target thread. - // Note that there are differences between the C and C++ versions - // of the argument ordering in the thread creation function. However, - // since the C version only takes one parameter (as opposed to multiple) - // we can simplify this search by considering only the first argument. - exists(FunctionCall fc, Function f, int n | - // Get the argument to which the mutex flowed. - fc.getArgument(n) = sink.asExpr() and - // Get the thread function we are calling. - f = fc.getArgument(0).(FunctionAccess).getTarget() and - // in C++, there is an extra argument to the `std::thread` call - // so we must subtract 1 since this is not passed to the thread. - ( - result = DataFlow::exprNode(f.getParameter(n - 1).getAnAccess()) - or - // In C, only one argument is allowed. Thus IF the flow predicate holds, - // it will be to the first argument - result = DataFlow::exprNode(f.getParameter(0).getAnAccess()) - ) - ) - } - - /** - * Produces the set of dataflow nodes to thread creation for threads - * that are dependent on this mutex. - */ - DataFlow::Node getADependentThreadCreationExpr() { - exists(FunctionCall fc | - fc.getAnArgument() = sink.asExpr() and - result = DataFlow::exprNode(fc) - ) - } - - /** - * Gets a set of usages of this mutex in both the local and thread scope. - * In the case of scoped usage, this also captures typical accesses of variables. - */ - DataFlow::Node getAUsage() { TaintTracking::localTaint(getASource(), result) } -} - -/** - * This class models the type of thread/mutex dependency that is established - * through the typical parameter passing mechanisms found in C++. - */ -class FlowBasedThreadDependentMutex extends ThreadDependentMutex { - FlowBasedThreadDependentMutex() { - // some sort of dataflow, likely through parameter passing. - ThreadDependentMutexFlow::flow(this, sink) - } -} - -/** - * This class models the type of thread/mutex dependency that is established by - * either scope based accesses (e.g., global variables) or block scope differences. - */ -class AccessBasedThreadDependentMutex extends ThreadDependentMutex { - Variable variableSource; - - AccessBasedThreadDependentMutex() { - // encapsulates usages from outside scopes not directly expressed - // in dataflow. - exists(MutexSource mutexSrc, ThreadedFunction f | - DataFlow::exprNode(mutexSrc) = this and - // find a variable that was assigned the mutex - TaintTracking::localTaint(DataFlow::exprNode(mutexSrc), - DataFlow::exprNode(variableSource.getAnAssignedValue())) and - // find all subsequent accesses of that variable that are within a - // function and set those to the sink - exists(VariableAccess va | - va = variableSource.getAnAccess() and - va.getEnclosingFunction() = f and - sink = DataFlow::exprNode(va) - ) - ) - } - - override DataFlow::Node getAUsage() { DataFlow::exprNode(variableSource.getAnAccess()) = result } -} - -/** - * In the typical C thread model, a mutex is a created by a function that is not responsible - * for creating the variable. Thus this class encodes a slightly different semantics - * wherein the usage pattern is that of variables that have been both initialized - * and then subsequently passed into a thread directly. - */ -class DeclarationInitBasedThreadDependentMutex extends ThreadDependentMutex { - Variable variableSource; - - DeclarationInitBasedThreadDependentMutex() { - exists(MutexSource ms, ThreadCreationFunction tcf | - this = DataFlow::exprNode(ms) and - // accessed as a mutex source - TaintTracking::localTaint(DataFlow::exprNode(variableSource.getAnAccess()), - DataFlow::exprNode(ms.getAnArgument())) and - // subsequently passed to a thread creation function (order not strictly - // enforced for performance reasons) - sink = DataFlow::exprNode(tcf.getAnArgument()) and - TaintTracking::localTaint(DataFlow::exprNode(variableSource.getAnAccess()), sink) - ) - } - - override DataFlow::Node getAUsage() { - TaintTracking::localTaint(getASource(), result) or - DataFlow::exprNode(variableSource.getAnAccess()) = result - } - - override DataFlow::Node getASource() { - // the source is either the thing that declared - // the mutex - result = this - or - // or the thread we are using it in - result = getAThreadSource() - } - - DataFlow::Node getSink() { result = sink } - - /** - * Gets the dataflow nodes corresponding to thread local usages of the - * dependent mutex. - */ - override DataFlow::Node getAThreadSource() { - // here we line up the actual parameter at the thread creation - // site with the formal parameter in the target thread. - // Note that there are differences between the C and C++ versions - // of the argument ordering in the thread creation function. However, - // since the C version only takes one parameter (as opposed to multiple) - // we can simplify this search by considering only the first argument. - exists( - FunctionCall fc, Function f, int n // CPP Version - | - fc.getArgument(n) = sink.asExpr() and - f = fc.getArgument(0).(FunctionAccess).getTarget() and - // in C++, there is an extra argument to the `std::thread` call - // so we must subtract 1 since this is not passed to the thread. - result = DataFlow::exprNode(f.getParameter(n - 1).getAnAccess()) - ) - or - exists( - FunctionCall fc, Function f // C Version - | - fc.getAnArgument() = sink.asExpr() and - // in C, the second argument is the function - f = fc.getArgument(1).(FunctionAccess).getTarget() and - // in C, the passed argument is always the zeroth argument - result = DataFlow::exprNode(f.getParameter(0).getAnAccess()) - ) - } -} - -/** - * In the typical C model, another way to use mutexes is to work with global variables - * that can be initialized at various points -- one of which must be inside a thread. - * This class encapsulates this pattern. - */ -class DeclarationInitAccessBasedThreadDependentMutex extends ThreadDependentMutex { - Variable variableSource; - - DeclarationInitAccessBasedThreadDependentMutex() { - exists(MutexSource ms, ThreadedFunction tf, VariableAccess va | - this = DataFlow::exprNode(ms) and - // accessed as a mutex source - TaintTracking::localTaint(DataFlow::exprNode(variableSource.getAnAccess()), - DataFlow::exprNode(ms.getAnArgument())) and - // is accessed somewhere else - va = variableSource.getAnAccess() and - sink = DataFlow::exprNode(va) and - // one of which must be a thread - va.getEnclosingFunction() = tf - ) - } - - override DataFlow::Node getAUsage() { result = DataFlow::exprNode(variableSource.getAnAccess()) } -} - -module ThreadDependentMutexConfig implements DataFlow::ConfigSig { - predicate isSource(DataFlow::Node node) { node.asExpr() instanceof MutexSource } - - predicate isSink(DataFlow::Node node) { - exists(ThreadCreationFunction f | f.getAnArgument() = node.asExpr()) - } -} - -module ThreadDependentMutexFlow = TaintTracking::Global; - -/** - * Models expressions that destroy mutexes. - */ -abstract class MutexDestroyer extends StmtParent { - /** - * Gets the expression that references the mutex being destroyed. - */ - abstract Expr getMutexExpr(); -} - -/** - * Models C style mutex destruction via `mtx_destroy`. - */ -class C11MutexDestroyer extends MutexDestroyer, FunctionCall { - C11MutexDestroyer() { getTarget().getName() = "mtx_destroy" } - - /** - * Returns the `Expr` being destroyed. - */ - override Expr getMutexExpr() { result = getArgument(0) } -} - -/** - * Models a delete expression -- note it is necessary to add this in - * addition to destructors to handle certain implementations of the - * standard library which obscure the destructors of mutexes. - */ -class DeleteMutexDestroyer extends MutexDestroyer { - DeleteMutexDestroyer() { this instanceof DeleteExpr } - - override Expr getMutexExpr() { this.(DeleteExpr).getExpr() = result } -} - -/** - * Models a possible mutex variable that if it goes - * out of scope would destroy an underlying mutex. - */ -class LocalMutexDestroyer extends MutexDestroyer { - Expr assignedValue; - - LocalMutexDestroyer() { - exists(LocalVariable lv | - // static types aren't destroyers - not lv.isStatic() and - // neither are pointers - not lv.getType() instanceof PointerType and - lv.getAnAssignedValue() = assignedValue and - // map the location to the return statements of the - // enclosing function - exists(ReturnStmt rs | - rs.getEnclosingFunction() = assignedValue.getEnclosingFunction() and - rs = this - ) - ) - } - - override Expr getMutexExpr() { result = assignedValue } -} - -/** - * Models implicit or explicit calls to the destructor of a mutex, either via - * a `delete` statement or a variable going out of scope. - */ -class DestructorMutexDestroyer extends MutexDestroyer, DestructorCall { - DestructorMutexDestroyer() { getTarget().getDeclaringType().hasQualifiedName("std", "mutex") } - - /** - * Returns the `Expr` being deleted. - */ - override Expr getMutexExpr() { getQualifier() = result } -} - -/** - * Models a conditional variable denoted by `std::condition_variable`. - */ -class ConditionalVariable extends Variable { - ConditionalVariable() { - getUnderlyingType().(Class).hasQualifiedName("std", "condition_variable") - } -} - -/** - * Models a conditional function, which is a function that depends on the value - * of a conditional variable. - */ -class ConditionalFunction extends Function { - ConditionalFunction() { - exists(ConditionalVariable cv | cv.getAnAccess().getEnclosingFunction() = this) - } -} - -/** - * Models calls to thread specific storage function calls. - */ -abstract class ThreadSpecificStorageFunctionCall extends FunctionCall { - /** - * Gets the key to which this call references. - */ - Expr getKey() { getArgument(0) = result } -} - -/** - * Models calls to `tss_get`. - */ -class TSSGetFunctionCall extends ThreadSpecificStorageFunctionCall { - TSSGetFunctionCall() { getTarget().getName() = "tss_get" } -} - -/** - * Models calls to `tss_set`. - */ -class TSSSetFunctionCall extends ThreadSpecificStorageFunctionCall { - TSSSetFunctionCall() { getTarget().getName() = "tss_set" } -} - -/** - * Models calls to `tss_create` - */ -class TSSCreateFunctionCall extends ThreadSpecificStorageFunctionCall { - TSSCreateFunctionCall() { getTarget().getName() = "tss_create" } - - predicate hasDeallocator() { - not exists(MacroInvocation mi, NullMacro nm | - getArgument(1) = mi.getExpr() and - mi = nm.getAnInvocation() - ) - } -} - -/** - * Models calls to `tss_delete` - */ -class TSSDeleteFunctionCall extends ThreadSpecificStorageFunctionCall { - TSSDeleteFunctionCall() { getTarget().getName() = "tss_delete" } -} - -/** - * Gets a call to `DeallocationExpr` that deallocates memory owned by thread specific - * storage. - */ -predicate getAThreadSpecificStorageDeallocationCall(C11ThreadCreateCall tcc, DeallocationExpr dexp) { - exists(TSSGetFunctionCall tsg | - tcc.getFunction().getEntryPoint().getASuccessor*() = tsg and - DataFlow::localFlow(DataFlow::exprNode(tsg), DataFlow::exprNode(dexp.getFreedExpr())) - ) -} - -/** - * Models calls to routines `atomic_compare_exchange_weak` and - * `atomic_compare_exchange_weak_explicit` in the `stdatomic` library. - * Note that these are typically implemented as macros within Clang and - * GCC's standard libraries. - */ -class AtomicCompareExchange extends MacroInvocation { - AtomicCompareExchange() { - getMacroName() = "atomic_compare_exchange_weak" - or - // some compilers model `atomic_compare_exchange_weak` as a macro that - // expands to `atomic_compare_exchange_weak_explicit` so this defeats that - // and other similar modeling. - getMacroName() = "atomic_compare_exchange_weak_explicit" and - not exists(MacroInvocation m | - m.getMacroName() = "atomic_compare_exchange_weak" and - m.getAnExpandedElement() = getAnExpandedElement() - ) - } -} - -/** - * Models calls to routines `atomic_store` and - * `atomic_store_explicit` in the `stdatomic` library. - * Note that these are typically implemented as macros within Clang and - * GCC's standard libraries. - */ -class AtomicStore extends MacroInvocation { - AtomicStore() { - getMacroName() = "atomic_store" - or - // some compilers model `atomic_compare_exchange_weak` as a macro that - // expands to `atomic_compare_exchange_weak_explicit` so this defeats that - // and other similar modeling. - getMacroName() = "atomic_store_explicit" and - not exists(MacroInvocation m | - m.getMacroName() = "atomic_store" and - m.getAnExpandedElement() = getAnExpandedElement() - ) - } -} +import codingstandards.cpp.concurrency.Atomic +import codingstandards.cpp.concurrency.CConditionOperation +import codingstandards.cpp.concurrency.ControlFlow +import codingstandards.cpp.concurrency.ConditionalWait +import codingstandards.cpp.concurrency.LockingOperation +import codingstandards.cpp.concurrency.LockProtectedControlFlow +import codingstandards.cpp.concurrency.MutexDestroyer +import codingstandards.cpp.concurrency.ThreadCreation +import codingstandards.cpp.concurrency.ThreadedFunction +import codingstandards.cpp.concurrency.ThreadDependentMutex +import codingstandards.cpp.concurrency.ThreadSpecificStorage +import codingstandards.cpp.concurrency.ThreadWaitDetach +import codingstandards.cpp.concurrency.Types diff --git a/cpp/common/src/codingstandards/cpp/concurrency/Atomic.qll b/cpp/common/src/codingstandards/cpp/concurrency/Atomic.qll new file mode 100644 index 0000000000..44101f08bb --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/Atomic.qll @@ -0,0 +1,43 @@ +import cpp + +/** + * Models calls to routines `atomic_compare_exchange_weak` and + * `atomic_compare_exchange_weak_explicit` in the `stdatomic` library. + * Note that these are typically implemented as macros within Clang and + * GCC's standard libraries. + */ +class AtomicCompareExchange extends MacroInvocation { + AtomicCompareExchange() { + getMacroName() = "atomic_compare_exchange_weak" + or + // some compilers model `atomic_compare_exchange_weak` as a macro that + // expands to `atomic_compare_exchange_weak_explicit` so this defeats that + // and other similar modeling. + getMacroName() = "atomic_compare_exchange_weak_explicit" and + not exists(MacroInvocation m | + m.getMacroName() = "atomic_compare_exchange_weak" and + m.getAnExpandedElement() = getAnExpandedElement() + ) + } +} + +/** + * Models calls to routines `atomic_store` and + * `atomic_store_explicit` in the `stdatomic` library. + * Note that these are typically implemented as macros within Clang and + * GCC's standard libraries. + */ +class AtomicStore extends MacroInvocation { + AtomicStore() { + getMacroName() = "atomic_store" + or + // some compilers model `atomic_compare_exchange_weak` as a macro that + // expands to `atomic_compare_exchange_weak_explicit` so this defeats that + // and other similar modeling. + getMacroName() = "atomic_store_explicit" and + not exists(MacroInvocation m | + m.getMacroName() = "atomic_store" and + m.getAnExpandedElement() = getAnExpandedElement() + ) + } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/CConditionOperation.qll b/cpp/common/src/codingstandards/cpp/concurrency/CConditionOperation.qll new file mode 100644 index 0000000000..adf230f08d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/CConditionOperation.qll @@ -0,0 +1,31 @@ +import cpp + +/** + * Models a function which uses a c condition variable. Not integrated into the thread aware CFG. + */ +class CConditionOperation extends FunctionCall { + CConditionOperation() { + getTarget().hasName(["cnd_broadcast", "cnd_signal", "cnd_timedwait", "cnd_wait", "cnd_init"]) + } + + predicate isInit() { getTarget().hasName("cnd_init") } + + predicate isUse() { not isInit() } + + Expr getConditionExpr() { result = getArgument(0) } + + /* Note: only holds for `cnd_wait()` and `cnd_timedwait()` */ + Expr getMutexExpr() { result = getArgument(1) } +} + +/** + * Models C style condition destruction via `cnd_destroy`. + */ +class C11ConditionDestroyer extends FunctionCall { + C11ConditionDestroyer() { getTarget().getName() = "cnd_destroy" } + + /** + * Returns the `Expr` being destroyed. + */ + Expr getConditionExpr() { result = getArgument(0) } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/ConditionalWait.qll b/cpp/common/src/codingstandards/cpp/concurrency/ConditionalWait.qll new file mode 100644 index 0000000000..e69ea2fee5 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/ConditionalWait.qll @@ -0,0 +1,26 @@ +import cpp + +/** + * Models a function that conditionally waits. + */ +abstract class ConditionalWait extends FunctionCall { } + +/** + * Models a function in CPP that will conditionally wait. + */ +class CPPConditionalWait extends ConditionalWait { + CPPConditionalWait() { + exists(MemberFunction mf | + mf = getTarget() and + mf.getDeclaringType().hasQualifiedName("std", "condition_variable") and + mf.getName() in ["wait", "wait_for", "wait_until"] + ) + } +} + +/** + * Models a function in C that will conditionally wait. + */ +class CConditionalWait extends ConditionalWait { + CConditionalWait() { getTarget().getName() in ["cnd_wait"] } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/ControlFlow.qll b/cpp/common/src/codingstandards/cpp/concurrency/ControlFlow.qll new file mode 100644 index 0000000000..15f8ab5a61 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/ControlFlow.qll @@ -0,0 +1,101 @@ +import cpp +private import codingstandards.cpp.concurrency.ThreadedFunction + +/** + * Models a control flow node within a function that may be executed by some + * thread. + */ +class ThreadedCFN extends ControlFlowNode { + ThreadedCFN() { + exists(ThreadedFunction tf | this = getAThreadContextAwareSuccessor(tf.getEntryPoint())) + } +} + +/** + * Models CFG nodes which should be added to a thread context. + */ +abstract class ThreadedCFGPathExtension extends ControlFlowNode { + /** + * Returns the next `ControlFlowNode` in this thread context. + */ + abstract ControlFlowNode getNext(); +} + +/** + * Models a `FunctionCall` invoked from a threaded context. + */ +class ThreadContextFunctionCall extends FunctionCall, ThreadedCFGPathExtension { + override ControlFlowNode getNext() { getTarget().getEntryPoint() = result } +} + +/** + * Models a specialized `FunctionCall` that may create a thread. + */ +abstract class ThreadCreationFunction extends FunctionCall, ThreadedCFGPathExtension { + /** + * Returns the function that will be invoked. + */ + abstract Function getFunction(); +} + +/** + * The thread-aware predecessor function is defined in terms of the thread aware + * successor function. This is because it is simpler to construct the forward + * paths of a thread's execution than the backwards paths. For this reason we + * require a `start` and `end` node. + * + * The logic of this function is that a thread aware predecessor is one that + * follows a `start` node, is not equal to the ending node, and does not follow + * the `end` node. Such nodes can only be predecessors of `end`. + * + * For this reason this function requires a `start` node from which to start + * considering something a predecessor of `end`. + */ +pragma[inline] +ControlFlowNode getAThreadContextAwarePredecessor(ControlFlowNode start, ControlFlowNode end) { + result = getAThreadContextAwareSuccessor(start) and + not result = getAThreadContextAwareSuccessor(end) and + not result = end +} + +/** + * A predicate for finding successors of `ControlFlowNode`s that are aware of + * the objects that my flow into a thread's context. This is achieved by adding + * additional edges to thread entry points and function calls. + */ +ControlFlowNode getAThreadContextAwareSuccessorR(ControlFlowNode cfn) { + result = cfn.getASuccessor() + or + result = cfn.(ThreadedCFGPathExtension).getNext() +} + +ControlFlowNode getAThreadContextAwareSuccessor(ControlFlowNode m) { + result = getAThreadContextAwareSuccessorR*(m) and + // for performance reasons we handle back edges by enforcing a lexical + // ordering restriction on these nodes if they are both in + // the same loop. One way of doing this is as follows: + // + // ````and ( + // exists(Loop loop | + // loop.getAChild*() = m and + // loop.getAChild*() = result + // ) + // implies + // not result.getLocation().isBefore(m.getLocation()) + // )``` + // In this implementation we opt for the more generic form below + // which seems to have reasonable performance. + ( + m.getEnclosingStmt().getParentStmt*() = result.getEnclosingStmt().getParentStmt*() + implies + not exists(Location l1, Location l2 | + l1 = result.getLocation() and + l2 = m.getLocation() + | + l1.getEndLine() < l2.getStartLine() + or + l1.getStartLine() = l2.getEndLine() and + l1.getEndColumn() < l2.getStartColumn() + ) + ) +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/LockProtectedControlFlow.qll b/cpp/common/src/codingstandards/cpp/concurrency/LockProtectedControlFlow.qll new file mode 100644 index 0000000000..a828ec8768 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/LockProtectedControlFlow.qll @@ -0,0 +1,49 @@ +import cpp +private import codingstandards.cpp.concurrency.ControlFlow +private import codingstandards.cpp.concurrency.LockingOperation + +/** + * Models a `ControlFlowNode` that is protected by some sort of lock. + */ +class LockProtectedControlFlowNode extends ThreadedCFN { + FunctionCall lockingFunction; + + LockProtectedControlFlowNode() { + exists(LockingOperation lock | + // there is a node that is a lock + lockingFunction = lock and + lock.isLock() and + // this node should be a successor of this lock + this = getAThreadContextAwareSuccessor(lock) and + // and there should not exist a predecessor of this + // node that is an unlock. Since we are doing thread context + // aware tracking it is easier to go forwards than backwards + // in constructing the call graph. Thus we can define predecessor + // in terms of a node that is a successor of the lock but NOT a + // successor of the current node. + not exists(ControlFlowNode unlock | + // it's an unlock + unlock = getAThreadContextAwarePredecessor(lock, this) and + unlock.(MutexFunctionCall).isUnlock() and + // note that we don't check that it's the same lock -- this is left + // to the caller to enforce this condition. + // Because of the way that `getAThreadContextAwarePredecessor` works, it is possible + // for operations PAST it to be technically part of the predecessors. + // Thus, we need to make sure that this node is a + // successor of the unlock in the CFG + getAThreadContextAwareSuccessor(unlock) = this + ) and + (lock instanceof MutexFunctionCall implies not this.(MutexFunctionCall).isUnlock()) + ) + } + + /** + * The `MutexFunctionCall` holding the lock that locks this node. + */ + FunctionCall coveredByLock() { result = lockingFunction } + + /** + * The lock underlying this `LockProtectedControlFlowNode`. + */ + Variable getAProtectingLock() { result = lockingFunction.(LockingOperation).getLock() } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll b/cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll new file mode 100644 index 0000000000..1dd753d122 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll @@ -0,0 +1,240 @@ +import cpp +import semmle.code.cpp.dataflow.TaintTracking + +abstract class LockingOperation extends FunctionCall { + /** + * Returns the target of the lock underlying this RAII-style lock. + */ + abstract Variable getLock(); + + /** + * Returns the lock underlying this RAII-style lock. + */ + abstract Expr getLockExpr(); + + /** + * Holds if this is a lock operation + */ + abstract predicate isLock(); + + /** + * Holds if this is an unlock operation + */ + abstract predicate isUnlock(); + + /** + * Holds if this locking operation is really a locking operation within a + * designated locking operation. This library assumes the underlying locking + * operations are implemented correctly in that calling a `LockingOperation` + * results in the creation of a singular lock. + */ + predicate isLockingOperationWithinLockingOperation(LockingOperation inner) { + exists(LockingOperation outer | outer.getTarget() = inner.getEnclosingFunction()) + } +} + +/** + * Common base class providing an interface into function call + * based mutex locks. + */ +abstract class MutexFunctionCall extends LockingOperation { + abstract predicate isRecursive(); + + abstract predicate isSpeculativeLock(); + + abstract predicate unlocks(MutexFunctionCall fc); +} + +/** + * Models calls to various mutex types found in CPP. + */ +class CPPMutexFunctionCall extends MutexFunctionCall { + VariableAccess var; + + CPPMutexFunctionCall() { + ( + // the non recursive kinds + getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "mutex") or + getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "timed_mutex") or + getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "shared_timed_mutex") or + // the recursive ones + getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_mutex") or + getTarget() + .(MemberFunction) + .getDeclaringType() + .hasQualifiedName("std", "recursive_timed_mutex") + ) and + var = getQualifier() + } + + /** + * Holds if this mutex is a recursive mutex. + */ + override predicate isRecursive() { + getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_mutex") or + getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_timed_mutex") + } + + /** + * Holds if this `CPPMutexFunctionCall` is a lock. + */ + override predicate isLock() { + not isLockingOperationWithinLockingOperation(this) and + getTarget().getName() = "lock" + } + + /** + * Holds if this `CPPMutexFunctionCall` is a speculative lock, defined as calling + * one of the speculative locking functions such as `try_lock`. + */ + override predicate isSpeculativeLock() { + getTarget().getName() in [ + "try_lock", "try_lock_for", "try_lock_until", "try_lock_shared_for", "try_lock_shared_until" + ] + } + + /** + * Returns the lock to which this `CPPMutexFunctionCall` refers to. + */ + override Variable getLock() { result = getQualifier().(VariableAccess).getTarget() } + + /** + * Returns the qualifier for this `CPPMutexFunctionCall`. + */ + override Expr getLockExpr() { result = var } + + /** + * Holds if this is a `unlock` and *may* unlock the previously locked `MutexFunctionCall`. + * This predicate does not check that the mutex is currently locked. + */ + override predicate unlocks(MutexFunctionCall fc) { + isUnlock() and + fc.getQualifier().(VariableAccess).getTarget() = getQualifier().(VariableAccess).getTarget() + } + + /** + * Holds if this is an unlock call. + */ + override predicate isUnlock() { getTarget().getName() = "unlock" } +} + +/** + * Models calls to various mutex types specialized to C code. + */ +class CMutexFunctionCall extends MutexFunctionCall { + Expr arg; + + CMutexFunctionCall() { + // the non recursive kinds + getTarget().getName() = ["mtx_lock", "mtx_unlock", "mtx_timedlock", "mtx_trylock"] and + arg = getArgument(0) + } + + /** + * Holds if this mutex is a recursive mutex. + */ + override predicate isRecursive() { none() } + + /** + * Holds if this `CMutexFunctionCall` is a lock. + */ + override predicate isLock() { + not isLockingOperationWithinLockingOperation(this) and + getTarget().getName() = ["mtx_lock", "mtx_timedlock", "mtx_trylock"] + } + + /** + * Holds if this `CMutexFunctionCall` is a speculative lock, defined as calling + * one of the speculative locking functions such as `try_lock`. + */ + override predicate isSpeculativeLock() { + getTarget().getName() in ["mtx_timedlock", "mtx_trylock"] + } + + /** + * Returns the `Variable` to which this `CMutexFunctionCall` refers to. For this + * style of lock it can reference a number of different variables. + */ + override Variable getLock() { + exists(VariableAccess va | + TaintTracking::localTaint(DataFlow::exprNode(va), DataFlow::exprNode(getLockExpr())) and + result = va.getTarget() + ) + } + + /** + * Returns the expression for this `CMutexFunctionCall`. + */ + override Expr getLockExpr() { result = arg } + + /** + * Holds if this is a `unlock` and *may* unlock the previously locked `CMutexFunctionCall`. + * This predicate does not check that the mutex is currently locked. + */ + override predicate unlocks(MutexFunctionCall fc) { + isUnlock() and + fc.getLock() = getLock() + } + + /** + * Holds if this is an unlock call. + */ + override predicate isUnlock() { getTarget().getName() = "mtx_unlock" } +} + +/** + * Models a RAII-Style lock. + */ +class RAIIStyleLock extends LockingOperation { + VariableAccess lock; + + RAIIStyleLock() { + ( + getTarget().getDeclaringType().hasQualifiedName("std", "lock_guard") or + getTarget().getDeclaringType().hasQualifiedName("std", "unique_lock") or + getTarget().getDeclaringType().hasQualifiedName("std", "scoped_lock") + ) and + ( + lock = getArgument(0).getAChild*() + or + this instanceof DestructorCall and + exists(RAIIStyleLock constructor | + constructor = getQualifier().(VariableAccess).getTarget().getInitializer().getExpr() and + lock = constructor.getArgument(0).getAChild*() + ) + ) + } + + /** + * Holds if this is a lock operation + */ + override predicate isLock() { + not isLockingOperationWithinLockingOperation(this) and + this instanceof ConstructorCall and + lock = getArgument(0).getAChild*() and + // defer_locks don't cause a lock + not exists(Expr exp | + exp = getArgument(1) and + exp.(VariableAccess) + .getTarget() + .getUnderlyingType() + .(Class) + .hasQualifiedName("std", "defer_lock_t") + ) + } + + /** + * Holds if this is an unlock operation + */ + override predicate isUnlock() { this instanceof DestructorCall } + + /** + * Returns the target of the lock underlying this RAII-style lock. + */ + override Variable getLock() { result = lock.getTarget() } + + /** + * Returns the lock underlying this RAII-style lock. + */ + override Expr getLockExpr() { result = lock } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/MutexDestroyer.qll b/cpp/common/src/codingstandards/cpp/concurrency/MutexDestroyer.qll new file mode 100644 index 0000000000..915efc6077 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/MutexDestroyer.qll @@ -0,0 +1,73 @@ +import cpp + +/** + * Models expressions that destroy mutexes. + */ +abstract class MutexDestroyer extends StmtParent { + /** + * Gets the expression that references the mutex being destroyed. + */ + abstract Expr getMutexExpr(); +} + +/** + * Models C style mutex destruction via `mtx_destroy`. + */ +class C11MutexDestroyer extends MutexDestroyer, FunctionCall { + C11MutexDestroyer() { getTarget().getName() = "mtx_destroy" } + + /** + * Returns the `Expr` being destroyed. + */ + override Expr getMutexExpr() { result = getArgument(0) } +} + +/** + * Models a delete expression -- note it is necessary to add this in + * addition to destructors to handle certain implementations of the + * standard library which obscure the destructors of mutexes. + */ +class DeleteMutexDestroyer extends MutexDestroyer { + DeleteMutexDestroyer() { this instanceof DeleteExpr } + + override Expr getMutexExpr() { this.(DeleteExpr).getExpr() = result } +} + +/** + * Models a possible mutex variable that if it goes + * out of scope would destroy an underlying mutex. + */ +class LocalMutexDestroyer extends MutexDestroyer { + Expr assignedValue; + + LocalMutexDestroyer() { + exists(LocalVariable lv | + // static types aren't destroyers + not lv.isStatic() and + // neither are pointers + not lv.getType() instanceof PointerType and + lv.getAnAssignedValue() = assignedValue and + // map the location to the return statements of the + // enclosing function + exists(ReturnStmt rs | + rs.getEnclosingFunction() = assignedValue.getEnclosingFunction() and + rs = this + ) + ) + } + + override Expr getMutexExpr() { result = assignedValue } +} + +/** + * Models implicit or explicit calls to the destructor of a mutex, either via + * a `delete` statement or a variable going out of scope. + */ +class DestructorMutexDestroyer extends MutexDestroyer, DestructorCall { + DestructorMutexDestroyer() { getTarget().getDeclaringType().hasQualifiedName("std", "mutex") } + + /** + * Returns the `Expr` being deleted. + */ + override Expr getMutexExpr() { getQualifier() = result } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/ThreadCreation.qll b/cpp/common/src/codingstandards/cpp/concurrency/ThreadCreation.qll new file mode 100644 index 0000000000..4499b993ad --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/ThreadCreation.qll @@ -0,0 +1,62 @@ +import cpp +private import codingstandards.cpp.concurrency.ControlFlow + +/** + * Models a call to a thread constructor via `std::thread`. + */ +class ThreadConstructorCall extends ConstructorCall, ThreadCreationFunction { + Function f; + + ThreadConstructorCall() { + getTarget().getDeclaringType().hasQualifiedName("std", "thread") and + f = getArgument(0).(FunctionAccess).getTarget() + } + + /** + * Returns the function that will be invoked by this `std::thread`. + */ + override Function getFunction() { result = f } + + override ControlFlowNode getNext() { result = getFunction().getEntryPoint() } +} + +/** + * Models a call to a thread creation via `thrd_create` or `pthread_create`. + */ +class CThreadCreateCall extends FunctionCall { + Function f; + int fArgIdx; + + CThreadCreateCall() { + ( + getTarget().getName() = "thrd_create" and + fArgIdx = 1 + or + getTarget().getName() = "pthread_create" and + fArgIdx = 2 + ) and + ( + f = getArgument(fArgIdx).(FunctionAccess).getTarget() or + f = getArgument(fArgIdx).(AddressOfExpr).getOperand().(FunctionAccess).getTarget() + ) + } + + /** + * Returns the function that will be invoked by this thread. + */ + Function getFunction() { result = f } +} + +/** + * Models a call to a thread constructor via `thrd_create`. + */ +class C11ThreadCreateCall extends ThreadCreationFunction, CThreadCreateCall { + C11ThreadCreateCall() { getTarget().getName() = "thrd_create" } + + /** + * Returns the function that will be invoked by this thread. + */ + override Function getFunction() { result = f } + + override ControlFlowNode getNext() { result = getFunction().getEntryPoint() } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/ThreadDependentMutex.qll b/cpp/common/src/codingstandards/cpp/concurrency/ThreadDependentMutex.qll new file mode 100644 index 0000000000..f86e94566f --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/ThreadDependentMutex.qll @@ -0,0 +1,246 @@ +import cpp +import semmle.code.cpp.dataflow.TaintTracking +private import codingstandards.cpp.concurrency.ControlFlow +private import codingstandards.cpp.concurrency.ThreadedFunction + +abstract class MutexSource extends FunctionCall { } + +/** + * Models a C++ style mutex. + */ +class CPPMutexSource extends MutexSource, ConstructorCall { + CPPMutexSource() { getTarget().getDeclaringType().hasQualifiedName("std", "mutex") } +} + +/** + * Models a C11 style mutex. + */ +class C11MutexSource extends MutexSource, FunctionCall { + C11MutexSource() { getTarget().hasName("mtx_init") } + + Expr getMutexExpr() { result = getArgument(0) } + + Expr getMutexTypeExpr() { result = getArgument(1) } + + predicate isRecursive() { + exists(EnumConstantAccess recursive | + recursive = getMutexTypeExpr().getAChild*() and + recursive.getTarget().hasName("mtx_recursive") + ) + } +} + +/** + * Models a thread dependent mutex. A thread dependent mutex is a mutex + * that is used by a thread. This dependency is established either by directly + * passing in a mutex or by referencing a mutex that is in the local scope. The utility + * of this class is it captures the `DataFlow::Node` source at which the mutex + * came from. For example, if it is passed in from a local function to a thread. + * This functionality is critical, since it allows one to inspect how the thread + * behaves with respect to the owner of a resource. + * + * To model the myriad ways this can happen, the subclasses of this class are + * responsible for implementing the various usage patterns. + */ +abstract class ThreadDependentMutex extends DataFlow::Node { + DataFlow::Node sink; + + DataFlow::Node getASource() { + // the source is either the thing that declared + // the mutex + result = this + or + // or the thread we are using it in + result = getAThreadSource() + } + + /** + * Gets the dataflow nodes corresponding to thread local usages of the + * dependent mutex. + */ + DataFlow::Node getAThreadSource() { + // here we line up the actual parameter at the thread creation + // site with the formal parameter in the target thread. + // Note that there are differences between the C and C++ versions + // of the argument ordering in the thread creation function. However, + // since the C version only takes one parameter (as opposed to multiple) + // we can simplify this search by considering only the first argument. + exists(FunctionCall fc, Function f, int n | + // Get the argument to which the mutex flowed. + fc.getArgument(n) = sink.asExpr() and + // Get the thread function we are calling. + f = fc.getArgument(0).(FunctionAccess).getTarget() and + // in C++, there is an extra argument to the `std::thread` call + // so we must subtract 1 since this is not passed to the thread. + ( + result = DataFlow::exprNode(f.getParameter(n - 1).getAnAccess()) + or + // In C, only one argument is allowed. Thus IF the flow predicate holds, + // it will be to the first argument + result = DataFlow::exprNode(f.getParameter(0).getAnAccess()) + ) + ) + } + + /** + * Produces the set of dataflow nodes to thread creation for threads + * that are dependent on this mutex. + */ + DataFlow::Node getADependentThreadCreationExpr() { + exists(FunctionCall fc | + fc.getAnArgument() = sink.asExpr() and + result = DataFlow::exprNode(fc) + ) + } + + /** + * Gets a set of usages of this mutex in both the local and thread scope. + * In the case of scoped usage, this also captures typical accesses of variables. + */ + DataFlow::Node getAUsage() { TaintTracking::localTaint(getASource(), result) } +} + +/** + * This class models the type of thread/mutex dependency that is established + * through the typical parameter passing mechanisms found in C++. + */ +class FlowBasedThreadDependentMutex extends ThreadDependentMutex { + FlowBasedThreadDependentMutex() { + // some sort of dataflow, likely through parameter passing. + ThreadDependentMutexFlow::flow(this, sink) + } +} + +/** + * This class models the type of thread/mutex dependency that is established by + * either scope based accesses (e.g., global variables) or block scope differences. + */ +class AccessBasedThreadDependentMutex extends ThreadDependentMutex { + Variable variableSource; + + AccessBasedThreadDependentMutex() { + // encapsulates usages from outside scopes not directly expressed + // in dataflow. + exists(MutexSource mutexSrc, ThreadedFunction f | + DataFlow::exprNode(mutexSrc) = this and + // find a variable that was assigned the mutex + TaintTracking::localTaint(DataFlow::exprNode(mutexSrc), + DataFlow::exprNode(variableSource.getAnAssignedValue())) and + // find all subsequent accesses of that variable that are within a + // function and set those to the sink + exists(VariableAccess va | + va = variableSource.getAnAccess() and + va.getEnclosingFunction() = f and + sink = DataFlow::exprNode(va) + ) + ) + } + + override DataFlow::Node getAUsage() { DataFlow::exprNode(variableSource.getAnAccess()) = result } +} + +/** + * In the typical C thread model, a mutex is a created by a function that is not responsible + * for creating the variable. Thus this class encodes a slightly different semantics + * wherein the usage pattern is that of variables that have been both initialized + * and then subsequently passed into a thread directly. + */ +class DeclarationInitBasedThreadDependentMutex extends ThreadDependentMutex { + Variable variableSource; + + DeclarationInitBasedThreadDependentMutex() { + exists(MutexSource ms, ThreadCreationFunction tcf | + this = DataFlow::exprNode(ms) and + // accessed as a mutex source + TaintTracking::localTaint(DataFlow::exprNode(variableSource.getAnAccess()), + DataFlow::exprNode(ms.getAnArgument())) and + // subsequently passed to a thread creation function (order not strictly + // enforced for performance reasons) + sink = DataFlow::exprNode(tcf.getAnArgument()) and + TaintTracking::localTaint(DataFlow::exprNode(variableSource.getAnAccess()), sink) + ) + } + + override DataFlow::Node getAUsage() { + TaintTracking::localTaint(getASource(), result) or + DataFlow::exprNode(variableSource.getAnAccess()) = result + } + + override DataFlow::Node getASource() { + // the source is either the thing that declared + // the mutex + result = this + or + // or the thread we are using it in + result = getAThreadSource() + } + + DataFlow::Node getSink() { result = sink } + + /** + * Gets the dataflow nodes corresponding to thread local usages of the + * dependent mutex. + */ + override DataFlow::Node getAThreadSource() { + // here we line up the actual parameter at the thread creation + // site with the formal parameter in the target thread. + // Note that there are differences between the C and C++ versions + // of the argument ordering in the thread creation function. However, + // since the C version only takes one parameter (as opposed to multiple) + // we can simplify this search by considering only the first argument. + exists( + FunctionCall fc, Function f, int n // CPP Version + | + fc.getArgument(n) = sink.asExpr() and + f = fc.getArgument(0).(FunctionAccess).getTarget() and + // in C++, there is an extra argument to the `std::thread` call + // so we must subtract 1 since this is not passed to the thread. + result = DataFlow::exprNode(f.getParameter(n - 1).getAnAccess()) + ) + or + exists( + FunctionCall fc, Function f // C Version + | + fc.getAnArgument() = sink.asExpr() and + // in C, the second argument is the function + f = fc.getArgument(1).(FunctionAccess).getTarget() and + // in C, the passed argument is always the zeroth argument + result = DataFlow::exprNode(f.getParameter(0).getAnAccess()) + ) + } +} + +/** + * In the typical C model, another way to use mutexes is to work with global variables + * that can be initialized at various points -- one of which must be inside a thread. + * This class encapsulates this pattern. + */ +class DeclarationInitAccessBasedThreadDependentMutex extends ThreadDependentMutex { + Variable variableSource; + + DeclarationInitAccessBasedThreadDependentMutex() { + exists(MutexSource ms, ThreadedFunction tf, VariableAccess va | + this = DataFlow::exprNode(ms) and + // accessed as a mutex source + TaintTracking::localTaint(DataFlow::exprNode(variableSource.getAnAccess()), + DataFlow::exprNode(ms.getAnArgument())) and + // is accessed somewhere else + va = variableSource.getAnAccess() and + sink = DataFlow::exprNode(va) and + // one of which must be a thread + va.getEnclosingFunction() = tf + ) + } + + override DataFlow::Node getAUsage() { result = DataFlow::exprNode(variableSource.getAnAccess()) } +} + +module ThreadDependentMutexConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node node) { node.asExpr() instanceof MutexSource } + + predicate isSink(DataFlow::Node node) { + exists(ThreadCreationFunction f | f.getAnArgument() = node.asExpr()) + } +} + +module ThreadDependentMutexFlow = TaintTracking::Global; diff --git a/cpp/common/src/codingstandards/cpp/concurrency/ThreadSpecificStorage.qll b/cpp/common/src/codingstandards/cpp/concurrency/ThreadSpecificStorage.qll new file mode 100644 index 0000000000..aa7daf972c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/ThreadSpecificStorage.qll @@ -0,0 +1,59 @@ +import cpp +private import semmle.code.cpp.dataflow.DataFlow +private import codingstandards.cpp.concurrency.ThreadCreation + +/** + * Models calls to thread specific storage function calls. + */ +abstract class ThreadSpecificStorageFunctionCall extends FunctionCall { + /** + * Gets the key to which this call references. + */ + Expr getKey() { getArgument(0) = result } +} + +/** + * Models calls to `tss_get`. + */ +class TSSGetFunctionCall extends ThreadSpecificStorageFunctionCall { + TSSGetFunctionCall() { getTarget().getName() = "tss_get" } +} + +/** + * Models calls to `tss_set`. + */ +class TSSSetFunctionCall extends ThreadSpecificStorageFunctionCall { + TSSSetFunctionCall() { getTarget().getName() = "tss_set" } +} + +/** + * Models calls to `tss_create` + */ +class TSSCreateFunctionCall extends ThreadSpecificStorageFunctionCall { + TSSCreateFunctionCall() { getTarget().getName() = "tss_create" } + + predicate hasDeallocator() { + not exists(MacroInvocation mi, NullMacro nm | + getArgument(1) = mi.getExpr() and + mi = nm.getAnInvocation() + ) + } +} + +/** + * Models calls to `tss_delete` + */ +class TSSDeleteFunctionCall extends ThreadSpecificStorageFunctionCall { + TSSDeleteFunctionCall() { getTarget().getName() = "tss_delete" } +} + +/** + * Gets a call to `DeallocationExpr` that deallocates memory owned by thread specific + * storage. + */ +predicate getAThreadSpecificStorageDeallocationCall(C11ThreadCreateCall tcc, DeallocationExpr dexp) { + exists(TSSGetFunctionCall tsg | + tcc.getFunction().getEntryPoint().getASuccessor*() = tsg and + DataFlow::localFlow(DataFlow::exprNode(tsg), DataFlow::exprNode(dexp.getFreedExpr())) + ) +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/ThreadWaitDetach.qll b/cpp/common/src/codingstandards/cpp/concurrency/ThreadWaitDetach.qll new file mode 100644 index 0000000000..6898dc54df --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/ThreadWaitDetach.qll @@ -0,0 +1,41 @@ +import cpp + +/** + * Models thread waiting functions. + */ +abstract class ThreadWait extends FunctionCall { } + +/** + * Models a call to a `std::thread` join. + */ +class CPPThreadWait extends ThreadWait { + VariableAccess var; + + CPPThreadWait() { + getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "thread") and + getTarget().getName() = "join" + } +} + +/** + * Models a call to `thrd_join` in C11. + */ +class C11ThreadWait extends ThreadWait { + VariableAccess var; + + C11ThreadWait() { getTarget().getName() = "thrd_join" } +} + +/** + * Models thread detach functions. + */ +abstract class ThreadDetach extends FunctionCall { } + +/** + * Models a call to `thrd_detach` in C11. + */ +class C11ThreadDetach extends ThreadWait { + VariableAccess var; + + C11ThreadDetach() { getTarget().getName() = "thrd_detach" } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/ThreadedFunction.qll b/cpp/common/src/codingstandards/cpp/concurrency/ThreadedFunction.qll new file mode 100644 index 0000000000..a8d2c609c5 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/ThreadedFunction.qll @@ -0,0 +1,37 @@ +import cpp +private import codingstandards.cpp.concurrency.ThreadCreation + +/** + * Models a function that may be executed by some thread. + */ +abstract class ThreadedFunctionBase extends Function { + abstract Expr getSpawnExpr(); + + predicate isMultiplySpawned() { getSpawnExpr().getBasicBlock().inLoop() } +} + +final class ThreadedFunction = ThreadedFunctionBase; + +/** + * Models a function that may be executed by some thread via + * C++ standard classes. + */ +class CPPThreadedFunction extends ThreadedFunctionBase { + ThreadConstructorCall tcc; + + CPPThreadedFunction() { tcc.getFunction() = this } + + override Expr getSpawnExpr() { result = tcc } +} + +/** + * Models a function that may be executed by some thread via + * C11 standard functions. + */ +class C11ThreadedFunction extends ThreadedFunctionBase { + C11ThreadCreateCall cc; + + C11ThreadedFunction() { cc.getFunction() = this } + + override Expr getSpawnExpr() { result = cc } +} diff --git a/cpp/common/src/codingstandards/cpp/concurrency/Types.qll b/cpp/common/src/codingstandards/cpp/concurrency/Types.qll new file mode 100644 index 0000000000..3b865d5171 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/concurrency/Types.qll @@ -0,0 +1,29 @@ +import cpp + +class C11MutexType extends TypedefType { + C11MutexType() { this.hasName("mtx_t") } +} + +class C11ThreadType extends TypedefType { + C11ThreadType() { this.hasName("thrd_t") } +} + +class C11ConditionType extends TypedefType { + C11ConditionType() { this.hasName("cnd_t") } +} + +class C11ThreadStorageType extends TypedefType { + C11ThreadStorageType() { this.hasName("tss_t") } +} + +class C11ThreadingObjectType extends TypedefType { + C11ThreadingObjectType() { + this instanceof C11MutexType + or + this instanceof C11ThreadType + or + this instanceof C11ConditionType + or + this instanceof C11ThreadStorageType + } +} diff --git a/cpp/common/src/codingstandards/cpp/dominance/BehavioralSet.qll b/cpp/common/src/codingstandards/cpp/dominance/BehavioralSet.qll new file mode 100644 index 0000000000..ba42246e73 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/dominance/BehavioralSet.qll @@ -0,0 +1,47 @@ +import cpp +import semmle.code.cpp.controlflow.ControlFlowGraph + +signature class TargetNode extends ControlFlowNode; + +signature module DominatingSetConfigSig { + predicate isTargetBehavior(ControlFlowNode behavior, Target target); + + default predicate isBlockingBehavior(ControlFlowNode behavior, Target target) { + none() + } +} + +/** + * A module to find whether there exists a dominator set for a node which performs a relevant + * behavior. + * + * For instance, we may wish to see that all paths leading to an `abort()` statement include a + * logging call. In this case, the `abort()` statement is the `Target` node, and the config module + * predicate `isTargetBehavior` logging statements. + * + * Additionally, the config may specify `isBlockingBehavior` to prevent searching too far for the + * relevant behavior. For instance, if analyzing that all paths to an `fflush()` call are preceded + * by a write, we should ignore paths from write operations that have already been flushed through + * an intermediary `fflush()` call. + */ +module DominatingBehavioralSet Config> { + + /** + * Holds if this search step can reach the entry or a blocking node, without passing through a + * target behavior, indicating that the target is has no relevant dominator set. + */ + private predicate searchStep(ControlFlowNode node, Target target) { + Config::isBlockingBehavior(node, target) + or + not Config::isTargetBehavior(node, target) and + exists (ControlFlowNode prev | prev = node.getAPredecessor() | + searchStep(prev, target) + ) + } + + predicate isDominatedByBehavior(Target target) { + forex(ControlFlowNode prev | prev = target.getAPredecessor() | + not searchStep(prev, target) + ) + } +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency9.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency9.qll new file mode 100644 index 0000000000..b013bbdabb --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Concurrency9.qll @@ -0,0 +1,146 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Concurrency9Query = + TPossibleDataRaceBetweenThreadsQuery() or + TThreadResourceDisposedBeforeThreadsJoinedQuery() or + TInvalidOperationOnUnlockedMutexQuery() or + TNonRecursiveMutexRecursivelyLockedQuery() or + TNonRecursiveMutexRecursivelyLockedAuditQuery() or + TConditionVariableUsedWithMultipleMutexesQuery() or + TThreadStorageNotInitializedBeforeUseQuery() or + TThreadStoragePointerInitializedInsideThreadQuery() + +predicate isConcurrency9QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `possibleDataRaceBetweenThreads` query + Concurrency9Package::possibleDataRaceBetweenThreadsQuery() and + queryId = + // `@id` for the `possibleDataRaceBetweenThreads` query + "c/misra/possible-data-race-between-threads" and + ruleId = "DIR-5-1" and + category = "required" + or + query = + // `Query` instance for the `threadResourceDisposedBeforeThreadsJoined` query + Concurrency9Package::threadResourceDisposedBeforeThreadsJoinedQuery() and + queryId = + // `@id` for the `threadResourceDisposedBeforeThreadsJoined` query + "c/misra/thread-resource-disposed-before-threads-joined" and + ruleId = "RULE-22-15" and + category = "required" + or + query = + // `Query` instance for the `invalidOperationOnUnlockedMutex` query + Concurrency9Package::invalidOperationOnUnlockedMutexQuery() and + queryId = + // `@id` for the `invalidOperationOnUnlockedMutex` query + "c/misra/invalid-operation-on-unlocked-mutex" and + ruleId = "RULE-22-17" and + category = "required" + or + query = + // `Query` instance for the `nonRecursiveMutexRecursivelyLocked` query + Concurrency9Package::nonRecursiveMutexRecursivelyLockedQuery() and + queryId = + // `@id` for the `nonRecursiveMutexRecursivelyLocked` query + "c/misra/non-recursive-mutex-recursively-locked" and + ruleId = "RULE-22-18" and + category = "required" + or + query = + // `Query` instance for the `nonRecursiveMutexRecursivelyLockedAudit` query + Concurrency9Package::nonRecursiveMutexRecursivelyLockedAuditQuery() and + queryId = + // `@id` for the `nonRecursiveMutexRecursivelyLockedAudit` query + "c/misra/non-recursive-mutex-recursively-locked-audit" and + ruleId = "RULE-22-18" and + category = "required" + or + query = + // `Query` instance for the `conditionVariableUsedWithMultipleMutexes` query + Concurrency9Package::conditionVariableUsedWithMultipleMutexesQuery() and + queryId = + // `@id` for the `conditionVariableUsedWithMultipleMutexes` query + "c/misra/condition-variable-used-with-multiple-mutexes" and + ruleId = "RULE-22-19" and + category = "required" + or + query = + // `Query` instance for the `threadStorageNotInitializedBeforeUse` query + Concurrency9Package::threadStorageNotInitializedBeforeUseQuery() and + queryId = + // `@id` for the `threadStorageNotInitializedBeforeUse` query + "c/misra/thread-storage-not-initialized-before-use" and + ruleId = "RULE-22-20" and + category = "mandatory" + or + query = + // `Query` instance for the `threadStoragePointerInitializedInsideThread` query + Concurrency9Package::threadStoragePointerInitializedInsideThreadQuery() and + queryId = + // `@id` for the `threadStoragePointerInitializedInsideThread` query + "c/misra/thread-storage-pointer-initialized-inside-thread" and + ruleId = "RULE-22-20" and + category = "mandatory" +} + +module Concurrency9Package { + Query possibleDataRaceBetweenThreadsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `possibleDataRaceBetweenThreads` query + TQueryC(TConcurrency9PackageQuery(TPossibleDataRaceBetweenThreadsQuery())) + } + + Query threadResourceDisposedBeforeThreadsJoinedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadResourceDisposedBeforeThreadsJoined` query + TQueryC(TConcurrency9PackageQuery(TThreadResourceDisposedBeforeThreadsJoinedQuery())) + } + + Query invalidOperationOnUnlockedMutexQuery() { + //autogenerate `Query` type + result = + // `Query` type for `invalidOperationOnUnlockedMutex` query + TQueryC(TConcurrency9PackageQuery(TInvalidOperationOnUnlockedMutexQuery())) + } + + Query nonRecursiveMutexRecursivelyLockedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonRecursiveMutexRecursivelyLocked` query + TQueryC(TConcurrency9PackageQuery(TNonRecursiveMutexRecursivelyLockedQuery())) + } + + Query nonRecursiveMutexRecursivelyLockedAuditQuery() { + //autogenerate `Query` type + result = + // `Query` type for `nonRecursiveMutexRecursivelyLockedAudit` query + TQueryC(TConcurrency9PackageQuery(TNonRecursiveMutexRecursivelyLockedAuditQuery())) + } + + Query conditionVariableUsedWithMultipleMutexesQuery() { + //autogenerate `Query` type + result = + // `Query` type for `conditionVariableUsedWithMultipleMutexes` query + TQueryC(TConcurrency9PackageQuery(TConditionVariableUsedWithMultipleMutexesQuery())) + } + + Query threadStorageNotInitializedBeforeUseQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadStorageNotInitializedBeforeUse` query + TQueryC(TConcurrency9PackageQuery(TThreadStorageNotInitializedBeforeUseQuery())) + } + + Query threadStoragePointerInitializedInsideThreadQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadStoragePointerInitializedInsideThread` query + TQueryC(TConcurrency9PackageQuery(TThreadStoragePointerInitializedInsideThreadQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index bb0e324fd5..6923c1af31 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -14,6 +14,7 @@ import Concurrency4 import Concurrency5 import Concurrency6 import Concurrency8 +import Concurrency9 import Contracts import Contracts1 import Contracts2 @@ -97,6 +98,7 @@ newtype TCQuery = TConcurrency5PackageQuery(Concurrency5Query q) or TConcurrency6PackageQuery(Concurrency6Query q) or TConcurrency8PackageQuery(Concurrency8Query q) or + TConcurrency9PackageQuery(Concurrency9Query q) or TContractsPackageQuery(ContractsQuery q) or TContracts1PackageQuery(Contracts1Query q) or TContracts2PackageQuery(Contracts2Query q) or @@ -180,6 +182,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isConcurrency5QueryMetadata(query, queryId, ruleId, category) or isConcurrency6QueryMetadata(query, queryId, ruleId, category) or isConcurrency8QueryMetadata(query, queryId, ruleId, category) or + isConcurrency9QueryMetadata(query, queryId, ruleId, category) or isContractsQueryMetadata(query, queryId, ruleId, category) or isContracts1QueryMetadata(query, queryId, ruleId, category) or isContracts2QueryMetadata(query, queryId, ruleId, category) or diff --git a/rule_packages/c/Concurrency9.json b/rule_packages/c/Concurrency9.json new file mode 100644 index 0000000000..4bdd6d9a96 --- /dev/null +++ b/rule_packages/c/Concurrency9.json @@ -0,0 +1,158 @@ +{ + "MISRA-C-2012": { + "DIR-5-1": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Threads shall not access the same memory location concurrently without utilization of thread synchronization objects.", + "kind": "problem", + "name": "There shall be no data races between threads", + "precision": "medium", + "severity": "error", + "short_name": "PossibleDataRaceBetweenThreads", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "There shall be no data races between threads" + }, + "RULE-22-15": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated", + "kind": "problem", + "name": "Thread synchronization objects and thread-specific storage pointers shall not be disposed unsafely", + "precision": "medium", + "severity": "error", + "short_name": "ThreadResourceDisposedBeforeThreadsJoined", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated" + }, + "RULE-22-17": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked before.", + "kind": "problem", + "name": "No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked", + "precision": "high", + "severity": "error", + "short_name": "InvalidOperationOnUnlockedMutex", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked before" + }, + "RULE-22-18": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Mutexes initialized with mtx_init() without mtx_recursive shall not be locked by a thread that has previously locked it.", + "kind": "problem", + "name": "Non-recursive mutexes shall not be recursively locked", + "precision": "very-high", + "severity": "error", + "short_name": "NonRecursiveMutexRecursivelyLocked", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + }, + { + "description": "Mutex that may be initialized without mtx_recursive shall not be locked by a thread that has previous may havec locked it.", + "kind": "problem", + "name": "(Audit) Non-recursive mutexes shall not be recursively locked", + "precision": "high", + "severity": "error", + "short_name": "NonRecursiveMutexRecursivelyLockedAudit", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4", + "audit" + ] + } + ], + "title": "Non-recursive mutexes shall not be recursively locked" + }, + "RULE-22-19": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Standard library functions cnd_wait() and cnd_timedwait() shall specify the same mutex object for each condition object in all calls.", + "kind": "problem", + "name": "A condition variable shall be associated with at most one mutex object", + "precision": "very-high", + "severity": "error", + "short_name": "ConditionVariableUsedWithMultipleMutexes", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "A condition variable shall be associated with at most one mutex object" + }, + "RULE-22-20": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "Thread specific storage pointers shall be initialized with the standard library functions before using them.", + "kind": "problem", + "name": "Thread-specific storage pointers shall be created before being accessed", + "precision": "high", + "severity": "error", + "short_name": "ThreadStorageNotInitializedBeforeUse", + "tags": [ + "correctness", + "concurrency", + "external/misra/c/2012/amendment4" + ] + }, + { + "description": "Thread specific storage pointers initialized inside of threads may result in indeterministic state.", + "kind": "problem", + "name": "Thread specific storage pointers shall be initialized deterministically", + "precision": "very-high", + "severity": "recommendation", + "short_name": "ThreadStoragePointerInitializedInsideThread", + "tags": [ + "readability", + "maintainability", + "concurrency", + "external/misra/c/2012/amendment4" + ] + } + ], + "title": "Thread-specific storage pointers shall be created before being accessed" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index cb0551b586..44c2f00357 100644 --- a/rules.csv +++ b/rules.csv @@ -617,7 +617,7 @@ c,MISRA-C-2012,DIR-4-12,Yes,Required,,,Dynamic memory allocation shall not be us c,MISRA-C-2012,DIR-4-13,No,Advisory,,,Functions which are designed to provide operations on a resource should be called in an appropriate sequence,,,,"Rule 22.1, 22.2 and 22.6 cover aspects of this rule. In other cases this is a design issue and needs to be checked manually." c,MISRA-C-2012,DIR-4-14,Yes,Required,,,The validity of values received from external sources shall be checked,,Contracts8,Hard,This is supported by CodeQLs default C security queries. c,MISRA-C-2012,DIR-4-15,Yes,Required,,,Evaluation of floating-point expressions shall not lead to the undetected generation of infinities and NaNs,FLP32-C and FLP04-C,FloatingTypes2,Medium, -c,MISRA-C-2012,DIR-5-1,Yes,Required,,,There shall be no data races between threads,CON43-C and CON32-C,Concurrency7,Very Hard, +c,MISRA-C-2012,DIR-5-1,Yes,Required,,,There shall be no data races between threads,CON43-C and CON32-C,Concurrency9,Very Hard, c,MISRA-C-2012,DIR-5-2,Yes,Required,,,There shall be no deadlocks between threads,CON35-C,Concurrency6,Import, c,MISRA-C-2012,DIR-5-3,Yes,Required,,,There shall be no dynamic thread creation,,Concurrency6,Easy, c,MISRA-C-2012,RULE-1-1,No,Required,,,"The program shall contain no violations of the standard C syntax and constraints, and shall not exceed the implementation's translation limits",,,Easy,"This should be checked via the compiler output, rather than CodeQL, which adds unnecessary steps." @@ -806,12 +806,12 @@ c,MISRA-C-2012,RULE-22-11,Yes,Required,,,A thread that was previously either joi c,MISRA-C-2012,RULE-22-12,Yes,Mandatory,,,"Thread objects, thread synchronization objects, and thread-specific storage pointers shall only be accessed by the appropriate Standard Library functions",,Concurrency8,Medium, c,MISRA-C-2012,RULE-22-13,Yes,Required,,,"Thread objects, thread synchronization objects, and thread specific storage pointers shall have appropriate storage duration",EXP54-CPP and CON34-C,Concurrency8,Medium, c,MISRA-C-2012,RULE-22-14,Yes,Mandatory,,,Thread synchronization objects shall be initialized before being accessed,EXP53-CPP,Concurrency8,Hard, -c,MISRA-C-2012,RULE-22-15,Yes,Required,,,Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated,,Concurrency7,Hard, +c,MISRA-C-2012,RULE-22-15,Yes,Required,,,Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated,,Concurrency9,Hard, c,MISRA-C-2012,RULE-22-16,Yes,Required,,,All mutex objects locked by a thread shall be explicitly unlocked by the same thread,MEM51-CPP,Concurrency8,Hard, -c,MISRA-C-2012,RULE-22-17,Yes,Required,,,No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked before,Rule 22.2,Concurrency7,Medium, -c,MISRA-C-2012,RULE-22-18,Yes,Required,,,Non-recursive mutexes shall not be recursively locked,CON56-CPP,Concurrency7,Medium, -c,MISRA-C-2012,RULE-22-19,Yes,Required,,,A condition variable shall be associated with at most one mutex object,,Concurrency7,Medium, -c,MISRA-C-2012,RULE-22-20,Yes,Mandatory,,,Thread-specific storage pointers shall be created before being accessed,,Concurrency7,Hard, +c,MISRA-C-2012,RULE-22-17,Yes,Required,,,No thread shall unlock a mutex or call cnd_wait() or cnd_timedwait() for a mutex it has not locked before,Rule 22.2,Concurrency9,Medium, +c,MISRA-C-2012,RULE-22-18,Yes,Required,,,Non-recursive mutexes shall not be recursively locked,CON56-CPP,Concurrency9,Medium, +c,MISRA-C-2012,RULE-22-19,Yes,Required,,,A condition variable shall be associated with at most one mutex object,,Concurrency9,Medium, +c,MISRA-C-2012,RULE-22-20,Yes,Mandatory,,,Thread-specific storage pointers shall be created before being accessed,,Concurrency9,Hard, c,MISRA-C-2012,RULE-23-1,Yes,Advisory,,,A generic selection should only be expanded from a macro,,Generics,Medium, c,MISRA-C-2012,RULE-23-2,Yes,Required,,,A generic selection that is not expanded from a macro shall not contain potential side effects in the controlling expression,,Generics,Hard, c,MISRA-C-2012,RULE-23-3,Yes,Advisory,,,A generic selection should contain at least one non-default association,,Generics,Easy, From 9e35e593bd116a22ae8a9f1e2de2fc41a75c9072 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 18 Feb 2025 23:07:52 +0000 Subject: [PATCH 268/628] Deviations: use getADeviationRecord Deviation code identifier markers can have multiple records. --- .../cpp/deviations/CodeIdentifierDeviation.qll | 12 ++++++------ .../codingstandards/cpp/deviations/Deviations.qll | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll index 9a694ccc8f..310a2b678b 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -224,7 +224,7 @@ class DeviationAttribute extends StdAttribute { "\"" + record.getCodeIdentifier() + "\"" = this.getAnArgument().getValueText() } - DeviationRecord getDeviationRecord() { result = record } + DeviationRecord getADeviationRecord() { result = record } pragma[nomagic] Element getASuppressedElement() { @@ -296,12 +296,12 @@ newtype TCodeIndentifierDeviation = endComment.getLocation().hasLocationInfo(filepath, suppressedEndLine, _, _, _) } or TCodeIdentifierDeviation(DeviationRecord record, DeviationAttribute attribute) { - attribute.getDeviationRecord() = record + attribute.getADeviationRecord() = record } class CodeIdentifierDeviation extends TCodeIndentifierDeviation { /** The deviation record associated with the deviation comment. */ - DeviationRecord getDeviationRecord() { + DeviationRecord getADeviationRecord() { this = TSingleLineDeviation(result, _, _, _) or this = TMultiLineDeviation(result, _, _, _, _, _) @@ -341,21 +341,21 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { exists(int suppressedLine | this = TSingleLineDeviation(_, _, filepath, suppressedLine) and result = - "Deviation record " + getDeviationRecord() + " applied to " + filepath + " Line " + + "Deviation record " + getADeviationRecord() + " applied to " + filepath + " Line " + suppressedLine ) or exists(int suppressedStartLine, int suppressedEndLine | this = TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedEndLine) and result = - "Deviation record " + getDeviationRecord() + " applied to " + filepath + " Line" + + "Deviation record " + getADeviationRecord() + " applied to " + filepath + " Line" + suppressedStartLine + ":" + suppressedEndLine ) ) or exists(DeviationAttribute attribute | this = TCodeIdentifierDeviation(_, attribute) and - result = "Deviation record " + getDeviationRecord() + " applied to " + attribute + result = "Deviation record " + getADeviationRecord() + " applied to " + attribute ) } } diff --git a/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll b/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll index 434d6988e9..e8c030cdd4 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/Deviations.qll @@ -221,7 +221,7 @@ class DeviationRecord extends XmlElement { } /** Gets a code identifier deviation in code which starts or ends with the code identifier comment. */ - CodeIdentifierDeviation getACodeIdentifierDeviation() { this = result.getDeviationRecord() } + CodeIdentifierDeviation getACodeIdentifierDeviation() { this = result.getADeviationRecord() } /** Gets the `rule-id` specified for this record, if any. */ private string getRawRuleId() { result = getAChild("rule-id").getTextValue() } From b273d0f66fbf252dcc5ab8bb865285fd79bdd3ed Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 18 Feb 2025 23:12:11 +0000 Subject: [PATCH 269/628] Deviations: Update expected tests --- .../deviations_basic_test/TypeLongDoubleUsed.expected | 2 +- .../deviations/deviations_basic_test/UnusedReturnValue.expected | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected b/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected index 172b623195..f2cfd03dc6 100644 --- a/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected +++ b/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected @@ -1,7 +1,7 @@ | attribute_syntax.cpp:6:15:6:17 | dd1 | Use of long double type. | | attribute_syntax.cpp:21:15:21:17 | d10 | Use of long double type. | | attribute_syntax.cpp:29:15:29:17 | d14 | Use of long double type. | -| attribute_syntax.cpp:33:20:33:22 | d16 | Use of long double type. | +| attribute_syntax.cpp:34:20:34:22 | d16 | Use of long double type. | | attribute_syntax.cpp:55:15:55:16 | d1 | Use of long double type. | | attribute_syntax.cpp:57:17:57:18 | d2 | Use of long double type. | | attribute_syntax.cpp:60:17:60:18 | d3 | Use of long double type. | diff --git a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected index 120337ffdc..fc7af4b197 100644 --- a/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected +++ b/cpp/common/test/deviations/deviations_basic_test/UnusedReturnValue.expected @@ -4,7 +4,7 @@ | attribute_syntax.cpp:24:5:24:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | | attribute_syntax.cpp:26:5:26:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | | attribute_syntax.cpp:30:3:30:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | -| attribute_syntax.cpp:41:3:41:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | +| attribute_syntax.cpp:42:3:42:6 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | | attribute_syntax.cpp:49:5:49:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | | attribute_syntax.cpp:61:5:61:8 | call to getZ | Return value from call to $@ is unused. | attribute_syntax.cpp:1:5:1:8 | getZ | getZ | | main.cpp:12:3:12:6 | call to getX | Return value from call to $@ is unused. | main.cpp:8:5:8:8 | getX | getX | From 3eecfa05ec5bea6900fbf149f4a3e070b4517afe Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 18 Feb 2025 20:55:16 -0800 Subject: [PATCH 270/628] Update StdFunctionOrMacro with feedback --- .../RULE-9-7/UninitializedAtomicObject.ql | 8 +---- .../cpp/StdFunctionOrMacro.qll | 29 +++++++++---------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql b/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql index b6e8bc82bc..dfb096189f 100644 --- a/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql +++ b/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql @@ -30,14 +30,8 @@ class ThreadSpawningFunction extends Function { } } -private string atomicInit() { result = "atomic_init" } - class AtomicInitAddressOfExpr extends AddressOfExpr { - AtomicInitAddressOfExpr() { - exists(StdFunctionOrMacro::Call c | - this = c.getArgument(0) - ) - } + AtomicInitAddressOfExpr() { exists(AtomicInitCall c | this = c.getArgument(0)) } } ControlFlowNode getARequiredInitializationPoint(LocalScopeVariable v) { diff --git a/cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll b/cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll index 5ae370183d..1067b7ad09 100644 --- a/cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll +++ b/cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll @@ -31,30 +31,28 @@ import cpp as cpp +private string atomicInit() { result = "atomic_init" } + +class AtomicInitCall = StdFunctionOrMacro::Call; + /** Specify the name of your function as a predicate */ -signature string getName(); +private signature string getName(); /** Signature module to implement custom argument resolution behavior in expanded macros */ -signature module InferMacroExpansionArguments { +private signature module InferMacroExpansionArguments { bindingset[mi, argumentIdx] cpp::Expr inferArgument(cpp::MacroInvocation mi, int argumentIdx); } -/** Assume all subexpressions of an expanded macro may be the result of any ith argument */ -module NoMacroExpansionInference implements InferMacroExpansionArguments { - bindingset[mi, argumentIdx] - cpp::Expr inferArgument(cpp::MacroInvocation mi, int argumentIdx) { - result.getParent*() = mi.getExpr() - } -} - /** Assume macro `f(x, y, ...)` expands to `__c11_f(x, y, ...)`. */ -module C11FunctionWrapperMacro implements InferMacroExpansionArguments { +private module C11FunctionWrapperMacro implements InferMacroExpansionArguments { bindingset[mi, argumentIdx] cpp::Expr inferArgument(cpp::MacroInvocation mi, int argumentIdx) { - if mi.getExpr().(cpp::FunctionCall).getTarget().hasName("__c11_" + mi.getMacroName()) - then result = mi.getExpr().(cpp::FunctionCall).getArgument(argumentIdx) - else result = NoMacroExpansionInference::inferArgument(mi, argumentIdx) + exists(cpp::FunctionCall fc | + fc = mi.getExpr() and + fc.getTarget().hasName("__c11_" + mi.getMacroName()) and + result = mi.getExpr().(cpp::FunctionCall).getArgument(argumentIdx) + ) } } @@ -72,7 +70,8 @@ module C11FunctionWrapperMacro implements InferMacroExpansionArguments { * select c.getArgument(0) * ``` */ -module StdFunctionOrMacro { +private module StdFunctionOrMacro +{ final private class Expr = cpp::Expr; final private class FunctionCall = cpp::FunctionCall; From 42adff5fe8890f07a4f736a2f4a6d9be671bba11 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 18 Feb 2025 21:14:25 -0800 Subject: [PATCH 271/628] Formatting & json validation --- c/common/src/codingstandards/c/SubObjects.qll | 10 +++------- .../c/initialization/GlobalInitializationAnalysis.qll | 2 +- rule_packages/c/Concurrency9.json | 4 ++-- schemas/rule-package.schema.json | 1 + 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/c/common/src/codingstandards/c/SubObjects.qll b/c/common/src/codingstandards/c/SubObjects.qll index d7aa1e976b..282b0fb5eb 100644 --- a/c/common/src/codingstandards/c/SubObjects.qll +++ b/c/common/src/codingstandards/c/SubObjects.qll @@ -44,12 +44,10 @@ class SubObject extends TSubObject { /** * Holds for object roots and for member accesses on that root, not for array accesses. - * + * * This is useful for cases where we do not wish to treat `x[y]` and `x[z]` as the same object. */ - predicate isPrecise() { - not getParent*() = TObjectIndex(_) - } + predicate isPrecise() { not getParent*() = TObjectIndex(_) } SubObject getParent() { exists(SubObject struct, MemberVariable m | @@ -79,9 +77,7 @@ class SubObject extends TSubObject { result.(ArrayExpr).getArrayBase() = getParent().getAnAccess() } - AddressOfExpr getAnAddressOfExpr() { - result.getOperand() = this.getAnAccess() - } + AddressOfExpr getAnAddressOfExpr() { result.getOperand() = this.getAnAccess() } ObjectIdentity getRootIdentity() { exists(ObjectIdentity i | diff --git a/c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll b/c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll index d2974f9924..90d0a4630a 100644 --- a/c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll +++ b/c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll @@ -4,7 +4,7 @@ import codingstandards.cpp.Concurrency import codingstandards.cpp.Type signature module GlobalInitializationAnalysisConfigSig { - /** A function which is not called or started as a thread */ + /** A function which is not called or started as a thread */ default predicate isRootFunction(Function f) { not exists(Function f2 | f2.calls(f)) and not f instanceof ThreadedFunction diff --git a/rule_packages/c/Concurrency9.json b/rule_packages/c/Concurrency9.json index 4bdd6d9a96..39c5cc58a8 100644 --- a/rule_packages/c/Concurrency9.json +++ b/rule_packages/c/Concurrency9.json @@ -27,7 +27,7 @@ }, "queries": [ { - "description": "Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated", + "description": "Thread synchronization objects and thread-specific storage pointers shall not be destroyed until after all threads accessing them have terminated.", "kind": "problem", "name": "Thread synchronization objects and thread-specific storage pointers shall not be disposed unsafely", "precision": "medium", @@ -92,7 +92,7 @@ "correctness", "concurrency", "external/misra/c/2012/amendment4", - "audit" + "external/misra/audit" ] } ], diff --git a/schemas/rule-package.schema.json b/schemas/rule-package.schema.json index 64fac6f396..b4f729afe2 100644 --- a/schemas/rule-package.schema.json +++ b/schemas/rule-package.schema.json @@ -342,6 +342,7 @@ "external/autosar/strict", "scope/single-translation-unit", "scope/system", + "external/misra/audit", "external/misra/c/2012/third-edition-first-revision", "external/misra/c/2012/amendment2", "external/misra/c/2012/amendment3", From 96171eeea1df7f033c7fc03c75804d7113aa1d7f Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 18 Feb 2025 21:16:16 -0800 Subject: [PATCH 272/628] cpp format --- .../cpp/dominance/BehavioralSet.qll | 43 ++++++++----------- 1 file changed, 18 insertions(+), 25 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/dominance/BehavioralSet.qll b/cpp/common/src/codingstandards/cpp/dominance/BehavioralSet.qll index ba42246e73..8609e3213b 100644 --- a/cpp/common/src/codingstandards/cpp/dominance/BehavioralSet.qll +++ b/cpp/common/src/codingstandards/cpp/dominance/BehavioralSet.qll @@ -4,44 +4,37 @@ import semmle.code.cpp.controlflow.ControlFlowGraph signature class TargetNode extends ControlFlowNode; signature module DominatingSetConfigSig { - predicate isTargetBehavior(ControlFlowNode behavior, Target target); + predicate isTargetBehavior(ControlFlowNode behavior, Target target); - default predicate isBlockingBehavior(ControlFlowNode behavior, Target target) { - none() - } + default predicate isBlockingBehavior(ControlFlowNode behavior, Target target) { none() } } /** * A module to find whether there exists a dominator set for a node which performs a relevant * behavior. - * + * * For instance, we may wish to see that all paths leading to an `abort()` statement include a * logging call. In this case, the `abort()` statement is the `Target` node, and the config module * predicate `isTargetBehavior` logging statements. - * + * * Additionally, the config may specify `isBlockingBehavior` to prevent searching too far for the * relevant behavior. For instance, if analyzing that all paths to an `fflush()` call are preceded * by a write, we should ignore paths from write operations that have already been flushed through * an intermediary `fflush()` call. */ module DominatingBehavioralSet Config> { + /** + * Holds if this search step can reach the entry or a blocking node, without passing through a + * target behavior, indicating that the target is has no relevant dominator set. + */ + private predicate searchStep(ControlFlowNode node, Target target) { + Config::isBlockingBehavior(node, target) + or + not Config::isTargetBehavior(node, target) and + exists(ControlFlowNode prev | prev = node.getAPredecessor() | searchStep(prev, target)) + } - /** - * Holds if this search step can reach the entry or a blocking node, without passing through a - * target behavior, indicating that the target is has no relevant dominator set. - */ - private predicate searchStep(ControlFlowNode node, Target target) { - Config::isBlockingBehavior(node, target) - or - not Config::isTargetBehavior(node, target) and - exists (ControlFlowNode prev | prev = node.getAPredecessor() | - searchStep(prev, target) - ) - } - - predicate isDominatedByBehavior(Target target) { - forex(ControlFlowNode prev | prev = target.getAPredecessor() | - not searchStep(prev, target) - ) - } -} \ No newline at end of file + predicate isDominatedByBehavior(Target target) { + forex(ControlFlowNode prev | prev = target.getAPredecessor() | not searchStep(prev, target)) + } +} From 2f619a4a82e025154b03fdbf86a77931041a1445 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 20 Feb 2025 00:26:53 -0800 Subject: [PATCH 273/628] Fix performance issue in ResourceLeakAnalysis.qll --- .../codingstandards/cpp/resources/ResourceLeakAnalysis.qll | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll b/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll index 7d767b5cb4..d1c1a369ef 100644 --- a/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll +++ b/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll @@ -1,6 +1,6 @@ import cpp import semmle.code.cpp.dataflow.DataFlow -import semmle.code.cpp.valuenumbering.GlobalValueNumbering +import semmle.code.cpp.valuenumbering.HashCons import semmle.code.cpp.controlflow.Dominance import codeql.util.Boolean @@ -40,13 +40,14 @@ signature module ResourceLeakConfigSig { predicate isFree(ControlFlowNode node, DataFlow::Node resource); + bindingset[node] default DataFlow::Node getAnAlias(DataFlow::Node node) { DataFlow::localFlow(node, result) or exists(Expr current, Expr after | current in [node.asExpr(), node.asDefiningArgument()] and after in [result.asExpr(), result.asDefiningArgument()] and - globalValueNumber(current) = globalValueNumber(after) and + hashCons(current) = hashCons(after) and strictlyDominates(current, after) ) } From 1c86573cb785615a5e050b4556dc98b1209df743 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 20 Feb 2025 17:48:08 -0800 Subject: [PATCH 274/628] Remove getAnAliasRecursive() --- c/misra/test/rules/RULE-22-16/test.c | 8 ++++++++ .../cpp/resources/ResourceLeakAnalysis.qll | 15 +-------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/c/misra/test/rules/RULE-22-16/test.c b/c/misra/test/rules/RULE-22-16/test.c index 00764645a4..d0d4f6ddcd 100644 --- a/c/misra/test/rules/RULE-22-16/test.c +++ b/c/misra/test/rules/RULE-22-16/test.c @@ -104,4 +104,12 @@ void f15(int p) { } mtx_unlock(&m); } +} + +void f16(int p) { + mtx_t* ptr; + mtx_t *ptr_m1 = ptr; + mtx_t *ptr_m2 = ptr; + mtx_lock(ptr_m1); // COMPLIANT[FALSE_POSITIVE] + mtx_unlock(ptr_m2); } \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll b/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll index d1c1a369ef..3dd61e934d 100644 --- a/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll +++ b/cpp/common/src/codingstandards/cpp/resources/ResourceLeakAnalysis.qll @@ -64,19 +64,6 @@ module ResourceLeak { Config::isAllocate(cfgNode, resource) } - /** - * Get an alias of a resource, and aliases of nodes that are aliased by a resource. - */ - private DataFlow::Node getAnAliasRecursive(DataFlow::Node node) { - result = Config::getAnAlias(node) and - Config::isAllocate(_, node) - or - exists(DataFlow::Node parent | - node = getAnAliasRecursive(parent) and - result = Config::getAnAlias(parent) - ) - } - private predicate isLeakedAtControlPoint(TResource resource, ControlFlowNode cfgNode) { // Holds if this control point is where the resource was allocated (and therefore not freed). resource = TJustResource(_, cfgNode) @@ -86,7 +73,7 @@ module ResourceLeak { isLeakedAtControlPoint(resource, cfgNode.getAPredecessor()) and not exists(DataFlow::Node freed, DataFlow::Node resourceNode | Config::isFree(cfgNode, freed) and - freed = getAnAliasRecursive(resourceNode) and + freed = Config::getAnAlias(resourceNode) and resource = TJustResource(resourceNode, _) ) } From 56f2996bb0758fe693c87cf87d645d975ae0ec1a Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 20 Feb 2025 18:21:12 -0800 Subject: [PATCH 275/628] Add change note --- .../2025-02-20-rule-22-16-update-aliasing-for-performance.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 change_notes/2025-02-20-rule-22-16-update-aliasing-for-performance.md diff --git a/change_notes/2025-02-20-rule-22-16-update-aliasing-for-performance.md b/change_notes/2025-02-20-rule-22-16-update-aliasing-for-performance.md new file mode 100644 index 0000000000..80ff92748f --- /dev/null +++ b/change_notes/2025-02-20-rule-22-16-update-aliasing-for-performance.md @@ -0,0 +1,3 @@ + - `RULE-22-16`, `ERR57-CPP`, `A15-1-4` - `MutexObjectsNotAlwaysUnlocked.ql`, `DoNotLeakResourcesWhenHandlingExceptions.ql`, `ValidResourcesStateBeforeThrow.ql`: + - Shared module `ResourceLeakAnalysis.qll` changed to not get aliases recursively for simplicity and improved performance. The recent update to these queries had logic intending to handle the case where an allocation node is an alias of a parent node, and the free operation releases that parent node. However, the behavior was incorrectly defined and not working, and in the presence of performance issues this behavior has been removed. + - (`RULE-22-16` only) The alias behavior has been updated to compare expressions with `HashCons` instead of `GlobalValueNumbering` for higher performance. GVN is more expensive generally, seemed to introduce low performance joins secondarily, and is stricter than `HashCons` in a contravening position, meaning a stricter analysis introduces a higher likelihood of false positives. \ No newline at end of file From 81663048818818eee39004e9d85f25a43ecad6ae Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 20 Feb 2025 18:48:40 -0800 Subject: [PATCH 276/628] format new test case --- c/misra/test/rules/RULE-22-16/test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/misra/test/rules/RULE-22-16/test.c b/c/misra/test/rules/RULE-22-16/test.c index d0d4f6ddcd..c97fb3d588 100644 --- a/c/misra/test/rules/RULE-22-16/test.c +++ b/c/misra/test/rules/RULE-22-16/test.c @@ -107,7 +107,7 @@ void f15(int p) { } void f16(int p) { - mtx_t* ptr; + mtx_t *ptr; mtx_t *ptr_m1 = ptr; mtx_t *ptr_m2 = ptr; mtx_lock(ptr_m1); // COMPLIANT[FALSE_POSITIVE] From 5a5f8b78901ff01ac12714b4c36576b5a23edce9 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 20 Feb 2025 22:55:24 -0800 Subject: [PATCH 277/628] Commit changed test expectations --- .../test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected b/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected index dbee52ed58..46a295d75f 100644 --- a/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected +++ b/c/misra/test/rules/RULE-22-16/MutexObjectsNotAlwaysUnlocked.expected @@ -7,3 +7,4 @@ WARNING: module 'DataFlow' has been deprecated and may be removed in future (Mut | test.c:72:3:72:10 | call to mtx_lock | Mutex 'g1' is locked here and may not always be subsequently unlocked. | | test.c:79:3:79:10 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | | test.c:101:5:101:12 | call to mtx_lock | Mutex 'm' is locked here and may not always be subsequently unlocked. | +| test.c:113:3:113:10 | call to mtx_lock | Mutex 'ptr_m1' is locked here and may not always be subsequently unlocked. | From 614c7ab925faab73b9cf1aeb51a43c8cdf62b679 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Wed, 5 Mar 2025 09:31:29 +0000 Subject: [PATCH 278/628] Update change_notes/2025-02-17-iofstream-performance.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- change_notes/2025-02-17-iofstream-performance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change_notes/2025-02-17-iofstream-performance.md b/change_notes/2025-02-17-iofstream-performance.md index 8a0be4c3ac..8e566d3778 100644 --- a/change_notes/2025-02-17-iofstream-performance.md +++ b/change_notes/2025-02-17-iofstream-performance.md @@ -1,2 +1,2 @@ - - `A27-0-3`, `FIO309-C` `FIO50-CPP`, `RULE-30-0-2` - `InterleavedInputOutputWithoutFlush.ql`, `DoNotAlternatelyIOFromStreamWithoutPositioning.ql`,`InterleavedInputOutputWithoutPosition.ql`, `ReadsAndWritesOnStreamNotSeparatedByPositioning.ql`: + - `A27-0-3`, `FIO309-C`, `FIO50-CPP`, `RULE-30-0-2` - `InterleavedInputOutputWithoutFlush.ql`, `DoNotAlternatelyIOFromStreamWithoutPositioning.ql`, `InterleavedInputOutputWithoutPosition.ql`, `ReadsAndWritesOnStreamNotSeparatedByPositioning.ql`: - Reduce evaluation time on complex codebases. \ No newline at end of file From 70c776ae2148b7b4a66134ba9c9c47846d8345d0 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 9 Mar 2025 11:24:54 +0000 Subject: [PATCH 279/628] RULE-8-7: Restructure test Move single translation unit items into the translation unit, not the shared header. --- .../RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected | 6 +++--- c/misra/test/rules/RULE-8-7/test.c | 3 +++ c/misra/test/rules/RULE-8-7/test.h | 5 +---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected b/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected index b6a53071d9..fb0b975e88 100644 --- a/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected +++ b/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected @@ -1,3 +1,3 @@ -| test.h:2:12:2:13 | i1 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:4:3:4:4 | i1 | i1 | -| test.h:3:5:3:6 | i2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:5:3:5:4 | i2 | i2 | -| test.h:5:13:5:14 | f2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:7:3:7:4 | call to f2 | call to f2 | +| test.c:2:5:2:6 | i2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:8:3:8:4 | i2 | i2 | +| test.h:2:12:2:13 | i1 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:7:3:7:4 | i1 | i1 | +| test.h:4:13:4:14 | f2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:10:3:10:4 | call to f2 | call to f2 | diff --git a/c/misra/test/rules/RULE-8-7/test.c b/c/misra/test/rules/RULE-8-7/test.c index b2cc2a0684..5b83445944 100644 --- a/c/misra/test/rules/RULE-8-7/test.c +++ b/c/misra/test/rules/RULE-8-7/test.c @@ -1,4 +1,7 @@ #include "test.h" +int i2; // NON_COMPLIANT - accessed one translation unit +static void f3(); // COMPLIANT - internal linkage +extern void f3(); // COMPLIANT - internal linkage void f() { i = 0; i1 = 0; diff --git a/c/misra/test/rules/RULE-8-7/test.h b/c/misra/test/rules/RULE-8-7/test.h index 692bb8e3db..218ec18c23 100644 --- a/c/misra/test/rules/RULE-8-7/test.h +++ b/c/misra/test/rules/RULE-8-7/test.h @@ -1,7 +1,4 @@ extern int i; // COMPLIANT - accessed multiple translation units extern int i1; // NON_COMPLIANT - accessed one translation unit -int i2; // NON_COMPLIANT - accessed one translation unit extern void f1(); // COMPLIANT - accessed multiple translation units -extern void f2(); // NON_COMPLIANT - accessed one translation unit -static void f3(); // COMPLIANT - internal linkage -extern void f3(); // COMPLIANT - internal linkage \ No newline at end of file +extern void f2(); // NON_COMPLIANT - accessed one translation unit \ No newline at end of file From 32fd091717729020734010580bf4b5775851b765 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 9 Mar 2025 11:28:46 +0000 Subject: [PATCH 280/628] RULE-8-7: Add appropriate definitions to test Ensure definitions occur in one translation unit only. --- .../ShouldNotBeDefinedWithExternalLinkage.expected | 6 +++--- c/misra/test/rules/RULE-8-7/test.c | 9 ++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected b/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected index fb0b975e88..5f04b41ac0 100644 --- a/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected +++ b/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected @@ -1,3 +1,3 @@ -| test.c:2:5:2:6 | i2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:8:3:8:4 | i2 | i2 | -| test.h:2:12:2:13 | i1 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:7:3:7:4 | i1 | i1 | -| test.h:4:13:4:14 | f2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:10:3:10:4 | call to f2 | call to f2 | +| test.c:3:5:3:6 | i1 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:10:3:10:4 | i1 | i1 | +| test.c:4:5:4:6 | i2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:11:3:11:4 | i2 | i2 | +| test.c:6:6:6:7 | f2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:13:3:13:4 | call to f2 | call to f2 | diff --git a/c/misra/test/rules/RULE-8-7/test.c b/c/misra/test/rules/RULE-8-7/test.c index 5b83445944..dc59be7394 100644 --- a/c/misra/test/rules/RULE-8-7/test.c +++ b/c/misra/test/rules/RULE-8-7/test.c @@ -1,7 +1,10 @@ #include "test.h" -int i2; // NON_COMPLIANT - accessed one translation unit -static void f3(); // COMPLIANT - internal linkage -extern void f3(); // COMPLIANT - internal linkage +int i = 0; +int i1 = 0; +int i2; // NON_COMPLIANT - accessed one translation unit +void f1() {} // Definition +void f2() {} // Definition +static void f3() {}; // COMPLIANT - internal linkage void f() { i = 0; i1 = 0; From 39f7c94a661c90c6903e092885e3c0d2b095330e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 9 Mar 2025 11:34:36 +0000 Subject: [PATCH 281/628] RULE-8-7: Require the reference to exist in the same TU The translation unit of the definition needs to be the same as the translation unit of the reference, otherwise it is not eligible for internal linkage. --- .../rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql | 4 +++- .../RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected | 6 +++--- c/misra/test/rules/RULE-8-7/test.c | 1 + c/misra/test/rules/RULE-8-7/test.h | 3 ++- c/misra/test/rules/RULE-8-7/test1.c | 1 + 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql b/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql index faa915fdd5..7b882821b8 100644 --- a/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql +++ b/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql @@ -51,6 +51,8 @@ where not exists(TranslationUnit t2 | isReferencedInTranslationUnit(e, _, t2) and not t1 = t2 - ) + ) and + // Definition is also in the same translation unit + e.getDefinition().getFile() = t1.getAUserFile() select e, "Declaration with external linkage is accessed in only one translation unit $@.", a1, a1.toString() diff --git a/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected b/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected index 5f04b41ac0..d2a6b0e53f 100644 --- a/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected +++ b/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected @@ -1,3 +1,3 @@ -| test.c:3:5:3:6 | i1 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:10:3:10:4 | i1 | i1 | -| test.c:4:5:4:6 | i2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:11:3:11:4 | i2 | i2 | -| test.c:6:6:6:7 | f2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:13:3:13:4 | call to f2 | call to f2 | +| test.c:3:5:3:6 | i1 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:11:3:11:4 | i1 | i1 | +| test.c:4:5:4:6 | i2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:12:3:12:4 | i2 | i2 | +| test.c:6:6:6:7 | f2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:14:3:14:4 | call to f2 | call to f2 | diff --git a/c/misra/test/rules/RULE-8-7/test.c b/c/misra/test/rules/RULE-8-7/test.c index dc59be7394..591f15a2c4 100644 --- a/c/misra/test/rules/RULE-8-7/test.c +++ b/c/misra/test/rules/RULE-8-7/test.c @@ -5,6 +5,7 @@ int i2; // NON_COMPLIANT - accessed one translation unit void f1() {} // Definition void f2() {} // Definition static void f3() {}; // COMPLIANT - internal linkage +void f4() {} // Definition void f() { i = 0; i1 = 0; diff --git a/c/misra/test/rules/RULE-8-7/test.h b/c/misra/test/rules/RULE-8-7/test.h index 218ec18c23..2b997928bd 100644 --- a/c/misra/test/rules/RULE-8-7/test.h +++ b/c/misra/test/rules/RULE-8-7/test.h @@ -1,4 +1,5 @@ extern int i; // COMPLIANT - accessed multiple translation units extern int i1; // NON_COMPLIANT - accessed one translation unit extern void f1(); // COMPLIANT - accessed multiple translation units -extern void f2(); // NON_COMPLIANT - accessed one translation unit \ No newline at end of file +extern void f2(); // NON_COMPLIANT - accessed one translation unit +extern void f4(); // COMPLIANT - accessed across translation units \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-7/test1.c b/c/misra/test/rules/RULE-8-7/test1.c index 77377e78df..c0ed69c7d0 100644 --- a/c/misra/test/rules/RULE-8-7/test1.c +++ b/c/misra/test/rules/RULE-8-7/test1.c @@ -2,4 +2,5 @@ void f() { i = 0; f1(); + f4(); } \ No newline at end of file From d6710e0c64acb7ac72dc2bef72d48d17a0711e65 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 9 Mar 2025 11:37:42 +0000 Subject: [PATCH 282/628] RULE-8-7: Only report external identifiers with definitions --- .../rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql | 2 ++ c/misra/test/rules/RULE-8-7/test.h | 3 ++- c/misra/test/rules/RULE-8-7/test1.c | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql b/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql index 7b882821b8..db8623d9f2 100644 --- a/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql +++ b/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql @@ -46,6 +46,8 @@ predicate isReferencedInTranslationUnit( from ExternalIdentifiers e, ExternalIdentifierReference a1, TranslationUnit t1 where not isExcluded(e, Declarations6Package::shouldNotBeDefinedWithExternalLinkageQuery()) and + // Only report external identifiers where we see the definition + e.hasDefinition() and isReferencedInTranslationUnit(e, a1, t1) and // Not referenced in any other translation unit not exists(TranslationUnit t2 | diff --git a/c/misra/test/rules/RULE-8-7/test.h b/c/misra/test/rules/RULE-8-7/test.h index 2b997928bd..782099de02 100644 --- a/c/misra/test/rules/RULE-8-7/test.h +++ b/c/misra/test/rules/RULE-8-7/test.h @@ -2,4 +2,5 @@ extern int i; // COMPLIANT - accessed multiple translation units extern int i1; // NON_COMPLIANT - accessed one translation unit extern void f1(); // COMPLIANT - accessed multiple translation units extern void f2(); // NON_COMPLIANT - accessed one translation unit -extern void f4(); // COMPLIANT - accessed across translation units \ No newline at end of file +extern void f4(); // COMPLIANT - accessed across translation units +extern void f5(); // COMPLIANT - no definition \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-7/test1.c b/c/misra/test/rules/RULE-8-7/test1.c index c0ed69c7d0..6d1eab16d0 100644 --- a/c/misra/test/rules/RULE-8-7/test1.c +++ b/c/misra/test/rules/RULE-8-7/test1.c @@ -3,4 +3,5 @@ void f() { i = 0; f1(); f4(); + f5(); } \ No newline at end of file From 569fa76250457eb2a6e05081c4365e15c96181b4 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 9 Mar 2025 18:39:50 +0000 Subject: [PATCH 283/628] RULE-8-7: Support use in headers. --- .../rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql | 3 ++- .../RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected | 1 + c/misra/test/rules/RULE-8-7/test1.c | 2 +- c/misra/test/rules/RULE-8-7/test2.h | 3 +++ 4 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 c/misra/test/rules/RULE-8-7/test2.h diff --git a/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql b/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql index db8623d9f2..9cdd6532a9 100644 --- a/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql +++ b/c/misra/src/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.ql @@ -40,7 +40,8 @@ predicate isReferencedInTranslationUnit( ExternalIdentifiers e, ExternalIdentifierReference r, TranslationUnit t ) { r.getExternalIdentifierTarget() = e and - r.getFile() = t + // Used within the translation unit or an included header + r.getFile() = t.getAUserFile() } from ExternalIdentifiers e, ExternalIdentifierReference a1, TranslationUnit t1 diff --git a/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected b/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected index d2a6b0e53f..6610bf236e 100644 --- a/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected +++ b/c/misra/test/rules/RULE-8-7/ShouldNotBeDefinedWithExternalLinkage.expected @@ -1,3 +1,4 @@ +| test2.h:2:13:2:14 | f6 | Declaration with external linkage is accessed in only one translation unit $@. | test2.h:3:22:3:23 | call to f6 | call to f6 | | test.c:3:5:3:6 | i1 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:11:3:11:4 | i1 | i1 | | test.c:4:5:4:6 | i2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:12:3:12:4 | i2 | i2 | | test.c:6:6:6:7 | f2 | Declaration with external linkage is accessed in only one translation unit $@. | test.c:14:3:14:4 | call to f2 | call to f2 | diff --git a/c/misra/test/rules/RULE-8-7/test1.c b/c/misra/test/rules/RULE-8-7/test1.c index 6d1eab16d0..5c3b3759c9 100644 --- a/c/misra/test/rules/RULE-8-7/test1.c +++ b/c/misra/test/rules/RULE-8-7/test1.c @@ -1,4 +1,4 @@ -#include "test.h" +#include "test2.h" void f() { i = 0; f1(); diff --git a/c/misra/test/rules/RULE-8-7/test2.h b/c/misra/test/rules/RULE-8-7/test2.h new file mode 100644 index 0000000000..d203c3259a --- /dev/null +++ b/c/misra/test/rules/RULE-8-7/test2.h @@ -0,0 +1,3 @@ +#include "test.h" +extern void f6() {} // NON_COMPLIANT +static void test() { f6(); } \ No newline at end of file From 8e3109342d122a58ce32805fbca423df451dc0ce Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 9 Mar 2025 18:42:43 +0000 Subject: [PATCH 284/628] Add change note. --- change_notes/2025-03-09-rule-8-7.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 change_notes/2025-03-09-rule-8-7.md diff --git a/change_notes/2025-03-09-rule-8-7.md b/change_notes/2025-03-09-rule-8-7.md new file mode 100644 index 0000000000..5308c97ce3 --- /dev/null +++ b/change_notes/2025-03-09-rule-8-7.md @@ -0,0 +1,4 @@ + - `RULE-8-7` - `ShouldNotBeDefinedWithExternalLinkage.ql`: + - Remove false positives where the declation is not defined in the database. + - Remove false positives where the definition and reference are in different translation units. + - Remove false positives where the reference occurs in a header file. \ No newline at end of file From 190f1ae536c7ac14fc27268bdd14509b04dd650b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Mar 2025 05:03:57 +0000 Subject: [PATCH 285/628] Bump peter-evans/create-pull-request from 7.0.6 to 7.0.8 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 7.0.6 to 7.0.8. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/67ccf781d68cd99b580ae25a5c18a1cc84ffff1f...271a8d0340265f705b14b6d32b9829c1cb33d45e) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/upgrade_codeql_dependencies.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/upgrade_codeql_dependencies.yml b/.github/workflows/upgrade_codeql_dependencies.yml index ca6779871e..1ffc874bb4 100644 --- a/.github/workflows/upgrade_codeql_dependencies.yml +++ b/.github/workflows/upgrade_codeql_dependencies.yml @@ -53,7 +53,7 @@ jobs: find c \( -name '*.ql' -or -name '*.qll' \) -print0 | xargs -0 --max-procs "$XARGS_MAX_PROCS" codeql query format --in-place - name: Create Pull Request - uses: peter-evans/create-pull-request@67ccf781d68cd99b580ae25a5c18a1cc84ffff1f # v7.0.6 + uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 with: title: "Upgrade `github/codeql` dependency to ${{ github.event.inputs.codeql_cli_version }}" body: | From 64b7684697b055b17df9a054e9f8141ab625b58f Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 9 Mar 2025 22:42:15 -0700 Subject: [PATCH 286/628] Implement generics package --- ...otAddOrSubtractAScaledIntegerToAPointer.ql | 2 +- .../IncompatibleFunctionDeclarations.ql | 8 +- c/common/src/codingstandards/c/Generic.qll | 155 +++++++ .../src/codingstandards/c/OutOfBounds.qll | 2 +- .../codingstandards/c/UndefinedBehavior.qll | 2 +- .../c/misra/EssentialTypes.qll | 18 +- ...rsionBetweenFunctionPointerAndOtherType.ql | 2 +- ...etweenIncompleteTypePointerAndOtherType.ql | 2 +- ...weenObjectPointerAndDifferentObjectType.ql | 2 +- ...ionBetweenPointerToObjectAndIntegerType.ql | 2 +- ...ionFromPointerToVoidIntoPointerToObject.ql | 2 +- ...stBetweenPointerToVoidAndArithmeticType.ql | 2 +- ...nPointerToObjectAndNonIntArithmeticType.ql | 2 +- ...NullNotUsedAsIntegerNullPointerConstant.ql | 2 +- ...ointersToVariablyModifiedArrayTypesUsed.ql | 2 +- .../rules/RULE-2-4/UnusedTagDeclaration.ql | 2 +- .../rules/RULE-2-8/UnusedObjectDefinition.ql | 2 +- .../RULE-2-8/UnusedObjectDefinitionStrict.ql | 2 +- ...veMemcmpArgNotPointersToCompatibleTypes.ql | 2 +- ...ricSelectionDoesntDependOnMacroArgument.ql | 26 ++ .../GenericSelectionNotExpandedFromAMacro.ql | 25 ++ ...ricSelectionNotFromMacroWithSideEffects.ql | 87 ++++ .../GenericWithoutNonDefaultAssociation.ql | 35 ++ .../GenericAssociationWithUnselectableType.ql | 111 +++++ ...rousDefaultSelectionForPointerInGeneric.ql | 78 ++++ ...ricExpressionWithIncorrectEssentialType.ql | 62 +++ .../InvalidGenericMacroArgumentEvaluation.ql | 60 +++ .../DefaultGenericSelectionNotFirstOrLast.ql | 93 ++++ ...interShouldPointToConstTypeWhenPossible.ql | 2 +- .../DeclarationsOfAFunctionSameNameAndType.ql | 18 +- .../DeclarationsOfAnObjectSameNameAndType.ql | 30 +- .../CompatibleDeclarationFunctionDefined.ql | 10 +- .../CompatibleDeclarationObjectDefined.ql | 14 +- .../RULE-2-8/UnusedObjectDefinition.expected | 24 +- .../UnusedObjectDefinitionStrict.expected | 8 +- ...ectionDoesntDependOnMacroArgument.expected | 3 + ...SelectionDoesntDependOnMacroArgument.qlref | 1 + ...ricSelectionNotExpandedFromAMacro.expected | 1 + ...enericSelectionNotExpandedFromAMacro.qlref | 1 + c/misra/test/rules/RULE-23-1/test.c | 25 ++ ...ectionNotFromMacroWithSideEffects.expected | 3 + ...SelectionNotFromMacroWithSideEffects.qlref | 1 + c/misra/test/rules/RULE-23-2/test.c | 49 ++ ...nericWithoutNonDefaultAssociation.expected | 2 + .../GenericWithoutNonDefaultAssociation.qlref | 1 + c/misra/test/rules/RULE-23-3/test.c | 23 + ...icAssociationWithUnselectableType.expected | 13 + ...nericAssociationWithUnselectableType.qlref | 1 + c/misra/test/rules/RULE-23-4/test.c | 73 +++ ...faultSelectionForPointerInGeneric.expected | 84 ++++ ...sDefaultSelectionForPointerInGeneric.qlref | 1 + c/misra/test/rules/RULE-23-5/test.c | 236 ++++++++++ ...ressionWithIncorrectEssentialType.expected | 4 + ...ExpressionWithIncorrectEssentialType.qlref | 1 + c/misra/test/rules/RULE-23-6/test.c | 33 ++ ...lidGenericMacroArgumentEvaluation.expected | 12 + ...nvalidGenericMacroArgumentEvaluation.qlref | 1 + c/misra/test/rules/RULE-23-7/test.c | 71 +++ ...ultGenericSelectionNotFirstOrLast.expected | 4 + ...efaultGenericSelectionNotFirstOrLast.qlref | 1 + c/misra/test/rules/RULE-23-8/test.c | 49 ++ ...rationsOfAFunctionSameNameAndType.expected | 26 +- ...arationsOfAnObjectSameNameAndType.expected | 44 +- c/misra/test/rules/RULE-8-3/function1.c | 2 +- c/misra/test/rules/RULE-8-3/function2.c | 2 +- .../2025-02-25-move-type-related-libraries.md | 2 + ...2-25-update-macro-deduplication-library.md | 4 + ...sential-types-with-explicit-conversions.md | 2 + ...25-03-04-more-accurate-type-comparisons.md | 6 + ...plementationShallComplyWithIeeeStandard.ql | 2 +- .../MoveConstructorUsesCopySemantics.ql | 2 +- .../NonTemplateMemberDefinedInTemplate.ql | 2 +- .../rules/A7-1-2/VariableMissingConstexpr.ql | 2 +- .../A8-4-7/TriviallyCopyableSmallType.qll | 2 +- .../src/rules/M0-1-4/SingleUsePODVariable.qll | 2 +- .../MEM53-CPP/ManuallyManagedLifetime.qll | 2 +- ...ConstructorCallForManuallyManagedObject.ql | 2 +- .../src/codingstandards/cpp/Compatible.qll | 30 -- .../cpp/MatchingParenthesis.qll | 264 +++++++++++ cpp/common/src/codingstandards/cpp/Type.qll | 98 +--- .../DeduplicateMacroResults.qll | 28 +- .../cpp/deadcode/UnusedObjects.qll | 6 +- .../cpp/exclusions/c/Generics.qll | 163 +++++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + .../CatchExceptionsByLvalueReference.qll | 2 +- ...dPointerToRestrictQualifiedParamShared.qll | 2 +- .../UnusedTypeDeclarations.qll | 2 +- .../codingstandards/cpp/types/Compatible.qll | 421 ++++++++++++++++++ .../src/codingstandards/cpp/types/Graph.qll | 15 + .../cpp/types/LvalueConversion.qll | 38 ++ .../cpp/{ => types}/Pointers.qll | 0 .../cpp/types/SimpleAssignment.qll | 45 ++ .../cpp/{ => types}/TrivialType.qll | 0 .../src/codingstandards/cpp/types/Type.qll | 96 ++++ .../cpp/{TypeUses.qll => types/Uses.qll} | 0 .../cpp/{ => types}/VariablyModifiedTypes.qll | 0 .../DisappliedQuery.ql | 2 +- .../cpp/trivialtypes/LiteralType.ql | 2 +- .../cpp/trivialtypes/TrivialType.ql | 2 +- .../cpp/trivialtypes/TriviallyCopyableType.ql | 2 +- rule_packages/c/Generics.json | 194 ++++++++ 101 files changed, 2846 insertions(+), 263 deletions(-) create mode 100644 c/common/src/codingstandards/c/Generic.qll create mode 100644 c/misra/src/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.ql create mode 100644 c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql create mode 100644 c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql create mode 100644 c/misra/src/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.ql create mode 100644 c/misra/src/rules/RULE-23-4/GenericAssociationWithUnselectableType.ql create mode 100644 c/misra/src/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.ql create mode 100644 c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql create mode 100644 c/misra/src/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.ql create mode 100644 c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql create mode 100644 c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.expected create mode 100644 c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.qlref create mode 100644 c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.expected create mode 100644 c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.qlref create mode 100644 c/misra/test/rules/RULE-23-1/test.c create mode 100644 c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.expected create mode 100644 c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.qlref create mode 100644 c/misra/test/rules/RULE-23-2/test.c create mode 100644 c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.expected create mode 100644 c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.qlref create mode 100644 c/misra/test/rules/RULE-23-3/test.c create mode 100644 c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.expected create mode 100644 c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.qlref create mode 100644 c/misra/test/rules/RULE-23-4/test.c create mode 100644 c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.expected create mode 100644 c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.qlref create mode 100644 c/misra/test/rules/RULE-23-5/test.c create mode 100644 c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.expected create mode 100644 c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.qlref create mode 100644 c/misra/test/rules/RULE-23-6/test.c create mode 100644 c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.expected create mode 100644 c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.qlref create mode 100644 c/misra/test/rules/RULE-23-7/test.c create mode 100644 c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.expected create mode 100644 c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.qlref create mode 100644 c/misra/test/rules/RULE-23-8/test.c create mode 100644 change_notes/2025-02-25-move-type-related-libraries.md create mode 100644 change_notes/2025-02-25-update-macro-deduplication-library.md create mode 100644 change_notes/2025-03-04-essential-types-with-explicit-conversions.md create mode 100644 change_notes/2025-03-04-more-accurate-type-comparisons.md delete mode 100644 cpp/common/src/codingstandards/cpp/Compatible.qll create mode 100644 cpp/common/src/codingstandards/cpp/MatchingParenthesis.qll create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Generics.qll create mode 100644 cpp/common/src/codingstandards/cpp/types/Compatible.qll create mode 100644 cpp/common/src/codingstandards/cpp/types/Graph.qll create mode 100644 cpp/common/src/codingstandards/cpp/types/LvalueConversion.qll rename cpp/common/src/codingstandards/cpp/{ => types}/Pointers.qll (100%) create mode 100644 cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll rename cpp/common/src/codingstandards/cpp/{ => types}/TrivialType.qll (100%) create mode 100644 cpp/common/src/codingstandards/cpp/types/Type.qll rename cpp/common/src/codingstandards/cpp/{TypeUses.qll => types/Uses.qll} (100%) rename cpp/common/src/codingstandards/cpp/{ => types}/VariablyModifiedTypes.qll (100%) create mode 100644 rule_packages/c/Generics.json diff --git a/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql b/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql index fd57bd6f75..61dd77f6f4 100644 --- a/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql +++ b/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.c.cert -import codingstandards.cpp.Pointers +import codingstandards.cpp.types.Pointers import semmle.code.cpp.dataflow.TaintTracking import ScaledIntegerPointerArithmeticFlow::PathGraph diff --git a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql index 20b6e5e59e..95ef0fd682 100644 --- a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql +++ b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.c.cert -import codingstandards.cpp.Compatible +import codingstandards.cpp.types.Compatible import ExternalIdentifiers from ExternalIdentifiers d, FunctionDeclarationEntry f1, FunctionDeclarationEntry f2 @@ -29,12 +29,10 @@ where f1.getName() = f2.getName() and ( //return type check - not typesCompatible(f1.getType(), f2.getType()) + not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, f2) or //parameter type check - parameterTypesIncompatible(f1, f2) - or - not f1.getNumberOfParameters() = f2.getNumberOfParameters() + not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, f2) ) and // Apply ordering on start line, trying to avoid the optimiser applying this join too early // in the pipeline diff --git a/c/common/src/codingstandards/c/Generic.qll b/c/common/src/codingstandards/c/Generic.qll new file mode 100644 index 0000000000..1bf4282017 --- /dev/null +++ b/c/common/src/codingstandards/c/Generic.qll @@ -0,0 +1,155 @@ +import cpp +import codingstandards.cpp.Macro +import codingstandards.cpp.MatchingParenthesis + +string genericRegexp() { result = ".*_Generic\\s*\\(\\s*(.+),.*" } + +bindingset[input] +string deparenthesize(string input) { + input = "(" + result + ")" and + result = input.substring(1, input.length() - 1) +} + + +class GenericMacro extends Macro { + string ctrlExpr; + + GenericMacro() { ctrlExpr = getBody().regexpCapture(genericRegexp(), 1).trim() } + + string getAParameter() { result = this.(FunctionLikeMacro).getAParameter() } + + string getControllingExprString() { + if exists(string s | s = deparenthesize(ctrlExpr)) + then result = deparenthesize(ctrlExpr).trim() + else result = ctrlExpr + } + + /** + * Whether the controlling expression of the `_Generic` expr in this macro's controlling + * expression refers to one of this macro's parameters. + */ + predicate hasControllingExprFromMacroParameter() { + getControllingExprString().matches(getAParameter()) + } +} + +class GenericMacroString extends string { + GenericMacroString() { this = any(Macro m).getBody() and this.matches("%_Generic%") } +} + +import MatchingParenthesis + +class ParsedGenericMacro extends Macro { + ParsedRoot macroBody; + Parsed genericBody; + string beforeGenericBody; + string afterGenericBody; + + ParsedGenericMacro() { + macroBody.getInputString() = this.getBody() and + exists(ParsedText genericText | + genericText.getText().matches("%_Generic%") and + genericBody = genericText.getParent().getChild(genericText.getChildIdx() + 1) and + genericBody.getRoot() = macroBody + ) and + beforeGenericBody = + textFrom(macroBody.getStartToken(), genericBody.getStartToken().getPrevious()) and + ( + if exists(genericBody.getEndToken().getNext()) + then afterGenericBody = textFrom(genericBody.getEndToken().getNext(), macroBody.getEndToken()) + else afterGenericBody = "" + ) + } + + string getAParameter() { + result = this.(FunctionLikeMacro).getAParameter() + } + + int getAParsedGenericCommaSeparatorOffset() { + exists(ParsedText text | + text.getParent() = genericBody and + result = text.getStartToken().getStartPos() + text.getText().indexOf(",") + ) + } + + int getAParsedGenericColonSeparatorOffset() { + exists(ParsedText text | + text.getParent() = genericBody and + result = text.getStartToken().getStartPos() + text.getText().indexOf(":") + ) + } + + int getParsedGenericCommaSeparatorOffset(int i) { + result = rank[i](int index | index = getAParsedGenericCommaSeparatorOffset()) + } + + bindingset[start, end] + int getParsedGenericColon(int start, int end) { + result = + min(int offset | + offset = getAParsedGenericColonSeparatorOffset() and + offset >= start and + offset <= end + ) + } + + predicate hasParsedFullSelectionRange(int idx, int start, int end) { + idx = 1 and + start = genericBody.getStartToken().getEndPos() and + end = getParsedGenericCommaSeparatorOffset(idx) + or + not exists(getParsedGenericCommaSeparatorOffset(idx)) and + start = getParsedGenericCommaSeparatorOffset(idx - 1) and + end = genericBody.getEndToken().getStartPos() + or + start = getParsedGenericCommaSeparatorOffset(idx - 1) and + end = getParsedGenericCommaSeparatorOffset(idx) + } + + string getSelectionString(int idx) { + exists(int start, int rawStart, int end | + hasParsedFullSelectionRange(idx, rawStart, end) and + ( + if exists(getParsedGenericColon(rawStart, end)) + then start = getParsedGenericColon(rawStart, end) + else start = rawStart + ) and + result = genericBody.getInputString().substring(start, end) + ) + } + + string getControllingExprString() { + result = getSelectionString(1) + } + + bindingset[str, word] + private int countWordInString(string word, string str) { + result = + max(int occurrence | + exists(str.regexpFind("\\b" + word + "\\b", occurrence, _)) or occurrence = -1 + | + occurrence + 1 + ) + } + + int expansionsOutsideExpr(string parameter) { + parameter = getAParameter() and + result = + countWordInString(parameter, beforeGenericBody) + + countWordInString(parameter, afterGenericBody) + } + + int expansionsInsideSelection(string parameter, int idx) { + parameter = getAParameter() and + result = countWordInString(parameter, getSelectionString(idx)) + } + + int expansionsInsideControllingExpr(string parameter) { + result = expansionsInsideSelection(parameter, 1) + } + + int expansionsInsideAssociation(string parameter, int idx) { + not idx = 0 and + result = expansionsInsideSelection(parameter, idx + 1) + } +} \ No newline at end of file diff --git a/c/common/src/codingstandards/c/OutOfBounds.qll b/c/common/src/codingstandards/c/OutOfBounds.qll index 220cf5a0a0..bb7d1bd124 100644 --- a/c/common/src/codingstandards/c/OutOfBounds.qll +++ b/c/common/src/codingstandards/c/OutOfBounds.qll @@ -5,7 +5,7 @@ */ import cpp -import codingstandards.cpp.Pointers +import codingstandards.cpp.types.Pointers import codingstandards.c.Variable import codingstandards.cpp.Allocations import codingstandards.cpp.Overflow diff --git a/c/common/src/codingstandards/c/UndefinedBehavior.qll b/c/common/src/codingstandards/c/UndefinedBehavior.qll index 6a72cb6eb7..47461aa613 100644 --- a/c/common/src/codingstandards/c/UndefinedBehavior.qll +++ b/c/common/src/codingstandards/c/UndefinedBehavior.qll @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.Pointers +import codingstandards.cpp.types.Pointers import codingstandards.cpp.UndefinedBehavior /** diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 02b8498ecb..afdbefdb7d 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -164,14 +164,14 @@ EssentialTypeCategory getEssentialTypeCategory(Type type) { */ pragma[nomagic] Type getEssentialType(Expr e) { - if e.hasExplicitConversion() - then - if e.getConversion() instanceof ParenthesisExpr - then - if e.getConversion().(ParenthesisExpr).hasExplicitConversion() - then result = e.getConversion().(ParenthesisExpr).getConversion().getType() - else result = e.getConversion().(ParenthesisExpr).getExpr().(EssentialExpr).getEssentialType() - else result = e.getConversion().getType() + if e.hasConversion() + then result = getEssentialTypeOfConversion(e.getFullyConverted()) + else result = e.(EssentialExpr).getEssentialType() +} + +Type getEssentialTypeOfConversion(Expr e) { + if e.(Conversion).isImplicit() or e instanceof ParenthesisExpr or e instanceof C11GenericExpr + then result = getEssentialTypeOfConversion(e.(Conversion).getExpr()) else result = e.(EssentialExpr).getEssentialType() } @@ -446,7 +446,7 @@ class EssentialLiteral extends EssentialExpr, Literal { if underlyingStandardType.(IntType).isSigned() then result = stlr(this) else result = utlr(this) - else result = underlyingStandardType + else result = getStandardType() ) ) } diff --git a/c/misra/src/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.ql b/c/misra/src/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.ql index 36157e130e..7678fc1d23 100644 --- a/c/misra/src/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.ql +++ b/c/misra/src/rules/RULE-11-1/ConversionBetweenFunctionPointerAndOtherType.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.Pointers +import codingstandards.cpp.types.Pointers from CStyleCast cast, Type type, Type newType where diff --git a/c/misra/src/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.ql b/c/misra/src/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.ql index 6c552b0f39..5c16dc1afb 100644 --- a/c/misra/src/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.ql +++ b/c/misra/src/rules/RULE-11-2/ConversionBetweenIncompleteTypePointerAndOtherType.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.Pointers +import codingstandards.cpp.types.Pointers import codingstandards.cpp.Type from Cast cast, Type type, Type newType diff --git a/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql b/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql index 8292bd3b6f..3a6fb28c2a 100644 --- a/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql +++ b/c/misra/src/rules/RULE-11-3/CastBetweenObjectPointerAndDifferentObjectType.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.Pointers +import codingstandards.cpp.types.Pointers from CStyleCast cast, Type baseTypeFrom, Type baseTypeTo where diff --git a/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql b/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql index 8877d04323..336f5d4643 100644 --- a/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql +++ b/c/misra/src/rules/RULE-11-4/ConversionBetweenPointerToObjectAndIntegerType.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.Macro -import codingstandards.cpp.Pointers +import codingstandards.cpp.types.Pointers MacroInvocation getAMacroInvocation(CStyleCast cast) { result.getAnExpandedElement() = cast } diff --git a/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql b/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql index 0363c28c19..b316b39a56 100644 --- a/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql +++ b/c/misra/src/rules/RULE-11-5/ConversionFromPointerToVoidIntoPointerToObject.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.Pointers +import codingstandards.cpp.types.Pointers from Cast cast, VoidPointerType type, PointerToObjectType newType where diff --git a/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql b/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql index cc0adf0517..2293ede61e 100644 --- a/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql +++ b/c/misra/src/rules/RULE-11-6/CastBetweenPointerToVoidAndArithmeticType.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.Pointers +import codingstandards.cpp.types.Pointers from CStyleCast cast, Type typeFrom, Type typeTo where diff --git a/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql b/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql index e499ea6485..82ac620aa7 100644 --- a/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql +++ b/c/misra/src/rules/RULE-11-7/CastBetweenPointerToObjectAndNonIntArithmeticType.ql @@ -14,7 +14,7 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.Pointers +import codingstandards.cpp.types.Pointers class MisraNonIntegerArithmeticType extends Type { MisraNonIntegerArithmeticType() { diff --git a/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql b/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql index cb18ed0d1d..28b256e85c 100644 --- a/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql +++ b/c/misra/src/rules/RULE-11-9/MacroNullNotUsedAsIntegerNullPointerConstant.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.Pointers +import codingstandards.cpp.types.Pointers import codingstandards.cpp.Type from Zero zero, Expr e, string type diff --git a/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql b/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql index 3a99ebd842..dc1433d5e4 100644 --- a/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql +++ b/c/misra/src/rules/RULE-18-10/PointersToVariablyModifiedArrayTypesUsed.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.VariablyModifiedTypes +import codingstandards.cpp.types.VariablyModifiedTypes from VmtDeclarationEntry v, string declstr, string adjuststr, string relationstr where diff --git a/c/misra/src/rules/RULE-2-4/UnusedTagDeclaration.ql b/c/misra/src/rules/RULE-2-4/UnusedTagDeclaration.ql index 08fe2568e9..88b0a5b05a 100644 --- a/c/misra/src/rules/RULE-2-4/UnusedTagDeclaration.ql +++ b/c/misra/src/rules/RULE-2-4/UnusedTagDeclaration.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.TypeUses +import codingstandards.cpp.types.Uses from UserType s where diff --git a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql index 2230a74592..13355b7f74 100644 --- a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql +++ b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinition.ql @@ -20,5 +20,5 @@ from ReportDeadObject report where not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionQuery()) and not report.hasAttrUnused() -select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(), +select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocatable(), report.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql index cc117763ee..4eb1ad9773 100644 --- a/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql +++ b/c/misra/src/rules/RULE-2-8/UnusedObjectDefinitionStrict.ql @@ -22,5 +22,5 @@ from ReportDeadObject report where not isExcluded(report.getPrimaryElement(), DeadCode2Package::unusedObjectDefinitionStrictQuery()) and report.hasAttrUnused() -select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(), +select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocatable(), report.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql index f5d8057b3a..28dce7b638 100644 --- a/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql +++ b/c/misra/src/rules/RULE-21-15/MemcpyMemmoveMemcmpArgNotPointersToCompatibleTypes.ql @@ -13,7 +13,7 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.Pointers +import codingstandards.cpp.types.Pointers class MemCmpMoveCpy extends Function { // Couldn't extend BuiltInFunction because it misses `memcmp` diff --git a/c/misra/src/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.ql b/c/misra/src/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.ql new file mode 100644 index 0000000000..0dc0e5273a --- /dev/null +++ b/c/misra/src/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.ql @@ -0,0 +1,26 @@ +/** + * @id c/misra/generic-selection-doesnt-depend-on-macro-argument + * @name RULE-23-1: A generic selection should depend on the type of a macro argument + * @description A generic selection should depend on the type of a macro argument. + * @kind problem + * @precision high + * @problem.severity warning + * @tags external/misra/id/rule-23-1 + * correctness + * maintainability + * external/misra/c/2012/amendment3 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Generic + +from ParsedGenericMacro macro, string ctrlExpr +where + not isExcluded(macro, GenericsPackage::genericSelectionDoesntDependOnMacroArgumentQuery()) and + ctrlExpr = macro.getControllingExprString().trim() and + not macro.expansionsInsideControllingExpr(_) > 0 +select macro, + "Generic macro " + macro.getName() + " uses controlling expr " + ctrlExpr + + ", which doesn't match any macro parameter." diff --git a/c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql b/c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql new file mode 100644 index 0000000000..ef2a2e75c5 --- /dev/null +++ b/c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql @@ -0,0 +1,25 @@ +/** + * @id c/misra/generic-selection-not-expanded-from-a-macro + * @name RULE-23-1: A generic selection should only be expanded from a macro + * @description A generic selection should only be expanded from a macro. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-23-1 + * maintainability + * external/misra/c/2012/amendment3 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra + +from C11GenericExpr generic, Expr ctrlExpr +where + not isExcluded(generic, GenericsPackage::genericSelectionNotExpandedFromAMacroQuery()) and + ctrlExpr = generic.getControllingExpr() and + not exists(MacroInvocation mi | + mi.getAGeneratedElement() = generic.getExpr() + ) +select generic, "Generic expression with controlling expression $@ is not expanded froma macro", +ctrlExpr, ctrlExpr.toString() diff --git a/c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql b/c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql new file mode 100644 index 0000000000..3ec53a08bf --- /dev/null +++ b/c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql @@ -0,0 +1,87 @@ +/** + * @id c/misra/generic-selection-not-from-macro-with-side-effects + * @name RULE-23-2: A generic selection shall not contain side-effects if it is not expanded from a macro + * @description A generic selection that is not expanded from a macro shall not contain potential + * side effects in the controlling expression. + * @kind problem + * @precision high + * @problem.severity warning + * @tags external/misra/id/rule-23-2 + * maintainability + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Generic +import codingstandards.cpp.SideEffect +import codingstandards.cpp.sideeffect.DefaultEffects +import codingstandards.cpp.alertreporting.DeduplicateMacroResults + +class GenericWithNonMacroSideEffect extends C11GenericExpr { + SideEffect sideEffect; + + GenericWithNonMacroSideEffect() { + not exists(MacroInvocation mi | + mi.getAGeneratedElement() = getExpr() and + mi.getMacro().(GenericMacro).hasControllingExprFromMacroParameter() + ) and + sideEffect = getASideEffect(getControllingExpr()) + } + + SideEffect getASideEffect() { result = sideEffect } +} + +module GenericSideEffectConfig implements DeduplicateMacroConfigSig { + string describe(GenericWithNonMacroSideEffect e) { + result = "side effect '" + e.getASideEffect() + "'" + } +} + +module GenericSideEffectReportConfig implements MacroReportConfigSig { + /* Create a message to describe this macro, with a string describing its `ResultElement`. */ + bindingset[description] + string getMessageSameResultInAllExpansions(Macro m, string description) { + result = + "Generic selection macro " + m.getName() + " contains a " + description + + ", which is not from macro invocation arguments." + } + + /* Create a message to describe this macro, using '$@' to describe an example `ResultElement`. */ + string getMessageVariedResultInAllExpansions(Macro m) { + result = + "Generic selection in macro " + m.getName() + + " contains an invocation-dependent side effect which is not from macro invocation arguments, for example $@." + } + + /** + * Create a message to describe this macro expansion which produces a `ResultElement`, using '$@' + * to describe the relevant macro. + */ + string getMessageResultInIsolatedExpansion(GenericWithNonMacroSideEffect element) { + // A result in an isolated expansion indicates that the side effect is not always present when + // macro is expanded, and therefore the side-effect is not in the macro definition but rather + // originates in one of the macro arguments. + none() + } + + /** + * Create a message to describe a `ResultElement` which is not generated by a macro expansion. + */ + string getMessageNotInMacro( + GenericWithNonMacroSideEffect element, Locatable optLoc1, string optStr1 + ) { + none() + } +} + +import DeduplicateMacroResults as Deduplicate +import Deduplicate::Report as Report + +from Report::ReportResult res +where + not isExcluded(res.getPrimaryElement(), + GenericsPackage::genericSelectionNotFromMacroWithSideEffectsQuery()) +select res.getPrimaryElement(), res.getMessage(), res.getOptionalPlaceholderLocatable(), + res.getOptionalPlaceholderMessage() \ No newline at end of file diff --git a/c/misra/src/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.ql b/c/misra/src/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.ql new file mode 100644 index 0000000000..f3a0227022 --- /dev/null +++ b/c/misra/src/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.ql @@ -0,0 +1,35 @@ +/** + * @id c/misra/generic-without-non-default-association + * @name RULE-23-3: A generic selection should contain at least one non-default association + * @description A generic selection should contain at least one non-default association. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-23-3 + * correctness + * maintainability + * external/misra/c/2012/amendment3 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.AlertReporting + +class InvalidGeneric extends C11GenericExpr { + InvalidGeneric() { + not exists(Type t | + t = getAnAssociationType() and + not t instanceof VoidType + ) + } +} + +from C11GenericExpr generic, Element primaryElement +where + not isExcluded(primaryElement, GenericsPackage::genericWithoutNonDefaultAssociationQuery()) and + not exists(Type t | + t = generic.getAnAssociationType() and + not t instanceof VoidType + ) and primaryElement = MacroUnwrapper::unwrapElement(generic) +select primaryElement, "Generic selection contains no non-default association." diff --git a/c/misra/src/rules/RULE-23-4/GenericAssociationWithUnselectableType.ql b/c/misra/src/rules/RULE-23-4/GenericAssociationWithUnselectableType.ql new file mode 100644 index 0000000000..e8ed88f757 --- /dev/null +++ b/c/misra/src/rules/RULE-23-4/GenericAssociationWithUnselectableType.ql @@ -0,0 +1,111 @@ +/** + * @id c/misra/generic-association-with-unselectable-type + * @name RULE-23-4: A generic association shall list an appropriate type + * @description Generic selections undergo lvalue conversion before type comparison, leading to + * certain types being impossible to select. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-23-4 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.types.LvalueConversion +import codingstandards.cpp.types.Graph +import codingstandards.cpp.alertreporting.DeduplicateMacroResults + +/** + * Check if a type contains an unmatchable anonymous struct or union. + * + * Anonymous structs and unions are only equal to themselves. So any anonymous struct, or compound + * type containing an anonymous struct, is unmatchable. + * + * However, there is an exception if the anonymous struct is behind a typedef. All uses of that + * typedef will resolve to the same anonymous struct, and so the typedef is matchable. + */ +predicate containsAnonymousType(Type t) { + t.(Struct).isAnonymous() + or + not t instanceof TypedefType and + exists(Type next | typeGraph(t, next) | containsAnonymousType(next)) +} + +predicate invalidType(Type t, string reason) { + containsAnonymousType(t) and + reason = "containing an anonymous struct or union type" + or + exists(performLvalueConversion(t, reason)) +} + +class InvalidSelection extends Expr { + Type selectionType; + int idx; + C11GenericExpr generic; + string reason; + + InvalidSelection() { + this = generic.getAssociationExpr(idx) and + selectionType = generic.getAssociationType(idx) and + invalidType(selectionType, reason) + } + + Type getSelectionType() { result = selectionType } + + string getReason() { result = reason } +} + +module InvalidSelectionConfig implements DeduplicateMacroConfigSig { + string describe(InvalidSelection e) { + result = "'" + e.getSelectionType().toString() + "', due to " + e.getReason() + } +} + +import InvalidSelectionConfig + +module InvalidSelectionReportConfig implements MacroReportConfigSig { + /* Create a message to describe this macro, with a string describing its `ResultElement`. */ + bindingset[description] + string getMessageSameResultInAllExpansions(Macro m, string description) { + result = "Generic in macro " + m.getName() + " has unselectable type " + description + "." + } + + /* Create a message to describe this macro, using '$@' to describe an example `ResultElement`. */ + string getMessageVariedResultInAllExpansions(Macro m) { + result = + "Generic in macro " + m.getName() + + " has an invocation-dependent unselectable type, for example $@." + } + + /** + * Create a message to describe this macro expansion which produces a `ResultElement`, using '$@' + * to describe the relevant macro. + */ + string getMessageResultInIsolatedExpansion(InvalidSelection element) { + result = + "Generic resulting from invocation of macro $@ contains an unselectable type " + + describe(element) + "." + } + + /** + * Create a message to describe a `ResultElement` which is not generated by a macro expansion. + */ + string getMessageNotInMacro(InvalidSelection element, Locatable optLoc1, string optStr1) { + result = "Generic selection uses unselectable type " + describe(element) + "'." and + optLoc1 = element and + optStr1 = "side effect" + } +} + +import DeduplicateMacroResults as Deduplicate +import Deduplicate::Report as Report + +from Report::ReportResult res +where + not isExcluded(res.getPrimaryElement(), + GenericsPackage::genericSelectionNotFromMacroWithSideEffectsQuery()) +select res.getPrimaryElement(), res.getMessage(), res.getOptionalPlaceholderLocatable(), + res.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.ql b/c/misra/src/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.ql new file mode 100644 index 0000000000..a009ba1b2a --- /dev/null +++ b/c/misra/src/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.ql @@ -0,0 +1,78 @@ +/** + * @id c/misra/dangerous-default-selection-for-pointer-in-generic + * @name RULE-23-5: A generic selection should not depend on implicit pointer type conversion + * @description Pointer types in a generic selection do not undergo pointer conversions and should + * not counterintuitively fall through to the default association. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-23-5 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.AlertReporting +import codingstandards.cpp.types.Compatible +import codingstandards.cpp.types.LvalueConversion +import codingstandards.cpp.types.SimpleAssignment + +predicate typesCompatible(Type t1, Type t2) { + TypeEquivalence::equalTypes(t1, t2) +} + +class TypeFromGeneric extends Type { + TypeFromGeneric() { + exists(C11GenericExpr g | + ( + this = g.getAssociationType(_) or + this = g.getControllingExpr().getFullyConverted().getType() + ) + ) + } +} + +predicate missesOnPointerConversion(Type provided, Type expected) { + // The provided type is not compatible with the expected type: + not typesCompatible(provided, expected) and + // But 6.5.16.1 simple assignment constraints would have been satisfied: + ( + // Check as if the controlling expr is assigned to the expected type: + SimpleAssignment::satisfiesSimplePointerAssignment(expected, provided) + or + // Since developers typically rely on the compiler to catch const/non-const assignment + // errors, don't assume a const-to-non-const generic selection miss was intentional. + SimpleAssignment::satisfiesSimplePointerAssignment(provided, expected) + ) +} + +from + C11GenericExpr generic, Expr controllingExpr, Type providedType, Type missedType, + Type lvalueConverted, Element extraElement, string extraString, string extraElementName +where + not isExcluded(generic, GenericsPackage::dangerousDefaultSelectionForPointerInGenericQuery()) and + controllingExpr = generic.getControllingExpr() and + providedType = generic.getControllingExpr().getFullyConverted().getType() and + // The controlling expression undergoes lvalue conversion: + lvalueConverted = getLvalueConverted(providedType) and + // There is no perfect match + not typesCompatible(lvalueConverted, generic.getAnAssociationType()) and + // There is a default selector. + exists(VoidType default | default = generic.getAnAssociationType()) and + missedType = generic.getAnAssociationType() and + missesOnPointerConversion(lvalueConverted, missedType) and + extraElement = MacroUnwrapper::unwrapElement(generic) and + ( + if extraElement instanceof Macro + then ( + extraString = " in generic macro $@" and extraElementName = extraElement.(Macro).getName() + ) else ( + extraString = "" and extraElementName = "" + ) + ) +select generic, + "Generic matched default selection, as controlling argument type " + lvalueConverted.toString() + + " does not undergo pointer conversion to " + missedType.toString() + extraString + ".", + extraElement, extraElementName diff --git a/c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql b/c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql new file mode 100644 index 0000000000..c27ce3dc55 --- /dev/null +++ b/c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql @@ -0,0 +1,62 @@ +/** + * @id c/misra/generic-expression-with-incorrect-essential-type + * @name RULE-23-6: The controlling expression of a generic selection shall have an essential type that matches its standard type + * @description The controlling expression of a generic selection shall have an essential type that + * matches its standard type. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-23-6 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.misra.EssentialTypes +import codingstandards.cpp.Cpp14Literal +import codingstandards.cpp.AlertReporting + +predicate allowedByException(Expr expr, Type essentialType) { + // Constant expressions + exists(expr.getValue()) and + ( + // with essentially signed or unsigned type + getEssentialTypeCategory(essentialType) = EssentiallySignedType() + or + getEssentialTypeCategory(essentialType) = EssentiallyUnsignedType() + ) and + // with lower rank than `int` + essentialType.getSize() < any(IntType t).getSize() and + // and not a character constant + not expr instanceof Cpp14Literal::CharLiteral +} + +from + C11GenericExpr generic, Expr ctrlExpr, Type ctrlType, Type ctrlEssentialType, + Element extraElement, string extraString, string extraMessage +where + not isExcluded(ctrlExpr, GenericsPackage::genericExpressionWithIncorrectEssentialTypeQuery()) and + ctrlExpr = generic.getControllingExpr() and + ctrlType = ctrlExpr.getFullyConverted().getType() and + ctrlEssentialType = getEssentialType(ctrlExpr) and + // Exclude lvalue conversion on const structs + exists(getEssentialTypeCategory(ctrlEssentialType)) and + ( + not ctrlEssentialType = ctrlType + or + getEssentialTypeCategory(ctrlEssentialType) = EssentiallyEnumType() + ) and + not allowedByException(ctrlExpr, ctrlEssentialType) and + extraElement = MacroUnwrapper::unwrapElement(generic) and + ( + if extraElement instanceof Macro + then ( + extraMessage = "macro $@ " and extraString = extraElement.(Macro).getName() + ) else ( + extraMessage = "" and extraString = "" + ) + ) +select generic, + "Controlling expression in generic " + extraMessage + + "has standard type " + ctrlType.toString() + ", which doesn't match its essential type " + + ctrlEssentialType.toString() + ".", extraElement, extraString \ No newline at end of file diff --git a/c/misra/src/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.ql b/c/misra/src/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.ql new file mode 100644 index 0000000000..04952ae960 --- /dev/null +++ b/c/misra/src/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.ql @@ -0,0 +1,60 @@ +/** + * @id c/misra/invalid-generic-macro-argument-evaluation + * @name RULE-23-7: A generic selection that is expanded from a macro should evaluate its argument only once + * @description A generic selection that is expanded from a macro should evaluate its argument only + * once. + * @kind problem + * @precision medium + * @problem.severity warning + * @tags external/misra/id/rule-23-7 + * correctness + * maintainability + * external/misra/c/2012/amendment3 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Generic + +predicate allowedByException(string parameter, ParsedGenericMacro genericMacro) { + genericMacro.expansionsOutsideExpr(parameter) = 0 and + not genericMacro.expansionsInsideAssociation(parameter, _) > 0 and + forall(MacroInvocation mi, C11GenericExpr expr | + mi.getMacro() = genericMacro and + mi.getAGeneratedElement() = expr + | + forall(Expr assoc | assoc = expr.getAnAssociationExpr() | exists(assoc.getValue())) + ) +} + +from ParsedGenericMacro genericMacro, string parameter, string reason +where + not isExcluded(genericMacro, GenericsPackage::invalidGenericMacroArgumentEvaluationQuery()) and + parameter = genericMacro.getAParameter() and + genericMacro.expansionsInsideControllingExpr(parameter) > 0 and + ( + genericMacro.expansionsOutsideExpr(parameter) > 1 and + reason = "expanded multiple times outside the generic selection" + or + genericMacro.expansionsOutsideExpr(parameter) = 1 and + genericMacro.expansionsInsideAssociation(parameter, _) > 0 and + reason = "expanded outside the generic selection and inside the generic selection" + or + genericMacro.expansionsOutsideExpr(parameter) = 0 and + exists(int i | + genericMacro.expansionsInsideAssociation(parameter, i) > 1 and + reason = "expanded in generic selection " + i.toString() + " more than once" + ) + or + genericMacro.expansionsOutsideExpr(parameter) = 0 and + exists(int i | + genericMacro.expansionsInsideAssociation(parameter, i) = 0 and + reason = "not expanded in generic selection " + i.toString() + ) and + not allowedByException(parameter, genericMacro) + ) and + not genericMacro.getBody().matches(["%sizeof%", "%__alignof%", "%typeof%", "%offsetof%"]) +select genericMacro, + "Generic macro " + genericMacro.getName() + " may have unexpected behavior from side effects " + + "in parameter " + parameter + ", as it is " + reason + "." diff --git a/c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql b/c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql new file mode 100644 index 0000000000..04b12ac436 --- /dev/null +++ b/c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql @@ -0,0 +1,93 @@ +/** + * @id c/misra/default-generic-selection-not-first-or-last + * @name RULE-23-8: A default association shall appear as either the first or the last association of a generic + * @description A default association shall appear as either the first or the last association of a + * generic selection + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-23-8 + * maintainability + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.alertreporting.DeduplicateMacroResults + +class GenericWithMisplacedDefault extends C11GenericExpr { + int defaultIdx; + + GenericWithMisplacedDefault() { + getAssociationType(defaultIdx) instanceof VoidType and + not defaultIdx = 0 and + not defaultIdx = max(int i | exists(getAssociationType(i))) + } + + int getDefaultIdx() { result = defaultIdx } +} + +module GenericWithMisplacedDefaultConfig implements + DeduplicateMacroConfigSig +{ + string describe(GenericWithMisplacedDefault e) { + exists(int i | i = e.getDefaultIdx() + 1 | + i = 1 and result = "1st" + or + i = 2 and result = "2nd" + or + i = 3 and result = "3rd" + or + i > 3 and result = i.toString() + "th" + ) + } +} + +import GenericWithMisplacedDefaultConfig + +module GenericMisplacedDefaultReportConfig implements + MacroReportConfigSig +{ + /* Create a message to describe this macro, with a string describing its `ResultElement`. */ + bindingset[description] + string getMessageSameResultInAllExpansions(Macro m, string description) { + result = + "Generic macro " + m.getName() + " has default as " + description + " association, which is not first or last." + } + + /* Create a message to describe this macro, using '$@' to describe an example `ResultElement`. */ + string getMessageVariedResultInAllExpansions(Macro m) { + result = + "Generic macro " + m.getName() + " has a default association which is not first or last, for example $@." + } + + /** + * Create a message to describe this macro expansion which produces a `ResultElement`, using '$@' + * to describe the relevant macro. + */ + string getMessageResultInIsolatedExpansion(GenericWithMisplacedDefault element) { + result = + "Generic macro $@, in this expansion, has default as " + describe(element) + " association, which is not first or last." + } + + /** + * Create a message to describe a `ResultElement` which is not generated by a macro expansion. + */ + string getMessageNotInMacro(GenericWithMisplacedDefault element, Locatable optLoc1, string optStr1) { + result = + "Generic has default as " + describe(element) + " association, which is not first or last." and + optLoc1 = element and + optStr1 = "" + } +} + +import DeduplicateMacroResults as Deduplicate +import Deduplicate::Report as Report + +from Report::ReportResult res +where + not isExcluded(res.getPrimaryElement(), + GenericsPackage::defaultGenericSelectionNotFirstOrLastQuery()) +select res.getPrimaryElement(), res.getMessage(), res.getOptionalPlaceholderLocatable(), + res.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.ql b/c/misra/src/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.ql index ddb8cbcdcc..6a2c123907 100644 --- a/c/misra/src/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.ql +++ b/c/misra/src/rules/RULE-8-13/PointerShouldPointToConstTypeWhenPossible.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.Pointers +import codingstandards.cpp.types.Pointers import codingstandards.cpp.SideEffect import codingstandards.cpp.alertreporting.HoldsForAllCopies diff --git a/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql b/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql index 8c80c64a40..a0d7c0c9ab 100644 --- a/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql +++ b/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql @@ -14,9 +14,9 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.Compatible +import codingstandards.cpp.types.Compatible -from FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, string case +from FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, string case, string pluralDo where not isExcluded(f1, Declarations4Package::declarationsOfAFunctionSameNameAndTypeQuery()) and not isExcluded(f2, Declarations4Package::declarationsOfAFunctionSameNameAndTypeQuery()) and @@ -24,16 +24,16 @@ where f1.getDeclaration() = f2.getDeclaration() and //return type check ( - not typesCompatible(f1.getType(), f2.getType()) and - case = "return type" + not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, f2) and + case = "return type" and pluralDo = "does" or //parameter type check - parameterTypesIncompatible(f1, f2) and - case = "parameter types" + not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, f2) and + case = "parameter types" and pluralDo = "do" or //parameter name check - parameterNamesIncompatible(f1, f2) and - case = "parameter names" + parameterNamesUnmatched(f1, f2) and + case = "parameter names" and pluralDo = "do" ) -select f1, "The " + case + " of re-declaration of $@ is not compatible with declaration $@", f1, +select f1, "The " + case + " of re-declaration of $@ " + pluralDo + " not use the same type names as declaration $@", f1, f1.getName(), f2, f2.getName() diff --git a/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql b/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql index 421998c582..83c67e2efa 100644 --- a/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql +++ b/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql @@ -14,12 +14,18 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.Compatible +import codingstandards.cpp.types.Compatible -from VariableDeclarationEntry decl1, VariableDeclarationEntry decl2 -where - not isExcluded(decl1, Declarations4Package::declarationsOfAnObjectSameNameAndTypeQuery()) and - not isExcluded(decl2, Declarations4Package::declarationsOfAnObjectSameNameAndTypeQuery()) and +class RelevantType extends Type { + RelevantType() { + exists(VariableDeclarationEntry decl | + (relevantPair(decl, _) or relevantPair(_, decl)) and + decl.getType() = this + ) + } +} + +predicate relevantPair(VariableDeclarationEntry decl1, VariableDeclarationEntry decl2) { not decl1 = decl2 and not decl1.getVariable().getDeclaringType().isAnonymous() and // Declarations are for the same qualified name @@ -34,9 +40,17 @@ where or decl1.getVariable().(Field).getDeclaringType().(Class).getALinkTarget() = decl2.getVariable().(Field).getDeclaringType().(Class).getALinkTarget() - ) and - not typesCompatible(decl1.getType(), decl2.getType()) + ) +} + +from VariableDeclarationEntry decl1, VariableDeclarationEntry decl2 +where + not isExcluded(decl1, Declarations4Package::declarationsOfAnObjectSameNameAndTypeQuery()) and + not isExcluded(decl2, Declarations4Package::declarationsOfAnObjectSameNameAndTypeQuery()) and + relevantPair(decl1, decl2) and + not TypeEquivalence::equalTypes(decl1.getType(), + decl2.getType()) select decl1, "The object $@ of type " + decl1.getType().toString() + - " is not compatible with re-declaration $@ of type " + decl2.getType().toString(), decl1, + " does not use the same type names as re-declaration $@ of type " + decl2.getType().toString(), decl1, decl1.getName(), decl2, decl2.getName() diff --git a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql index 63f70d3541..98876ad1bd 100644 --- a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql +++ b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql @@ -17,7 +17,7 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.Identifiers -import codingstandards.cpp.Compatible +import codingstandards.cpp.types.Compatible from FunctionDeclarationEntry f1 where @@ -36,15 +36,15 @@ where f1.getName() = f2.getName() and not f2.isDefinition() and f2.getDeclaration() = f1.getDeclaration() and - //return types differ ( - not typesCompatible(f1.getType(), f2.getType()) + //return types differ + not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, f2) or //parameter types differ - parameterTypesIncompatible(f1, f2) + not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, f2) or //parameter names differ - parameterNamesIncompatible(f1, f2) + parameterNamesUnmatched(f1, f2) ) ) ) diff --git a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationObjectDefined.ql b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationObjectDefined.ql index 7e5baacd9a..613ce56806 100644 --- a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationObjectDefined.ql +++ b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationObjectDefined.ql @@ -17,7 +17,16 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.Identifiers -import codingstandards.cpp.Compatible +import codingstandards.cpp.types.Compatible + +class RelevantType extends Type { + RelevantType() { + exists(VariableDeclarationEntry decl | + count(VariableDeclarationEntry others | others.getDeclaration() = decl.getDeclaration()) > 1 and + decl.getType() = this + ) + } +} from VariableDeclarationEntry decl1 where @@ -28,6 +37,7 @@ where not exists(VariableDeclarationEntry decl2 | not decl2.isDefinition() and decl1.getDeclaration() = decl2.getDeclaration() and - typesCompatible(decl1.getType(), decl2.getType()) + TypeEquivalence::equalTypes(decl1.getType(), + decl2.getType()) ) select decl1, "No separate compatible declaration found for this definition." diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected index 731aebb1be..9a373a644c 100644 --- a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinition.expected @@ -1,12 +1,12 @@ -| test.c:6:5:6:6 | definition of g2 | Unused object 'g2'. | test.c:6:5:6:6 | test.c:6:5:6:6 | (ignored) | -| test.c:9:5:9:6 | definition of g3 | Unused object 'g3'. | test.c:9:5:9:6 | test.c:9:5:9:6 | (ignored) | -| test.c:20:7:20:8 | definition of l2 | Unused object 'l2'. | test.c:20:7:20:8 | test.c:20:7:20:8 | (ignored) | -| test.c:27:7:27:8 | definition of l5 | Unused object 'l5'. | test.c:27:7:27:8 | test.c:27:7:27:8 | (ignored) | -| test.c:37:10:37:11 | definition of g5 | Unused object 'g5'. | test.c:37:10:37:11 | test.c:37:10:37:11 | (ignored) | -| test.c:45:9:45:10 | definition of g6 | Unused object 'g6'. | test.c:45:9:45:10 | test.c:45:9:45:10 | (ignored) | -| test.c:51:5:51:6 | definition of g7 | Unused object 'g7'. | test.c:51:5:51:6 | test.c:51:5:51:6 | (ignored) | -| test.c:64:3:64:18 | ONLY_DEF_VAR(x) | Invocation of macro '$@' defines unused object 'l2'. | test.c:60:1:60:34 | test.c:60:1:60:34 | ONLY_DEF_VAR | -| test.c:68:1:71:5 | #define ALSO_DEF_VAR(x) int x = 0; while (1) ; | Macro 'ALSO_DEF_VAR' defines unused object with an invocation-dependent name, for example, '$@'. | test.c:73:16:73:17 | test.c:73:16:73:17 | l1 | -| test.c:77:1:82:3 | #define DEF_UNUSED_INNER_VAR() { int _v = 0; while (1) ; } | Macro 'DEF_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:77:1:82:3 | test.c:77:1:82:3 | (ignored) | -| test.c:119:11:119:13 | definition of g10 | Unused object 'g10'. | test.c:119:11:119:13 | test.c:119:11:119:13 | (ignored) | -| test.c:124:13:124:14 | definition of l2 | Unused object 'l2'. | test.c:124:13:124:14 | test.c:124:13:124:14 | (ignored) | +| test.c:6:5:6:6 | definition of g2 | Unused object 'g2'. | test.c:6:5:6:6 | definition of g2 | (ignored) | +| test.c:9:5:9:6 | definition of g3 | Unused object 'g3'. | test.c:9:5:9:6 | definition of g3 | (ignored) | +| test.c:20:7:20:8 | definition of l2 | Unused object 'l2'. | test.c:20:7:20:8 | definition of l2 | (ignored) | +| test.c:27:7:27:8 | definition of l5 | Unused object 'l5'. | test.c:27:7:27:8 | definition of l5 | (ignored) | +| test.c:37:10:37:11 | definition of g5 | Unused object 'g5'. | test.c:37:10:37:11 | definition of g5 | (ignored) | +| test.c:45:9:45:10 | definition of g6 | Unused object 'g6'. | test.c:45:9:45:10 | definition of g6 | (ignored) | +| test.c:51:5:51:6 | definition of g7 | Unused object 'g7'. | test.c:51:5:51:6 | definition of g7 | (ignored) | +| test.c:64:3:64:18 | ONLY_DEF_VAR(x) | Invocation of macro '$@' defines unused object 'l2'. | test.c:60:1:60:34 | #define ONLY_DEF_VAR(x) int x = 0; | ONLY_DEF_VAR | +| test.c:68:1:71:5 | #define ALSO_DEF_VAR(x) int x = 0; while (1) ; | Macro 'ALSO_DEF_VAR' defines unused object with an invocation-dependent name, for example, '$@'. | test.c:73:16:73:17 | definition of l1 | l1 | +| test.c:77:1:82:3 | #define DEF_UNUSED_INNER_VAR() { int _v = 0; while (1) ; } | Macro 'DEF_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:77:1:82:3 | #define DEF_UNUSED_INNER_VAR() { int _v = 0; while (1) ; } | (ignored) | +| test.c:119:11:119:13 | definition of g10 | Unused object 'g10'. | test.c:119:11:119:13 | definition of g10 | (ignored) | +| test.c:124:13:124:14 | definition of l2 | Unused object 'l2'. | test.c:124:13:124:14 | definition of l2 | (ignored) | diff --git a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected index cf3c0b64e1..fa191e5d68 100644 --- a/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected +++ b/c/misra/test/rules/RULE-2-8/UnusedObjectDefinitionStrict.expected @@ -1,4 +1,4 @@ -| test.c:87:29:87:30 | definition of g8 | Unused object 'g8'. | test.c:87:29:87:30 | test.c:87:29:87:30 | (ignored) | -| test.c:92:3:92:30 | ONLY_DEF_ATTR_UNUSED_VAR(x) | Invocation of macro '$@' defines unused object 'l2'. | test.c:88:1:88:70 | test.c:88:1:88:70 | ONLY_DEF_ATTR_UNUSED_VAR | -| test.c:96:1:99:5 | #define ALSO_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0; while (1) ; | Macro 'ALSO_DEF_ATTR_UNUSED_VAR' defines unused object with an invocation-dependent name, for example, '$@'. | test.c:101:28:101:29 | test.c:101:28:101:29 | l1 | -| test.c:106:1:111:3 | #define DEF_ATTR_UNUSED_INNER_VAR() { __attribute__((unused)) int _v = 0; while (1) ; } | Macro 'DEF_ATTR_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:106:1:111:3 | test.c:106:1:111:3 | (ignored) | +| test.c:87:29:87:30 | definition of g8 | Unused object 'g8'. | test.c:87:29:87:30 | definition of g8 | (ignored) | +| test.c:92:3:92:30 | ONLY_DEF_ATTR_UNUSED_VAR(x) | Invocation of macro '$@' defines unused object 'l2'. | test.c:88:1:88:70 | #define ONLY_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0; | ONLY_DEF_ATTR_UNUSED_VAR | +| test.c:96:1:99:5 | #define ALSO_DEF_ATTR_UNUSED_VAR(x) __attribute__((unused)) int x = 0; while (1) ; | Macro 'ALSO_DEF_ATTR_UNUSED_VAR' defines unused object with an invocation-dependent name, for example, '$@'. | test.c:101:28:101:29 | definition of l1 | l1 | +| test.c:106:1:111:3 | #define DEF_ATTR_UNUSED_INNER_VAR() { __attribute__((unused)) int _v = 0; while (1) ; } | Macro 'DEF_ATTR_UNUSED_INNER_VAR' defines unused object '_v'. | test.c:106:1:111:3 | #define DEF_ATTR_UNUSED_INNER_VAR() { __attribute__((unused)) int _v = 0; while (1) ; } | (ignored) | diff --git a/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.expected b/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.expected new file mode 100644 index 0000000000..2534e47012 --- /dev/null +++ b/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.expected @@ -0,0 +1,3 @@ +| test.c:2:1:2:30 | #define M1 _Generic(1, int: 1) | Generic macro M1 uses controlling expr 1, which doesn't match any macro parameter. | +| test.c:4:1:4:33 | #define M2(X) _Generic(1, int: X) | Generic macro M2 uses controlling expr 1, which doesn't match any macro parameter. | +| test.c:18:1:18:38 | #define M9(X) g(_Generic((Y), int: 1)) | Generic macro M9 uses controlling expr (Y), which doesn't match any macro parameter. | diff --git a/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.qlref b/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.qlref new file mode 100644 index 0000000000..1ca5f792fa --- /dev/null +++ b/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.qlref @@ -0,0 +1 @@ +rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.expected b/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.expected new file mode 100644 index 0000000000..476a9320b8 --- /dev/null +++ b/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.expected @@ -0,0 +1 @@ +| test.c:21:3:21:21 | _Generic | Generic expression with controlling expression $@ is not expanded froma macro | test.c:21:12:21:12 | 1 | 1 | diff --git a/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.qlref b/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.qlref new file mode 100644 index 0000000000..59fae02b7f --- /dev/null +++ b/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.qlref @@ -0,0 +1 @@ +rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-1/test.c b/c/misra/test/rules/RULE-23-1/test.c new file mode 100644 index 0000000000..f27541dd38 --- /dev/null +++ b/c/misra/test/rules/RULE-23-1/test.c @@ -0,0 +1,25 @@ +// NON_COMPLIANT: +#define M1 _Generic(1, int: 1) +// NON_COMPLIANT: +#define M2(X) _Generic(1, int: X) +// COMPLIANT: +#define M3(X) _Generic((X), int: 1) +// COMPLIANT: +#define M4(X) _Generic((X), int: 1) +// COMPLIANT: +#define M5(X) _Generic((X + X), int: 1) +int f1(int a, int b); +// COMPLIANT: +#define M6(X) _Generic(f(1, (X)), int: 1) +#define M7(X) 1 + _Generic((X), int: 1) +// COMPLIANT: +#define M8(X) g(_Generic((X), int: 1)) +// NON_COMPLIANT: +#define M9(X) g(_Generic((Y), int: 1)) + +void f2() { + _Generic(1, int: 1); // NON_COMPLIANT + M1; // NON_COMPLIANT + M2(1); // NON_COMPLIANT + M3(1); // COMPLIANT +} diff --git a/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.expected b/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.expected new file mode 100644 index 0000000000..1abcb4f2bb --- /dev/null +++ b/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.expected @@ -0,0 +1,3 @@ +| test.c:4:1:4:37 | #define M2(X) _Generic((X)++, int: 1) | Generic selection macro M2 contains a side effect '... ++', which is not from macro invocation arguments. | test.c:4:1:4:37 | #define M2(X) _Generic((X)++, int: 1) | (ignored) | +| test.c:7:1:7:38 | #define M3(X) _Generic(l1++, int: (X)) | Generic selection macro M3 contains a side effect '... ++', which is not from macro invocation arguments. | test.c:7:1:7:38 | #define M3(X) _Generic(l1++, int: (X)) | (ignored) | +| test.c:42:1:44:24 | #define M5(X) static volatile l ## X; _Generic(l ## X, int: 1) | Generic selection in macro M5 contains an invocation-dependent side effect which is not from macro invocation arguments, for example $@. | test.c:47:3:47:7 | _Generic | side effect 'la' | diff --git a/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.qlref b/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.qlref new file mode 100644 index 0000000000..bb3e39a58c --- /dev/null +++ b/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.qlref @@ -0,0 +1 @@ +rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-2/test.c b/c/misra/test/rules/RULE-23-2/test.c new file mode 100644 index 0000000000..6a25e15189 --- /dev/null +++ b/c/misra/test/rules/RULE-23-2/test.c @@ -0,0 +1,49 @@ +#define M1(X) _Generic((X), int: 1) + +// NON_COMPLIANT: +#define M2(X) _Generic((X)++, int: 1) + +// NON_COMPLIANT: +#define M3(X) _Generic(l1++, int: (X)) + +// COMPLIANT: +#define M3_WRAPPER(X) M3(X) + +#define M4(X) _Generic((X)(), int: 1) + +void f1() { + int l1; + + _Generic(1, int: 1); // COMPLIANT + M1(1); // COMPLIANT + _Generic(l1, int: 1); // COMPLIANT + M1(l1); // COMPLIANT + + _Generic(l1++, + int: 1); // COMPLIANT: side effect is not from a macro argument. + M1(l1++); // COMPLIANT + M2(l1); // NON-COMPLIANT: at macro definition + M3(1); // NON-COMPLIANT: at macro definition + M3_WRAPPER(1); // NON-COMPLIANT: at definition of M3 +} + +int g1; +int pure() { return g1; } + +int impure() { return g1++; } + +void f2() { + M1(pure()); // COMPLIANT + M1(impure()); // COMPLIANT + M4(pure); // COMPLIANT + M4(impure); // NON_COMPLIANT[False negative] +} + +#define M5(X) \ + static volatile l##X; \ + _Generic(l##X, int: 1) + +void f3() { + M5(a); // NON-COMPLIANT + M5(b); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.expected b/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.expected new file mode 100644 index 0000000000..50d6277e84 --- /dev/null +++ b/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.expected @@ -0,0 +1,2 @@ +| test.c:2:1:2:35 | #define M1 _Generic(1, default: 1); | Generic selection contains no non-default association. | +| test.c:14:3:14:25 | _Generic | Generic selection contains no non-default association. | diff --git a/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.qlref b/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.qlref new file mode 100644 index 0000000000..b44de9083e --- /dev/null +++ b/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.qlref @@ -0,0 +1 @@ +rules/RULE-23-3/GenericWithoutNonDefaultAssociation.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-3/test.c b/c/misra/test/rules/RULE-23-3/test.c new file mode 100644 index 0000000000..d3f093f242 --- /dev/null +++ b/c/misra/test/rules/RULE-23-3/test.c @@ -0,0 +1,23 @@ +// NON-COMPLIANT +#define M1 _Generic(1, default: 1); +// COMPLIANT +#define M2 _Generic(1, int: 1); +// COMPLIANT +#define M3 _Generic(1, int: 1, default: 1); +// COMPLIANT +#define M4 _Generic(1, int: 1, long: 1); + +void f() { + // Invalid generics: + // _Generic(1); + // _Generic(1, void: 1); + _Generic(1, default: 1); // NON-COMPLIANT + _Generic(1, int: 1); // COMPLIANT + _Generic(1, int: 1, default: 1); // COMPLIANT + _Generic(1, int: 1, long: 1); // COMPLIANT + + M1; + M2; + M3; + M4; +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.expected b/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.expected new file mode 100644 index 0000000000..27030fc768 --- /dev/null +++ b/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.expected @@ -0,0 +1,13 @@ +| test.c:11:18:11:18 | 1 | Generic selection uses unselectable type 'const int', due to qualifiers removed'. | test.c:11:18:11:18 | 1 | side effect | +| test.c:12:21:12:21 | 1 | Generic selection uses unselectable type 'volatile int', due to qualifiers removed'. | test.c:12:21:12:21 | 1 | side effect | +| test.c:13:20:13:20 | 1 | Generic selection uses unselectable type '_Atomic(int)', due to qualifiers removed'. | test.c:13:20:13:20 | 1 | side effect | +| test.c:16:27:16:27 | 1 | Generic selection uses unselectable type 'const volatile int', due to qualifiers removed'. | test.c:16:27:16:27 | 1 | side effect | +| test.c:18:18:18:18 | 1 | Generic selection uses unselectable type '(unnamed class/struct/union)', due to containing an anonymous struct or union type'. | test.c:18:18:18:18 | 1 | side effect | +| test.c:19:20:19:20 | 1 | Generic selection uses unselectable type 'struct *', due to containing an anonymous struct or union type'. | test.c:19:20:19:20 | 1 | side effect | +| test.c:24:17:24:17 | 1 | Generic selection uses unselectable type '(unnamed class/struct/union)', due to containing an anonymous struct or union type'. | test.c:24:17:24:17 | 1 | side effect | +| test.c:25:19:25:19 | 1 | Generic selection uses unselectable type 'union *', due to containing an anonymous struct or union type'. | test.c:25:19:25:19 | 1 | side effect | +| test.c:31:15:31:15 | 1 | Generic selection uses unselectable type 'int[3]', due to array-to-pointer decay'. | test.c:31:15:31:15 | 1 | side effect | +| test.c:40:1:40:53 | #define M1(X) _Generic((X), const int: 1, default: 0) | Generic in macro M1 has unselectable type 'const int', due to qualifiers removed. | test.c:40:1:40:53 | #define M1(X) _Generic((X), const int: 1, default: 0) | (ignored) | +| test.c:42:1:42:46 | #define M2(X) _Generic(1, X[3]: 1, default: 0) | Generic in macro M2 has an invocation-dependent unselectable type, for example $@. | test.c:49:3:49:10 | 1 | 'char[3]', due to array-to-pointer decay | +| test.c:52:3:52:15 | M3(X) | Generic resulting from invocation of macro $@ contains an unselectable type 'const int', due to qualifiers removed. | test.c:44:1:44:43 | #define M3(X) _Generic(1, X: 1, default: 0) | M3 | +| test.c:64:18:64:18 | 1 | Generic selection uses unselectable type 'const_int', due to qualifiers removed'. | test.c:64:18:64:18 | 1 | side effect | diff --git a/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.qlref b/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.qlref new file mode 100644 index 0000000000..1214be7ce2 --- /dev/null +++ b/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.qlref @@ -0,0 +1 @@ +rules/RULE-23-4/GenericAssociationWithUnselectableType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-4/test.c b/c/misra/test/rules/RULE-23-4/test.c new file mode 100644 index 0000000000..135ab4d0f7 --- /dev/null +++ b/c/misra/test/rules/RULE-23-4/test.c @@ -0,0 +1,73 @@ +typedef struct { +} empty_struct_t; +struct empty_struct {}; +typedef union { +} empty_union_t; +union empty_union {}; + +void f() { + _Generic(1, + int: 1, // COMPLIANT + const int: 1, // NON-COMPLIANT + volatile int: 1, // NON-COMPLIANT + _Atomic int: 1, // NON-COMPLIANT + int *: 1, // COMPLIANT + int const *: 1, // COMPLIANT + const volatile int: 1, // NON-COMPLIANT + int volatile const *: 1, // COMPLIANT + struct {}: 1, // NON-COMPLIANT + struct {} *: 1, // NON-COMPLIANT + empty_struct_t: 1, // COMPLIANT + struct empty_struct: 1, // COMPLIANT + empty_struct_t *: 1, // COMPLIANT + struct empty_struct *: 1, // COMPLIANT + union {}: 1, // NON-COMPLIANT + union {} *: 1, // NON-COMPLIANT + empty_union_t: 1, // COMPLIANT + union empty_union: 1, // COMPLIANT + empty_union_t *: 1, // COMPLIANT + union empty_union *: 1, // COMPLIANT + // int[]: 1, // compile error + int[3]: 1, // NON-COMPLIANT + int(*)[3]: 1, // COMPLIANT: pointer to array OK + // int (int*): 1, // compile error + int (*)(int *): 1, // COMPLIANT: function pointers OK + default: 1 // COMPLIANT + ); +} + +// NON-COMPLIANT +#define M1(X) _Generic((X), const int: 1, default: 0) +// NON-COMPLIANT +#define M2(X) _Generic(1, X[3]: 1, default: 0) +// COMPLIANT +#define M3(X) _Generic(1, X: 1, default: 0) + +void f2() { + M1(1); + M2(int); + M2(char); + + M3(int); // COMPLIANT + M3(const int); // NON-COMPLIANT +} + +typedef int int_t; +typedef int *int_ptr; +const typedef int const_int; +const typedef int *const_int_ptr; +typedef long const *long_const_ptr; + +void f3() { + _Generic(1, + int_t: 1, // COMPLIANT + const_int: 1, // NON-COMPLIANT + const_int_ptr: 1, // COMPLIANT + long_const_ptr: 1, // COMPLIANT + const int_ptr: 1, // COMPLIANT + default: 1 // COMPLIANT + ); +} + +// Type written here so it gets added to the database, see LvalueConversion.qll. +char *g; \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.expected b/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.expected new file mode 100644 index 0000000000..994d55968c --- /dev/null +++ b/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.expected @@ -0,0 +1,84 @@ +| test.c:41:3:41:44 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:41:3:41:44 | _Generic | | +| test.c:42:3:42:47 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to volatile int *. | test.c:42:3:42:47 | _Generic | | +| test.c:43:3:43:53 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile int *. | test.c:43:3:43:53 | _Generic | | +| test.c:44:3:44:39 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:44:3:44:39 | _Generic | | +| test.c:45:3:45:45 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const void *. | test.c:45:3:45:45 | _Generic | | +| test.c:46:3:46:54 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile void *. | test.c:46:3:46:54 | _Generic | | +| test.c:48:3:48:38 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:48:3:48:38 | _Generic | | +| test.c:50:3:50:39 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to void *. | test.c:50:3:50:39 | _Generic | | +| test.c:51:3:51:45 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const void *. | test.c:51:3:51:45 | _Generic | | +| test.c:52:3:52:54 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile void *. | test.c:52:3:52:54 | _Generic | | +| test.c:57:3:57:53 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile int *. | test.c:57:3:57:53 | _Generic | | +| test.c:59:3:59:38 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to int *. | test.c:59:3:59:38 | _Generic | | +| test.c:61:3:61:53 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile int *. | test.c:61:3:61:53 | _Generic | | +| test.c:62:3:62:39 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to void *. | test.c:62:3:62:39 | _Generic | | +| test.c:63:3:63:54 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile void *. | test.c:63:3:63:54 | _Generic | | +| test.c:69:3:69:38 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to int *. | test.c:69:3:69:38 | _Generic | | +| test.c:70:3:70:44 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const int *. | test.c:70:3:70:44 | _Generic | | +| test.c:71:3:71:47 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to volatile int *. | test.c:71:3:71:47 | _Generic | | +| test.c:73:3:73:39 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to void *. | test.c:73:3:73:39 | _Generic | | +| test.c:74:3:74:45 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const void *. | test.c:74:3:74:45 | _Generic | | +| test.c:75:3:75:54 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const volatile void *. | test.c:75:3:75:54 | _Generic | | +| test.c:77:3:77:38 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to int *. | test.c:77:3:77:38 | _Generic | | +| test.c:78:3:78:44 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const int *. | test.c:78:3:78:44 | _Generic | | +| test.c:79:3:79:47 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to volatile int *. | test.c:79:3:79:47 | _Generic | | +| test.c:80:3:80:53 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const volatile int *. | test.c:80:3:80:53 | _Generic | | +| test.c:82:3:82:45 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const void *. | test.c:82:3:82:45 | _Generic | | +| test.c:83:3:83:54 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const volatile void *. | test.c:83:3:83:54 | _Generic | | +| test.c:85:3:85:38 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to int *. | test.c:85:3:85:38 | _Generic | | +| test.c:86:3:86:44 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to const int *. | test.c:86:3:86:44 | _Generic | | +| test.c:87:3:87:53 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to const volatile int *. | test.c:87:3:87:53 | _Generic | | +| test.c:88:3:88:39 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to void *. | test.c:88:3:88:39 | _Generic | | +| test.c:90:3:90:54 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to const volatile void *. | test.c:90:3:90:54 | _Generic | | +| test.c:94:3:94:38 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to int *. | test.c:94:3:94:38 | _Generic | | +| test.c:95:3:95:44 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to const int *. | test.c:95:3:95:44 | _Generic | | +| test.c:96:3:96:47 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to volatile int *. | test.c:96:3:96:47 | _Generic | | +| test.c:97:3:97:53 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to const volatile int *. | test.c:97:3:97:53 | _Generic | | +| test.c:98:3:98:39 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to void *. | test.c:98:3:98:39 | _Generic | | +| test.c:99:3:99:45 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to const void *. | test.c:99:3:99:45 | _Generic | | +| test.c:119:3:119:45 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:119:3:119:45 | _Generic | | +| test.c:120:3:120:48 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to volatile int *. | test.c:120:3:120:48 | _Generic | | +| test.c:121:3:121:54 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile int *. | test.c:121:3:121:54 | _Generic | | +| test.c:122:3:122:40 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:122:3:122:40 | _Generic | | +| test.c:123:3:123:46 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const void *. | test.c:123:3:123:46 | _Generic | | +| test.c:124:3:124:55 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile void *. | test.c:124:3:124:55 | _Generic | | +| test.c:126:3:126:39 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:126:3:126:39 | _Generic | | +| test.c:128:3:128:40 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to void *. | test.c:128:3:128:40 | _Generic | | +| test.c:129:3:129:46 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const void *. | test.c:129:3:129:46 | _Generic | | +| test.c:130:3:130:55 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile void *. | test.c:130:3:130:55 | _Generic | | +| test.c:135:3:135:54 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile int *. | test.c:135:3:135:54 | _Generic | | +| test.c:137:3:137:39 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to int *. | test.c:137:3:137:39 | _Generic | | +| test.c:139:3:139:54 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile int *. | test.c:139:3:139:54 | _Generic | | +| test.c:140:3:140:40 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to void *. | test.c:140:3:140:40 | _Generic | | +| test.c:141:3:141:55 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile void *. | test.c:141:3:141:55 | _Generic | | +| test.c:147:3:147:39 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to int *. | test.c:147:3:147:39 | _Generic | | +| test.c:148:3:148:45 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const int *. | test.c:148:3:148:45 | _Generic | | +| test.c:149:3:149:48 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to volatile int *. | test.c:149:3:149:48 | _Generic | | +| test.c:151:3:151:40 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to void *. | test.c:151:3:151:40 | _Generic | | +| test.c:152:3:152:46 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const void *. | test.c:152:3:152:46 | _Generic | | +| test.c:153:3:153:55 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const volatile void *. | test.c:153:3:153:55 | _Generic | | +| test.c:156:3:156:45 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:156:3:156:45 | _Generic | | +| test.c:157:3:157:48 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to volatile int *. | test.c:157:3:157:48 | _Generic | | +| test.c:158:3:158:54 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile int *. | test.c:158:3:158:54 | _Generic | | +| test.c:159:3:159:40 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:159:3:159:40 | _Generic | | +| test.c:160:3:160:46 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const void *. | test.c:160:3:160:46 | _Generic | | +| test.c:161:3:161:55 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile void *. | test.c:161:3:161:55 | _Generic | | +| test.c:163:3:163:39 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:163:3:163:39 | _Generic | | +| test.c:165:3:165:40 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to void *. | test.c:165:3:165:40 | _Generic | | +| test.c:166:3:166:46 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const void *. | test.c:166:3:166:46 | _Generic | | +| test.c:167:3:167:55 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile void *. | test.c:167:3:167:55 | _Generic | | +| test.c:172:3:172:54 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile int *. | test.c:172:3:172:54 | _Generic | | +| test.c:180:3:180:48 | _Generic | Generic matched default selection, as controlling argument type int(*)[3] does not undergo pointer conversion to int(*const)[3]. | test.c:180:3:180:48 | _Generic | | +| test.c:188:3:191:18 | _Generic | Generic matched default selection, as controlling argument type int(*)[3] does not undergo pointer conversion to int(*const)[3]. | test.c:188:3:191:18 | _Generic | | +| test.c:200:3:200:47 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to int *. | test.c:200:3:200:47 | _Generic | | +| test.c:201:3:201:47 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:201:3:201:47 | _Generic | | +| test.c:215:3:215:44 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:215:3:215:44 | _Generic | | +| test.c:216:3:216:46 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int_t *. | test.c:216:3:216:46 | _Generic | | +| test.c:217:3:217:42 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to c_int_t *. | test.c:217:3:217:42 | _Generic | | +| test.c:221:3:221:45 | _Generic | Generic matched default selection, as controlling argument type int_t * does not undergo pointer conversion to const int *. | test.c:221:3:221:45 | _Generic | | +| test.c:222:3:222:47 | _Generic | Generic matched default selection, as controlling argument type int_t * does not undergo pointer conversion to const int_t *. | test.c:222:3:222:47 | _Generic | | +| test.c:223:3:223:43 | _Generic | Generic matched default selection, as controlling argument type int_t * does not undergo pointer conversion to c_int_t *. | test.c:223:3:223:43 | _Generic | | +| test.c:225:3:225:38 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:225:3:225:38 | _Generic | | +| test.c:226:3:226:40 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int_t *. | test.c:226:3:226:40 | _Generic | | +| test.c:231:3:231:39 | _Generic | Generic matched default selection, as controlling argument type c_int_t * does not undergo pointer conversion to int *. | test.c:231:3:231:39 | _Generic | | +| test.c:232:3:232:41 | _Generic | Generic matched default selection, as controlling argument type c_int_t * does not undergo pointer conversion to int_t *. | test.c:232:3:232:41 | _Generic | | diff --git a/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.qlref b/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.qlref new file mode 100644 index 0000000000..c6b02b6273 --- /dev/null +++ b/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.qlref @@ -0,0 +1 @@ +rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-5/test.c b/c/misra/test/rules/RULE-23-5/test.c new file mode 100644 index 0000000000..d9e140f0af --- /dev/null +++ b/c/misra/test/rules/RULE-23-5/test.c @@ -0,0 +1,236 @@ +void f1(); + +void f2() { + int l1; + int *l2; + const int *l3; + volatile int *l4; + volatile const int *l5; + void *l6; + const void *l7; + volatile void *l8; + const volatile void *l9; + + // No violation for missing pointer/integral conversions: + _Generic(l1, // COMPLIANT + int *: f1, + const int *: f1, + volatile int *: f1, + void *: f1, + const void *: f1, + default: f1); // COMPLIANT + _Generic(l2, int: f1, default: f1); // COMPLIANT + _Generic(l3, int: f1, default: f1); // COMPLIANT + _Generic(l4, int: f1, default: f1); // COMPLIANT + _Generic(l5, int: f1, default: f1); // COMPLIANT + + // Compliant, default case is not matched + _Generic(l1, int: f1); // COMPLIANT + _Generic(l2, int *: f1); // COMPLIANT + _Generic(l3, const int *: f1); // COMPLIANT + _Generic(l4, volatile int *: f1); // COMPLIANT + _Generic(l5, volatile const int *: f1); // COMPLIANT + _Generic(l6, void *: f1); // COMPLIANT + _Generic(l7, const void *: f1); // COMPLIANT + _Generic(l8, volatile void *: f1); // COMPLIANT + _Generic(l9, const volatile void *: f1); // COMPLIANT + + // Violation, match default case due to lack of pointer to pointer + // conversions: + _Generic(l2, int *: f1, default: f1); // COMPLIANT + _Generic(l2, const int *: f1, default: f1); // NON-COMPLIANT + _Generic(l2, volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l2, const volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l2, void *: f1, default: f1); // NON-COMPLIANT + _Generic(l2, const void *: f1, default: f1); // NON-COMPLIANT + _Generic(l2, const volatile void *: f1, default: f1); // NON-COMPLIANT + + _Generic(l3, int *: f1, default: f1); // NON-COMPLIANT + _Generic(l3, const int *: f1, default: f1); // COMPLIANT + _Generic(l3, void *: f1, default: f1); // NON-COMPLIANT + _Generic(l3, const void *: f1, default: f1); // NON-COMPLIANT + _Generic(l3, const volatile void *: f1, default: f1); // NON-COMPLIANT + // Obviously not volatile: + _Generic(l3, volatile int *: f1, default: f1); // COMPLIANT + // Debatable, but volatile const int* is assignable to const int* so its + // considered risky + _Generic(l3, const volatile int *: f1, default: f1); // NON-COMPLIANT + + _Generic(l4, int *: f1, default: f1); // NON-COMPLIANT + _Generic(l4, volatile int *: f1, default: f1); // COMPLIANT + _Generic(l4, const volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l4, void *: f1, default: f1); // NON-COMPLIANT + _Generic(l4, const volatile void *: f1, default: f1); // NON-COMPLIANT + // Debatable, but volatile int* isn't assignable to const int* or vice versa. + _Generic(l4, const int *: f1, default: f1); // COMPLIANT + // Debatable, but volatile int* isn't assignable to const void* or vice versa. + _Generic(l4, const void *: f1, default: f1); // COMPLIANT + + _Generic(l5, int *: f1, default: f1); // NON-COMPLIANT + _Generic(l5, const int *: f1, default: f1); // NON-COMPLIANT + _Generic(l5, volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l5, const volatile int *: f1, default: f1); // COMPLIANT + _Generic(l5, void *: f1, default: f1); // NON-COMPLIANT + _Generic(l5, const void *: f1, default: f1); // NON-COMPLIANT + _Generic(l5, const volatile void *: f1, default: f1); // NON-COMPLIANT + + _Generic(l6, int *: f1, default: f1); // NON-COMPLIANT + _Generic(l6, const int *: f1, default: f1); // NON-COMPLIANT + _Generic(l6, volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l6, const volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l6, void *: f1, default: f1); // COMPLIANT + _Generic(l6, const void *: f1, default: f1); // NON-COMPLIANT + _Generic(l6, const volatile void *: f1, default: f1); // NON-COMPLIANT + + _Generic(l7, int *: f1, default: f1); // NON-COMPLIANT + _Generic(l7, const int *: f1, default: f1); // NON-COMPLIANT + _Generic(l7, const volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l7, void *: f1, default: f1); // NON-COMPLIANT + _Generic(l7, const void *: f1, default: f1); // COMPLIANT + _Generic(l7, const volatile void *: f1, default: f1); // NON-COMPLIANT + // Debatable, but const void* isn't assignable to volatile int* or vice versa. + _Generic(l7, volatile int *: f1, default: f1); // COMPLIANT + + _Generic(l9, int *: f1, default: f1); // NON-COMPLIANT + _Generic(l9, const int *: f1, default: f1); // NON-COMPLIANT + _Generic(l9, volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l9, const volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l9, void *: f1, default: f1); // NON-COMPLIANT + _Generic(l9, const void *: f1, default: f1); // NON-COMPLIANT + _Generic(l9, const volatile void *: f1, default: f1); // COMPLIANT + + /** + * Edge case 1: The controlling expression undergoes lvalue conversion, so + * arrays become pointers and qualifiers on pointers are stripped. + */ + int l10[3]; + const int l11[3]; + volatile int l12[3]; + const volatile int l13[3]; + int *const l14; + const int *const l15; + + _Generic(l10, int *: f1, default: f1); // COMPLIANT + _Generic(l11, const int *: f1, default: f1); // COMPLIANT + _Generic(l12, volatile int *: f1, default: f1); // COMPLIANT + _Generic(l13, const volatile int *: f1, default: f1); // COMPLIANT + + _Generic(l10, int *: f1, default: f1); // COMPLIANT + _Generic(l10, const int *: f1, default: f1); // NON-COMPLIANT + _Generic(l10, volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l10, const volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l10, void *: f1, default: f1); // NON-COMPLIANT + _Generic(l10, const void *: f1, default: f1); // NON-COMPLIANT + _Generic(l10, const volatile void *: f1, default: f1); // NON-COMPLIANT + + _Generic(l11, int *: f1, default: f1); // NON-COMPLIANT + _Generic(l11, const int *: f1, default: f1); // COMPLIANT + _Generic(l11, void *: f1, default: f1); // NON-COMPLIANT + _Generic(l11, const void *: f1, default: f1); // NON-COMPLIANT + _Generic(l11, const volatile void *: f1, default: f1); // NON-COMPLIANT + // Obviously not volatile: + _Generic(l11, volatile int *: f1, default: f1); // COMPLIANT + // Debatable, but volatile const int* is assignable to const int* so its + // considered risky + _Generic(l11, const volatile int *: f1, default: f1); // NON-COMPLIANT + + _Generic(l12, int *: f1, default: f1); // NON-COMPLIANT + _Generic(l12, volatile int *: f1, default: f1); // COMPLIANT + _Generic(l12, const volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l12, void *: f1, default: f1); // NON-COMPLIANT + _Generic(l12, const volatile void *: f1, default: f1); // NON-COMPLIANT + // Debatab12e, but volatile int* isn't assignable to const int* or vice versa. + _Generic(l12, const int *: f1, default: f1); // COMPLIANT + // Debatable, but volatile int* isn't assignable to const void* or vice versa. + _Generic(l12, const void *: f1, default: f1); // COMPLIANT + + _Generic(l13, int *: f1, default: f1); // NON-COMPLIANT + _Generic(l13, const int *: f1, default: f1); // NON-COMPLIANT + _Generic(l13, volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l13, const volatile int *: f1, default: f1); // COMPLIANT + _Generic(l13, void *: f1, default: f1); // NON-COMPLIANT + _Generic(l13, const void *: f1, default: f1); // NON-COMPLIANT + _Generic(l13, const volatile void *: f1, default: f1); // NON-COMPLIANT + + _Generic(l14, int *: f1, default: f1); // COMPLIANT + _Generic(l14, const int *: f1, default: f1); // NON-COMPLIANT + _Generic(l14, volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l14, const volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l14, void *: f1, default: f1); // NON-COMPLIANT + _Generic(l14, const void *: f1, default: f1); // NON-COMPLIANT + _Generic(l14, const volatile void *: f1, default: f1); // NON-COMPLIANT + + _Generic(l15, int *: f1, default: f1); // NON-COMPLIANT + _Generic(l15, const int *: f1, default: f1); // COMPLIANT + _Generic(l15, void *: f1, default: f1); // NON-COMPLIANT + _Generic(l15, const void *: f1, default: f1); // NON-COMPLIANT + _Generic(l15, const volatile void *: f1, default: f1); // NON-COMPLIANT + // Obviously not volatile: + _Generic(l15, volatile int *: f1, default: f1); // COMPLIANT + // Debatable, but volatile const int* is assignable to const int* so its + // considered risky + _Generic(l15, const volatile int *: f1, default: f1); // NON-COMPLIANT + + /** + * Edge case 2: Types don't have to be identical to be compatible. + */ + int(*l16)[3]; + + // This is a risky conversion that should be reported: + _Generic(l16, int(*const)[3]: f1, default: f1); // NON-COMPLIANT + // However, in this one, there is a match on the second selector, because it + // it is an array type with a compatible element type, and sizes only have to + // match if both arrays have a constant size. Therefore, the default selector + // is not chosen and this is not a violation. + _Generic(l16, int(*const)[3]: f1, int(*)[]: f1, default: f1); // COMPLIANT + // In this case, the second selector is not a compatible type because the + // array has a constant size that doesn't match, and this should be reported. + _Generic(l16, + int(*const)[3]: f1, + int(*)[4]: f1, + default: f1); // NON-COMPLIANT + + /** + * Edge case 3: Conversion on _Generic, make sure we use the fully converted + * type when considering compliance. + */ + int *l17; + void *l18; + _Generic((void *)l17, void *: f1, default: f1); // COMPLIANT + _Generic((void *)l17, int *: f1, default: f1); // NON-COMPLIANT + _Generic((int *)l18, void *: f1, default: f1); // NON-COMPLIANT + _Generic((int *)l18, int *: f1, default: f1); // COMPLIANT + + /** + * Edge case 4: Typedefs must be resolved properly. + */ + typedef int int_t; + const typedef int c_int_t; + int_t *l19; + c_int_t *l20; + volatile c_int_t *l21; + + _Generic(l2, int *: f1, default: f1); // COMPLIANT + _Generic(l2, int_t *: f1, default: f1); // COMPLIANT + _Generic(l2, const int *: f1, default: f1); // NON-COMPLIANT + _Generic(l2, const int_t *: f1, default: f1); // NON-COMPLIANT + _Generic(l2, c_int_t *: f1, default: f1); // NON-COMPLIANT + + _Generic(l19, int *: f1, default: f1); // COMPLIANT + _Generic(l19, int_t *: f1, default: f1); // COMPLIANT + _Generic(l19, const int *: f1, default: f1); // NON-COMPLIANT + _Generic(l19, const int_t *: f1, default: f1); // NON-COMPLIANT + _Generic(l19, c_int_t *: f1, default: f1); // NON-COMPLIANT + + _Generic(l3, int *: f1, default: f1); // NON-COMPLIANT + _Generic(l3, int_t *: f1, default: f1); // NON-COMPLIANT + _Generic(l3, const int *: f1, default: f1); // COMPLIANT + _Generic(l3, const int_t *: f1, default: f1); // COMPLIANT + _Generic(l3, c_int_t *: f1, default: f1); // COMPLIANT + + _Generic(l20, int *: f1, default: f1); // NON-COMPLIANT + _Generic(l20, int_t *: f1, default: f1); // NON-COMPLIANT + _Generic(l20, const int *: f1, default: f1); // COMPLIANT + _Generic(l20, const int_t *: f1, default: f1); // COMPLIANT + _Generic(l20, c_int_t *: f1, default: f1); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.expected b/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.expected new file mode 100644 index 0000000000..1cdcc82698 --- /dev/null +++ b/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.expected @@ -0,0 +1,4 @@ +| test.c:11:3:11:8 | _Generic | Controlling expression in generic macro $@ has standard type (unnamed enum), which doesn't match its essential type (unnamed enum). | test.c:6:1:6:71 | #define M1(X) _Generic((X), int: 1, unsigned int: 1, short: 2, long: 3) | M1 | +| test.c:15:3:15:13 | _Generic | Controlling expression in generic macro $@ has standard type int, which doesn't match its essential type short. | test.c:6:1:6:71 | #define M1(X) _Generic((X), int: 1, unsigned int: 1, short: 2, long: 3) | M1 | +| test.c:18:3:18:23 | _Generic | Controlling expression in generic has standard type int, which doesn't match its essential type char. | test.c:18:3:18:23 | _Generic | | +| test.c:19:3:19:53 | _Generic | Controlling expression in generic has standard type int, which doesn't match its essential type short. | test.c:19:3:19:53 | _Generic | | diff --git a/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.qlref b/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.qlref new file mode 100644 index 0000000000..b91bbefec6 --- /dev/null +++ b/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.qlref @@ -0,0 +1 @@ +rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-6/test.c b/c/misra/test/rules/RULE-23-6/test.c new file mode 100644 index 0000000000..7d59c1e199 --- /dev/null +++ b/c/misra/test/rules/RULE-23-6/test.c @@ -0,0 +1,33 @@ +short l1; +int l2; +long l3; +enum { E1 } l4; + +#define M1(X) _Generic((X), int: 1, unsigned int: 1, short: 2, long: 3) +void f1() { + M1(l1); // COMPLIANT + M1(l2); // COMPLIANT + M1(l3); // COMPLIANT + M1(l4); // NON-COMPLIANT + + M1(1); // COMPLIANT + M1(1u); // COMPLIANT + M1(l1 + l1); // NON-COMPLIANT + M1((int)(l1 + l1)); // COMPLIANT + M1('c'); // NON-COMPLIANT[false negative] + _Generic('c', int: 1); // NON-COMPLIANT + _Generic(_Generic(0, default: l1 + l1), default: 1); // NON-COMPLIANT + _Generic(((short)_Generic(0, default: (l1 + l1))), default: 1); // COMPLIANT +} + +void f2() { + // Edge case: lvalue conversion of a const struct yields an implicit + // conversion to a non-const struct which is ignored by EssentialTypes.qll, + // meaning the essential type does not match the static type. However, we + // shouldn't report an issue here as the static/essential types are not one + // of the essential type categories. + struct S1 { + int m1; + }; + _Generic((const struct S1){.m1 = 0}, default: 1); +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.expected b/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.expected new file mode 100644 index 0000000000..57eecd6be8 --- /dev/null +++ b/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.expected @@ -0,0 +1,12 @@ +| test.c:9:1:9:51 | #define M3(X) _Generic((X), int: f1(X), default: 0) | Generic macro M3 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 2. | +| test.c:10:1:10:61 | #define M4(X) (X) + _Generic((X), int: f1(X), default: f1(X)) | Generic macro M4 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | +| test.c:11:1:11:61 | #define M5(X) _Generic((X), int: f1(X), default: f1(X)) + (X) | Generic macro M5 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | +| test.c:12:1:12:63 | #define M6(X) _Generic((X), int: f1((X) + (X)), default: f1(X)) | Generic macro M6 may have unexpected behavior from side effects in parameter X, as it is expanded in generic selection 1 more than once. | +| test.c:21:1:21:36 | #define M9(X) _Generic((X), int: f1) | Generic macro M9 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 1. | +| test.c:23:1:23:40 | #define M10(X) _Generic((X), int: f1(1)) | Generic macro M10 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 1. | +| test.c:32:1:32:58 | #define M12(X) _Generic((X) + (X), int: f1(X), default: 1) | Generic macro M12 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 2. | +| test.c:33:1:33:68 | #define M13(X) _Generic((X) + (X), int: f1(X), default: f1(X)) + (X) | Generic macro M13 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | +| test.c:43:1:43:77 | #define M17(X,Y) _Generic((X) + (Y), int: f2((X), (Y)), default: f2((X), 1)) | Generic macro M17 may have unexpected behavior from side effects in parameter Y, as it is not expanded in generic selection 2. | +| test.c:67:1:67:78 | #define M26(X) _Generic((X), int: IGNORE_2ND(X, X), default: IGNORE_2ND(X, X)) | Generic macro M26 may have unexpected behavior from side effects in parameter X, as it is expanded in generic selection 1 more than once. | +| test.c:67:1:67:78 | #define M26(X) _Generic((X), int: IGNORE_2ND(X, X), default: IGNORE_2ND(X, X)) | Generic macro M26 may have unexpected behavior from side effects in parameter X, as it is expanded in generic selection 2 more than once. | +| test.c:68:1:68:75 | #define M27(X) _Generic((X), int: f1(IGNORE(X)), default: f1(IGNORE(X)))(X) | Generic macro M27 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | diff --git a/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.qlref b/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.qlref new file mode 100644 index 0000000000..3156bdce91 --- /dev/null +++ b/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.qlref @@ -0,0 +1 @@ +rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-7/test.c b/c/misra/test/rules/RULE-23-7/test.c new file mode 100644 index 0000000000..41a5d6ab6c --- /dev/null +++ b/c/misra/test/rules/RULE-23-7/test.c @@ -0,0 +1,71 @@ +int f1(int p1); +int f2(int p1, int p2); + +// COMPLIANT -- standard correct cases: +#define M1(X) _Generic((X), int: f1, default: f1)(X) +#define M2(X) _Generic((X), int: f1(X), default: f1(X)) + +// NON-COMPLIANT -- standard incorrect cases: +#define M3(X) _Generic((X), int: f1(X), default: 0) +#define M4(X) (X) + _Generic((X), int: f1(X), default: f1(X)) +#define M5(X) _Generic((X), int: f1(X), default: f1(X)) + (X) +#define M6(X) _Generic((X), int: f1((X) + (X)), default: f1(X)) + +// Compliant by exception +// COMPLIANT +#define M7(X) _Generic((X), int: 1, default: 0) +// NON-COMPLIANT[FALSE NEGATIVE] -- Without an expansion, we can't tell if this +// macro has only constant expressions or not. +#define M8(X) _Generic((X), int: f1(1)) +// NON-COMPLIANT -- If the macro is expanded we can detect constant expressions +#define M9(X) _Generic((X), int: f1) +// NON-COMPLIANT -- If the macro is expanded we can detect constant expressions +#define M10(X) _Generic((X), int: f1(1)) +void f3() { + M9(1); + M10(1); +} + +// COMPLIANT -- multiple uses in the controlling expression is OK: +#define M11(X) _Generic((X) + (X), int: f1(X), default: f1(X)) +// NON-COMPLIANT -- the rule should still be enforced otherwise: +#define M12(X) _Generic((X) + (X), int: f1(X), default: 1) +#define M13(X) _Generic((X) + (X), int: f1(X), default: f1(X)) + (X) + +// COMPLIANT -- the argument is not used in the controlling expression: +#define M14(X) _Generic(1, int: f1((X) + (X)), default: f1(X)) +#define M15(X) _Generic(1, int: f1(X), default: f1(X)) + (X) + +// Test cases with more than one argument: +// COMPLIANT -- Y is not used in the controlling expression: +#define M16(X, Y) _Generic((X), int: f2((X), (Y)), default: f2((X), 1)) +// NON-COMPLIANT -- Y is used in the controlling expression +#define M17(X, Y) _Generic((X) + (Y), int: f2((X), (Y)), default: f2((X), 1)) +// COMPLIANT -- Y is used in the controlling expression correctly +#define M18(X, Y) _Generic((X) + (Y), int: f2((X), (Y)), default: f2((X), (Y))) + +// Test unevaluated contexts: +// COMPLIANT -- sizeof is not evaluated: +#define M19(X) _Generic((X), int[sizeof(X)]: f1, default: f1)(X) +#define M20(X) _Generic((X), int: f1(sizeof(X)), default: f1)(X) +#define M21(X) _Generic((X), int: f1(X), default: f1(X)) + sizeof(X) +// NON-COMPLIANT[FALSE NEGATIVE] -- sizeof plus evaluated context +#define M22(X) _Generic((X), int: f1(sizeof(X) + X), default: f1(X))(X) +// NON-COMPLIANT[FALSE NEGATIVE] -- array type sizes may be evaluated +#define M23(X) _Generic((X), int[X]: f1, default: f1)(X) +// COMPLIANT -- alignof, typeof are not evaluated: +#define M24(X) _Generic((X), int[X]: f1, default: f1)(X) + +// Nested macros: +#define ONCE(X) (X) +#define TWICE(X) (X) + (X) +#define IGNORE(X) (1) +#define IGNORE_2ND(X, Y) (X) +// COMPLIANT +#define M25(X) _Generic((X), int: ONCE(f1(X)), default: ONCE(f1(X)) +// COMPLIANT[FALSE POSITIVE] +#define M26(X) _Generic((X), int: IGNORE_2ND(X, X), default: IGNORE_2ND(X, X)) +#define M27(X) _Generic((X), int: f1(IGNORE(X)), default: f1(IGNORE(X)))(X) +// NON-COMPLIANT[FASE NEGATIVE] +#define M28(X) _Generic((X), int: f1(IGNORE(X)), default: f1(IGNORE(X))) +#define M29(X) _Generic((X), int: TWICE(f1(X)), default: TWICE(f1(X))) \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.expected b/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.expected new file mode 100644 index 0000000000..5951834d00 --- /dev/null +++ b/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.expected @@ -0,0 +1,4 @@ +| test.c:11:1:11:64 | #define M4(X) _Generic((X), int: 1, default: 0, unsigned int: 2) | Generic macro M4 has default as 2nd association, which is not first or last. | test.c:11:1:11:64 | #define M4(X) _Generic((X), int: 1, default: 0, unsigned int: 2) | (ignored) | +| test.c:17:1:17:60 | #define M5(__VA_ARGS__...) _Generic(0, __VA_ARGS__, default: 0, int: 1) | Generic macro M5 has a default association which is not first or last, for example $@. | test.c:28:5:28:23 | _Generic | 2nd | +| test.c:34:5:34:27 | M6(__VA_ARGS__...) | Generic macro $@, in this expansion, has default as 2nd association, which is not first or last. | test.c:19:1:19:48 | #define M6(__VA_ARGS__...) _Generic(0, __VA_ARGS__, int: 1) | M6 | +| test.c:44:5:44:52 | _Generic | Generic has default as 2nd association, which is not first or last. | test.c:44:5:44:52 | _Generic | | diff --git a/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.qlref b/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.qlref new file mode 100644 index 0000000000..06fe786e7d --- /dev/null +++ b/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.qlref @@ -0,0 +1 @@ +rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-8/test.c b/c/misra/test/rules/RULE-23-8/test.c new file mode 100644 index 0000000000..fdd6e66044 --- /dev/null +++ b/c/misra/test/rules/RULE-23-8/test.c @@ -0,0 +1,49 @@ +/** + * Cases where the macro itself is always compliant or non compliant: + */ +// COMPLIANT +#define M1(X) _Generic((X), int: 1, unsigned int: 2) +// COMPLIANT +#define M2(X) _Generic((X), int: 1, unsigned int: 2, default: 0) +// COMPLIANT +#define M3(X) _Generic((X), default: 0, int: 1, unsigned int: 2) +// NON-COMPLIANT +#define M4(X) _Generic((X), int: 1, default: 0, unsigned int: 2) + +/** + * Macros that are compliant or not based on use: + */ +// NON-COMPLIANT: because every use is non compliant +#define M5(...) _Generic(0, __VA_ARGS__, default: 0, int: 1) +// COMPLIANT: because some uses are compliant +#define M6(...) _Generic(0, __VA_ARGS__, int: 1) + +void f1() { + M1(0); // COMPLIANT + M2(0); // COMPLIANT + M3(0); // COMPLIANT + M4(0); // COMPLIANT: the macro invocation is compliant, the macro definition + // is not. + + // COMPLIANT: all invocations of M5 are non compliant so the macro is reported + // instead. + M5(unsigned int : 1); + M5(unsigned int : 1, long : 2); + + // Some invocations of M6() will be compliant, so we'll report the issue at + // each invocation. + M6(default : 0); // COMPLIANT + M6(default : 0, long : 1); // COMPLIANT + M6(long : 1, default : 0); // NON-COMPLIANT +} + +/** + * For completeness, non macro cases, though these are not likely and violate + * RULE-23-1. + */ +void f2() { + _Generic(0, int: 1, unsigned int: 2); // COMPLIANT + _Generic(0, int: 1, unsigned int: 2, default: 0); // COMPLIANT + _Generic(0, default: 0, int: 1, unsigned int: 2); // COMPLIANT + _Generic(0, int: 1, default: 0, unsigned int: 2); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.expected b/c/misra/test/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.expected index 08e419ef4f..f2b438aaf1 100644 --- a/c/misra/test/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.expected +++ b/c/misra/test/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.expected @@ -1,12 +1,14 @@ -| function1.c:6:6:6:7 | declaration of f3 | The return type of re-declaration of $@ is not compatible with declaration $@ | function1.c:6:6:6:7 | declaration of f3 | f3 | function1.c:8:4:8:5 | declaration of f3 | f3 | -| function1.c:8:4:8:5 | declaration of f3 | The return type of re-declaration of $@ is not compatible with declaration $@ | function1.c:8:4:8:5 | declaration of f3 | f3 | function1.c:6:6:6:7 | declaration of f3 | f3 | -| function1.c:8:4:8:5 | declaration of f3 | The return type of re-declaration of $@ is not compatible with declaration $@ | function1.c:8:4:8:5 | declaration of f3 | f3 | function2.c:4:6:4:7 | declaration of f3 | f3 | -| function1.c:9:6:9:7 | declaration of f4 | The return type of re-declaration of $@ is not compatible with declaration $@ | function1.c:9:6:9:7 | declaration of f4 | f4 | function2.c:5:5:5:6 | declaration of f4 | f4 | -| function1.c:13:5:13:6 | definition of f6 | The return type of re-declaration of $@ is not compatible with declaration $@ | function1.c:13:5:13:6 | definition of f6 | f6 | function2.c:9:6:9:7 | definition of f6 | f6 | -| function1.c:21:3:21:5 | definition of f21 | The parameter types of re-declaration of $@ is not compatible with declaration $@ | function1.c:21:3:21:5 | definition of f21 | f21 | function2.c:17:10:17:12 | declaration of f21 | f21 | -| function1.c:25:6:25:8 | definition of f22 | The parameter names of re-declaration of $@ is not compatible with declaration $@ | function1.c:25:6:25:8 | definition of f22 | f22 | function2.c:19:13:19:15 | declaration of f22 | f22 | -| function2.c:4:6:4:7 | declaration of f3 | The return type of re-declaration of $@ is not compatible with declaration $@ | function2.c:4:6:4:7 | declaration of f3 | f3 | function1.c:8:4:8:5 | declaration of f3 | f3 | -| function2.c:5:5:5:6 | declaration of f4 | The return type of re-declaration of $@ is not compatible with declaration $@ | function2.c:5:5:5:6 | declaration of f4 | f4 | function1.c:9:6:9:7 | declaration of f4 | f4 | -| function2.c:9:6:9:7 | definition of f6 | The return type of re-declaration of $@ is not compatible with declaration $@ | function2.c:9:6:9:7 | definition of f6 | f6 | function1.c:13:5:13:6 | definition of f6 | f6 | -| function2.c:17:10:17:12 | declaration of f21 | The parameter types of re-declaration of $@ is not compatible with declaration $@ | function2.c:17:10:17:12 | declaration of f21 | f21 | function1.c:21:3:21:5 | definition of f21 | f21 | -| function2.c:19:13:19:15 | declaration of f22 | The parameter names of re-declaration of $@ is not compatible with declaration $@ | function2.c:19:13:19:15 | declaration of f22 | f22 | function1.c:25:6:25:8 | definition of f22 | f22 | +| function1.c:6:6:6:7 | declaration of f3 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function1.c:6:6:6:7 | declaration of f3 | f3 | function1.c:8:4:8:5 | declaration of f3 | f3 | +| function1.c:8:4:8:5 | declaration of f3 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function1.c:8:4:8:5 | declaration of f3 | f3 | function1.c:6:6:6:7 | declaration of f3 | f3 | +| function1.c:8:4:8:5 | declaration of f3 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function1.c:8:4:8:5 | declaration of f3 | f3 | function2.c:4:6:4:7 | declaration of f3 | f3 | +| function1.c:9:6:9:7 | declaration of f4 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function1.c:9:6:9:7 | declaration of f4 | f4 | function2.c:5:5:5:6 | declaration of f4 | f4 | +| function1.c:13:5:13:6 | definition of f6 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function1.c:13:5:13:6 | definition of f6 | f6 | function2.c:9:6:9:7 | definition of f6 | f6 | +| function1.c:15:5:15:7 | declaration of f20 | The parameter types of re-declaration of $@ do not use the same type names as declaration $@ | function1.c:15:5:15:7 | declaration of f20 | f20 | function2.c:11:5:11:7 | declaration of f20 | f20 | +| function1.c:21:3:21:5 | definition of f21 | The parameter types of re-declaration of $@ do not use the same type names as declaration $@ | function1.c:21:3:21:5 | definition of f21 | f21 | function2.c:17:10:17:12 | declaration of f21 | f21 | +| function1.c:25:6:25:8 | definition of f22 | The parameter names of re-declaration of $@ do not use the same type names as declaration $@ | function1.c:25:6:25:8 | definition of f22 | f22 | function2.c:19:13:19:15 | declaration of f22 | f22 | +| function2.c:4:6:4:7 | declaration of f3 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function2.c:4:6:4:7 | declaration of f3 | f3 | function1.c:8:4:8:5 | declaration of f3 | f3 | +| function2.c:5:5:5:6 | declaration of f4 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function2.c:5:5:5:6 | declaration of f4 | f4 | function1.c:9:6:9:7 | declaration of f4 | f4 | +| function2.c:9:6:9:7 | definition of f6 | The return type of re-declaration of $@ does not use the same type names as declaration $@ | function2.c:9:6:9:7 | definition of f6 | f6 | function1.c:13:5:13:6 | definition of f6 | f6 | +| function2.c:11:5:11:7 | declaration of f20 | The parameter types of re-declaration of $@ do not use the same type names as declaration $@ | function2.c:11:5:11:7 | declaration of f20 | f20 | function1.c:15:5:15:7 | declaration of f20 | f20 | +| function2.c:17:10:17:12 | declaration of f21 | The parameter types of re-declaration of $@ do not use the same type names as declaration $@ | function2.c:17:10:17:12 | declaration of f21 | f21 | function1.c:21:3:21:5 | definition of f21 | f21 | +| function2.c:19:13:19:15 | declaration of f22 | The parameter names of re-declaration of $@ do not use the same type names as declaration $@ | function2.c:19:13:19:15 | declaration of f22 | f22 | function1.c:25:6:25:8 | definition of f22 | f22 | diff --git a/c/misra/test/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.expected b/c/misra/test/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.expected index c63681c7be..8b8e7f8a48 100644 --- a/c/misra/test/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.expected +++ b/c/misra/test/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.expected @@ -1,22 +1,22 @@ -| object1.c:5:6:5:7 | definition of a3 | The object $@ of type long is not compatible with re-declaration $@ of type LL | object1.c:5:6:5:7 | definition of a3 | a3 | object2.c:11:11:11:12 | declaration of a3 | a3 | -| object1.c:6:6:6:7 | definition of a4 | The object $@ of type long is not compatible with re-declaration $@ of type int | object1.c:6:6:6:7 | definition of a4 | a4 | object2.c:13:12:13:13 | declaration of a4 | a4 | -| object1.c:7:5:7:6 | definition of a5 | The object $@ of type int is not compatible with re-declaration $@ of type long | object1.c:7:5:7:6 | definition of a5 | a5 | object2.c:15:13:15:14 | declaration of a5 | a5 | -| object1.c:8:6:8:7 | definition of a6 | The object $@ of type long is not compatible with re-declaration $@ of type int | object1.c:8:6:8:7 | definition of a6 | a6 | object2.c:19:1:19:3 | declaration of a6 | a6 | -| object1.c:9:5:9:6 | definition of a7 | The object $@ of type int is not compatible with re-declaration $@ of type LL | object1.c:9:5:9:6 | definition of a7 | a7 | object2.c:21:11:21:12 | declaration of a7 | a7 | -| object1.c:15:5:15:7 | definition of a10 | The object $@ of type int[100] is not compatible with re-declaration $@ of type LI[100] | object1.c:15:5:15:7 | definition of a10 | a10 | object2.c:24:4:24:6 | definition of a10 | a10 | -| object1.c:16:5:16:7 | definition of a11 | The object $@ of type int[100] is not compatible with re-declaration $@ of type int[101] | object1.c:16:5:16:7 | definition of a11 | a11 | object2.c:25:12:25:14 | declaration of a11 | a11 | -| object1.c:19:12:19:14 | definition of a13 | The object $@ of type int *const is not compatible with re-declaration $@ of type int * | object1.c:19:12:19:14 | definition of a13 | a13 | object2.c:28:13:28:15 | declaration of a13 | a13 | -| object1.c:23:10:23:13 | definition of size | The object $@ of type size_t is not compatible with re-declaration $@ of type unsigned char | object1.c:23:10:23:13 | definition of size | size | object2.c:32:17:32:20 | definition of size | size | -| object1.c:24:3:24:4 | definition of s0 | The object $@ of type NamedStruct0 is not compatible with re-declaration $@ of type NamedStruct0 | object1.c:24:3:24:4 | definition of s0 | s0 | object2.c:33:3:33:4 | definition of s0 | s0 | -| object1.c:29:3:29:4 | definition of s1 | The object $@ of type NamedStruct1 is not compatible with re-declaration $@ of type NamedStruct1 | object1.c:29:3:29:4 | definition of s1 | s1 | object2.c:38:3:38:4 | definition of s1 | s1 | -| object2.c:11:11:11:12 | declaration of a3 | The object $@ of type LL is not compatible with re-declaration $@ of type long | object2.c:11:11:11:12 | declaration of a3 | a3 | object1.c:5:6:5:7 | definition of a3 | a3 | -| object2.c:13:12:13:13 | declaration of a4 | The object $@ of type int is not compatible with re-declaration $@ of type long | object2.c:13:12:13:13 | declaration of a4 | a4 | object1.c:6:6:6:7 | definition of a4 | a4 | -| object2.c:15:13:15:14 | declaration of a5 | The object $@ of type long is not compatible with re-declaration $@ of type int | object2.c:15:13:15:14 | declaration of a5 | a5 | object1.c:7:5:7:6 | definition of a5 | a5 | -| object2.c:19:1:19:3 | declaration of a6 | The object $@ of type int is not compatible with re-declaration $@ of type long | object2.c:19:1:19:3 | declaration of a6 | a6 | object1.c:8:6:8:7 | definition of a6 | a6 | -| object2.c:21:11:21:12 | declaration of a7 | The object $@ of type LL is not compatible with re-declaration $@ of type int | object2.c:21:11:21:12 | declaration of a7 | a7 | object1.c:9:5:9:6 | definition of a7 | a7 | -| object2.c:24:4:24:6 | definition of a10 | The object $@ of type LI[100] is not compatible with re-declaration $@ of type int[100] | object2.c:24:4:24:6 | definition of a10 | a10 | object1.c:15:5:15:7 | definition of a10 | a10 | -| object2.c:25:12:25:14 | declaration of a11 | The object $@ of type int[101] is not compatible with re-declaration $@ of type int[100] | object2.c:25:12:25:14 | declaration of a11 | a11 | object1.c:16:5:16:7 | definition of a11 | a11 | -| object2.c:28:13:28:15 | declaration of a13 | The object $@ of type int * is not compatible with re-declaration $@ of type int *const | object2.c:28:13:28:15 | declaration of a13 | a13 | object1.c:19:12:19:14 | definition of a13 | a13 | -| object2.c:32:17:32:20 | definition of size | The object $@ of type unsigned char is not compatible with re-declaration $@ of type size_t | object2.c:32:17:32:20 | definition of size | size | object1.c:23:10:23:13 | definition of size | size | -| object2.c:33:3:33:4 | definition of s0 | The object $@ of type NamedStruct0 is not compatible with re-declaration $@ of type NamedStruct0 | object2.c:33:3:33:4 | definition of s0 | s0 | object1.c:24:3:24:4 | definition of s0 | s0 | -| object2.c:38:3:38:4 | definition of s1 | The object $@ of type NamedStruct1 is not compatible with re-declaration $@ of type NamedStruct1 | object2.c:38:3:38:4 | definition of s1 | s1 | object1.c:29:3:29:4 | definition of s1 | s1 | +| object1.c:5:6:5:7 | definition of a3 | The object $@ of type long does not use the same type names as re-declaration $@ of type LL | object1.c:5:6:5:7 | definition of a3 | a3 | object2.c:11:11:11:12 | declaration of a3 | a3 | +| object1.c:6:6:6:7 | definition of a4 | The object $@ of type long does not use the same type names as re-declaration $@ of type int | object1.c:6:6:6:7 | definition of a4 | a4 | object2.c:13:12:13:13 | declaration of a4 | a4 | +| object1.c:7:5:7:6 | definition of a5 | The object $@ of type int does not use the same type names as re-declaration $@ of type long | object1.c:7:5:7:6 | definition of a5 | a5 | object2.c:15:13:15:14 | declaration of a5 | a5 | +| object1.c:8:6:8:7 | definition of a6 | The object $@ of type long does not use the same type names as re-declaration $@ of type int | object1.c:8:6:8:7 | definition of a6 | a6 | object2.c:19:1:19:3 | declaration of a6 | a6 | +| object1.c:9:5:9:6 | definition of a7 | The object $@ of type int does not use the same type names as re-declaration $@ of type LL | object1.c:9:5:9:6 | definition of a7 | a7 | object2.c:21:11:21:12 | declaration of a7 | a7 | +| object1.c:15:5:15:7 | definition of a10 | The object $@ of type int[100] does not use the same type names as re-declaration $@ of type LI[100] | object1.c:15:5:15:7 | definition of a10 | a10 | object2.c:24:4:24:6 | definition of a10 | a10 | +| object1.c:16:5:16:7 | definition of a11 | The object $@ of type int[100] does not use the same type names as re-declaration $@ of type int[101] | object1.c:16:5:16:7 | definition of a11 | a11 | object2.c:25:12:25:14 | declaration of a11 | a11 | +| object1.c:19:12:19:14 | definition of a13 | The object $@ of type int *const does not use the same type names as re-declaration $@ of type int * | object1.c:19:12:19:14 | definition of a13 | a13 | object2.c:28:13:28:15 | declaration of a13 | a13 | +| object1.c:23:10:23:13 | definition of size | The object $@ of type size_t does not use the same type names as re-declaration $@ of type unsigned char | object1.c:23:10:23:13 | definition of size | size | object2.c:32:17:32:20 | definition of size | size | +| object1.c:24:3:24:4 | definition of s0 | The object $@ of type NamedStruct0 does not use the same type names as re-declaration $@ of type NamedStruct0 | object1.c:24:3:24:4 | definition of s0 | s0 | object2.c:33:3:33:4 | definition of s0 | s0 | +| object1.c:29:3:29:4 | definition of s1 | The object $@ of type NamedStruct1 does not use the same type names as re-declaration $@ of type NamedStruct1 | object1.c:29:3:29:4 | definition of s1 | s1 | object2.c:38:3:38:4 | definition of s1 | s1 | +| object2.c:11:11:11:12 | declaration of a3 | The object $@ of type LL does not use the same type names as re-declaration $@ of type long | object2.c:11:11:11:12 | declaration of a3 | a3 | object1.c:5:6:5:7 | definition of a3 | a3 | +| object2.c:13:12:13:13 | declaration of a4 | The object $@ of type int does not use the same type names as re-declaration $@ of type long | object2.c:13:12:13:13 | declaration of a4 | a4 | object1.c:6:6:6:7 | definition of a4 | a4 | +| object2.c:15:13:15:14 | declaration of a5 | The object $@ of type long does not use the same type names as re-declaration $@ of type int | object2.c:15:13:15:14 | declaration of a5 | a5 | object1.c:7:5:7:6 | definition of a5 | a5 | +| object2.c:19:1:19:3 | declaration of a6 | The object $@ of type int does not use the same type names as re-declaration $@ of type long | object2.c:19:1:19:3 | declaration of a6 | a6 | object1.c:8:6:8:7 | definition of a6 | a6 | +| object2.c:21:11:21:12 | declaration of a7 | The object $@ of type LL does not use the same type names as re-declaration $@ of type int | object2.c:21:11:21:12 | declaration of a7 | a7 | object1.c:9:5:9:6 | definition of a7 | a7 | +| object2.c:24:4:24:6 | definition of a10 | The object $@ of type LI[100] does not use the same type names as re-declaration $@ of type int[100] | object2.c:24:4:24:6 | definition of a10 | a10 | object1.c:15:5:15:7 | definition of a10 | a10 | +| object2.c:25:12:25:14 | declaration of a11 | The object $@ of type int[101] does not use the same type names as re-declaration $@ of type int[100] | object2.c:25:12:25:14 | declaration of a11 | a11 | object1.c:16:5:16:7 | definition of a11 | a11 | +| object2.c:28:13:28:15 | declaration of a13 | The object $@ of type int * does not use the same type names as re-declaration $@ of type int *const | object2.c:28:13:28:15 | declaration of a13 | a13 | object1.c:19:12:19:14 | definition of a13 | a13 | +| object2.c:32:17:32:20 | definition of size | The object $@ of type unsigned char does not use the same type names as re-declaration $@ of type size_t | object2.c:32:17:32:20 | definition of size | size | object1.c:23:10:23:13 | definition of size | size | +| object2.c:33:3:33:4 | definition of s0 | The object $@ of type NamedStruct0 does not use the same type names as re-declaration $@ of type NamedStruct0 | object2.c:33:3:33:4 | definition of s0 | s0 | object1.c:24:3:24:4 | definition of s0 | s0 | +| object2.c:38:3:38:4 | definition of s1 | The object $@ of type NamedStruct1 does not use the same type names as re-declaration $@ of type NamedStruct1 | object2.c:38:3:38:4 | definition of s1 | s1 | object1.c:29:3:29:4 | definition of s1 | s1 | diff --git a/c/misra/test/rules/RULE-8-3/function1.c b/c/misra/test/rules/RULE-8-3/function1.c index 2072748047..7fcf775167 100644 --- a/c/misra/test/rules/RULE-8-3/function1.c +++ b/c/misra/test/rules/RULE-8-3/function1.c @@ -12,7 +12,7 @@ long f5(int f5a) { return 0; } // COMPLIANT int f6(int f6a) { return 0; } // NON_COMPLIANT -int f20(int f20a); // COMPLIANT - overloaded function +int f20(int f20a); // NON_COMPLIANT typedef int wi; typedef int hi; diff --git a/c/misra/test/rules/RULE-8-3/function2.c b/c/misra/test/rules/RULE-8-3/function2.c index 979e002466..b33dc73c1c 100644 --- a/c/misra/test/rules/RULE-8-3/function2.c +++ b/c/misra/test/rules/RULE-8-3/function2.c @@ -8,7 +8,7 @@ long f5(int f5a) { return 0; } // COMPLIANT long f6(int f6a) { return 0; } // NON_COMPLIANT -int f20(int f20a, int f20b); // COMPLIANT -- overloaded function +int f20(int f20a, int f20b); // NON_COMPLIANT typedef int wi; typedef int hi; diff --git a/change_notes/2025-02-25-move-type-related-libraries.md b/change_notes/2025-02-25-move-type-related-libraries.md new file mode 100644 index 0000000000..9f4fbd0bf2 --- /dev/null +++ b/change_notes/2025-02-25-move-type-related-libraries.md @@ -0,0 +1,2 @@ + - All rules using `Type.qll`, `TypeUses.qll`, `Pointers.qll`, `TrivialType.qll`, `VariablyModifiedTypes.qll`: + - Files moved into `cpp/common/types` directory. No external changes in behavior expected. \ No newline at end of file diff --git a/change_notes/2025-02-25-update-macro-deduplication-library.md b/change_notes/2025-02-25-update-macro-deduplication-library.md new file mode 100644 index 0000000000..90b3ef51af --- /dev/null +++ b/change_notes/2025-02-25-update-macro-deduplication-library.md @@ -0,0 +1,4 @@ +- `RULE-2-8` - `UnusedObjectDefinition.ql`, `UnusedObjectDefinitionStrict.ql`: + - Refactor to allow additional parameters in non-macro results for library `DeduplicateMacroResults.qll`. + - Refactor to replace `Location` with `Locatable` in API of library `DeduplicationMacroResults.qll`. + - No observable difference in behavior expected. diff --git a/change_notes/2025-03-04-essential-types-with-explicit-conversions.md b/change_notes/2025-03-04-essential-types-with-explicit-conversions.md new file mode 100644 index 0000000000..aa32044087 --- /dev/null +++ b/change_notes/2025-03-04-essential-types-with-explicit-conversions.md @@ -0,0 +1,2 @@ + - `EssentialType` - for all queries related to essential types: + - Updated the way essential types of expressions with "conversions" (including explicit casts, parenthesis, and implicit conversions such as array-to-pointer conversions) are handled, to get proper essential types when parenthesis, casts, and generics interact. \ No newline at end of file diff --git a/change_notes/2025-03-04-more-accurate-type-comparisons.md b/change_notes/2025-03-04-more-accurate-type-comparisons.md new file mode 100644 index 0000000000..942d76f7af --- /dev/null +++ b/change_notes/2025-03-04-more-accurate-type-comparisons.md @@ -0,0 +1,6 @@ + - `RULE-8-3` - `DeclarationsOfAFunctionSameNameAndType.ql`, `DeclarationsOfAnObjectSameNameAndType.ql`: + - New shared module used to fix false positives for compound types referring to the same basic integer types under a different name, e.g., query will not report for `signed[4]` used in place of `int[4]` as per MISRA spec. + - Now query will report incompatibilities for two functions of the same name with a different number of parameters. + - Query result string updated to not use the word "Compatible," which is confusing, as it may falsely appear that the query is testing for compatibility as defined by C17. + - `RULE-8-4`, `DCL-40C` - `CompatibleDeclarationFunctionDefined.ql`, `CompatibleDeclarationObjectDefined.ql`, `IncomptatibleFunctionDeclarations.ql`: + - New shared module used to fix false positives by updating "compatible" type checks to more closely match the C17 standard. For instance, `int[3]` and `int[]` are compatible declarations (while `int[3]` and `int[4]` are not), and typedefs are now resolved as well. Some false positives may still occur regarding structs from different compilation units. \ No newline at end of file diff --git a/cpp/autosar/src/rules/A0-4-1/FloatingPointImplementationShallComplyWithIeeeStandard.ql b/cpp/autosar/src/rules/A0-4-1/FloatingPointImplementationShallComplyWithIeeeStandard.ql index 9123e7de2f..0a59b423d0 100644 --- a/cpp/autosar/src/rules/A0-4-1/FloatingPointImplementationShallComplyWithIeeeStandard.ql +++ b/cpp/autosar/src/rules/A0-4-1/FloatingPointImplementationShallComplyWithIeeeStandard.ql @@ -18,7 +18,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.TypeUses +import codingstandards.cpp.types.Uses class NumericLimits extends Class { NumericLimits() { this.hasQualifiedName("std", ["numeric_limits", "__libcpp_numeric_limits"]) } diff --git a/cpp/autosar/src/rules/A12-8-4/MoveConstructorUsesCopySemantics.ql b/cpp/autosar/src/rules/A12-8-4/MoveConstructorUsesCopySemantics.ql index 4996afd34e..a71d49d844 100644 --- a/cpp/autosar/src/rules/A12-8-4/MoveConstructorUsesCopySemantics.ql +++ b/cpp/autosar/src/rules/A12-8-4/MoveConstructorUsesCopySemantics.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType /** * A literal with no values. diff --git a/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql b/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql index 7f9ced9909..61b00ba852 100644 --- a/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql +++ b/cpp/autosar/src/rules/A14-5-2/NonTemplateMemberDefinedInTemplate.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.TypeUses +import codingstandards.cpp.types.Uses import codingstandards.cpp.Operator predicate templateDefinitionMentionsTypeParameter(Declaration d, TemplateParameter tp) { diff --git a/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql b/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql index a07dbd43f7..af3a00fadb 100644 --- a/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql +++ b/cpp/autosar/src/rules/A7-1-2/VariableMissingConstexpr.ql @@ -15,7 +15,7 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType import codingstandards.cpp.SideEffect import semmle.code.cpp.controlflow.SSA import codingstandards.cpp.Expr diff --git a/cpp/autosar/src/rules/A8-4-7/TriviallyCopyableSmallType.qll b/cpp/autosar/src/rules/A8-4-7/TriviallyCopyableSmallType.qll index be7cd76bd2..09c6cdae69 100644 --- a/cpp/autosar/src/rules/A8-4-7/TriviallyCopyableSmallType.qll +++ b/cpp/autosar/src/rules/A8-4-7/TriviallyCopyableSmallType.qll @@ -1,6 +1,6 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType /** * Get the largest word size, in bytes. Some projects may have multiple different diff --git a/cpp/autosar/src/rules/M0-1-4/SingleUsePODVariable.qll b/cpp/autosar/src/rules/M0-1-4/SingleUsePODVariable.qll index c0a32baba9..8985f7254e 100644 --- a/cpp/autosar/src/rules/M0-1-4/SingleUsePODVariable.qll +++ b/cpp/autosar/src/rules/M0-1-4/SingleUsePODVariable.qll @@ -1,7 +1,7 @@ /** A module providing predicates that support identifying single use non volatile POD variables. */ import cpp -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType import codingstandards.cpp.deadcode.UnusedVariables /** diff --git a/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll b/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll index 4392b598f7..0eaf9f8dfa 100644 --- a/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll +++ b/cpp/cert/src/rules/MEM53-CPP/ManuallyManagedLifetime.qll @@ -1,6 +1,6 @@ import codingstandards.cpp.cert import codingstandards.cpp.Conversion -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType import ManuallyManagedLifetime import semmle.code.cpp.controlflow.Dominance import semmle.code.cpp.dataflow.TaintTracking diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql index 6e3121e46d..5398aa04e1 100644 --- a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql +++ b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql @@ -12,7 +12,7 @@ import cpp import codingstandards.cpp.cert -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType import ManuallyManagedLifetime import semmle.code.cpp.dataflow.TaintTracking import AllocToStaticCastFlow::PathGraph diff --git a/cpp/common/src/codingstandards/cpp/Compatible.qll b/cpp/common/src/codingstandards/cpp/Compatible.qll deleted file mode 100644 index 0f6e2108ff..0000000000 --- a/cpp/common/src/codingstandards/cpp/Compatible.qll +++ /dev/null @@ -1,30 +0,0 @@ -import cpp - -pragma[noinline] -pragma[nomagic] -predicate typesCompatible(Type t1, Type t2) { - t1 = t2 - or - //signed int is same as int ect - t1.(IntegralType).getCanonicalArithmeticType() = t2.(IntegralType).getCanonicalArithmeticType() -} - -predicate parameterTypesIncompatible(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { - f1.getDeclaration() = f2.getDeclaration() and - exists(ParameterDeclarationEntry p1, ParameterDeclarationEntry p2, int i | - p1 = f1.getParameterDeclarationEntry(i) and - p2 = f2.getParameterDeclarationEntry(i) - | - not typesCompatible(p1.getType(), p2.getType()) - ) -} - -predicate parameterNamesIncompatible(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { - f1.getDeclaration() = f2.getDeclaration() and - exists(ParameterDeclarationEntry p1, ParameterDeclarationEntry p2, int i | - p1 = f1.getParameterDeclarationEntry(i) and - p2 = f2.getParameterDeclarationEntry(i) - | - not p1.getName() = p2.getName() - ) -} diff --git a/cpp/common/src/codingstandards/cpp/MatchingParenthesis.qll b/cpp/common/src/codingstandards/cpp/MatchingParenthesis.qll new file mode 100644 index 0000000000..8a28bd0517 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/MatchingParenthesis.qll @@ -0,0 +1,264 @@ +/** + * A library for parsing a string of parentheses and non-parentheses characters. + * + * Simply implement the signature class `InputString` for the set of strings that you wish to parse, + * and then use the `MatchingParenthesis` module which exposes the following classes/predicates: + * - `ParsedRoot`: The root of the parse tree. + * - `ParsedGroup`: Parenthesis groups. The root is also a group, even if not parenthesized. + * - `ParsedText`: All text that is not '(' or ')'. + * - `Tokenized`: A linked list of the tokens in the input string. + * - `textFrom(start, end)`: A function to get the text between two tokens. + * + * The parenthesis AST has functions `getChild(int i)` and `getParent()` to navigate the tree, as + * well as `getRoot()` and `getText()` for `ParsedText` nodes. They also have methods + * `getStartToken()`, `getEndToken()` which are especially useful with the method `textFrom(...)`. + * + * This module can allow for slightly more intelligent interpretation of macro strings, but it has + * limitations. + * - It _only_ handles the parenthesis. + * - It assumes parentheses are matched. + * - It does not handle the case where a parenthesis is inside a string literal. + * - It does not handle the case where a parenthesis is inside a comment. + * + * This module has been moderately optimized, but still it is best to be selective with the set of + * strings you attempt to parse with it. + */ + +import codeql.util.Option + +signature class InputString extends string; + +module MatchingParenthesis { + newtype TTokenType = + TOpenParen() or + TCloseParen() or + TNotParen() + + bindingset[char] + private TTokenType tokenTypeOfChar(string char) { + result = TOpenParen() and char = "(" + or + result = TCloseParen() and char = ")" + } + + private int inputId(Input i) { rank[result](Input inp) = i } + + private newtype TTokenized = + TTokenizerStart(int iid) { iid = inputId(_) } or + TToken(int iid, TTokenized prev, TTokenType token, int occurrence, int endPos) { + exists(string inputStr, int prevEndPos, int prevOccurrence, string char | + iid = inputId(inputStr) and + ( + prev = TTokenizerStart(iid) and prevOccurrence = -1 and prevEndPos = 0 + or + prev = TToken(iid, _, _, prevOccurrence, prevEndPos) + ) and + inputStr.charAt(prevEndPos) = char and + if char = ["(", ")"] + then ( + endPos = prevEndPos + 1 and + token = tokenTypeOfChar(char) and + occurrence = prevOccurrence + 1 + ) else ( + token = TNotParen() and + exists(inputStr.regexpFind("\\(|\\)", prevOccurrence + 1, endPos)) and + occurrence = prevOccurrence + ) + ) + } + + class Tokenized extends TTokenized { + string toString() { + getTokenType() = TOpenParen() and result = "(" + or + getTokenType() = TCloseParen() and result = ")" + or + getTokenType() = TNotParen() and result = "non-parenthesis" + } + + int getInputId() { this = TToken(result, _, _, _, _) } + + TTokenType getTokenType() { this = TToken(_, _, result, _, _) } + + Tokenized getPrevious() { this = TToken(_, result, _, _, _) } + + string getInputString() { + this = TToken(inputId(result), _, _, _, _) or this = TTokenizerStart(inputId(result)) + } + + int getStartPos() { + if exists(getPrevious()) then result = getPrevious().getEndPos() else result = 0 + } + + int getEndPos() { + this = TToken(_, _, _, _, result) + or + this = TTokenizerStart(_) and result = 0 + } + + string getText() { result = textFrom(this, this) } + + Tokenized getNext() { result.getPrevious() = this } + + Tokenized getLast() { + if exists(getNext()) then result = getNext().getLast() else result = this + } + } + + /** + * The root of the parse tree. + */ + class ParsedRoot extends ParsedGroup { + ParsedRoot() { not exists(getParent()) } + + override ParsedRoot getRoot() { result = this } + + override string getDebugText() { result = this.(Tokenized).getInputString() } + } + + /** + * A group of tokens that may be parenthesized. + * + * The `ParseRoot` is the only group that isn't parenthesized. + */ + class ParsedGroup extends Parsed { + ParsedGroup() { isGroup() } + + Parsed getChild(int i) { + result.getParent() = this and + result.getChildIdx() = i + } + } + + /** + * Get the text from the `start` token to the `end` token (inclusive on both ends). + */ + pragma[inline] + string textFrom(Tokenized start, Tokenized end) { + result = start.getInputString().substring(start.getStartPos(), end.getEndPos()) + } + + /** + * All text that is not '(' or ')'. + */ + class ParsedText extends Parsed { + ParsedText() { not isGroup() } + + string getText() { result = textFrom(getStartToken(), getEndToken()) } + } + + /** + * The AST for the input string parsed with matching parenthesis. + */ + class Parsed extends TTokenized { + Option::Option parent; + int childIdx; + boolean isGroup; + + Parsed() { + this.(Tokenized).getTokenType() = TNotParen() and + parseStepAppend(this, parent.asSome(), childIdx) and + isGroup = false + or + this.(Tokenized).getTokenType() = TOpenParen() and + parseStepOpen(this, parent.asSome(), childIdx) and + isGroup = true + or + this = TTokenizerStart(_) and + parent.isNone() and + childIdx = 0 and + isGroup = true + } + + ParsedRoot getRoot() { result = getParent().getRoot() } + + string getInputString() { result = this.(Tokenized).getInputString() } + + /** + * The token that starts this group. + * + * For `ParsedText`, this is the same as the end token. + */ + Tokenized getStartToken() { result = this } + + /** + * The token that endns this group. + * + * For `ParsedText`, this is the same as the start token. If parentheses are not matched, this + * may not have a result. + */ + Tokenized getEndToken() { + this.(Tokenized).getTokenType() = TNotParen() and + result = this + or + this.(Tokenized).getTokenType() = TOpenParen() and + parseStepClose(result, this) + or + this = TTokenizerStart(_) and + result = getStartToken().(Tokenized).getLast() + } + + /** + * The index of this child in the parent group. + */ + int getChildIdx() { result = childIdx } + + ParsedGroup getParent() { result = parent.asSome() } + + predicate isGroup() { isGroup = true } + + string getDebugText() { result = textFrom(getStartToken(), getEndToken()) } + + string toString() { result = this.(Tokenized).toString() } + } + + /** + * Parse open parenthesis and add it to the open group or parse root. Parsing algorithm may not + * behave reliably for mismatched parenthesis. + */ + private predicate parseStepOpen(Tokenized consumeToken, ParsedGroup parent, int childIdx) { + consumeToken.getTokenType() = TOpenParen() and + ( + consumeToken.getPrevious() = parent.getStartToken() and + childIdx = 0 + or + exists(Parsed prevSibling | + prevSibling.getEndToken() = consumeToken.getPrevious() and + childIdx = prevSibling.getChildIdx() + 1 and + parent = prevSibling.getParent() + ) + ) + } + + /** + * Parse raw text that isn't '(' or ')' and add it to the open group or parse root. + */ + private predicate parseStepAppend(Tokenized consumeToken, ParsedGroup parent, int childIdx) { + consumeToken.getTokenType() = TNotParen() and + ( + consumeToken.getPrevious() = parent.getStartToken() and childIdx = 0 + or + exists(Parsed prevSibling | + prevSibling.getEndToken() = consumeToken.getPrevious() and + childIdx = prevSibling.getChildIdx() + 1 and + parent = prevSibling.getParent() + ) + ) + } + + /** + * Parse a close parenthesis to close the currently open group. Parsing algorithm may not behave + * properly for mismatched parenthesis. + */ + private predicate parseStepClose(Tokenized consumeToken, ParsedGroup closed) { + consumeToken.getTokenType() = TCloseParen() and + ( + closed.getStartToken() = consumeToken.getPrevious() + or + exists(Parsed finalChild | + consumeToken.getPrevious() = finalChild.getEndToken() and + finalChild.getParent() = closed + ) + ) + } +} diff --git a/cpp/common/src/codingstandards/cpp/Type.qll b/cpp/common/src/codingstandards/cpp/Type.qll index 42d77b8055..32c139fd89 100644 --- a/cpp/common/src/codingstandards/cpp/Type.qll +++ b/cpp/common/src/codingstandards/cpp/Type.qll @@ -1,96 +1,2 @@ -/** - * A module for representing different `Type`s. - */ - -import cpp - -/** - * A fundamental type, as defined by `[basic.fundamental]`. - */ -class FundamentalType extends BuiltInType { - FundamentalType() { - // A fundamental type is any `BuiltInType` except types indicating errors during extraction, or - // "unknown" types inserted into uninstantiated templates - not this instanceof ErroneousType and - not this instanceof UnknownType - } -} - -/** - * A type that is incomplete. - */ -class IncompleteType extends Class { - IncompleteType() { not hasDefinition() } -} - -/** - * A type that implements the BitmaskType trait. - * https://en.cppreference.com/w/cpp/named_req/BitmaskType - */ -abstract class BitmaskType extends Type { } - -/** - * Holds if `enum` implements required overload `overload` to implement - * the BitmaskType trait. - */ -private predicate isRequiredEnumOverload(Enum enum, Function overload) { - overload.getName().regexpMatch("operator([&|^~]|&=|\\|=)") and - forex(Parameter p | p = overload.getAParameter() | - ( - p.getType() = enum - or - p.getType().(ReferenceType).getBaseType() = enum - ) - ) -} - -private class EnumBitmaskType extends BitmaskType, Enum { - EnumBitmaskType() { - // Implements all the required overload - count(Function overload | isRequiredEnumOverload(this, overload)) = 6 - } -} - -/** - * A type without `const` and `volatile` specifiers. - */ -Type stripSpecifiers(Type type) { - if type instanceof SpecifiedType - then result = stripSpecifiers(type.(SpecifiedType).getBaseType()) - else result = type -} - -signature class PossiblySpecifiedBaseType extends Type; - -/** - * This module defines a class `Type` which holds for types `T` and `const/volatile T` etc. - * - * Similar to `getUnspecifiedType()`, but does not resolve typedefs. Useful for matching - * potentially qualified versions of standard typedef types, such as `const mtx_t`. - * - * Example usage: `someType.(PossiblySpecified::Type).strip()` - */ -module PossiblySpecified { - import cpp as cpp - - final class CppType = cpp::Type; - - class Type extends CppType { - BaseType baseType; - - Type() { baseType = stripSpecifiers(this) } - - BaseType strip() { result = baseType } - } -} - -/** - * Get the precision of an integral type, where precision is defined as the number of bits - * that can be used to represent the numeric value. - * https://wiki.sei.cmu.edu/confluence/display/c/INT35-C.+Use+correct+integer+precisions - */ -int getPrecision(IntegralType type) { - type.isExplicitlyUnsigned() and result = type.getSize() * 8 - or - type.isExplicitlySigned() and result = type.getSize() * 8 - 1 -} +import codingstandards.cpp.types.Type +import codingstandards.cpp.types.Uses \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll b/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll index b3c3d44ff4..b41de3ef9a 100644 --- a/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll +++ b/cpp/common/src/codingstandards/cpp/alertreporting/DeduplicateMacroResults.qll @@ -38,7 +38,7 @@ signature module MacroReportConfigSig { /** * Create a message to describe a `ResultElement` which is not generated by a macro expansion. */ - string getMessageNotInMacro(ResultElement element); + string getMessageNotInMacro(ResultElement element, Locatable optExtraLoc1, string optExtraStr1); } /** @@ -120,7 +120,7 @@ signature module MacroReportConfigSig { * * from Report::ReportResult report * where not excluded(report.getPrimaryElement(), ...) - * select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(), + * select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocatable(), * report.getOptionalPlaceholderMessage() * ``` * @@ -295,7 +295,7 @@ module DeduplicateMacroResults< * To show a report, use the following methods: * - `report.getPrimaryElement()` * - `report.getMessage()` - * - `report.getOptionalPlaceholderLocation()` + * - `report.getOptionalPlaceholderLocatable()` * - `report.getOptionalPlaceholderMessage()` * * The values returned by these methods are configured by the `MacroReportConfigSig` @@ -337,7 +337,7 @@ module DeduplicateMacroResults< or exists(ResultElement def | this = TReportNotInMacro(def) and - result = ReportConfig::getMessageNotInMacro(def) + result = ReportConfig::getMessageNotInMacro(def, _, _) ) } @@ -351,25 +351,25 @@ module DeduplicateMacroResults< this = TReportNotInMacro(result) } - Location getOptionalPlaceholderLocation() { + Locatable getOptionalPlaceholderLocatable() { exists(PrimaryMacroDifferentResultElementInAllInvocations def | this = TReportMacroResultWithVariedName(def) and - result = def.getExampleResultElement().getLocation() + result = def.getExampleResultElement() ) or exists(PrimaryMacroSameResultElementInAllInvocations def | this = TReportMacroResultWithSameName(def) and - result = def.getLocation() + result = def ) or exists(IsolatedMacroExpansionWithResultElement def | this = TReportIsolatedMacroResult(def) and - result = def.getMacro().getLocation() + result = def.getMacro() ) or exists(ResultElement def | this = TReportNotInMacro(def) and - result = def.getLocation() + exists(ReportConfig::getMessageNotInMacro(def, result, _)) ) } @@ -379,14 +379,16 @@ module DeduplicateMacroResults< result = Config::describe(def.getExampleResultElement()) ) or - ( - this = TReportMacroResultWithSameName(_) or - this = TReportNotInMacro(_) - ) and + this = TReportMacroResultWithSameName(_) and result = "(ignored)" or this = TReportIsolatedMacroResult(_) and result = getMacro().getName() + or + exists(ResultElement def | + this = TReportNotInMacro(def) and + exists(ReportConfig::getMessageNotInMacro(def, _, result)) + ) } Macro getMacro() { diff --git a/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll b/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll index 60e732873a..94ae16ec4f 100644 --- a/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll +++ b/cpp/common/src/codingstandards/cpp/deadcode/UnusedObjects.qll @@ -57,8 +57,10 @@ module ReportDeadObjectConfig implements MacroReportConfigSig; + +/** + * Signature module for handling various kinds of potentially recursive type equivalence using the + * module `TypeEquivalence`. + * + * The various kinds of types to be compared all have an overridable predicate with default + * behavior here, and a boolean flag that indicates whether the base types are equal. This pattern + * is used because we can't make a default implementation of a predicate such as + * `equalPointerTypes` that recurses into the `TypeEquivalence` module. Instead, the + * `TypeEquivalence` module drives all of the recursion, and these predicates take the result of + * that recursion and use it to determine whether the types are equivalent. + */ +signature module TypeEquivalenceSig { + /** + * Whether two leaf types are equivalent, such as `int`s and structs. By default, we assume only + * that types are equal to themselves and that equivalent arithmetic types are equal. + */ + bindingset[t1, t2] + default predicate equalLeafTypes(Type t1, Type t2) { + t1 = t2 + or + t1.(IntegralType).getCanonicalArithmeticType() = t2.(IntegralType).getCanonicalArithmeticType() + } + + /** + * A predicate to arbitrarily override the default behavior of the `TypeEquivalence` module, + * including preventing recursion. If this predicate holds for a pair of types, then + * `TypeEquivalence::equalTypes()` holds only if `areEqual` is true. + */ + bindingset[t1, t2] + default predicate overrideTypeComparison(Type t1, Type t2, Boolean areEqual) { none() } + + /** + * Whether two specified types are equivalent. By default, we assume that the specifier sets are + * exactly the same, and the inner types also match. + */ + bindingset[t1, t2] + default predicate equalSpecifiedTypes( + SpecifiedType t1, SpecifiedType t2, Boolean unspecifiedTypesEqual + ) { + specifiersMatchExactly(t1, t2) and + unspecifiedTypesEqual = true + } + + /** + * Whether two specified types are equivalent. By default, we only require that the base (pointed + * to) types match. + */ + bindingset[t1, t2] + default predicate equalPointerTypes(PointerType t1, PointerType t2, Boolean baseTypesEqual) { + baseTypesEqual = true + } + + /** + * Whether two array types are equivalent. By default, we only require that the element types and + * array sizes match. + */ + bindingset[t1, t2] + default predicate equalArrayTypes(ArrayType t1, ArrayType t2, Boolean baseTypesEqual) { + t1.getSize() = t2.getSize() and + baseTypesEqual = true + } + + /** + * Whether two reference types are equivalent. By default, we only require that the base types match. + */ + bindingset[t1, t2] + default predicate equalReferenceTypes(ReferenceType t1, ReferenceType t2, Boolean baseTypesEqual) { + baseTypesEqual = true + } + + /** + * Whether typedefs should be resolved before comparison. By default, we assume `TypeEquivalence` + * should resolve typedefs before comparison. + */ + default predicate resolveTypedefs() { any() } + + /** + * Whether two typedef types are equivalent. + * + * This predicate is only used if `resolveTypedefs()` is false. If so, then we assume two + * typedefs are the same if they have the same name and their base types are equal. + */ + bindingset[t1, t2] + default predicate equalTypedefTypes(TypedefType t1, TypedefType t2, Boolean baseTypesEqual) { + t1.getName() = t2.getName() and + baseTypesEqual = true + } + + /** + * Whether two routine types are equivalent. By default, we only require that the return types and + * parameter types match. + */ + bindingset[t1, t2] + default predicate equalRoutineTypes( + RoutineType t1, RoutineType t2, Boolean returnTypeEqual, Boolean parameterTypesEqual + ) { + returnTypeEqual = true and parameterTypesEqual = true + } + + /** + * Whether two function pointer/reference types are equivalent. By default, we only require that + * the return types and parameter types match. + */ + bindingset[t1, t2] + default predicate equalFunctionPointerIshTypes( + FunctionPointerIshType t1, FunctionPointerIshType t2, Boolean returnTypeEqual, + Boolean parameterTypesEqual + ) { + returnTypeEqual = true and parameterTypesEqual = true + } +} + +/** + * The default equivalence behavior for the `TypeEquivalence` module. + */ +module DefaultEquivalence implements TypeEquivalenceSig { } + +/** + * A signature class used to restrict the set of types considered by `TypeEquivalence`, for + * performance reasons. + */ +signature class TypeSubset extends Type; + +/** + * A module to check the equivalence of two types, as defined by the provided `TypeEquivalenceSig`. + * + * For performance reasons, this module is designed to be used with a `TypeSubset` that restricts + * the set of considered types. All types reachable (in the type graph) from a type in the subset + * will be considered. (See `RelevantType`.) + * + * To use this module, define a `TypeEquivalenceSig` module and implement a subset of `Type` that + * selects the relevant root types to be considered. Then use the predicate `equalTypes(a, b)`. + */ +module TypeEquivalence { + /** + * Check whether two types are equivalent, as defined by the `TypeEquivalenceSig` module. + */ + predicate equalTypes(RelevantType t1, RelevantType t2) { + if Config::overrideTypeComparison(t1, t2, _) + then Config::overrideTypeComparison(t1, t2, true) + else + if t1 instanceof TypedefType and Config::resolveTypedefs() + then equalTypes(t1.(TypedefType).getBaseType(), t2) + else + if t2 instanceof TypedefType and Config::resolveTypedefs() + then equalTypes(t1, t2.(TypedefType).getBaseType()) + else ( + not t1 instanceof DerivedType and + not t2 instanceof DerivedType and + not t1 instanceof TypedefType and + not t2 instanceof TypedefType and + LeafEquiv::getEquivalenceClass(t1) = LeafEquiv::getEquivalenceClass(t2) + or + equalDerivedTypes(t1, t2) + or + equalTypedefTypes(t1, t2) + or + equalFunctionTypes(t1, t2) + ) + } + + /** + * A type that is either part of the type subset, or that is reachable from a type in the subset. + */ + private class RelevantType instanceof Type { + RelevantType() { exists(T t | typeGraph*(t, this)) } + + string toString() { result = this.(Type).toString() } + } + + private class RelevantDerivedType extends RelevantType instanceof DerivedType { + RelevantType getBaseType() { result = this.(DerivedType).getBaseType() } + } + + private class RelevantFunctionType extends RelevantType instanceof FunctionType { + RelevantType getReturnType() { result = this.(FunctionType).getReturnType() } + + RelevantType getParameterType(int i) { result = this.(FunctionType).getParameterType(i) } + } + + private class RelevantTypedefType extends RelevantType instanceof TypedefType { + RelevantType getBaseType() { result = this.(TypedefType).getBaseType() } + } + + private module LeafEquiv = QlBuiltins::EquivalenceRelation; + + private predicate equalLeafRelation(RelevantType t1, RelevantType t2) { + Config::equalLeafTypes(t1, t2) + } + + private RelevantType unspecify(SpecifiedType t) { + // This subtly and importantly handles the complicated cases of typedefs. Under most scenarios, + // if we see a typedef in `equalTypes()` we can simply get the base type and continue. However, + // there is an exception if we have a specified type that points to a typedef that points to + // another specified type. In this case, `SpecifiedType::getASpecifier()` will return all of + // specifiers, not just those above the TypedefType, and `stripTopLevelSpecifiers` will return + // the innermost type that is not a TypedefType or a SpecifiedType, which is what we want, as + // all specifiers have already been accounted for when we visit the outermost `SpecifiedType`. + if Config::resolveTypedefs() + then result = t.(SpecifiedType).stripTopLevelSpecifiers() + else result = t.(SpecifiedType).getBaseType() + } + + bindingset[t1, t2] + private predicate equalDerivedTypes(RelevantDerivedType t1, RelevantDerivedType t2) { + exists(Boolean baseTypesEqual | + (baseTypesEqual = true implies equalTypes(t1.getBaseType(), t2.getBaseType())) and + ( + Config::equalPointerTypes(t1, t2, baseTypesEqual) + or + Config::equalArrayTypes(t1, t2, baseTypesEqual) + or + Config::equalReferenceTypes(t1, t2, baseTypesEqual) + ) + ) + or + exists(Boolean unspecifiedTypesEqual | + // Note that this case is different from the above, in that we don't merely get the base + // type (as that could be a TypedefType that points to another SpecifiedType). We need to + // unspecify the type to see if the base types are equal. + (unspecifiedTypesEqual = true implies equalTypes(unspecify(t1), unspecify(t2))) and + Config::equalSpecifiedTypes(t1, t2, unspecifiedTypesEqual) + ) + } + + bindingset[t1, t2] + private predicate equalFunctionTypes(RelevantFunctionType t1, RelevantFunctionType t2) { + exists(Boolean returnTypeEqual, Boolean parameterTypesEqual | + (returnTypeEqual = true implies equalTypes(t1.getReturnType(), t2.getReturnType())) and + ( + parameterTypesEqual = true + implies + forall(int i | exists([t1, t2].getParameterType(i)) | + equalTypes(t1.getParameterType(i), t2.getParameterType(i)) + ) + ) and + ( + Config::equalRoutineTypes(t1, t2, returnTypeEqual, parameterTypesEqual) + or + Config::equalFunctionPointerIshTypes(t1, t2, returnTypeEqual, parameterTypesEqual) + ) + ) + } + + bindingset[t1, t2] + private predicate equalTypedefTypes(RelevantTypedefType t1, RelevantTypedefType t2) { + exists(Boolean baseTypesEqual | + (baseTypesEqual = true implies equalTypes(t1.getBaseType(), t2.getBaseType())) and + Config::equalTypedefTypes(t1, t2, baseTypesEqual) + ) + } +} + +module FunctionDeclarationTypeEquivalence { + predicate equalReturnTypes(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + TypeEquivalence::equalTypes(f1.getType(), f2.getType()) + } + + predicate equalParameterTypes(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + f1.getDeclaration() = f2.getDeclaration() and + forall(int i | exists([f1, f2].getParameterDeclarationEntry(i)) | + TypeEquivalence::equalTypes(f1.getParameterDeclarationEntry(i) + .getType(), f2.getParameterDeclarationEntry(i).getType()) + ) + } +} + +/** + * Convenience class to reduce the awkwardness of how `RoutineType` and `FunctionPointerIshType` + * don't have a common ancestor. + */ +private class FunctionType extends Type { + FunctionType() { this instanceof RoutineType or this instanceof FunctionPointerIshType } + + Type getReturnType() { + result = this.(RoutineType).getReturnType() or + result = this.(FunctionPointerIshType).getReturnType() + } + + Type getParameterType(int i) { + result = this.(RoutineType).getParameterType(i) or + result = this.(FunctionPointerIshType).getParameterType(i) + } +} +/* + * predicate typesCompatibleImpl(Type t1, Type t2) { + * // A type is compatible with itself + * t1 = t2 + * or + * // All specifiers must match, but the order does not matter: + * ( + * t1 instanceof SpecifiedType and + * t2 instanceof SpecifiedType + * ) and + * specifiersMatchExactly(t1, t2) and + * typesCompatibleImpl(t1.stripTopLevelSpecifiers(), t2.stripTopLevelSpecifiers()) + * or + * // Identically qualified pointers are compatible if they point to compatible types. + * typesCompatibleImpl(t1.(PointerType).getBaseType(), t2.(PointerType).getBaseType()) + * or + * // Array objects are compatible if they have a compatible element type. If both have a constant + * // size then that size must match. + * typesCompatibleImpl(t1.(ArrayType).getBaseType(), t2.(ArrayType).getBaseType()) and + * count(int i | i = [t1, t2].(ArrayType).getSize()) < 2 + * or + * // Enum types are compatible with one of char, int, or signed int, but the implementation + * // decides. + * [t1, t2] instanceof Enum and + * ([t1, t2] instanceof CharType or [t1, t2] instanceof IntType) + * or + * // `int` is the same as `signed`, `signed int`, while `unsigned` is the same as `unsigned int`. + * t1.(IntegralType).getCanonicalArithmeticType() = t2.(IntegralType).getCanonicalArithmeticType() + * or + * // Function types are compatible if they have the same return type and compatible parameters. + * // Technically, variadic functions are have special behavior not covered here. + * exists(RoutineType f1, RoutineType f2 | f1 = t1 and f2 = t2 | + * typesCompatibleImpl(f1.getReturnType(), f2.getReturnType()) and + * forall(int i | exists([f1, f2].getParameterType(i)) | + * typesCompatibleImpl(f1.getParameterType(i), f2.getParameterType(i)) + * ) + * ) + * or + * // Function pointer types should be covered by `PointerType` and `RoutineType` above, but that is + * // not how they are implemented in CodeQL. + * exists(FunctionPointerIshType f1, FunctionPointerIshType f2 | f1 = t1 and f2 = t2 | + * typesCompatibleImpl(f1.getReturnType(), f2.getReturnType()) and + * forall(int i | exists([f1, f2].getParameterType(i)) | + * typesCompatibleImpl(f1.getParameterType(i), f2.getParameterType(i)) + * ) + * ) + * } + */ + diff --git a/cpp/common/src/codingstandards/cpp/types/Graph.qll b/cpp/common/src/codingstandards/cpp/types/Graph.qll new file mode 100644 index 0000000000..70c51a40ba --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/types/Graph.qll @@ -0,0 +1,15 @@ +import cpp + +predicate typeGraph(Type t, Type refersTo) { + refersTo = t.(DerivedType).getBaseType() + or + refersTo = t.(RoutineType).getReturnType() + or + refersTo = t.(RoutineType).getAParameterType() + or + refersTo = t.(FunctionPointerIshType).getReturnType() + or + refersTo = t.(FunctionPointerIshType).getAParameterType() + or + refersTo = t.(TypedefType).getBaseType() +} diff --git a/cpp/common/src/codingstandards/cpp/types/LvalueConversion.qll b/cpp/common/src/codingstandards/cpp/types/LvalueConversion.qll new file mode 100644 index 0000000000..252e783438 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/types/LvalueConversion.qll @@ -0,0 +1,38 @@ +import cpp + +/** + * Get the type of an lvalue after lvalue conversion. + * + * This will return the type itself if no conversion is performed. + */ +Type getLvalueConverted(Type t) { + if exists(performLvalueConversion(t, _)) + then result = performLvalueConversion(t, _) + else result = t +} + +/** + * Perform lvalue conversion on a type, allowing for a description of why the type was converted + * if it was. + * + * Does not return a value if no lvalue conversion was performed. + * + * Warning: This predicate may not return a result if the resulting type is not in the database. + * For convenience, this is accepted here, otherwise we would have to create a new type to return + * that wouldn't implement the type APIs and likely wouldn't be very useful. + */ +Type performLvalueConversion(Type t, string reason) { + result.(PointerType).getBaseType() = t.(ArrayType).getBaseType() and + reason = "array-to-pointer decay" + or + t instanceof RoutineType and + result.(PointerType).getBaseType() = t and + reason = "function-to-function-pointer decay" + or + isObjectType(t) and + exists(t.getASpecifier()) and + result = t.stripTopLevelSpecifiers() and + reason = "qualifiers removed" +} + +private predicate isObjectType(Type t) { not t.stripTopLevelSpecifiers() instanceof PointerType } diff --git a/cpp/common/src/codingstandards/cpp/Pointers.qll b/cpp/common/src/codingstandards/cpp/types/Pointers.qll similarity index 100% rename from cpp/common/src/codingstandards/cpp/Pointers.qll rename to cpp/common/src/codingstandards/cpp/types/Pointers.qll diff --git a/cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll b/cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll new file mode 100644 index 0000000000..e9804c29c4 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll @@ -0,0 +1,45 @@ +import codingstandards.cpp.types.LvalueConversion +import codingstandards.cpp.types.Compatible + +module SimpleAssignment { + final private class FinalType = Type; + + private class RelevantType extends FinalType { + RelevantType() { exists(T t | typeGraph*(t, this) or typeGraph(getLvalueConverted(t), this)) } + + string toString() { result = "relevant type" } + } + + /** + * Whether a pair of qualified or unqualified pointer types satisfy the simple assignment + * constraints from 6.5.16.1. + * + * There are additional constraints not implemented here involving one or more arithmetic types. + */ + predicate satisfiesSimplePointerAssignment(RelevantType left, RelevantType right) { + simplePointerAssignmentImpl(getLvalueConverted(left), right) + } + + /** + * Implementation of 6.5.16.1 for a pair of pointer types, that assumes lvalue conversion has been + * performed on the left operand. + */ + private predicate simplePointerAssignmentImpl(RelevantType left, RelevantType right) { + exists(RelevantType leftBase, RelevantType rightBase | + // The left operand has atomic, qualified, or unqualified pointer type: + leftBase = left.stripTopLevelSpecifiers().(PointerType).getBaseType() and + rightBase = right.stripTopLevelSpecifiers().(PointerType).getBaseType() and + ( + // and both operands are pointers to qualified or unqualified versions of compatible types: + TypeEquivalence::equalTypes(leftBase + .stripTopLevelSpecifiers(), rightBase.stripTopLevelSpecifiers()) + or + // or one operand is a pointer to a qualified or unqualified version of void + [leftBase, rightBase].stripTopLevelSpecifiers() instanceof VoidType + ) and + // and the type pointed to by the left has all the qualifiers of the type pointed to by the + // right: + forall(Specifier s | s = rightBase.getASpecifier() | s = leftBase.getASpecifier()) + ) + } +} diff --git a/cpp/common/src/codingstandards/cpp/TrivialType.qll b/cpp/common/src/codingstandards/cpp/types/TrivialType.qll similarity index 100% rename from cpp/common/src/codingstandards/cpp/TrivialType.qll rename to cpp/common/src/codingstandards/cpp/types/TrivialType.qll diff --git a/cpp/common/src/codingstandards/cpp/types/Type.qll b/cpp/common/src/codingstandards/cpp/types/Type.qll new file mode 100644 index 0000000000..42d77b8055 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/types/Type.qll @@ -0,0 +1,96 @@ +/** + * A module for representing different `Type`s. + */ + +import cpp + +/** + * A fundamental type, as defined by `[basic.fundamental]`. + */ +class FundamentalType extends BuiltInType { + FundamentalType() { + // A fundamental type is any `BuiltInType` except types indicating errors during extraction, or + // "unknown" types inserted into uninstantiated templates + not this instanceof ErroneousType and + not this instanceof UnknownType + } +} + +/** + * A type that is incomplete. + */ +class IncompleteType extends Class { + IncompleteType() { not hasDefinition() } +} + +/** + * A type that implements the BitmaskType trait. + * https://en.cppreference.com/w/cpp/named_req/BitmaskType + */ +abstract class BitmaskType extends Type { } + +/** + * Holds if `enum` implements required overload `overload` to implement + * the BitmaskType trait. + */ +private predicate isRequiredEnumOverload(Enum enum, Function overload) { + overload.getName().regexpMatch("operator([&|^~]|&=|\\|=)") and + forex(Parameter p | p = overload.getAParameter() | + ( + p.getType() = enum + or + p.getType().(ReferenceType).getBaseType() = enum + ) + ) +} + +private class EnumBitmaskType extends BitmaskType, Enum { + EnumBitmaskType() { + // Implements all the required overload + count(Function overload | isRequiredEnumOverload(this, overload)) = 6 + } +} + +/** + * A type without `const` and `volatile` specifiers. + */ +Type stripSpecifiers(Type type) { + if type instanceof SpecifiedType + then result = stripSpecifiers(type.(SpecifiedType).getBaseType()) + else result = type +} + +signature class PossiblySpecifiedBaseType extends Type; + +/** + * This module defines a class `Type` which holds for types `T` and `const/volatile T` etc. + * + * Similar to `getUnspecifiedType()`, but does not resolve typedefs. Useful for matching + * potentially qualified versions of standard typedef types, such as `const mtx_t`. + * + * Example usage: `someType.(PossiblySpecified::Type).strip()` + */ +module PossiblySpecified { + import cpp as cpp + + final class CppType = cpp::Type; + + class Type extends CppType { + BaseType baseType; + + Type() { baseType = stripSpecifiers(this) } + + BaseType strip() { result = baseType } + } +} + +/** + * Get the precision of an integral type, where precision is defined as the number of bits + * that can be used to represent the numeric value. + * https://wiki.sei.cmu.edu/confluence/display/c/INT35-C.+Use+correct+integer+precisions + */ +int getPrecision(IntegralType type) { + type.isExplicitlyUnsigned() and result = type.getSize() * 8 + or + type.isExplicitlySigned() and result = type.getSize() * 8 - 1 +} diff --git a/cpp/common/src/codingstandards/cpp/TypeUses.qll b/cpp/common/src/codingstandards/cpp/types/Uses.qll similarity index 100% rename from cpp/common/src/codingstandards/cpp/TypeUses.qll rename to cpp/common/src/codingstandards/cpp/types/Uses.qll diff --git a/cpp/common/src/codingstandards/cpp/VariablyModifiedTypes.qll b/cpp/common/src/codingstandards/cpp/types/VariablyModifiedTypes.qll similarity index 100% rename from cpp/common/src/codingstandards/cpp/VariablyModifiedTypes.qll rename to cpp/common/src/codingstandards/cpp/types/VariablyModifiedTypes.qll diff --git a/cpp/common/test/guideline_recategorizations/DisappliedQuery.ql b/cpp/common/test/guideline_recategorizations/DisappliedQuery.ql index 0254eca9bd..58ba3239e0 100644 --- a/cpp/common/test/guideline_recategorizations/DisappliedQuery.ql +++ b/cpp/common/test/guideline_recategorizations/DisappliedQuery.ql @@ -10,7 +10,7 @@ import cpp import codingstandards.cpp.CodingStandards -import codingstandards.cpp.TypeUses +import codingstandards.cpp.types.Uses import codingstandards.cpp.exclusions.cpp.RuleMetadata from UserType ut, string reason diff --git a/cpp/common/test/library/codingstandards/cpp/trivialtypes/LiteralType.ql b/cpp/common/test/library/codingstandards/cpp/trivialtypes/LiteralType.ql index 4d0f8567d0..e7a1d5ebd3 100644 --- a/cpp/common/test/library/codingstandards/cpp/trivialtypes/LiteralType.ql +++ b/cpp/common/test/library/codingstandards/cpp/trivialtypes/LiteralType.ql @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType from Type t where diff --git a/cpp/common/test/library/codingstandards/cpp/trivialtypes/TrivialType.ql b/cpp/common/test/library/codingstandards/cpp/trivialtypes/TrivialType.ql index a85fcf5676..edbfbe5303 100644 --- a/cpp/common/test/library/codingstandards/cpp/trivialtypes/TrivialType.ql +++ b/cpp/common/test/library/codingstandards/cpp/trivialtypes/TrivialType.ql @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType from Type t where diff --git a/cpp/common/test/library/codingstandards/cpp/trivialtypes/TriviallyCopyableType.ql b/cpp/common/test/library/codingstandards/cpp/trivialtypes/TriviallyCopyableType.ql index 3b3f498796..1667372f4b 100644 --- a/cpp/common/test/library/codingstandards/cpp/trivialtypes/TriviallyCopyableType.ql +++ b/cpp/common/test/library/codingstandards/cpp/trivialtypes/TriviallyCopyableType.ql @@ -1,5 +1,5 @@ import cpp -import codingstandards.cpp.TrivialType +import codingstandards.cpp.types.TrivialType from TriviallyCopyableClass t select t diff --git a/rule_packages/c/Generics.json b/rule_packages/c/Generics.json new file mode 100644 index 0000000000..1183bdc709 --- /dev/null +++ b/rule_packages/c/Generics.json @@ -0,0 +1,194 @@ +{ + "MISRA-C-2012": { + "RULE-23-1": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "A generic selection should only be expanded from a macro.", + "kind": "problem", + "name": "A generic selection should only be expanded from a macro", + "precision": "very-high", + "severity": "warning", + "short_name": "GenericSelectionNotExpandedFromAMacro", + "tags": [ + "maintainability", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "A generic selection should depend on the type of a macro argument.", + "kind": "problem", + "name": "A generic selection should depend on the type of a macro argument", + "precision": "high", + "severity": "warning", + "short_name": "GenericSelectionDoesntDependOnMacroArgument", + "tags": [ + "correctness", + "maintainability", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "A generic selection should only be expanded from a macro" + }, + "RULE-23-2": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "A generic selection that is not expanded from a macro shall not contain potential side effects in the controlling expression.", + "kind": "problem", + "name": "A generic selection shall not contain side-effects if it is not expanded from a macro", + "precision": "high", + "severity": "warning", + "short_name": "GenericSelectionNotFromMacroWithSideEffects", + "tags": [ + "maintainability", + "external/misra/c/2012/amendment3" + ] + } + ], + "implementation_scope": { + "items": [ + "Due to limited information in the CodeQL database for macro argument expansions, this implementation reports generics not of the form `_Generic((X)` where all invocations of that generic contain a side effect in the controlling expression." + ] + }, + "title": "A generic selection that is not expanded from a macro shall not contain potential side effects in the controlling expression" + }, + "RULE-23-3": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "A generic selection should contain at least one non-default association.", + "kind": "problem", + "name": "A generic selection should contain at least one non-default association", + "precision": "very-high", + "severity": "warning", + "short_name": "GenericWithoutNonDefaultAssociation", + "tags": [ + "correctness", + "maintainability", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "A generic selection should contain at least one non-default association" + }, + "RULE-23-4": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Generic selections undergo lvalue conversion before type comparison, leading to certain types being impossible to select.", + "kind": "problem", + "name": "A generic association shall list an appropriate type", + "precision": "very-high", + "severity": "error", + "short_name": "GenericAssociationWithUnselectableType", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "A generic association shall list an appropriate type" + }, + "RULE-23-5": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Pointer types in a generic selection do not undergo pointer conversions and should not counterintuitively fall through to the default association.", + "kind": "problem", + "name": "A generic selection should not depend on implicit pointer type conversion", + "precision": "very-high", + "severity": "warning", + "short_name": "DangerousDefaultSelectionForPointerInGeneric", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "A generic selection should not depend on implicit pointer type conversion" + }, + "RULE-23-6": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "The controlling expression of a generic selection shall have an essential type that matches its standard type.", + "kind": "problem", + "name": "The controlling expression of a generic selection shall have an essential type that matches its standard type", + "precision": "high", + "severity": "error", + "short_name": "GenericExpressionWithIncorrectEssentialType", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "implementation_scope": { + "items": [ + "The CodeQL extractor will expand character literals passed into macros into integer literals, and therefore the essential type system for character literals will not necessarily be analyzed correctly." + ] + }, + "title": "The controlling expression of a generic selection shall have an essential type that matches its standard type" + }, + "RULE-23-7": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "A generic selection that is expanded from a macro should evaluate its argument only once.", + "kind": "problem", + "name": "A generic selection that is expanded from a macro should evaluate its argument only once", + "precision": "medium", + "severity": "warning", + "short_name": "InvalidGenericMacroArgumentEvaluation", + "tags": [ + "correctness", + "maintainability", + "external/misra/c/2012/amendment3" + ] + } + ], + "implementation_scope": { + "items": [ + "Due to limited information in the CodeQL database for macro argument expansions, this implementation performs string matching on the macro parameters against the macro body to determine where parameters are expanded. If text indicating a nonevaluated context such as sizeof() or _Alignof() appear, there will be no positive result." + ] + }, + "title": "A generic selection that is expanded from a macro should evaluate its argument only once" + }, + "RULE-23-8": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "A default association shall appear as either the first or the last association of a generic selection", + "kind": "problem", + "name": "A default association shall appear as either the first or the last association of a generic", + "precision": "very-high", + "severity": "warning", + "short_name": "DefaultGenericSelectionNotFirstOrLast", + "tags": [ + "maintainability", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "A default association shall appear as either the first or the last association of a generic selection" + } + } +} \ No newline at end of file From cec1948777ab22388c622f460e1dfde9577f66d9 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 9 Mar 2025 23:05:52 -0700 Subject: [PATCH 287/628] Use clang-format v11, which is closer to v14 installed on ci/cd --- c/misra/test/rules/RULE-23-1/test.c | 26 +-- c/misra/test/rules/RULE-23-2/test.c | 28 +-- c/misra/test/rules/RULE-23-3/test.c | 16 +- c/misra/test/rules/RULE-23-4/test.c | 70 +++---- c/misra/test/rules/RULE-23-5/test.c | 301 ++++++++++++++-------------- c/misra/test/rules/RULE-23-6/test.c | 20 +- c/misra/test/rules/RULE-23-7/test.c | 57 +++--- c/misra/test/rules/RULE-23-8/test.c | 20 +- 8 files changed, 270 insertions(+), 268 deletions(-) diff --git a/c/misra/test/rules/RULE-23-1/test.c b/c/misra/test/rules/RULE-23-1/test.c index f27541dd38..c7d33b1a70 100644 --- a/c/misra/test/rules/RULE-23-1/test.c +++ b/c/misra/test/rules/RULE-23-1/test.c @@ -1,25 +1,25 @@ // NON_COMPLIANT: -#define M1 _Generic(1, int: 1) +#define M1 _Generic(1, int : 1) // NON_COMPLIANT: -#define M2(X) _Generic(1, int: X) +#define M2(X) _Generic(1, int : X) // COMPLIANT: -#define M3(X) _Generic((X), int: 1) +#define M3(X) _Generic((X), int : 1) // COMPLIANT: -#define M4(X) _Generic((X), int: 1) +#define M4(X) _Generic((X), int : 1) // COMPLIANT: -#define M5(X) _Generic((X + X), int: 1) +#define M5(X) _Generic((X + X), int : 1) int f1(int a, int b); // COMPLIANT: -#define M6(X) _Generic(f(1, (X)), int: 1) -#define M7(X) 1 + _Generic((X), int: 1) +#define M6(X) _Generic(f(1, (X)), int : 1) +#define M7(X) 1 + _Generic((X), int : 1) // COMPLIANT: -#define M8(X) g(_Generic((X), int: 1)) +#define M8(X) g(_Generic((X), int : 1)) // NON_COMPLIANT: -#define M9(X) g(_Generic((Y), int: 1)) +#define M9(X) g(_Generic((Y), int : 1)) void f2() { - _Generic(1, int: 1); // NON_COMPLIANT - M1; // NON_COMPLIANT - M2(1); // NON_COMPLIANT - M3(1); // COMPLIANT + _Generic(1, int : 1); // NON_COMPLIANT + M1; // NON_COMPLIANT + M2(1); // NON_COMPLIANT + M3(1); // COMPLIANT } diff --git a/c/misra/test/rules/RULE-23-2/test.c b/c/misra/test/rules/RULE-23-2/test.c index 6a25e15189..9e4c6ca6b2 100644 --- a/c/misra/test/rules/RULE-23-2/test.c +++ b/c/misra/test/rules/RULE-23-2/test.c @@ -1,30 +1,30 @@ -#define M1(X) _Generic((X), int: 1) +#define M1(X) _Generic((X), int : 1) // NON_COMPLIANT: -#define M2(X) _Generic((X)++, int: 1) +#define M2(X) _Generic((X)++, int : 1) // NON_COMPLIANT: -#define M3(X) _Generic(l1++, int: (X)) +#define M3(X) _Generic(l1++, int : (X)) // COMPLIANT: #define M3_WRAPPER(X) M3(X) -#define M4(X) _Generic((X)(), int: 1) +#define M4(X) _Generic((X)(), int : 1) void f1() { int l1; - _Generic(1, int: 1); // COMPLIANT - M1(1); // COMPLIANT - _Generic(l1, int: 1); // COMPLIANT - M1(l1); // COMPLIANT + _Generic(1, int : 1); // COMPLIANT + M1(1); // COMPLIANT + _Generic(l1, int : 1); // COMPLIANT + M1(l1); // COMPLIANT _Generic(l1++, - int: 1); // COMPLIANT: side effect is not from a macro argument. - M1(l1++); // COMPLIANT - M2(l1); // NON-COMPLIANT: at macro definition - M3(1); // NON-COMPLIANT: at macro definition - M3_WRAPPER(1); // NON-COMPLIANT: at definition of M3 + int : 1); // COMPLIANT: side effect is not from a macro argument. + M1(l1++); // COMPLIANT + M2(l1); // NON-COMPLIANT: at macro definition + M3(1); // NON-COMPLIANT: at macro definition + M3_WRAPPER(1); // NON-COMPLIANT: at definition of M3 } int g1; @@ -41,7 +41,7 @@ void f2() { #define M5(X) \ static volatile l##X; \ - _Generic(l##X, int: 1) + _Generic(l##X, int : 1) void f3() { M5(a); // NON-COMPLIANT diff --git a/c/misra/test/rules/RULE-23-3/test.c b/c/misra/test/rules/RULE-23-3/test.c index d3f093f242..616c14bc80 100644 --- a/c/misra/test/rules/RULE-23-3/test.c +++ b/c/misra/test/rules/RULE-23-3/test.c @@ -1,20 +1,20 @@ // NON-COMPLIANT -#define M1 _Generic(1, default: 1); +#define M1 _Generic(1, default : 1); // COMPLIANT -#define M2 _Generic(1, int: 1); +#define M2 _Generic(1, int : 1); // COMPLIANT -#define M3 _Generic(1, int: 1, default: 1); +#define M3 _Generic(1, int : 1, default : 1); // COMPLIANT -#define M4 _Generic(1, int: 1, long: 1); +#define M4 _Generic(1, int : 1, long : 1); void f() { // Invalid generics: // _Generic(1); // _Generic(1, void: 1); - _Generic(1, default: 1); // NON-COMPLIANT - _Generic(1, int: 1); // COMPLIANT - _Generic(1, int: 1, default: 1); // COMPLIANT - _Generic(1, int: 1, long: 1); // COMPLIANT + _Generic(1, default : 1); // NON-COMPLIANT + _Generic(1, int : 1); // COMPLIANT + _Generic(1, int : 1, default : 1); // COMPLIANT + _Generic(1, int : 1, long : 1); // COMPLIANT M1; M2; diff --git a/c/misra/test/rules/RULE-23-4/test.c b/c/misra/test/rules/RULE-23-4/test.c index 135ab4d0f7..cfef26318c 100644 --- a/c/misra/test/rules/RULE-23-4/test.c +++ b/c/misra/test/rules/RULE-23-4/test.c @@ -7,41 +7,41 @@ union empty_union {}; void f() { _Generic(1, - int: 1, // COMPLIANT - const int: 1, // NON-COMPLIANT - volatile int: 1, // NON-COMPLIANT - _Atomic int: 1, // NON-COMPLIANT - int *: 1, // COMPLIANT - int const *: 1, // COMPLIANT - const volatile int: 1, // NON-COMPLIANT - int volatile const *: 1, // COMPLIANT - struct {}: 1, // NON-COMPLIANT - struct {} *: 1, // NON-COMPLIANT - empty_struct_t: 1, // COMPLIANT - struct empty_struct: 1, // COMPLIANT - empty_struct_t *: 1, // COMPLIANT - struct empty_struct *: 1, // COMPLIANT - union {}: 1, // NON-COMPLIANT - union {} *: 1, // NON-COMPLIANT - empty_union_t: 1, // COMPLIANT - union empty_union: 1, // COMPLIANT - empty_union_t *: 1, // COMPLIANT - union empty_union *: 1, // COMPLIANT - // int[]: 1, // compile error - int[3]: 1, // NON-COMPLIANT - int(*)[3]: 1, // COMPLIANT: pointer to array OK - // int (int*): 1, // compile error - int (*)(int *): 1, // COMPLIANT: function pointers OK - default: 1 // COMPLIANT + int : 1, // COMPLIANT + const int : 1, // NON-COMPLIANT + volatile int : 1, // NON-COMPLIANT + _Atomic int : 1, // NON-COMPLIANT + int * : 1, // COMPLIANT + int const * : 1, // COMPLIANT + const volatile int : 1, // NON-COMPLIANT + int volatile const * : 1, // COMPLIANT + struct {} : 1, // NON-COMPLIANT + struct {} * : 1, // NON-COMPLIANT + empty_struct_t : 1, // COMPLIANT + struct empty_struct : 1, // COMPLIANT + empty_struct_t * : 1, // COMPLIANT + struct empty_struct * : 1, // COMPLIANT + union {} : 1, // NON-COMPLIANT + union {} * : 1, // NON-COMPLIANT + empty_union_t : 1, // COMPLIANT + union empty_union : 1, // COMPLIANT + empty_union_t * : 1, // COMPLIANT + union empty_union * : 1, // COMPLIANT + // int[]: 1, // compile error + int[3] : 1, // NON-COMPLIANT + int(*)[3] : 1, // COMPLIANT: pointer to array OK + // int (int*): 1, // compile error + int (*)(int *) : 1, // COMPLIANT: function pointers OK + default : 1 // COMPLIANT ); } // NON-COMPLIANT -#define M1(X) _Generic((X), const int: 1, default: 0) +#define M1(X) _Generic((X), const int : 1, default : 0) // NON-COMPLIANT -#define M2(X) _Generic(1, X[3]: 1, default: 0) +#define M2(X) _Generic(1, X[3] : 1, default : 0) // COMPLIANT -#define M3(X) _Generic(1, X: 1, default: 0) +#define M3(X) _Generic(1, X : 1, default : 0) void f2() { M1(1); @@ -60,12 +60,12 @@ typedef long const *long_const_ptr; void f3() { _Generic(1, - int_t: 1, // COMPLIANT - const_int: 1, // NON-COMPLIANT - const_int_ptr: 1, // COMPLIANT - long_const_ptr: 1, // COMPLIANT - const int_ptr: 1, // COMPLIANT - default: 1 // COMPLIANT + int_t : 1, // COMPLIANT + const_int : 1, // NON-COMPLIANT + const_int_ptr : 1, // COMPLIANT + long_const_ptr : 1, // COMPLIANT + const int_ptr : 1, // COMPLIANT + default : 1 // COMPLIANT ); } diff --git a/c/misra/test/rules/RULE-23-5/test.c b/c/misra/test/rules/RULE-23-5/test.c index d9e140f0af..5d48cc58bd 100644 --- a/c/misra/test/rules/RULE-23-5/test.c +++ b/c/misra/test/rules/RULE-23-5/test.c @@ -19,85 +19,85 @@ void f2() { void *: f1, const void *: f1, default: f1); // COMPLIANT - _Generic(l2, int: f1, default: f1); // COMPLIANT - _Generic(l3, int: f1, default: f1); // COMPLIANT - _Generic(l4, int: f1, default: f1); // COMPLIANT - _Generic(l5, int: f1, default: f1); // COMPLIANT + _Generic(l2, int : f1, default : f1); // COMPLIANT + _Generic(l3, int : f1, default : f1); // COMPLIANT + _Generic(l4, int : f1, default : f1); // COMPLIANT + _Generic(l5, int : f1, default : f1); // COMPLIANT // Compliant, default case is not matched - _Generic(l1, int: f1); // COMPLIANT - _Generic(l2, int *: f1); // COMPLIANT - _Generic(l3, const int *: f1); // COMPLIANT - _Generic(l4, volatile int *: f1); // COMPLIANT - _Generic(l5, volatile const int *: f1); // COMPLIANT - _Generic(l6, void *: f1); // COMPLIANT - _Generic(l7, const void *: f1); // COMPLIANT - _Generic(l8, volatile void *: f1); // COMPLIANT - _Generic(l9, const volatile void *: f1); // COMPLIANT + _Generic(l1, int : f1); // COMPLIANT + _Generic(l2, int * : f1); // COMPLIANT + _Generic(l3, const int * : f1); // COMPLIANT + _Generic(l4, volatile int * : f1); // COMPLIANT + _Generic(l5, volatile const int * : f1); // COMPLIANT + _Generic(l6, void * : f1); // COMPLIANT + _Generic(l7, const void * : f1); // COMPLIANT + _Generic(l8, volatile void * : f1); // COMPLIANT + _Generic(l9, const volatile void * : f1); // COMPLIANT // Violation, match default case due to lack of pointer to pointer // conversions: - _Generic(l2, int *: f1, default: f1); // COMPLIANT - _Generic(l2, const int *: f1, default: f1); // NON-COMPLIANT - _Generic(l2, volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l2, const volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l2, void *: f1, default: f1); // NON-COMPLIANT - _Generic(l2, const void *: f1, default: f1); // NON-COMPLIANT - _Generic(l2, const volatile void *: f1, default: f1); // NON-COMPLIANT - - _Generic(l3, int *: f1, default: f1); // NON-COMPLIANT - _Generic(l3, const int *: f1, default: f1); // COMPLIANT - _Generic(l3, void *: f1, default: f1); // NON-COMPLIANT - _Generic(l3, const void *: f1, default: f1); // NON-COMPLIANT - _Generic(l3, const volatile void *: f1, default: f1); // NON-COMPLIANT + _Generic(l2, int * : f1, default : f1); // COMPLIANT + _Generic(l2, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l2, volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l2, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l2, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l2, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l2, const volatile void * : f1, default : f1); // NON-COMPLIANT + + _Generic(l3, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l3, const int * : f1, default : f1); // COMPLIANT + _Generic(l3, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l3, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l3, const volatile void * : f1, default : f1); // NON-COMPLIANT // Obviously not volatile: - _Generic(l3, volatile int *: f1, default: f1); // COMPLIANT + _Generic(l3, volatile int * : f1, default : f1); // COMPLIANT // Debatable, but volatile const int* is assignable to const int* so its // considered risky - _Generic(l3, const volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l3, const volatile int * : f1, default : f1); // NON-COMPLIANT - _Generic(l4, int *: f1, default: f1); // NON-COMPLIANT - _Generic(l4, volatile int *: f1, default: f1); // COMPLIANT - _Generic(l4, const volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l4, void *: f1, default: f1); // NON-COMPLIANT - _Generic(l4, const volatile void *: f1, default: f1); // NON-COMPLIANT + _Generic(l4, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l4, volatile int * : f1, default : f1); // COMPLIANT + _Generic(l4, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l4, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l4, const volatile void * : f1, default : f1); // NON-COMPLIANT // Debatable, but volatile int* isn't assignable to const int* or vice versa. - _Generic(l4, const int *: f1, default: f1); // COMPLIANT + _Generic(l4, const int * : f1, default : f1); // COMPLIANT // Debatable, but volatile int* isn't assignable to const void* or vice versa. - _Generic(l4, const void *: f1, default: f1); // COMPLIANT - - _Generic(l5, int *: f1, default: f1); // NON-COMPLIANT - _Generic(l5, const int *: f1, default: f1); // NON-COMPLIANT - _Generic(l5, volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l5, const volatile int *: f1, default: f1); // COMPLIANT - _Generic(l5, void *: f1, default: f1); // NON-COMPLIANT - _Generic(l5, const void *: f1, default: f1); // NON-COMPLIANT - _Generic(l5, const volatile void *: f1, default: f1); // NON-COMPLIANT - - _Generic(l6, int *: f1, default: f1); // NON-COMPLIANT - _Generic(l6, const int *: f1, default: f1); // NON-COMPLIANT - _Generic(l6, volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l6, const volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l6, void *: f1, default: f1); // COMPLIANT - _Generic(l6, const void *: f1, default: f1); // NON-COMPLIANT - _Generic(l6, const volatile void *: f1, default: f1); // NON-COMPLIANT - - _Generic(l7, int *: f1, default: f1); // NON-COMPLIANT - _Generic(l7, const int *: f1, default: f1); // NON-COMPLIANT - _Generic(l7, const volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l7, void *: f1, default: f1); // NON-COMPLIANT - _Generic(l7, const void *: f1, default: f1); // COMPLIANT - _Generic(l7, const volatile void *: f1, default: f1); // NON-COMPLIANT + _Generic(l4, const void * : f1, default : f1); // COMPLIANT + + _Generic(l5, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l5, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l5, volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l5, const volatile int * : f1, default : f1); // COMPLIANT + _Generic(l5, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l5, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l5, const volatile void * : f1, default : f1); // NON-COMPLIANT + + _Generic(l6, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l6, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l6, volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l6, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l6, void * : f1, default : f1); // COMPLIANT + _Generic(l6, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l6, const volatile void * : f1, default : f1); // NON-COMPLIANT + + _Generic(l7, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l7, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l7, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l7, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l7, const void * : f1, default : f1); // COMPLIANT + _Generic(l7, const volatile void * : f1, default : f1); // NON-COMPLIANT // Debatable, but const void* isn't assignable to volatile int* or vice versa. - _Generic(l7, volatile int *: f1, default: f1); // COMPLIANT + _Generic(l7, volatile int * : f1, default : f1); // COMPLIANT - _Generic(l9, int *: f1, default: f1); // NON-COMPLIANT - _Generic(l9, const int *: f1, default: f1); // NON-COMPLIANT - _Generic(l9, volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l9, const volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l9, void *: f1, default: f1); // NON-COMPLIANT - _Generic(l9, const void *: f1, default: f1); // NON-COMPLIANT - _Generic(l9, const volatile void *: f1, default: f1); // COMPLIANT + _Generic(l9, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l9, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l9, volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l9, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l9, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l9, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l9, const volatile void * : f1, default : f1); // COMPLIANT /** * Edge case 1: The controlling expression undergoes lvalue conversion, so @@ -110,66 +110,66 @@ void f2() { int *const l14; const int *const l15; - _Generic(l10, int *: f1, default: f1); // COMPLIANT - _Generic(l11, const int *: f1, default: f1); // COMPLIANT - _Generic(l12, volatile int *: f1, default: f1); // COMPLIANT - _Generic(l13, const volatile int *: f1, default: f1); // COMPLIANT - - _Generic(l10, int *: f1, default: f1); // COMPLIANT - _Generic(l10, const int *: f1, default: f1); // NON-COMPLIANT - _Generic(l10, volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l10, const volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l10, void *: f1, default: f1); // NON-COMPLIANT - _Generic(l10, const void *: f1, default: f1); // NON-COMPLIANT - _Generic(l10, const volatile void *: f1, default: f1); // NON-COMPLIANT - - _Generic(l11, int *: f1, default: f1); // NON-COMPLIANT - _Generic(l11, const int *: f1, default: f1); // COMPLIANT - _Generic(l11, void *: f1, default: f1); // NON-COMPLIANT - _Generic(l11, const void *: f1, default: f1); // NON-COMPLIANT - _Generic(l11, const volatile void *: f1, default: f1); // NON-COMPLIANT + _Generic(l10, int * : f1, default : f1); // COMPLIANT + _Generic(l11, const int * : f1, default : f1); // COMPLIANT + _Generic(l12, volatile int * : f1, default : f1); // COMPLIANT + _Generic(l13, const volatile int * : f1, default : f1); // COMPLIANT + + _Generic(l10, int * : f1, default : f1); // COMPLIANT + _Generic(l10, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l10, volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l10, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l10, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l10, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l10, const volatile void * : f1, default : f1); // NON-COMPLIANT + + _Generic(l11, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l11, const int * : f1, default : f1); // COMPLIANT + _Generic(l11, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l11, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l11, const volatile void * : f1, default : f1); // NON-COMPLIANT // Obviously not volatile: - _Generic(l11, volatile int *: f1, default: f1); // COMPLIANT + _Generic(l11, volatile int * : f1, default : f1); // COMPLIANT // Debatable, but volatile const int* is assignable to const int* so its // considered risky - _Generic(l11, const volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l11, const volatile int * : f1, default : f1); // NON-COMPLIANT - _Generic(l12, int *: f1, default: f1); // NON-COMPLIANT - _Generic(l12, volatile int *: f1, default: f1); // COMPLIANT - _Generic(l12, const volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l12, void *: f1, default: f1); // NON-COMPLIANT - _Generic(l12, const volatile void *: f1, default: f1); // NON-COMPLIANT + _Generic(l12, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l12, volatile int * : f1, default : f1); // COMPLIANT + _Generic(l12, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l12, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l12, const volatile void * : f1, default : f1); // NON-COMPLIANT // Debatab12e, but volatile int* isn't assignable to const int* or vice versa. - _Generic(l12, const int *: f1, default: f1); // COMPLIANT + _Generic(l12, const int * : f1, default : f1); // COMPLIANT // Debatable, but volatile int* isn't assignable to const void* or vice versa. - _Generic(l12, const void *: f1, default: f1); // COMPLIANT - - _Generic(l13, int *: f1, default: f1); // NON-COMPLIANT - _Generic(l13, const int *: f1, default: f1); // NON-COMPLIANT - _Generic(l13, volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l13, const volatile int *: f1, default: f1); // COMPLIANT - _Generic(l13, void *: f1, default: f1); // NON-COMPLIANT - _Generic(l13, const void *: f1, default: f1); // NON-COMPLIANT - _Generic(l13, const volatile void *: f1, default: f1); // NON-COMPLIANT - - _Generic(l14, int *: f1, default: f1); // COMPLIANT - _Generic(l14, const int *: f1, default: f1); // NON-COMPLIANT - _Generic(l14, volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l14, const volatile int *: f1, default: f1); // NON-COMPLIANT - _Generic(l14, void *: f1, default: f1); // NON-COMPLIANT - _Generic(l14, const void *: f1, default: f1); // NON-COMPLIANT - _Generic(l14, const volatile void *: f1, default: f1); // NON-COMPLIANT - - _Generic(l15, int *: f1, default: f1); // NON-COMPLIANT - _Generic(l15, const int *: f1, default: f1); // COMPLIANT - _Generic(l15, void *: f1, default: f1); // NON-COMPLIANT - _Generic(l15, const void *: f1, default: f1); // NON-COMPLIANT - _Generic(l15, const volatile void *: f1, default: f1); // NON-COMPLIANT + _Generic(l12, const void * : f1, default : f1); // COMPLIANT + + _Generic(l13, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l13, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l13, volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l13, const volatile int * : f1, default : f1); // COMPLIANT + _Generic(l13, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l13, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l13, const volatile void * : f1, default : f1); // NON-COMPLIANT + + _Generic(l14, int * : f1, default : f1); // COMPLIANT + _Generic(l14, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l14, volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l14, const volatile int * : f1, default : f1); // NON-COMPLIANT + _Generic(l14, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l14, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l14, const volatile void * : f1, default : f1); // NON-COMPLIANT + + _Generic(l15, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l15, const int * : f1, default : f1); // COMPLIANT + _Generic(l15, void * : f1, default : f1); // NON-COMPLIANT + _Generic(l15, const void * : f1, default : f1); // NON-COMPLIANT + _Generic(l15, const volatile void * : f1, default : f1); // NON-COMPLIANT // Obviously not volatile: - _Generic(l15, volatile int *: f1, default: f1); // COMPLIANT + _Generic(l15, volatile int * : f1, default : f1); // COMPLIANT // Debatable, but volatile const int* is assignable to const int* so its // considered risky - _Generic(l15, const volatile int *: f1, default: f1); // NON-COMPLIANT + _Generic(l15, const volatile int * : f1, default : f1); // NON-COMPLIANT /** * Edge case 2: Types don't have to be identical to be compatible. @@ -177,18 +177,19 @@ void f2() { int(*l16)[3]; // This is a risky conversion that should be reported: - _Generic(l16, int(*const)[3]: f1, default: f1); // NON-COMPLIANT + _Generic(l16, int(*const)[3] : f1, default : f1); // NON-COMPLIANT // However, in this one, there is a match on the second selector, because it // it is an array type with a compatible element type, and sizes only have to // match if both arrays have a constant size. Therefore, the default selector // is not chosen and this is not a violation. - _Generic(l16, int(*const)[3]: f1, int(*)[]: f1, default: f1); // COMPLIANT + _Generic(l16, int(*const)[3] : f1, int(*)[] : f1, default : f1); // COMPLIANT // In this case, the second selector is not a compatible type because the // array has a constant size that doesn't match, and this should be reported. - _Generic(l16, - int(*const)[3]: f1, - int(*)[4]: f1, - default: f1); // NON-COMPLIANT + _Generic(l16, int(*const)[3] + : f1, int(*)[4] + : f1, + default + : f1); // NON-COMPLIANT /** * Edge case 3: Conversion on _Generic, make sure we use the fully converted @@ -196,10 +197,10 @@ void f2() { */ int *l17; void *l18; - _Generic((void *)l17, void *: f1, default: f1); // COMPLIANT - _Generic((void *)l17, int *: f1, default: f1); // NON-COMPLIANT - _Generic((int *)l18, void *: f1, default: f1); // NON-COMPLIANT - _Generic((int *)l18, int *: f1, default: f1); // COMPLIANT + _Generic((void *)l17, void * : f1, default : f1); // COMPLIANT + _Generic((void *)l17, int * : f1, default : f1); // NON-COMPLIANT + _Generic((int *)l18, void * : f1, default : f1); // NON-COMPLIANT + _Generic((int *)l18, int * : f1, default : f1); // COMPLIANT /** * Edge case 4: Typedefs must be resolved properly. @@ -210,27 +211,27 @@ void f2() { c_int_t *l20; volatile c_int_t *l21; - _Generic(l2, int *: f1, default: f1); // COMPLIANT - _Generic(l2, int_t *: f1, default: f1); // COMPLIANT - _Generic(l2, const int *: f1, default: f1); // NON-COMPLIANT - _Generic(l2, const int_t *: f1, default: f1); // NON-COMPLIANT - _Generic(l2, c_int_t *: f1, default: f1); // NON-COMPLIANT - - _Generic(l19, int *: f1, default: f1); // COMPLIANT - _Generic(l19, int_t *: f1, default: f1); // COMPLIANT - _Generic(l19, const int *: f1, default: f1); // NON-COMPLIANT - _Generic(l19, const int_t *: f1, default: f1); // NON-COMPLIANT - _Generic(l19, c_int_t *: f1, default: f1); // NON-COMPLIANT - - _Generic(l3, int *: f1, default: f1); // NON-COMPLIANT - _Generic(l3, int_t *: f1, default: f1); // NON-COMPLIANT - _Generic(l3, const int *: f1, default: f1); // COMPLIANT - _Generic(l3, const int_t *: f1, default: f1); // COMPLIANT - _Generic(l3, c_int_t *: f1, default: f1); // COMPLIANT - - _Generic(l20, int *: f1, default: f1); // NON-COMPLIANT - _Generic(l20, int_t *: f1, default: f1); // NON-COMPLIANT - _Generic(l20, const int *: f1, default: f1); // COMPLIANT - _Generic(l20, const int_t *: f1, default: f1); // COMPLIANT - _Generic(l20, c_int_t *: f1, default: f1); // COMPLIANT + _Generic(l2, int * : f1, default : f1); // COMPLIANT + _Generic(l2, int_t * : f1, default : f1); // COMPLIANT + _Generic(l2, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l2, const int_t * : f1, default : f1); // NON-COMPLIANT + _Generic(l2, c_int_t * : f1, default : f1); // NON-COMPLIANT + + _Generic(l19, int * : f1, default : f1); // COMPLIANT + _Generic(l19, int_t * : f1, default : f1); // COMPLIANT + _Generic(l19, const int * : f1, default : f1); // NON-COMPLIANT + _Generic(l19, const int_t * : f1, default : f1); // NON-COMPLIANT + _Generic(l19, c_int_t * : f1, default : f1); // NON-COMPLIANT + + _Generic(l3, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l3, int_t * : f1, default : f1); // NON-COMPLIANT + _Generic(l3, const int * : f1, default : f1); // COMPLIANT + _Generic(l3, const int_t * : f1, default : f1); // COMPLIANT + _Generic(l3, c_int_t * : f1, default : f1); // COMPLIANT + + _Generic(l20, int * : f1, default : f1); // NON-COMPLIANT + _Generic(l20, int_t * : f1, default : f1); // NON-COMPLIANT + _Generic(l20, const int * : f1, default : f1); // COMPLIANT + _Generic(l20, const int_t * : f1, default : f1); // COMPLIANT + _Generic(l20, c_int_t * : f1, default : f1); // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-6/test.c b/c/misra/test/rules/RULE-23-6/test.c index 7d59c1e199..2b18f4cd2c 100644 --- a/c/misra/test/rules/RULE-23-6/test.c +++ b/c/misra/test/rules/RULE-23-6/test.c @@ -3,21 +3,21 @@ int l2; long l3; enum { E1 } l4; -#define M1(X) _Generic((X), int: 1, unsigned int: 1, short: 2, long: 3) +#define M1(X) _Generic((X), int : 1, unsigned int : 1, short : 2, long : 3) void f1() { M1(l1); // COMPLIANT M1(l2); // COMPLIANT M1(l3); // COMPLIANT M1(l4); // NON-COMPLIANT - M1(1); // COMPLIANT - M1(1u); // COMPLIANT - M1(l1 + l1); // NON-COMPLIANT - M1((int)(l1 + l1)); // COMPLIANT - M1('c'); // NON-COMPLIANT[false negative] - _Generic('c', int: 1); // NON-COMPLIANT - _Generic(_Generic(0, default: l1 + l1), default: 1); // NON-COMPLIANT - _Generic(((short)_Generic(0, default: (l1 + l1))), default: 1); // COMPLIANT + M1(1); // COMPLIANT + M1(1u); // COMPLIANT + M1(l1 + l1); // NON-COMPLIANT + M1((int)(l1 + l1)); // COMPLIANT + M1('c'); // NON-COMPLIANT[false negative] + _Generic('c', int : 1); // NON-COMPLIANT + _Generic(_Generic(0, default : l1 + l1), default : 1); // NON-COMPLIANT + _Generic(((short)_Generic(0, default : (l1 + l1))), default : 1); // COMPLIANT } void f2() { @@ -29,5 +29,5 @@ void f2() { struct S1 { int m1; }; - _Generic((const struct S1){.m1 = 0}, default: 1); + _Generic((const struct S1){.m1 = 0}, default : 1); } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-7/test.c b/c/misra/test/rules/RULE-23-7/test.c index 41a5d6ab6c..e2f5e98ee5 100644 --- a/c/misra/test/rules/RULE-23-7/test.c +++ b/c/misra/test/rules/RULE-23-7/test.c @@ -2,59 +2,60 @@ int f1(int p1); int f2(int p1, int p2); // COMPLIANT -- standard correct cases: -#define M1(X) _Generic((X), int: f1, default: f1)(X) -#define M2(X) _Generic((X), int: f1(X), default: f1(X)) +#define M1(X) _Generic((X), int : f1, default : f1)(X) +#define M2(X) _Generic((X), int : f1(X), default : f1(X)) // NON-COMPLIANT -- standard incorrect cases: -#define M3(X) _Generic((X), int: f1(X), default: 0) -#define M4(X) (X) + _Generic((X), int: f1(X), default: f1(X)) -#define M5(X) _Generic((X), int: f1(X), default: f1(X)) + (X) -#define M6(X) _Generic((X), int: f1((X) + (X)), default: f1(X)) +#define M3(X) _Generic((X), int : f1(X), default : 0) +#define M4(X) (X) + _Generic((X), int : f1(X), default : f1(X)) +#define M5(X) _Generic((X), int : f1(X), default : f1(X)) + (X) +#define M6(X) _Generic((X), int : f1((X) + (X)), default : f1(X)) // Compliant by exception // COMPLIANT -#define M7(X) _Generic((X), int: 1, default: 0) +#define M7(X) _Generic((X), int : 1, default : 0) // NON-COMPLIANT[FALSE NEGATIVE] -- Without an expansion, we can't tell if this // macro has only constant expressions or not. -#define M8(X) _Generic((X), int: f1(1)) +#define M8(X) _Generic((X), int : f1(1)) // NON-COMPLIANT -- If the macro is expanded we can detect constant expressions -#define M9(X) _Generic((X), int: f1) +#define M9(X) _Generic((X), int : f1) // NON-COMPLIANT -- If the macro is expanded we can detect constant expressions -#define M10(X) _Generic((X), int: f1(1)) +#define M10(X) _Generic((X), int : f1(1)) void f3() { M9(1); M10(1); } // COMPLIANT -- multiple uses in the controlling expression is OK: -#define M11(X) _Generic((X) + (X), int: f1(X), default: f1(X)) +#define M11(X) _Generic((X) + (X), int : f1(X), default : f1(X)) // NON-COMPLIANT -- the rule should still be enforced otherwise: -#define M12(X) _Generic((X) + (X), int: f1(X), default: 1) -#define M13(X) _Generic((X) + (X), int: f1(X), default: f1(X)) + (X) +#define M12(X) _Generic((X) + (X), int : f1(X), default : 1) +#define M13(X) _Generic((X) + (X), int : f1(X), default : f1(X)) + (X) // COMPLIANT -- the argument is not used in the controlling expression: -#define M14(X) _Generic(1, int: f1((X) + (X)), default: f1(X)) -#define M15(X) _Generic(1, int: f1(X), default: f1(X)) + (X) +#define M14(X) _Generic(1, int : f1((X) + (X)), default : f1(X)) +#define M15(X) _Generic(1, int : f1(X), default : f1(X)) + (X) // Test cases with more than one argument: // COMPLIANT -- Y is not used in the controlling expression: -#define M16(X, Y) _Generic((X), int: f2((X), (Y)), default: f2((X), 1)) +#define M16(X, Y) _Generic((X), int : f2((X), (Y)), default : f2((X), 1)) // NON-COMPLIANT -- Y is used in the controlling expression -#define M17(X, Y) _Generic((X) + (Y), int: f2((X), (Y)), default: f2((X), 1)) +#define M17(X, Y) _Generic((X) + (Y), int : f2((X), (Y)), default : f2((X), 1)) // COMPLIANT -- Y is used in the controlling expression correctly -#define M18(X, Y) _Generic((X) + (Y), int: f2((X), (Y)), default: f2((X), (Y))) +#define M18(X, Y) \ + _Generic((X) + (Y), int : f2((X), (Y)), default : f2((X), (Y))) // Test unevaluated contexts: // COMPLIANT -- sizeof is not evaluated: -#define M19(X) _Generic((X), int[sizeof(X)]: f1, default: f1)(X) -#define M20(X) _Generic((X), int: f1(sizeof(X)), default: f1)(X) -#define M21(X) _Generic((X), int: f1(X), default: f1(X)) + sizeof(X) +#define M19(X) _Generic((X), int[sizeof(X)] : f1, default : f1)(X) +#define M20(X) _Generic((X), int : f1(sizeof(X)), default : f1)(X) +#define M21(X) _Generic((X), int : f1(X), default : f1(X)) + sizeof(X) // NON-COMPLIANT[FALSE NEGATIVE] -- sizeof plus evaluated context -#define M22(X) _Generic((X), int: f1(sizeof(X) + X), default: f1(X))(X) +#define M22(X) _Generic((X), int : f1(sizeof(X) + X), default : f1(X))(X) // NON-COMPLIANT[FALSE NEGATIVE] -- array type sizes may be evaluated -#define M23(X) _Generic((X), int[X]: f1, default: f1)(X) +#define M23(X) _Generic((X), int[X] : f1, default : f1)(X) // COMPLIANT -- alignof, typeof are not evaluated: -#define M24(X) _Generic((X), int[X]: f1, default: f1)(X) +#define M24(X) _Generic((X), int[X] : f1, default : f1)(X) // Nested macros: #define ONCE(X) (X) @@ -64,8 +65,8 @@ void f3() { // COMPLIANT #define M25(X) _Generic((X), int: ONCE(f1(X)), default: ONCE(f1(X)) // COMPLIANT[FALSE POSITIVE] -#define M26(X) _Generic((X), int: IGNORE_2ND(X, X), default: IGNORE_2ND(X, X)) -#define M27(X) _Generic((X), int: f1(IGNORE(X)), default: f1(IGNORE(X)))(X) +#define M26(X) _Generic((X), int : IGNORE_2ND(X, X), default : IGNORE_2ND(X, X)) +#define M27(X) _Generic((X), int : f1(IGNORE(X)), default : f1(IGNORE(X)))(X) // NON-COMPLIANT[FASE NEGATIVE] -#define M28(X) _Generic((X), int: f1(IGNORE(X)), default: f1(IGNORE(X))) -#define M29(X) _Generic((X), int: TWICE(f1(X)), default: TWICE(f1(X))) \ No newline at end of file +#define M28(X) _Generic((X), int : f1(IGNORE(X)), default : f1(IGNORE(X))) +#define M29(X) _Generic((X), int : TWICE(f1(X)), default : TWICE(f1(X))) \ No newline at end of file diff --git a/c/misra/test/rules/RULE-23-8/test.c b/c/misra/test/rules/RULE-23-8/test.c index fdd6e66044..340ddb16db 100644 --- a/c/misra/test/rules/RULE-23-8/test.c +++ b/c/misra/test/rules/RULE-23-8/test.c @@ -2,21 +2,21 @@ * Cases where the macro itself is always compliant or non compliant: */ // COMPLIANT -#define M1(X) _Generic((X), int: 1, unsigned int: 2) +#define M1(X) _Generic((X), int : 1, unsigned int : 2) // COMPLIANT -#define M2(X) _Generic((X), int: 1, unsigned int: 2, default: 0) +#define M2(X) _Generic((X), int : 1, unsigned int : 2, default : 0) // COMPLIANT -#define M3(X) _Generic((X), default: 0, int: 1, unsigned int: 2) +#define M3(X) _Generic((X), default : 0, int : 1, unsigned int : 2) // NON-COMPLIANT -#define M4(X) _Generic((X), int: 1, default: 0, unsigned int: 2) +#define M4(X) _Generic((X), int : 1, default : 0, unsigned int : 2) /** * Macros that are compliant or not based on use: */ // NON-COMPLIANT: because every use is non compliant -#define M5(...) _Generic(0, __VA_ARGS__, default: 0, int: 1) +#define M5(...) _Generic(0, __VA_ARGS__, default : 0, int : 1) // COMPLIANT: because some uses are compliant -#define M6(...) _Generic(0, __VA_ARGS__, int: 1) +#define M6(...) _Generic(0, __VA_ARGS__, int : 1) void f1() { M1(0); // COMPLIANT @@ -42,8 +42,8 @@ void f1() { * RULE-23-1. */ void f2() { - _Generic(0, int: 1, unsigned int: 2); // COMPLIANT - _Generic(0, int: 1, unsigned int: 2, default: 0); // COMPLIANT - _Generic(0, default: 0, int: 1, unsigned int: 2); // COMPLIANT - _Generic(0, int: 1, default: 0, unsigned int: 2); // NON-COMPLIANT + _Generic(0, int : 1, unsigned int : 2); // COMPLIANT + _Generic(0, int : 1, unsigned int : 2, default : 0); // COMPLIANT + _Generic(0, default : 0, int : 1, unsigned int : 2); // COMPLIANT + _Generic(0, int : 1, default : 0, unsigned int : 2); // NON-COMPLIANT } \ No newline at end of file From b2aef27eb8227aabb772ff1da27c597a4678c169 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 9 Mar 2025 23:10:33 -0700 Subject: [PATCH 288/628] Format Type.qll --- cpp/common/src/codingstandards/cpp/Type.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/Type.qll b/cpp/common/src/codingstandards/cpp/Type.qll index 32c139fd89..052096559a 100644 --- a/cpp/common/src/codingstandards/cpp/Type.qll +++ b/cpp/common/src/codingstandards/cpp/Type.qll @@ -1,2 +1,2 @@ import codingstandards.cpp.types.Type -import codingstandards.cpp.types.Uses \ No newline at end of file +import codingstandards.cpp.types.Uses From 183100e621e5eb5c72ba36552d7111d14bdef32c Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 9 Mar 2025 23:10:44 -0700 Subject: [PATCH 289/628] Fix Generics.json package --- rule_packages/c/Generics.json | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/rule_packages/c/Generics.json b/rule_packages/c/Generics.json index 1183bdc709..02c7cb2364 100644 --- a/rule_packages/c/Generics.json +++ b/rule_packages/c/Generics.json @@ -52,9 +52,8 @@ } ], "implementation_scope": { - "items": [ + "description": "Due to limited information in the CodeQL database for macro argument expansions, this implementation reports generics not of the form `_Generic((X)` where all invocations of that generic contain a side effect in the controlling expression." - ] }, "title": "A generic selection that is not expanded from a macro shall not contain potential side effects in the controlling expression" }, @@ -138,9 +137,8 @@ } ], "implementation_scope": { - "items": [ + "description": "The CodeQL extractor will expand character literals passed into macros into integer literals, and therefore the essential type system for character literals will not necessarily be analyzed correctly." - ] }, "title": "The controlling expression of a generic selection shall have an essential type that matches its standard type" }, @@ -164,9 +162,8 @@ } ], "implementation_scope": { - "items": [ + "description": "Due to limited information in the CodeQL database for macro argument expansions, this implementation performs string matching on the macro parameters against the macro body to determine where parameters are expanded. If text indicating a nonevaluated context such as sizeof() or _Alignof() appear, there will be no positive result." - ] }, "title": "A generic selection that is expanded from a macro should evaluate its argument only once" }, @@ -176,7 +173,7 @@ }, "queries": [ { - "description": "A default association shall appear as either the first or the last association of a generic selection", + "description": "A default association shall appear as either the first or the last association of a generic selection.", "kind": "problem", "name": "A default association shall appear as either the first or the last association of a generic", "precision": "very-high", From 61b2852f614e0143f4af11abb99c8126ce43d033 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 9 Mar 2025 23:10:59 -0700 Subject: [PATCH 290/628] Fix DeduplicateMacroResults test --- .../DeduplicateMacroResults.expected | 14 +++++++------- .../cpp/alertreporting/DeduplicateMacroResults.ql | 6 ++++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected index d9a7fe6a07..c273346e3b 100644 --- a/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected +++ b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.expected @@ -1,7 +1,7 @@ -| deduplicatemacroresults.cpp:4:8:4:9 | definition of g1 | Findme var 'g1'. | deduplicatemacroresults.cpp:4:8:4:9 | deduplicatemacroresults.cpp:4:8:4:9 | (ignored) | -| deduplicatemacroresults.cpp:10:1:10:34 | SOMETIMES_HAS_RESULTS1(type,name) | Invocation of macro $@ has findme var 'g3'. | deduplicatemacroresults.cpp:6:1:6:52 | deduplicatemacroresults.cpp:6:1:6:52 | SOMETIMES_HAS_RESULTS1 | -| deduplicatemacroresults.cpp:13:1:13:34 | SOMETIMES_HAS_RESULTS2(type,name) | Invocation of macro $@ has findme var 'g5'. | deduplicatemacroresults.cpp:7:1:7:53 | deduplicatemacroresults.cpp:7:1:7:53 | SOMETIMES_HAS_RESULTS2 | -| deduplicatemacroresults.cpp:15:1:15:50 | #define ALWAYS_HAS_SAME_RESULT() extern findme g6; | Macro ALWAYS_HAS_SAME_RESULT always has findme var named g6 | deduplicatemacroresults.cpp:15:1:15:50 | deduplicatemacroresults.cpp:15:1:15:50 | (ignored) | -| deduplicatemacroresults.cpp:21:1:21:70 | #define ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name) extern findme name; | Macro ALWAYS_HAS_RESULT_VARIED_DESCRIPTION always has findme var, for example '$@'. | deduplicatemacroresults.cpp:23:38:23:39 | deduplicatemacroresults.cpp:23:38:23:39 | g7 | -| deduplicatemacroresults.cpp:30:1:31:50 | #define OUTER_ALWAYS_HAS_SAME_RESULT() extern INNER_SOMETIMES_HAS_RESULTS(findme, g10); | Macro OUTER_ALWAYS_HAS_SAME_RESULT always has findme var named g10 | deduplicatemacroresults.cpp:30:1:31:50 | deduplicatemacroresults.cpp:30:1:31:50 | (ignored) | -| deduplicatemacroresults.cpp:37:1:38:52 | #define OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name) INNER_SOMETIMES_HAS_RESULTS(findme, name ## suffix); | Macro OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION always has findme var, for example '$@'. | deduplicatemacroresults.cpp:40:44:40:47 | deduplicatemacroresults.cpp:40:44:40:47 | g11suffix | +| deduplicatemacroresults.cpp:4:8:4:9 | definition of g1 | Findme var 'g1'. | deduplicatemacroresults.cpp:4:8:4:9 | definition of g1 | | +| deduplicatemacroresults.cpp:10:1:10:34 | SOMETIMES_HAS_RESULTS1(type,name) | Invocation of macro $@ has findme var 'g3'. | deduplicatemacroresults.cpp:6:1:6:52 | #define SOMETIMES_HAS_RESULTS1(type,name) type name | SOMETIMES_HAS_RESULTS1 | +| deduplicatemacroresults.cpp:13:1:13:34 | SOMETIMES_HAS_RESULTS2(type,name) | Invocation of macro $@ has findme var 'g5'. | deduplicatemacroresults.cpp:7:1:7:53 | #define SOMETIMES_HAS_RESULTS2(type,name) type name; | SOMETIMES_HAS_RESULTS2 | +| deduplicatemacroresults.cpp:15:1:15:50 | #define ALWAYS_HAS_SAME_RESULT() extern findme g6; | Macro ALWAYS_HAS_SAME_RESULT always has findme var named g6 | deduplicatemacroresults.cpp:15:1:15:50 | #define ALWAYS_HAS_SAME_RESULT() extern findme g6; | (ignored) | +| deduplicatemacroresults.cpp:21:1:21:70 | #define ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name) extern findme name; | Macro ALWAYS_HAS_RESULT_VARIED_DESCRIPTION always has findme var, for example '$@'. | deduplicatemacroresults.cpp:23:38:23:39 | declaration of g7 | g7 | +| deduplicatemacroresults.cpp:30:1:31:50 | #define OUTER_ALWAYS_HAS_SAME_RESULT() extern INNER_SOMETIMES_HAS_RESULTS(findme, g10); | Macro OUTER_ALWAYS_HAS_SAME_RESULT always has findme var named g10 | deduplicatemacroresults.cpp:30:1:31:50 | #define OUTER_ALWAYS_HAS_SAME_RESULT() extern INNER_SOMETIMES_HAS_RESULTS(findme, g10); | (ignored) | +| deduplicatemacroresults.cpp:37:1:38:52 | #define OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION(name) INNER_SOMETIMES_HAS_RESULTS(findme, name ## suffix); | Macro OUTER_ALWAYS_HAS_RESULT_VARIED_DESCRIPTION always has findme var, for example '$@'. | deduplicatemacroresults.cpp:40:44:40:47 | definition of g11suffix | g11suffix | diff --git a/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql index 3c9f2fc345..68cfc9a78f 100644 --- a/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql +++ b/cpp/common/test/library/codingstandards/cpp/alertreporting/DeduplicateMacroResults.ql @@ -23,12 +23,14 @@ module FindMeReportConfig implements MacroReportConfigSig { result = "Invocation of macro $@ has findme var '" + f.getName() + "'." } - string getMessageNotInMacro(FindMe f) { result = "Findme var '" + f.getName() + "'." } + string getMessageNotInMacro(FindMe f, Locatable extra, string extraString) { + result = "Findme var '" + f.getName() + "'." and extra = f and extraString = "" + } } import DeduplicateMacroResults import DeduplicateMacroResults::Report from ReportResult report -select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocation(), +select report.getPrimaryElement(), report.getMessage(), report.getOptionalPlaceholderLocatable(), report.getOptionalPlaceholderMessage() From 30748787907f4ac2ccf2042f2adec6417bb87f92 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 9 Mar 2025 23:17:48 -0700 Subject: [PATCH 291/628] Fix query formats --- c/common/src/codingstandards/c/Generic.qll | 11 +++-------- .../GenericSelectionNotExpandedFromAMacro.ql | 6 ++---- .../GenericSelectionNotFromMacroWithSideEffects.ql | 2 +- .../GenericWithoutNonDefaultAssociation.ql | 3 ++- .../GenericAssociationWithUnselectableType.ql | 4 ++-- .../GenericExpressionWithIncorrectEssentialType.ql | 6 +++--- .../DefaultGenericSelectionNotFirstOrLast.ql | 9 ++++++--- .../DeclarationsOfAFunctionSameNameAndType.ql | 14 +++++++++----- .../DeclarationsOfAnObjectSameNameAndType.ql | 4 ++-- 9 files changed, 30 insertions(+), 29 deletions(-) diff --git a/c/common/src/codingstandards/c/Generic.qll b/c/common/src/codingstandards/c/Generic.qll index 1bf4282017..784c16778e 100644 --- a/c/common/src/codingstandards/c/Generic.qll +++ b/c/common/src/codingstandards/c/Generic.qll @@ -10,7 +10,6 @@ string deparenthesize(string input) { result = input.substring(1, input.length() - 1) } - class GenericMacro extends Macro { string ctrlExpr; @@ -61,9 +60,7 @@ class ParsedGenericMacro extends Macro { ) } - string getAParameter() { - result = this.(FunctionLikeMacro).getAParameter() - } + string getAParameter() { result = this.(FunctionLikeMacro).getAParameter() } int getAParsedGenericCommaSeparatorOffset() { exists(ParsedText text | @@ -118,9 +115,7 @@ class ParsedGenericMacro extends Macro { ) } - string getControllingExprString() { - result = getSelectionString(1) - } + string getControllingExprString() { result = getSelectionString(1) } bindingset[str, word] private int countWordInString(string word, string str) { @@ -152,4 +147,4 @@ class ParsedGenericMacro extends Macro { not idx = 0 and result = expansionsInsideSelection(parameter, idx + 1) } -} \ No newline at end of file +} diff --git a/c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql b/c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql index ef2a2e75c5..540804ffc4 100644 --- a/c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql +++ b/c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql @@ -18,8 +18,6 @@ from C11GenericExpr generic, Expr ctrlExpr where not isExcluded(generic, GenericsPackage::genericSelectionNotExpandedFromAMacroQuery()) and ctrlExpr = generic.getControllingExpr() and - not exists(MacroInvocation mi | - mi.getAGeneratedElement() = generic.getExpr() - ) + not exists(MacroInvocation mi | mi.getAGeneratedElement() = generic.getExpr()) select generic, "Generic expression with controlling expression $@ is not expanded froma macro", -ctrlExpr, ctrlExpr.toString() + ctrlExpr, ctrlExpr.toString() diff --git a/c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql b/c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql index 3ec53a08bf..4b1a2d26c3 100644 --- a/c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql +++ b/c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql @@ -84,4 +84,4 @@ where not isExcluded(res.getPrimaryElement(), GenericsPackage::genericSelectionNotFromMacroWithSideEffectsQuery()) select res.getPrimaryElement(), res.getMessage(), res.getOptionalPlaceholderLocatable(), - res.getOptionalPlaceholderMessage() \ No newline at end of file + res.getOptionalPlaceholderMessage() diff --git a/c/misra/src/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.ql b/c/misra/src/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.ql index f3a0227022..bb2d57a714 100644 --- a/c/misra/src/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.ql +++ b/c/misra/src/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.ql @@ -31,5 +31,6 @@ where not exists(Type t | t = generic.getAnAssociationType() and not t instanceof VoidType - ) and primaryElement = MacroUnwrapper::unwrapElement(generic) + ) and + primaryElement = MacroUnwrapper::unwrapElement(generic) select primaryElement, "Generic selection contains no non-default association." diff --git a/c/misra/src/rules/RULE-23-4/GenericAssociationWithUnselectableType.ql b/c/misra/src/rules/RULE-23-4/GenericAssociationWithUnselectableType.ql index e8ed88f757..2d707548fa 100644 --- a/c/misra/src/rules/RULE-23-4/GenericAssociationWithUnselectableType.ql +++ b/c/misra/src/rules/RULE-23-4/GenericAssociationWithUnselectableType.ql @@ -20,10 +20,10 @@ import codingstandards.cpp.alertreporting.DeduplicateMacroResults /** * Check if a type contains an unmatchable anonymous struct or union. - * + * * Anonymous structs and unions are only equal to themselves. So any anonymous struct, or compound * type containing an anonymous struct, is unmatchable. - * + * * However, there is an exception if the anonymous struct is behind a typedef. All uses of that * typedef will resolve to the same anonymous struct, and so the typedef is matchable. */ diff --git a/c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql b/c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql index c27ce3dc55..6bf93947d8 100644 --- a/c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql +++ b/c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql @@ -57,6 +57,6 @@ where ) ) select generic, - "Controlling expression in generic " + extraMessage + - "has standard type " + ctrlType.toString() + ", which doesn't match its essential type " + - ctrlEssentialType.toString() + ".", extraElement, extraString \ No newline at end of file + "Controlling expression in generic " + extraMessage + "has standard type " + ctrlType.toString() + + ", which doesn't match its essential type " + ctrlEssentialType.toString() + ".", extraElement, + extraString diff --git a/c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql b/c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql index 04b12ac436..164ffffb1e 100644 --- a/c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql +++ b/c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql @@ -53,13 +53,15 @@ module GenericMisplacedDefaultReportConfig implements bindingset[description] string getMessageSameResultInAllExpansions(Macro m, string description) { result = - "Generic macro " + m.getName() + " has default as " + description + " association, which is not first or last." + "Generic macro " + m.getName() + " has default as " + description + + " association, which is not first or last." } /* Create a message to describe this macro, using '$@' to describe an example `ResultElement`. */ string getMessageVariedResultInAllExpansions(Macro m) { result = - "Generic macro " + m.getName() + " has a default association which is not first or last, for example $@." + "Generic macro " + m.getName() + + " has a default association which is not first or last, for example $@." } /** @@ -68,7 +70,8 @@ module GenericMisplacedDefaultReportConfig implements */ string getMessageResultInIsolatedExpansion(GenericWithMisplacedDefault element) { result = - "Generic macro $@, in this expansion, has default as " + describe(element) + " association, which is not first or last." + "Generic macro $@, in this expansion, has default as " + describe(element) + + " association, which is not first or last." } /** diff --git a/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql b/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql index a0d7c0c9ab..2de2e4fd0a 100644 --- a/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql +++ b/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql @@ -25,15 +25,19 @@ where //return type check ( not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, f2) and - case = "return type" and pluralDo = "does" + case = "return type" and + pluralDo = "does" or //parameter type check not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, f2) and - case = "parameter types" and pluralDo = "do" + case = "parameter types" and + pluralDo = "do" or //parameter name check parameterNamesUnmatched(f1, f2) and - case = "parameter names" and pluralDo = "do" + case = "parameter names" and + pluralDo = "do" ) -select f1, "The " + case + " of re-declaration of $@ " + pluralDo + " not use the same type names as declaration $@", f1, - f1.getName(), f2, f2.getName() +select f1, + "The " + case + " of re-declaration of $@ " + pluralDo + + " not use the same type names as declaration $@", f1, f1.getName(), f2, f2.getName() diff --git a/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql b/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql index 83c67e2efa..12ff583b6b 100644 --- a/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql +++ b/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql @@ -52,5 +52,5 @@ where decl2.getType()) select decl1, "The object $@ of type " + decl1.getType().toString() + - " does not use the same type names as re-declaration $@ of type " + decl2.getType().toString(), decl1, - decl1.getName(), decl2, decl2.getName() + " does not use the same type names as re-declaration $@ of type " + decl2.getType().toString(), + decl1, decl1.getName(), decl2, decl2.getName() From f1ec355fc7d08bcf8f1cc05c1dc61d0d1a15f47a Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 9 Mar 2025 23:19:09 -0700 Subject: [PATCH 292/628] Fix query metadata --- .../RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql | 4 +++- .../rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql b/c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql index 6bf93947d8..f02f92b45a 100644 --- a/c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql +++ b/c/misra/src/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.ql @@ -4,9 +4,11 @@ * @description The controlling expression of a generic selection shall have an essential type that * matches its standard type. * @kind problem - * @precision very-high + * @precision high * @problem.severity error * @tags external/misra/id/rule-23-6 + * correctness + * external/misra/c/2012/amendment3 * external/misra/obligation/required */ diff --git a/c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql b/c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql index 164ffffb1e..6e443bd162 100644 --- a/c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql +++ b/c/misra/src/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.ql @@ -2,7 +2,7 @@ * @id c/misra/default-generic-selection-not-first-or-last * @name RULE-23-8: A default association shall appear as either the first or the last association of a generic * @description A default association shall appear as either the first or the last association of a - * generic selection + * generic selection. * @kind problem * @precision very-high * @problem.severity warning From c8433d72c106e85a1a740942123a83791aeb439e Mon Sep 17 00:00:00 2001 From: knewbury01 Date: Tue, 11 Mar 2025 17:54:55 +0000 Subject: [PATCH 293/628] Bump version to 2.43.0-dev --- c/cert/src/qlpack.yml | 2 +- c/cert/test/qlpack.yml | 2 +- c/common/src/qlpack.yml | 2 +- c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- c/misra/test/qlpack.yml | 2 +- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/qlpack.yml | 2 +- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- docs/user_manual.md | 12 ++++++------ 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 6e023bc238..8498e9447d 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.42.0-dev +version: 2.43.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index 98d9895612..2b44a05fdf 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.42.0-dev +version: 2.43.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 9188ad8bda..685a3a0144 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.42.0-dev +version: 2.43.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index f76badccfc..8f8486949b 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.42.0-dev +version: 2.43.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 721a052e6b..5b8b1fc0b2 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.42.0-dev +version: 2.43.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index bf45171e18..aa5c5d86ae 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.42.0-dev +version: 2.43.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index e4d17b7309..1116e9534d 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.42.0-dev +version: 2.43.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index a1c802fec5..d540b01a32 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.42.0-dev +version: 2.43.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index b0645353f6..89b5196f23 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.42.0-dev +version: 2.43.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index 9c49caac9f..ceedca4647 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.42.0-dev +version: 2.43.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index 4b4619e6b9..ce7e896ced 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards -version: 2.42.0-dev +version: 2.43.0-dev license: MIT dependencies: codeql/cpp-all: 2.1.1 diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index a207965a5e..e2201b887e 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.42.0-dev +version: 2.43.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 2c8f21a82f..7c104631d1 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.42.0-dev +version: 2.43.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index d0bd3a8b5a..08bdda24eb 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.42.0-dev +version: 2.43.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index 3203133ffc..73a6e189a3 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.42.0-dev +version: 2.43.0-dev license: MIT dependencies: codeql/cpp-all: 2.1.1 diff --git a/docs/user_manual.md b/docs/user_manual.md index df3ce9a6b8..d7924a9fcd 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -34,14 +34,14 @@ ## Release information -This user manual documents release `2.42.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.43.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: - `coding-standards-codeql-packs-2.37.0-dev.zip`: CodeQL packs that can be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `code-scanning-cpp-query-pack-2.42.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.42.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.42.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.42.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.43.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.43.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.43.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.43.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -583,7 +583,7 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.42.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.43.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | From 63b8e77d7aa9954a503abc9708d0dc8e45314c71 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 11 Mar 2025 17:30:51 -0700 Subject: [PATCH 294/628] Use regexpFind instead of regexpMatch Otherwise we need to match the entire receiver. --- .../src/codingstandards/cpp/HardwareOrProtocolInterface.qll | 2 +- .../OrderingPredicateMustBeStrictlyWeak.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/autosar/src/codingstandards/cpp/HardwareOrProtocolInterface.qll b/cpp/autosar/src/codingstandards/cpp/HardwareOrProtocolInterface.qll index 410fa1292f..b0b20b82d9 100644 --- a/cpp/autosar/src/codingstandards/cpp/HardwareOrProtocolInterface.qll +++ b/cpp/autosar/src/codingstandards/cpp/HardwareOrProtocolInterface.qll @@ -5,7 +5,7 @@ abstract class HardwareOrProtocolInterfaceClass extends Class { } class HardwareOrProtocolInterfaceComment extends Comment { HardwareOrProtocolInterfaceComment() { - getContents().regexpMatch("(?m)^\\s*(//|\\*)\\s*@HardwareOrProtocolInterface\\s*$") + exists(getContents().regexpFind("(?m)^\\s*(//|\\*)\\s*@HardwareOrProtocolInterface\\s*$", _, _)) } } diff --git a/cpp/common/src/codingstandards/cpp/rules/orderingpredicatemustbestrictlyweak/OrderingPredicateMustBeStrictlyWeak.qll b/cpp/common/src/codingstandards/cpp/rules/orderingpredicatemustbestrictlyweak/OrderingPredicateMustBeStrictlyWeak.qll index 66563bb9ff..1e9c025e4d 100644 --- a/cpp/common/src/codingstandards/cpp/rules/orderingpredicatemustbestrictlyweak/OrderingPredicateMustBeStrictlyWeak.qll +++ b/cpp/common/src/codingstandards/cpp/rules/orderingpredicatemustbestrictlyweak/OrderingPredicateMustBeStrictlyWeak.qll @@ -16,7 +16,7 @@ Query getQuery() { result instanceof OrderingPredicateMustBeStrictlyWeakSharedQu class IsStrictlyWeaklyOrderedComment extends Comment { IsStrictlyWeaklyOrderedComment() { - getContents().regexpMatch("(?m)^\\s*(//|\\*)\\s*@IsStrictlyWeaklyOrdered\\s*$") + exists(getContents().regexpFind("(?m)^\\s*(//|\\*)\\s*@IsStrictlyWeaklyOrdered\\s*$", _, _)) } } From c73badfcc7697b291b05ffa1da41c6afe902d826 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Wed, 12 Mar 2025 00:36:26 +0000 Subject: [PATCH 295/628] Update change_notes/2025-03-09-rule-8-7.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- change_notes/2025-03-09-rule-8-7.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change_notes/2025-03-09-rule-8-7.md b/change_notes/2025-03-09-rule-8-7.md index 5308c97ce3..3c3678ca6d 100644 --- a/change_notes/2025-03-09-rule-8-7.md +++ b/change_notes/2025-03-09-rule-8-7.md @@ -1,4 +1,4 @@ - `RULE-8-7` - `ShouldNotBeDefinedWithExternalLinkage.ql`: - - Remove false positives where the declation is not defined in the database. + - Remove false positives where the declaration is not defined in the database. - Remove false positives where the definition and reference are in different translation units. - Remove false positives where the reference occurs in a header file. \ No newline at end of file From ce45538a5a72d80440a2c36d2210790309c54995 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 11 Mar 2025 17:42:41 -0700 Subject: [PATCH 296/628] Reformat C test case --- c/misra/test/rules/RULE-8-7/test.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/c/misra/test/rules/RULE-8-7/test.c b/c/misra/test/rules/RULE-8-7/test.c index 591f15a2c4..3789a1d269 100644 --- a/c/misra/test/rules/RULE-8-7/test.c +++ b/c/misra/test/rules/RULE-8-7/test.c @@ -1,11 +1,11 @@ #include "test.h" int i = 0; int i1 = 0; -int i2; // NON_COMPLIANT - accessed one translation unit -void f1() {} // Definition -void f2() {} // Definition -static void f3() {}; // COMPLIANT - internal linkage -void f4() {} // Definition +int i2; // NON_COMPLIANT - accessed one translation unit +void f1() {} // Definition +void f2() {} // Definition +static void f3(){}; // COMPLIANT - internal linkage +void f4() {} // Definition void f() { i = 0; i1 = 0; From 076b1c4faa72573c0a5f1488049332e47ecfa29a Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 11 Mar 2025 18:15:17 -0700 Subject: [PATCH 297/628] Implement EssentialTypes2 package --- c/common/src/codingstandards/c/TgMath.qll | 68 ++++ .../TgMathArgumentWithInvalidEssentialType.ql | 47 +++ ...gMathArgumentsWithDifferingStandardType.ql | 65 ++++ ...hArgumentWithInvalidEssentialType.expected | 132 +++++++ ...MathArgumentWithInvalidEssentialType.qlref | 1 + c/misra/test/rules/RULE-21-22/test.c | 323 ++++++++++++++++++ ...rgumentsWithDifferingStandardType.expected | 139 ++++++++ ...thArgumentsWithDifferingStandardType.qlref | 1 + c/misra/test/rules/RULE-21-23/test.c | 288 ++++++++++++++++ .../cpp/exclusions/c/EssentialTypes2.qll | 44 +++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + rule_packages/c/EssentialTypes2.json | 47 +++ 12 files changed, 1158 insertions(+) create mode 100644 c/common/src/codingstandards/c/TgMath.qll create mode 100644 c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql create mode 100644 c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql create mode 100644 c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected create mode 100644 c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.qlref create mode 100644 c/misra/test/rules/RULE-21-22/test.c create mode 100644 c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected create mode 100644 c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.qlref create mode 100644 c/misra/test/rules/RULE-21-23/test.c create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes2.qll create mode 100644 rule_packages/c/EssentialTypes2.json diff --git a/c/common/src/codingstandards/c/TgMath.qll b/c/common/src/codingstandards/c/TgMath.qll new file mode 100644 index 0000000000..f5488194c6 --- /dev/null +++ b/c/common/src/codingstandards/c/TgMath.qll @@ -0,0 +1,68 @@ + +import cpp + +private string getATgMathMacroName(boolean allowComplex) { + allowComplex = true and + result = + [ + "acos", "acosh", "asin", "asinh", "atan", "atanh", "carg", "cimag", "conj", "cos", "cosh", + "cproj", "creal", "exp", "fabs", "log", "pow", "sin", "sinh", "sqrt", "tan", "tanh" + ] + or + allowComplex = false and + result = + [ + "atan2", "cbrt", "ceil", "copysign", "erf", "erfc", "exp2", "expm1", "fdim", "floor", "fma", + "fmax", "fmin", "fmod", "frexp", "hypot", "ilogb", "ldexp", "lgamma", "llrint", "llround", + "log10", "log1p", "log2", "logb", "lrint", "lround", "nearbyint", "nextafter", "nexttoward", + "remainder", "remquo", "rint", "round", "scalbn", "scalbln", "tgamma", "trunc", + ] +} + +private predicate hasOutputArgument(string macroName, int index) { + macroName = "frexp" and index = 1 + or + macroName = "remquo" and index = 2 +} + +class TgMathInvocation extends MacroInvocation { + Call call; + boolean allowComplex; + + TgMathInvocation() { + this.getMacro().getName() = getATgMathMacroName(allowComplex) and + call = getBestCallInExpansion(this) + } + + Expr getOperandArgument(int i) { + result = call.getArgument(i) + and not hasOutputArgument(call.getTarget().getName(), i) + } + + int getNumberOfOperandArguments() { + result = call.getNumberOfArguments() - count(int i | hasOutputArgument(getMacroName(), i)) + } + + Expr getAnOperandArgument() { + result = getOperandArgument(_) + } + + predicate allowsComplex() { + allowComplex = true + } +} + +private Call getACallInExpansion(MacroInvocation mi) { result = mi.getAnExpandedElement() } + +private Call getNameMatchedCallInExpansion(MacroInvocation mi) { + result = getACallInExpansion(mi) and result.getTarget().getName() = mi.getMacroName() +} + +private Call getBestCallInExpansion(MacroInvocation mi) { + count(getACallInExpansion(mi)) = 1 and result = getACallInExpansion(mi) + or + count(getNameMatchedCallInExpansion(mi)) = 1 and result = getNameMatchedCallInExpansion(mi) + or + count(getNameMatchedCallInExpansion(mi)) > 1 and + result = rank[1](Call c | c = getACallInExpansion(mi) | c order by c.getTarget().getName()) +} \ No newline at end of file diff --git a/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql b/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql new file mode 100644 index 0000000000..f06ca54979 --- /dev/null +++ b/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql @@ -0,0 +1,47 @@ +/** + * @id c/misra/tg-math-argument-with-invalid-essential-type + * @name RULE-21-22: All operand arguments to any type-generic macros in shall have an appropriate essential + * @description All operand arguments to any type-generic macros in shall have an + * appropriate essential type + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-21-22 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/mandatory + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.TgMath +import codingstandards.c.misra.EssentialTypes + +EssentialTypeCategory getAnAllowedEssentialTypeCategory(TgMathInvocation call) { + result = EssentiallySignedType() + or + result = EssentiallyUnsignedType() + or + result = EssentiallyFloatingType(Real()) + or + call.allowsComplex() and + result = EssentiallyFloatingType(Complex()) +} + +string getAllowedTypesString(TgMathInvocation call) { + if call.allowsComplex() + then result = "essentially signed, unsigned, or floating type" + else result = "essentially signed, unsigned, or real floating type" +} + +from TgMathInvocation call, Expr arg, int argIndex, Type type, EssentialTypeCategory category +where + not isExcluded(call, EssentialTypes2Package::tgMathArgumentWithInvalidEssentialTypeQuery()) and + arg = call.getOperandArgument(argIndex) and + type = getEssentialType(arg) and + category = getEssentialTypeCategory(type) and + not category = getAnAllowedEssentialTypeCategory(call) +select arg, + "Argument " + (argIndex + 1) + " provided to type-generic macro '" + call.getMacroName() + + "' has " + category.toString().toLowerCase() + ", which is not " + getAllowedTypesString(call) + + "." diff --git a/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql b/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql new file mode 100644 index 0000000000..b6daf7bb6a --- /dev/null +++ b/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql @@ -0,0 +1,65 @@ +/** + * @id c/misra/tg-math-arguments-with-differing-standard-type + * @name RULE-21-23: All operand arguments to any multi-argument type-generic macros in shall have the same + * @description All operand arguments to any multi-argument type-generic macros in shall + * have the same standard type + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-21-23 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.TgMath + +Expr getFullyExplicitlyConverted(Expr e) { + if e.hasExplicitConversion() + then result = getFullyExplicitlyConverted(e.getExplicitlyConverted()) + else result = e +} + +string argTypesString(TgMathInvocation call, int i) { + exists(string typeStr | + typeStr = getEffectiveStandardType(call.getOperandArgument(i)).toString() and + ( + i = 0 and result = typeStr + or + i > 0 and result = argTypesString(call, i - 1) + ", " + typeStr + ) + ) +} + +predicate promotes(Type type) { type.(IntegralType).getSize() < any(IntType t).getSize() } + +Type integerPromote(Type type) { + promotes(type) and result.(IntType).isSigned() + or + not promotes(type) and result = type +} + +Type canonicalize(Type type) { + if type instanceof IntegralType + then result = type.(IntegralType).getCanonicalArithmeticType() + else result = type +} + +Type getEffectiveStandardType(Expr e) { + result = + canonicalize(integerPromote(getFullyExplicitlyConverted(e).getType().stripTopLevelSpecifiers())) +} + +from TgMathInvocation call, Type firstType +where + not isExcluded(call, EssentialTypes2Package::tgMathArgumentsWithDifferingStandardTypeQuery()) and + firstType = getEffectiveStandardType(call.getAnOperandArgument()) and + not forall(Expr arg | arg = call.getAnOperandArgument() | + firstType = getEffectiveStandardType(arg) + ) +select call, + "Call to type-generic macro '" + call.getMacroName() + + "' has arguments with differing standard types (" + + argTypesString(call, call.getNumberOfOperandArguments() - 1) + ")." diff --git a/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected new file mode 100644 index 0000000000..7c30f68204 --- /dev/null +++ b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected @@ -0,0 +1,132 @@ +| test.c:29:7:29:7 | c | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:40:7:40:7 | e | Argument 1 provided to type-generic macro 'cos' has essentially enum type, which is not essentially signed, unsigned, or floating type. | +| test.c:41:7:41:7 | b | Argument 1 provided to type-generic macro 'cos' has essentially boolean type, which is not essentially signed, unsigned, or floating type. | +| test.c:156:8:156:8 | c | Argument 1 provided to type-generic macro 'acos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:157:9:157:9 | c | Argument 1 provided to type-generic macro 'acosh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:158:8:158:8 | c | Argument 1 provided to type-generic macro 'asin' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:159:9:159:9 | c | Argument 1 provided to type-generic macro 'asinh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:160:9:160:9 | c | Argument 1 provided to type-generic macro 'atan2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:161:12:161:12 | c | Argument 2 provided to type-generic macro 'atan2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:162:9:162:9 | c | Argument 1 provided to type-generic macro 'atanh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:163:8:163:8 | c | Argument 1 provided to type-generic macro 'carg' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:164:8:164:8 | c | Argument 1 provided to type-generic macro 'ceil' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:165:9:165:9 | c | Argument 1 provided to type-generic macro 'cimag' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:166:8:166:8 | c | Argument 1 provided to type-generic macro 'conj' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:167:15:167:15 | c | Argument 2 provided to type-generic macro 'copysign' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:168:12:168:12 | c | Argument 1 provided to type-generic macro 'copysign' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:169:8:169:8 | c | Argument 1 provided to type-generic macro 'cosh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:170:9:170:9 | c | Argument 1 provided to type-generic macro 'cproj' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:171:9:171:9 | c | Argument 1 provided to type-generic macro 'creal' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:172:7:172:7 | c | Argument 1 provided to type-generic macro 'erf' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:173:8:173:8 | c | Argument 1 provided to type-generic macro 'erfc' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:174:7:174:7 | c | Argument 1 provided to type-generic macro 'exp' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:175:8:175:8 | c | Argument 1 provided to type-generic macro 'exp2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:176:9:176:9 | c | Argument 1 provided to type-generic macro 'expm1' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:177:8:177:8 | c | Argument 1 provided to type-generic macro 'fabs' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:178:8:178:8 | c | Argument 1 provided to type-generic macro 'fdim' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:179:11:179:11 | c | Argument 2 provided to type-generic macro 'fdim' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:180:9:180:9 | c | Argument 1 provided to type-generic macro 'floor' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:181:7:181:7 | c | Argument 1 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:182:10:182:10 | c | Argument 2 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:183:13:183:13 | c | Argument 3 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:184:8:184:8 | c | Argument 1 provided to type-generic macro 'fmax' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:185:11:185:11 | c | Argument 2 provided to type-generic macro 'fmax' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:186:8:186:8 | c | Argument 1 provided to type-generic macro 'fmin' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:187:11:187:11 | c | Argument 2 provided to type-generic macro 'fmin' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:188:8:188:8 | c | Argument 1 provided to type-generic macro 'fmod' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:189:11:189:11 | c | Argument 2 provided to type-generic macro 'fmod' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:190:9:190:9 | c | Argument 1 provided to type-generic macro 'frexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:191:9:191:9 | c | Argument 1 provided to type-generic macro 'hypot' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:192:12:192:12 | c | Argument 2 provided to type-generic macro 'hypot' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:193:9:193:9 | c | Argument 1 provided to type-generic macro 'ilogb' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:194:9:194:9 | c | Argument 1 provided to type-generic macro 'ldexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:195:12:195:12 | c | Argument 2 provided to type-generic macro 'ldexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:196:10:196:10 | c | Argument 1 provided to type-generic macro 'lgamma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:197:10:197:10 | c | Argument 1 provided to type-generic macro 'llrint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:198:11:198:11 | c | Argument 1 provided to type-generic macro 'llround' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:199:7:199:7 | c | Argument 1 provided to type-generic macro 'log' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:200:9:200:9 | c | Argument 1 provided to type-generic macro 'log10' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:201:9:201:9 | c | Argument 1 provided to type-generic macro 'log1p' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:202:8:202:8 | c | Argument 1 provided to type-generic macro 'log2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:203:8:203:8 | c | Argument 1 provided to type-generic macro 'logb' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:204:9:204:9 | c | Argument 1 provided to type-generic macro 'lrint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:205:10:205:10 | c | Argument 1 provided to type-generic macro 'lround' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:206:13:206:13 | c | Argument 1 provided to type-generic macro 'nearbyint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:207:13:207:13 | c | Argument 1 provided to type-generic macro 'nextafter' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:208:16:208:16 | c | Argument 2 provided to type-generic macro 'nextafter' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:209:14:209:14 | c | Argument 1 provided to type-generic macro 'nexttoward' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:210:17:210:17 | c | Argument 2 provided to type-generic macro 'nexttoward' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:211:7:211:7 | c | Argument 1 provided to type-generic macro 'pow' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:212:10:212:10 | c | Argument 2 provided to type-generic macro 'pow' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:213:13:213:13 | c | Argument 1 provided to type-generic macro 'remainder' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:214:16:214:16 | c | Argument 2 provided to type-generic macro 'remainder' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:215:10:215:10 | c | Argument 1 provided to type-generic macro 'remquo' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:216:13:216:13 | c | Argument 2 provided to type-generic macro 'remquo' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:217:8:217:8 | c | Argument 1 provided to type-generic macro 'rint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:218:9:218:9 | c | Argument 1 provided to type-generic macro 'round' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:219:10:219:10 | c | Argument 1 provided to type-generic macro 'scalbn' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:220:13:220:13 | c | Argument 2 provided to type-generic macro 'scalbn' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:221:11:221:11 | c | Argument 1 provided to type-generic macro 'scalbln' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:222:14:222:14 | c | Argument 2 provided to type-generic macro 'scalbln' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:223:7:223:7 | c | Argument 1 provided to type-generic macro 'sin' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:224:8:224:8 | c | Argument 1 provided to type-generic macro 'sinh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:225:8:225:8 | c | Argument 1 provided to type-generic macro 'sqrt' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:226:7:226:7 | c | Argument 1 provided to type-generic macro 'tan' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:227:8:227:8 | c | Argument 1 provided to type-generic macro 'tanh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:228:10:228:10 | c | Argument 1 provided to type-generic macro 'tgamma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:229:9:229:9 | c | Argument 1 provided to type-generic macro 'trunc' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:239:9:239:10 | cf | Argument 1 provided to type-generic macro 'atan2' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:240:12:240:13 | cf | Argument 2 provided to type-generic macro 'atan2' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:243:8:243:9 | cf | Argument 1 provided to type-generic macro 'cbrt' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:244:8:244:9 | cf | Argument 1 provided to type-generic macro 'ceil' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:247:15:247:16 | cf | Argument 2 provided to type-generic macro 'copysign' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:248:12:248:13 | cf | Argument 1 provided to type-generic macro 'copysign' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:249:15:249:16 | cf | Argument 2 provided to type-generic macro 'copysign' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:254:7:254:8 | cf | Argument 1 provided to type-generic macro 'erf' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:255:8:255:9 | cf | Argument 1 provided to type-generic macro 'erfc' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:257:8:257:9 | cf | Argument 1 provided to type-generic macro 'exp2' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:258:9:258:10 | cf | Argument 1 provided to type-generic macro 'expm1' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:260:8:260:9 | cf | Argument 1 provided to type-generic macro 'fdim' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:261:11:261:12 | cf | Argument 2 provided to type-generic macro 'fdim' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:262:9:262:10 | cf | Argument 1 provided to type-generic macro 'floor' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:263:7:263:8 | cf | Argument 1 provided to type-generic macro 'fma' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:264:10:264:11 | cf | Argument 2 provided to type-generic macro 'fma' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:265:13:265:14 | cf | Argument 3 provided to type-generic macro 'fma' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:266:8:266:9 | cf | Argument 1 provided to type-generic macro 'fmax' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:267:11:267:12 | cf | Argument 2 provided to type-generic macro 'fmax' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:268:8:268:9 | cf | Argument 1 provided to type-generic macro 'fmin' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:269:11:269:12 | cf | Argument 2 provided to type-generic macro 'fmin' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:270:8:270:9 | cf | Argument 1 provided to type-generic macro 'fmod' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:271:11:271:12 | cf | Argument 2 provided to type-generic macro 'fmod' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:272:9:272:10 | cf | Argument 1 provided to type-generic macro 'frexp' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:273:9:273:10 | cf | Argument 1 provided to type-generic macro 'hypot' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:274:12:274:13 | cf | Argument 2 provided to type-generic macro 'hypot' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:275:9:275:10 | cf | Argument 1 provided to type-generic macro 'ilogb' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:276:9:276:10 | cf | Argument 1 provided to type-generic macro 'ldexp' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:277:12:277:13 | cf | Argument 2 provided to type-generic macro 'ldexp' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:278:10:278:11 | cf | Argument 1 provided to type-generic macro 'lgamma' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:279:10:279:11 | cf | Argument 1 provided to type-generic macro 'llrint' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:280:11:280:12 | cf | Argument 1 provided to type-generic macro 'llround' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:282:9:282:10 | cf | Argument 1 provided to type-generic macro 'log10' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:283:9:283:10 | cf | Argument 1 provided to type-generic macro 'log1p' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:284:8:284:9 | cf | Argument 1 provided to type-generic macro 'log2' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:285:8:285:9 | cf | Argument 1 provided to type-generic macro 'logb' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:286:9:286:10 | cf | Argument 1 provided to type-generic macro 'lrint' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:287:10:287:11 | cf | Argument 1 provided to type-generic macro 'lround' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:288:13:288:14 | cf | Argument 1 provided to type-generic macro 'nearbyint' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:289:13:289:14 | cf | Argument 1 provided to type-generic macro 'nextafter' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:290:16:290:17 | cf | Argument 2 provided to type-generic macro 'nextafter' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:291:14:291:15 | cf | Argument 1 provided to type-generic macro 'nexttoward' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:292:17:292:18 | cf | Argument 2 provided to type-generic macro 'nexttoward' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:294:13:294:14 | cf | Argument 1 provided to type-generic macro 'remainder' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:295:16:295:17 | cf | Argument 2 provided to type-generic macro 'remainder' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:296:10:296:11 | cf | Argument 1 provided to type-generic macro 'remquo' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:297:13:297:14 | cf | Argument 2 provided to type-generic macro 'remquo' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:298:8:298:9 | cf | Argument 1 provided to type-generic macro 'rint' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:299:9:299:10 | cf | Argument 1 provided to type-generic macro 'round' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:300:10:300:11 | cf | Argument 1 provided to type-generic macro 'scalbn' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:301:13:301:14 | cf | Argument 2 provided to type-generic macro 'scalbn' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:302:11:302:12 | cf | Argument 1 provided to type-generic macro 'scalbln' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:303:14:303:15 | cf | Argument 2 provided to type-generic macro 'scalbln' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:309:10:309:11 | cf | Argument 1 provided to type-generic macro 'tgamma' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:310:9:310:10 | cf | Argument 1 provided to type-generic macro 'trunc' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | diff --git a/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.qlref b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.qlref new file mode 100644 index 0000000000..cb7206db11 --- /dev/null +++ b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.qlref @@ -0,0 +1 @@ +rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-22/test.c b/c/misra/test/rules/RULE-21-22/test.c new file mode 100644 index 0000000000..cc456c17fb --- /dev/null +++ b/c/misra/test/rules/RULE-21-22/test.c @@ -0,0 +1,323 @@ +#include +#include +#include +#include + +void f1() { + int i = 0; + unsigned int ui = 0; + short s = 0; + unsigned short us = 0; + char c = 0; + unsigned char uc = 0; + signed char sc = 0; + long l = 0; + unsigned long ul = 0; + float f = 0.0f; + float _Complex cf = 0.0f + 0.0f * I; + double d = 0.0; + char *p = 0; + void *vp = 0; + uintptr_t uip = p; + enum { e1 } e = e1; + bool b = true; + + cos(i); // COMPLIANT + cos(ui); // COMPLIANT + cos(s); // COMPLIANT + cos(us); // COMPLIANT + cos(c); // NON-COMPLIANT + cos(uc); // COMPLIANT + cos(sc); // COMPLIANT + cos(l); // COMPLIANT + cos(ul); // COMPLIANT + cos(f); // COMPLIANT + cos(cf); // COMPLIANT + cos(d); // COMPLIANT + // cos(p); // Doesn't compile + // cos(vp); // Doesn't compile + cos(uip); // COMPLIANT + cos(e); // NON-COMPLIANT + cos(b); // NON-COMPLIANT + cos(1); // COMPLIANT + cos(1.1f); // COMPLIANT + cos('a'); // NON-COMPLIANT[false negative] + + /** + * Int, float, and complex allowed: + */ + acos(i); // COMPLIANT + acos(f); // COMPLIANT + acosh(i); // COMPLIANT + acosh(f); // COMPLIANT + asin(i); // COMPLIANT + asin(f); // COMPLIANT + asinh(i); // COMPLIANT + asinh(f); // COMPLIANT + atan(i); // COMPLIANT + atan(f); // COMPLIANT + atan2(i, i); // COMPLIANT + atan2(f, f); // COMPLIANT + atanh(i); // COMPLIANT + atanh(f); // COMPLIANT + carg(i); // COMPLIANT + carg(f); // COMPLIANT + cbrt(i); // COMPLIANT + cbrt(f); // COMPLIANT + ceil(i); // COMPLIANT + ceil(f); // COMPLIANT + cimag(i); // COMPLIANT + cimag(f); // COMPLIANT + conj(i); // COMPLIANT + conj(f); // COMPLIANT + copysign(i, i); // COMPLIANT + copysign(f, f); // COMPLIANT + cos(i); // COMPLIANT + cos(f); // COMPLIANT + cosh(i); // COMPLIANT + cosh(f); // COMPLIANT + cproj(i); // COMPLIANT + cproj(f); // COMPLIANT + creal(i); // COMPLIANT + creal(f); // COMPLIANT + erf(i); // COMPLIANT + erf(f); // COMPLIANT + erfc(i); // COMPLIANT + erfc(f); // COMPLIANT + exp(i); // COMPLIANT + exp(f); // COMPLIANT + exp2(i); // COMPLIANT + exp2(f); // COMPLIANT + expm1(i); // COMPLIANT + expm1(f); // COMPLIANT + fabs(i); // COMPLIANT + fabs(f); // COMPLIANT + fdim(i, i); // COMPLIANT + fdim(f, f); // COMPLIANT + floor(i); // COMPLIANT + floor(f); // COMPLIANT + fma(i, i, i); // COMPLIANT + fma(f, f, f); // COMPLIANT + fmax(i, i); // COMPLIANT + fmax(f, f); // COMPLIANT + fmin(i, i); // COMPLIANT + fmin(f, f); // COMPLIANT + fmod(i, i); // COMPLIANT + fmod(f, f); // COMPLIANT + frexp(i, &i); // COMPLIANT + frexp(f, &p); // COMPLIANT + hypot(i, i); // COMPLIANT + hypot(f, f); // COMPLIANT + ilogb(i); // COMPLIANT + ilogb(f); // COMPLIANT + llrint(i); // COMPLIANT + llrint(f); // COMPLIANT + ldexp(i, i); // COMPLIANT + ldexp(f, f); // COMPLIANT + lgamma(i); // COMPLIANT + lgamma(f); // COMPLIANT + llround(i); // COMPLIANT + llround(f); // COMPLIANT + log(i); // COMPLIANT + log(f); // COMPLIANT + pow(i, i); // COMPLIANT + pow(f, f); // COMPLIANT + remainder(i, i); // COMPLIANT + remainder(f, f); // COMPLIANT + remquo(i, i, &i); // COMPLIANT + remquo(f, f, &f); // COMPLIANT + rint(i); // COMPLIANT + rint(f); // COMPLIANT + round(i); // COMPLIANT + round(f); // COMPLIANT + scalbn(i, i); // COMPLIANT + scalbn(f, f); // COMPLIANT + scalbln(i, i); // COMPLIANT + scalbln(f, f); // COMPLIANT + sin(i); // COMPLIANT + sin(f); // COMPLIANT + sin(cf); // COMPLIANT + sinh(i); // COMPLIANT + sinh(f); // COMPLIANT + sqrt(i); // COMPLIANT + sqrt(f); // COMPLIANT + tan(i); // COMPLIANT + tan(f); // COMPLIANT + tanh(i); // COMPLIANT + tanh(f); // COMPLIANT + tgamma(i); // COMPLIANT + tgamma(f); // COMPLIANT + trunc(i); // COMPLIANT + trunc(f); // COMPLIANT + + /** + * Char not allowed: + */ + acos(c); // NON-COMPLIANT + acosh(c); // NON-COMPLIANT + asin(c); // NON-COMPLIANT + asinh(c); // NON-COMPLIANT + atan2(c, i); // NON-COMPLIANT + atan2(i, c); // NON-COMPLIANT + atanh(c); // NON-COMPLIANT + carg(c); // NON-COMPLIANT + ceil(c); // NON-COMPLIANT + cimag(c); // NON-COMPLIANT + conj(c); // NON-COMPLIANT + copysign(i, c); // NON-COMPLIANT + copysign(c, i); // NON-COMPLIANT + cosh(c); // NON-COMPLIANT + cproj(c); // NON-COMPLIANT + creal(c); // NON-COMPLIANT + erf(c); // NON-COMPLIANT + erfc(c); // NON-COMPLIANT + exp(c); // NON-COMPLIANT + exp2(c); // NON-COMPLIANT + expm1(c); // NON-COMPLIANT + fabs(c); // NON-COMPLIANT + fdim(c, i); // NON-COMPLIANT + fdim(i, c); // NON-COMPLIANT + floor(c); // NON-COMPLIANT + fma(c, i, i); // NON-COMPLIANT + fma(i, c, i); // NON-COMPLIANT + fma(i, i, c); // NON-COMPLIANT + fmax(c, i); // NON-COMPLIANT + fmax(i, c); // NON-COMPLIANT + fmin(c, i); // NON-COMPLIANT + fmin(i, c); // NON-COMPLIANT + fmod(c, i); // NON-COMPLIANT + fmod(i, c); // NON-COMPLIANT + frexp(c, i); // NON-COMPLIANT + hypot(c, i); // NON-COMPLIANT + hypot(i, c); // NON-COMPLIANT + ilogb(c); // NON-COMPLIANT + ldexp(c, i); // NON-COMPLIANT + ldexp(i, c); // NON-COMPLIANT + lgamma(c); // NON-COMPLIANT + llrint(c); // NON-COMPLIANT + llround(c); // NON-COMPLIANT + log(c); // NON-COMPLIANT + log10(c); // NON-COMPLIANT + log1p(c); // NON-COMPLIANT + log2(c); // NON-COMPLIANT + logb(c); // NON-COMPLIANT + lrint(c); // NON-COMPLIANT + lround(c); // NON-COMPLIANT + nearbyint(c); // NON-COMPLIANT + nextafter(c, i); // NON-COMPLIANT + nextafter(i, c); // NON-COMPLIANT + nexttoward(c, i); // NON-COMPLIANT + nexttoward(i, c); // NON-COMPLIANT + pow(c, i); // NON-COMPLIANT + pow(i, c); // NON-COMPLIANT + remainder(c, i); // NON-COMPLIANT + remainder(i, c); // NON-COMPLIANT + remquo(c, i, i); // NON-COMPLIANT + remquo(i, c, i); // NON-COMPLIANT + rint(c); // NON-COMPLIANT + round(c); // NON-COMPLIANT + scalbn(c, i); // NON-COMPLIANT + scalbn(i, c); // NON-COMPLIANT + scalbln(c, i); // NON-COMPLIANT + scalbln(i, c); // NON-COMPLIANT + sin(c); // NON-COMPLIANT + sinh(c); // NON-COMPLIANT + sqrt(c); // NON-COMPLIANT + tan(c); // NON-COMPLIANT + tanh(c); // NON-COMPLIANT + tgamma(c); // NON-COMPLIANT + trunc(c); // NON-COMPLIANT + + /** + * Complex types allowed in some calls, not others: + */ + acos(cf); // COMPLIANT + acosh(cf); // COMPLIANT + asin(cf); // COMPLIANT + asinh(cf); // COMPLIANT + atan(cf); // COMPLIANT + atan2(cf, i); // NON-COMPLIANT + atan2(i, cf); // NON-COMPLIANT + atanh(cf); // COMPLIANT + carg(cf); // COMPLIANT + cbrt(cf); // NON-COMPLIANT + ceil(cf); // NON-COMPLIANT + cimag(cf); // COMPLIANT + conj(cf); // COMPLIANT + copysign(i, cf); // NON-COMPLIANT + copysign(cf, i); // NON-COMPLIANT + copysign(i, cf); // NON-COMPLIANT + cos(cf); // COMPLIANT + cosh(cf); // COMPLIANT + cproj(cf); // COMPLIANT + creal(cf); // COMPLIANT + erf(cf); // NON-COMPLIANT + erfc(cf); // NON-COMPLIANT + exp(cf); // COMPLIANT + exp2(cf); // NON-COMPLIANT + expm1(cf); // NON-COMPLIANT + fabs(cf); // COMPLIANT + fdim(cf, i); // NON-COMPLIANT + fdim(i, cf); // NON-COMPLIANT + floor(cf); // NON-COMPLIANT + fma(cf, i, i); // NON-COMPLIANT + fma(i, cf, i); // NON-COMPLIANT + fma(i, i, cf); // NON-COMPLIANT + fmax(cf, i); // NON-COMPLIANT + fmax(i, cf); // NON-COMPLIANT + fmin(cf, i); // NON-COMPLIANT + fmin(i, cf); // NON-COMPLIANT + fmod(cf, i); // NON-COMPLIANT + fmod(i, cf); // NON-COMPLIANT + frexp(cf, i); // NON-COMPLIANT + hypot(cf, i); // NON-COMPLIANT + hypot(i, cf); // NON-COMPLIANT + ilogb(cf); // NON-COMPLIANT + ldexp(cf, i); // NON-COMPLIANT + ldexp(i, cf); // NON-COMPLIANT + lgamma(cf); // NON-COMPLIANT + llrint(cf); // NON-COMPLIANT + llround(cf); // NON-COMPLIANT + log(cf); // COMPLIANT + log10(cf); // NON-COMPLIANT + log1p(cf); // NON-COMPLIANT + log2(cf); // NON-COMPLIANT + logb(cf); // NON-COMPLIANT + lrint(cf); // NON-COMPLIANT + lround(cf); // NON-COMPLIANT + nearbyint(cf); // NON-COMPLIANT + nextafter(cf, i); // NON-COMPLIANT + nextafter(i, cf); // NON-COMPLIANT + nexttoward(cf, i); // NON-COMPLIANT + nexttoward(i, cf); // NON-COMPLIANT + pow(cf, cf); // COMPLIANT + remainder(cf, i); // NON-COMPLIANT + remainder(i, cf); // NON-COMPLIANT + remquo(cf, i, i); // NON-COMPLIANT + remquo(i, cf, i); // NON-COMPLIANT + rint(cf); // NON-COMPLIANT + round(cf); // NON-COMPLIANT + scalbn(cf, i); // NON-COMPLIANT + scalbn(i, cf); // NON-COMPLIANT + scalbln(cf, i); // NON-COMPLIANT + scalbln(i, cf); // NON-COMPLIANT + sin(cf); // COMPLIANT + sinh(cf); // COMPLIANT + sqrt(cf); // COMPLIANT + tan(cf); // COMPLIANT + tanh(cf); // COMPLIANT + tgamma(cf); // NON-COMPLIANT + trunc(cf); // NON-COMPLIANT + + /* Test output arguments thoroughly */ + frexp(i, &i); // COMPLIANT + frexp(i, vp); // COMPLIANT + frexp(i, 0); // COMPLIANT + frexp(i, 'c' - 'c'); // COMPLIANT + frexp(i, c); // COMPLIANT + remquo(i, i, &i); // COMPLIANT + remquo(i, i, vp); // COMPLIANT + remquo(i, i, 0); // COMPLIANT + remquo(i, i, 'c' - 'c'); // COMPLIANT + remquo(i, i, c); // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected new file mode 100644 index 0000000000..6136aa4314 --- /dev/null +++ b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected @@ -0,0 +1,139 @@ +| test.c:95:3:95:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:96:3:96:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:97:3:97:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:98:3:98:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:99:3:99:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:100:3:100:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:101:3:101:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:102:3:102:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:103:3:103:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:104:3:104:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:105:3:105:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:106:3:106:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:107:3:107:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:108:3:108:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:109:3:109:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:110:3:110:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:111:3:111:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:112:3:112:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:113:3:113:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:114:3:114:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:121:3:121:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:122:3:122:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:123:3:123:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:124:3:124:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:125:3:125:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:126:3:126:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:127:3:127:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:128:3:128:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:131:3:131:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:132:3:132:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:133:3:133:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:134:3:134:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:135:3:135:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:136:3:136:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:137:3:137:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:138:3:138:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:139:3:139:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:140:3:140:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:141:3:141:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:142:3:142:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:143:3:143:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:144:3:144:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:145:3:145:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:146:3:146:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:147:3:147:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:148:3:148:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:149:3:149:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:150:3:150:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:151:3:151:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:152:3:152:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:153:3:153:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:154:3:154:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:155:3:155:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:156:3:156:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:157:3:157:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:158:3:158:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:159:3:159:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:160:3:160:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:161:3:161:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:162:3:162:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:165:3:165:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:166:3:166:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:167:3:167:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:168:3:168:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:169:3:169:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:170:3:170:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:171:3:171:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:172:3:172:17 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:175:3:175:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (float, double). | +| test.c:176:3:176:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (float, long double). | +| test.c:177:3:177:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (double, float). | +| test.c:178:3:178:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (double, long double). | +| test.c:179:3:179:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long double, float). | +| test.c:180:3:180:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long double, double). | +| test.c:183:3:183:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:184:3:184:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:185:3:185:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:186:3:186:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:187:3:187:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:188:3:188:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:189:3:189:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:190:3:190:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:191:3:191:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:192:3:192:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:193:3:193:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:194:3:194:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:195:3:195:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:196:3:196:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:197:3:197:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:198:3:198:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:199:3:199:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:200:3:200:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:201:3:201:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:202:3:202:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:203:3:203:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:204:3:204:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:205:3:205:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:206:3:206:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:207:3:207:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:208:3:208:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:209:3:209:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:210:3:210:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:211:3:211:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:212:3:212:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:213:3:213:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, float). | +| test.c:214:3:214:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, double). | +| test.c:215:3:215:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long double). | +| test.c:216:3:216:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, float). | +| test.c:217:3:217:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, double). | +| test.c:218:3:218:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long double). | +| test.c:219:3:219:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, float). | +| test.c:220:3:220:13 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, double). | +| test.c:221:3:221:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, long double). | +| test.c:222:3:222:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, float). | +| test.c:223:3:223:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, double). | +| test.c:224:3:224:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, long double). | +| test.c:225:3:225:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, float). | +| test.c:226:3:226:14 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, double). | +| test.c:227:3:227:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long double). | +| test.c:228:3:228:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, float). | +| test.c:229:3:229:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, double). | +| test.c:230:3:230:16 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long double). | +| test.c:235:3:235:15 | atan2(x,y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:242:3:242:16 | copysign(x,y) | Call to type-generic macro 'copysign' has arguments with differing standard types (int, float). | +| test.c:245:3:245:12 | fdim(x,y) | Call to type-generic macro 'fdim' has arguments with differing standard types (int, float). | +| test.c:248:3:248:14 | fma(x,y,z) | Call to type-generic macro 'fma' has arguments with differing standard types (float, int, int). | +| test.c:249:3:249:14 | fma(x,y,z) | Call to type-generic macro 'fma' has arguments with differing standard types (int, float, int). | +| test.c:250:3:250:14 | fma(x,y,z) | Call to type-generic macro 'fma' has arguments with differing standard types (int, int, float). | +| test.c:253:3:253:12 | fmax(x,y) | Call to type-generic macro 'fmax' has arguments with differing standard types (int, float). | +| test.c:256:3:256:12 | fmin(x,y) | Call to type-generic macro 'fmin' has arguments with differing standard types (int, float). | +| test.c:259:3:259:12 | fmod(x,y) | Call to type-generic macro 'fmod' has arguments with differing standard types (int, float). | +| test.c:262:3:262:13 | hypot(x,y) | Call to type-generic macro 'hypot' has arguments with differing standard types (int, float). | +| test.c:265:3:265:13 | ldexp(x,y) | Call to type-generic macro 'ldexp' has arguments with differing standard types (int, float). | +| test.c:268:3:268:17 | nextafter(x,y) | Call to type-generic macro 'nextafter' has arguments with differing standard types (int, float). | +| test.c:271:3:271:18 | nexttoward(x,y) | Call to type-generic macro 'nexttoward' has arguments with differing standard types (int, float). | +| test.c:274:3:274:17 | remainder(x,y) | Call to type-generic macro 'remainder' has arguments with differing standard types (int, float). | +| test.c:277:3:277:17 | remquo(x,y,z) | Call to type-generic macro 'remquo' has arguments with differing standard types (int, float). | +| test.c:280:3:280:15 | scalbln(x,y) | Call to type-generic macro 'scalbln' has arguments with differing standard types (int, float). | +| test.c:283:3:283:14 | scalbn(x,y) | Call to type-generic macro 'scalbn' has arguments with differing standard types (int, float). | diff --git a/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.qlref b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.qlref new file mode 100644 index 0000000000..550893822f --- /dev/null +++ b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.qlref @@ -0,0 +1 @@ +rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-23/test.c b/c/misra/test/rules/RULE-21-23/test.c new file mode 100644 index 0000000000..08df1184a7 --- /dev/null +++ b/c/misra/test/rules/RULE-21-23/test.c @@ -0,0 +1,288 @@ +#include +#include + +void f1() { + signed char c = 0; + unsigned char uc = 0; + short s = 0; + unsigned short us = 0; + int i = 0; + unsigned int ui = 0; + long l = 0; + unsigned long ul = 0; + float f = 0.0f; + double d = 0.0; + long double ld = 0.0; + uint8_t u8 = 0; + int8_t i8 = 0; + uint16_t u16 = 0; + int16_t i16 = 0; + uint32_t u32 = 0; + int32_t i32 = 0; + uint64_t u64 = 0; + int64_t i64 = 0; + + /** + * Test exact types + */ + atan2(c, c); // COMPLIANT + atan2(uc, uc); // COMPLIANT + atan2(s, s); // COMPLIANT + atan2(us, us); // COMPLIANT + atan2(i, i); // COMPLIANT + atan2(ui, ui); // COMPLIANT + atan2(ui, ui); // COMPLIANT + atan2(l, l); // COMPLIANT + atan2(ul, ul); // COMPLIANT + atan2(f, f); // COMPLIANT + atan2(d, d); // COMPLIANT + atan2(ld, ld); // COMPLIANT + atan2(u8, u8); // COMPLIANT + atan2(i8, i8); // COMPLIANT + atan2(u16, u16); // COMPLIANT + atan2(i16, i16); // COMPLIANT + atan2(u32, u32); // COMPLIANT + atan2(i32, i32); // COMPLIANT + atan2(u64, u64); // COMPLIANT + atan2(i64, i64); // COMPLIANT + + /** Test equivalent types */ + atan2(c, i8); // COMPLIANT + atan2(i8, c); // COMPLIANT + atan2(uc, u8); // COMPLIANT + atan2(u8, uc); // COMPLIANT + atan2(s, i16); // COMPLIANT + atan2(i16, s); // COMPLIANT + atan2(us, u16); // COMPLIANT + atan2(u16, us); // COMPLIANT + atan2(i, i32); // COMPLIANT + atan2(i32, i); // COMPLIANT + atan2(ui, u32); // COMPLIANT + atan2(u32, ui); // COMPLIANT + atan2(l, i64); // COMPLIANT + atan2(i64, l); // COMPLIANT + atan2(ul, u64); // COMPLIANT + atan2(u64, ul); // COMPLIANT + + /** Types are the same after integer promotion */ + atan2(c, i8); // COMPLIANT + atan2(c, u8); // COMPLIANT + atan2(c, i16); // COMPLIANT + atan2(c, u16); // COMPLIANT + atan2(c, i32); // COMPLIANT + atan2(uc, i8); // COMPLIANT + atan2(uc, u8); // COMPLIANT + atan2(uc, i16); // COMPLIANT + atan2(uc, u16); // COMPLIANT + atan2(uc, i32); // COMPLIANT + atan2(s, i8); // COMPLIANT + atan2(s, u8); // COMPLIANT + atan2(s, i16); // COMPLIANT + atan2(s, u16); // COMPLIANT + atan2(s, i32); // COMPLIANT + atan2(us, i8); // COMPLIANT + atan2(us, u8); // COMPLIANT + atan2(us, i16); // COMPLIANT + atan2(us, u16); // COMPLIANT + atan2(us, i32); // COMPLIANT + atan2(i, i8); // COMPLIANT + atan2(i, u8); // COMPLIANT + atan2(i, i16); // COMPLIANT + atan2(i, u16); // COMPLIANT + atan2(i, i32); // COMPLIANT + + /** Integer promotion makes a signed int, not an unsigned int */ + atan2(c, ui); // NON-COMPLIANT + atan2(c, u32); // NON-COMPLIANT + atan2(i8, ui); // NON-COMPLIANT + atan2(i8, u32); // NON-COMPLIANT + atan2(uc, ui); // NON-COMPLIANT + atan2(uc, u32); // NON-COMPLIANT + atan2(u8, ui); // NON-COMPLIANT + atan2(u8, u32); // NON-COMPLIANT + atan2(s, ui); // NON-COMPLIANT + atan2(s, u32); // NON-COMPLIANT + atan2(i16, ui); // NON-COMPLIANT + atan2(i16, u32); // NON-COMPLIANT + atan2(us, ui); // NON-COMPLIANT + atan2(us, u32); // NON-COMPLIANT + atan2(u16, ui); // NON-COMPLIANT + atan2(u16, u32); // NON-COMPLIANT + atan2(i, ui); // NON-COMPLIANT + atan2(i, u32); // NON-COMPLIANT + atan2(i32, ui); // NON-COMPLIANT + atan2(i32, u32); // NON-COMPLIANT + atan2(ui, ui); // COMPLIANT + atan2(ui, u32); // COMPLIANT + atan2(u32, ui); // COMPLIANT + atan2(u32, u32); // COMPLIANT + + /** Integer promotion makes int, not long */ + atan2(c, l); // NON-COMPLIANT + atan2(i8, l); // NON-COMPLIANT + atan2(uc, l); // NON-COMPLIANT + atan2(u8, l); // NON-COMPLIANT + atan2(s, l); // NON-COMPLIANT + atan2(i16, l); // NON-COMPLIANT + atan2(us, l); // NON-COMPLIANT + atan2(u16, l); // NON-COMPLIANT + + /** Integer vs long */ + atan2(i, l); // NON-COMPLIANT + atan2(i32, l); // NON-COMPLIANT + atan2(ui, l); // NON-COMPLIANT + atan2(u32, l); // NON-COMPLIANT + atan2(l, i); // NON-COMPLIANT + atan2(l, ui); // NON-COMPLIANT + atan2(l, i32); // NON-COMPLIANT + atan2(l, u32); // NON-COMPLIANT + atan2(i, ul); // NON-COMPLIANT + atan2(i32, ul); // NON-COMPLIANT + atan2(ui, ul); // NON-COMPLIANT + atan2(u32, ul); // NON-COMPLIANT + atan2(ul, i); // NON-COMPLIANT + atan2(ul, ui); // NON-COMPLIANT + atan2(ul, i32); // NON-COMPLIANT + atan2(ul, u32); // NON-COMPLIANT + atan2(i, i64); // NON-COMPLIANT + atan2(i32, i64); // NON-COMPLIANT + atan2(ui, i64); // NON-COMPLIANT + atan2(u32, i64); // NON-COMPLIANT + atan2(i64, i); // NON-COMPLIANT + atan2(i64, ui); // NON-COMPLIANT + atan2(i64, i32); // NON-COMPLIANT + atan2(i64, u32); // NON-COMPLIANT + atan2(i, u64); // NON-COMPLIANT + atan2(i32, u64); // NON-COMPLIANT + atan2(ui, u64); // NON-COMPLIANT + atan2(u32, u64); // NON-COMPLIANT + atan2(u64, i); // NON-COMPLIANT + atan2(u64, ui); // NON-COMPLIANT + atan2(u64, i32); // NON-COMPLIANT + atan2(u64, u32); // NON-COMPLIANT + + /** Signed vs unsigned long, since those don't promote */ + atan2(l, ul); // NON-COMPLIANT + atan2(l, u64); // NON-COMPLIANT + atan2(i64, ul); // NON-COMPLIANT + atan2(i64, u64); // NON-COMPLIANT + atan2(ul, l); // NON-COMPLIANT + atan2(ul, i64); // NON-COMPLIANT + atan2(u64, l); // NON-COMPLIANT + atan2(u64, i64); // NON-COMPLIANT + + /** Mismatched float sizes */ + atan2(f, d); // NON-COMPLIANT + atan2(f, ld); // NON-COMPLIANT + atan2(d, f); // NON-COMPLIANT + atan2(d, ld); // NON-COMPLIANT + atan2(ld, f); // NON-COMPLIANT + atan2(ld, d); // NON-COMPLIANT + + /** Float vs int */ + atan2(c, f); // NON-COMPLIANT + atan2(c, d); // NON-COMPLIANT + atan2(c, ld); // NON-COMPLIANT + atan2(i8, f); // NON-COMPLIANT + atan2(i8, d); // NON-COMPLIANT + atan2(i8, ld); // NON-COMPLIANT + atan2(uc, f); // NON-COMPLIANT + atan2(uc, d); // NON-COMPLIANT + atan2(uc, ld); // NON-COMPLIANT + atan2(u8, f); // NON-COMPLIANT + atan2(u8, d); // NON-COMPLIANT + atan2(u8, ld); // NON-COMPLIANT + atan2(s, f); // NON-COMPLIANT + atan2(s, d); // NON-COMPLIANT + atan2(s, ld); // NON-COMPLIANT + atan2(i16, f); // NON-COMPLIANT + atan2(i16, d); // NON-COMPLIANT + atan2(i16, ld); // NON-COMPLIANT + atan2(us, f); // NON-COMPLIANT + atan2(us, d); // NON-COMPLIANT + atan2(us, ld); // NON-COMPLIANT + atan2(u16, f); // NON-COMPLIANT + atan2(u16, d); // NON-COMPLIANT + atan2(u16, ld); // NON-COMPLIANT + atan2(i, f); // NON-COMPLIANT + atan2(i, d); // NON-COMPLIANT + atan2(i, ld); // NON-COMPLIANT + atan2(i32, f); // NON-COMPLIANT + atan2(i32, d); // NON-COMPLIANT + atan2(i32, ld); // NON-COMPLIANT + atan2(ui, f); // NON-COMPLIANT + atan2(ui, d); // NON-COMPLIANT + atan2(ui, ld); // NON-COMPLIANT + atan2(u32, f); // NON-COMPLIANT + atan2(u32, d); // NON-COMPLIANT + atan2(u32, ld); // NON-COMPLIANT + atan2(l, f); // NON-COMPLIANT + atan2(l, d); // NON-COMPLIANT + atan2(l, ld); // NON-COMPLIANT + atan2(i64, f); // NON-COMPLIANT + atan2(i64, d); // NON-COMPLIANT + atan2(i64, ld); // NON-COMPLIANT + atan2(ul, f); // NON-COMPLIANT + atan2(ul, d); // NON-COMPLIANT + atan2(ul, ld); // NON-COMPLIANT + atan2(u64, f); // NON-COMPLIANT + atan2(u64, d); // NON-COMPLIANT + atan2(u64, ld); // NON-COMPLIANT + + /** Casts and conversions */ + atan2((float)i, f); // COMPLIANT + atan2(i, (int)f); // COMPLIANT + atan2((i), f); // NON-COMPLIANT + atan2(((float)i), f); // COMPLIANT + atan2((float)((int)l), f); // COMPLIANT + + /** Other functions */ + copysign(f, f); // COMPLIANT + copysign(i, i); // COMPLIANT + copysign(i, f); // NON-COMPLIANT + fdim(f, f); // COMPLIANT + fdim(i, i); // COMPLIANT + fdim(i, f); // NON-COMPLIANT + fma(f, f, f); // COMPLIANT + fma(i, i, i); // COMPLIANT + fma(f, i, i); // NON-COMPLIANT + fma(i, f, i); // NON-COMPLIANT + fma(i, i, f); // NON-COMPLIANT + fmax(f, f); // COMPLIANT + fmax(i, i); // COMPLIANT + fmax(i, f); // NON-COMPLIANT + fmin(f, f); // COMPLIANT + fmin(i, i); // COMPLIANT + fmin(i, f); // NON-COMPLIANT + fmod(f, f); // COMPLIANT + fmod(i, i); // COMPLIANT + fmod(i, f); // NON-COMPLIANT + hypot(f, f); // COMPLIANT + hypot(i, i); // COMPLIANT + hypot(i, f); // NON-COMPLIANT + ldexp(f, f); // COMPLIANT + ldexp(i, i); // COMPLIANT + ldexp(i, f); // NON-COMPLIANT + nextafter(f, f); // COMPLIANT + nextafter(i, i); // COMPLIANT + nextafter(i, f); // NON-COMPLIANT + nexttoward(f, f); // COMPLIANT + nexttoward(i, i); // COMPLIANT + nexttoward(i, f); // NON-COMPLIANT + remainder(f, f); // COMPLIANT + remainder(i, i); // COMPLIANT + remainder(i, f); // NON-COMPLIANT + remquo(f, f, 0); // COMPLIANT + remquo(i, i, 0); // COMPLIANT + remquo(i, f, 0); // NON-COMPLIANT + scalbln(f, f); // COMPLIANT + scalbln(i, i); // COMPLIANT + scalbln(i, f); // NON-COMPLIANT + scalbn(f, f); // COMPLIANT + scalbn(i, i); // COMPLIANT + scalbn(i, f); // NON-COMPLIANT + + // `frexp` has two parameters, but the second is an output parameter, and + // should not be covered by this rule. + frexp(f, 0); // COMPLIANT +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes2.qll new file mode 100644 index 0000000000..e1dd8d5636 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/EssentialTypes2.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype EssentialTypes2Query = + TTgMathArgumentWithInvalidEssentialTypeQuery() or + TTgMathArgumentsWithDifferingStandardTypeQuery() + +predicate isEssentialTypes2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `tgMathArgumentWithInvalidEssentialType` query + EssentialTypes2Package::tgMathArgumentWithInvalidEssentialTypeQuery() and + queryId = + // `@id` for the `tgMathArgumentWithInvalidEssentialType` query + "c/misra/tg-math-argument-with-invalid-essential-type" and + ruleId = "RULE-21-22" and + category = "mandatory" + or + query = + // `Query` instance for the `tgMathArgumentsWithDifferingStandardType` query + EssentialTypes2Package::tgMathArgumentsWithDifferingStandardTypeQuery() and + queryId = + // `@id` for the `tgMathArgumentsWithDifferingStandardType` query + "c/misra/tg-math-arguments-with-differing-standard-type" and + ruleId = "RULE-21-23" and + category = "required" +} + +module EssentialTypes2Package { + Query tgMathArgumentWithInvalidEssentialTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `tgMathArgumentWithInvalidEssentialType` query + TQueryC(TEssentialTypes2PackageQuery(TTgMathArgumentWithInvalidEssentialTypeQuery())) + } + + Query tgMathArgumentsWithDifferingStandardTypeQuery() { + //autogenerate `Query` type + result = + // `Query` type for `tgMathArgumentsWithDifferingStandardType` query + TQueryC(TEssentialTypes2PackageQuery(TTgMathArgumentsWithDifferingStandardTypeQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 2c3969861c..9b3e3efdd9 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -34,6 +34,7 @@ import Declarations6 import Declarations7 import Declarations8 import EssentialTypes +import EssentialTypes2 import Expressions import FloatingTypes import FunctionTypes @@ -118,6 +119,7 @@ newtype TCQuery = TDeclarations7PackageQuery(Declarations7Query q) or TDeclarations8PackageQuery(Declarations8Query q) or TEssentialTypesPackageQuery(EssentialTypesQuery q) or + TEssentialTypes2PackageQuery(EssentialTypes2Query q) or TExpressionsPackageQuery(ExpressionsQuery q) or TFloatingTypesPackageQuery(FloatingTypesQuery q) or TFunctionTypesPackageQuery(FunctionTypesQuery q) or @@ -202,6 +204,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isDeclarations7QueryMetadata(query, queryId, ruleId, category) or isDeclarations8QueryMetadata(query, queryId, ruleId, category) or isEssentialTypesQueryMetadata(query, queryId, ruleId, category) or + isEssentialTypes2QueryMetadata(query, queryId, ruleId, category) or isExpressionsQueryMetadata(query, queryId, ruleId, category) or isFloatingTypesQueryMetadata(query, queryId, ruleId, category) or isFunctionTypesQueryMetadata(query, queryId, ruleId, category) or diff --git a/rule_packages/c/EssentialTypes2.json b/rule_packages/c/EssentialTypes2.json new file mode 100644 index 0000000000..aded94817f --- /dev/null +++ b/rule_packages/c/EssentialTypes2.json @@ -0,0 +1,47 @@ +{ + "MISRA-C-2012": { + "RULE-21-22": { + "properties": { + "obligation": "mandatory" + }, + "queries": [ + { + "description": "All operand arguments to any type-generic macros in shall have an appropriate essential type", + "kind": "problem", + "name": "All operand arguments to any type-generic macros in shall have an appropriate essential", + "precision": "high", + "severity": "error", + "short_name": "TgMathArgumentWithInvalidEssentialType", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "implementation_scope": { + "description": "The CodeQL database may not contain the necessary information to determine the essential type of literal macro arguments such as character literals." + }, + "title": "All operand arguments to any type-generic macros in shall have an appropriate essential type" + }, + "RULE-21-23": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "All operand arguments to any multi-argument type-generic macros in shall have the same standard type", + "kind": "problem", + "name": "All operand arguments to any multi-argument type-generic macros in shall have the same", + "precision": "high", + "severity": "error", + "short_name": "TgMathArgumentsWithDifferingStandardType", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "All operand arguments to any multi-argument type-generic macros in shall have the same standard type" + } + } +} \ No newline at end of file From 6148518eb42b967f04bacb0cf18d7631f3478a28 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 11 Mar 2025 18:32:51 -0700 Subject: [PATCH 298/628] Format qll, update package metadata --- c/common/src/codingstandards/c/TgMath.qll | 15 +++++---------- .../TgMathArgumentWithInvalidEssentialType.ql | 4 ++-- .../TgMathArgumentsWithDifferingStandardType.ql | 4 ++-- rule_packages/c/EssentialTypes2.json | 8 ++++---- 4 files changed, 13 insertions(+), 18 deletions(-) diff --git a/c/common/src/codingstandards/c/TgMath.qll b/c/common/src/codingstandards/c/TgMath.qll index f5488194c6..36c47fb5a2 100644 --- a/c/common/src/codingstandards/c/TgMath.qll +++ b/c/common/src/codingstandards/c/TgMath.qll @@ -1,4 +1,3 @@ - import cpp private string getATgMathMacroName(boolean allowComplex) { @@ -35,21 +34,17 @@ class TgMathInvocation extends MacroInvocation { } Expr getOperandArgument(int i) { - result = call.getArgument(i) - and not hasOutputArgument(call.getTarget().getName(), i) + result = call.getArgument(i) and + not hasOutputArgument(call.getTarget().getName(), i) } int getNumberOfOperandArguments() { result = call.getNumberOfArguments() - count(int i | hasOutputArgument(getMacroName(), i)) } - Expr getAnOperandArgument() { - result = getOperandArgument(_) - } + Expr getAnOperandArgument() { result = getOperandArgument(_) } - predicate allowsComplex() { - allowComplex = true - } + predicate allowsComplex() { allowComplex = true } } private Call getACallInExpansion(MacroInvocation mi) { result = mi.getAnExpandedElement() } @@ -65,4 +60,4 @@ private Call getBestCallInExpansion(MacroInvocation mi) { or count(getNameMatchedCallInExpansion(mi)) > 1 and result = rank[1](Call c | c = getACallInExpansion(mi) | c order by c.getTarget().getName()) -} \ No newline at end of file +} diff --git a/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql b/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql index f06ca54979..2105567d04 100644 --- a/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql +++ b/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql @@ -1,8 +1,8 @@ /** * @id c/misra/tg-math-argument-with-invalid-essential-type - * @name RULE-21-22: All operand arguments to any type-generic macros in shall have an appropriate essential + * @name RULE-21-22: All operand arguments to type-generic macros in shall have an appropriate essential type * @description All operand arguments to any type-generic macros in shall have an - * appropriate essential type + * appropriate essential type. * @kind problem * @precision high * @problem.severity error diff --git a/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql b/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql index b6daf7bb6a..5156d81cef 100644 --- a/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql +++ b/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql @@ -1,8 +1,8 @@ /** * @id c/misra/tg-math-arguments-with-differing-standard-type - * @name RULE-21-23: All operand arguments to any multi-argument type-generic macros in shall have the same + * @name RULE-21-23: Operand arguments for an invocation of a type-generic macro shall have the same standard type * @description All operand arguments to any multi-argument type-generic macros in shall - * have the same standard type + * have the same standard type. * @kind problem * @precision high * @problem.severity error diff --git a/rule_packages/c/EssentialTypes2.json b/rule_packages/c/EssentialTypes2.json index aded94817f..5292eccdb8 100644 --- a/rule_packages/c/EssentialTypes2.json +++ b/rule_packages/c/EssentialTypes2.json @@ -6,9 +6,9 @@ }, "queries": [ { - "description": "All operand arguments to any type-generic macros in shall have an appropriate essential type", + "description": "All operand arguments to any type-generic macros in shall have an appropriate essential type.", "kind": "problem", - "name": "All operand arguments to any type-generic macros in shall have an appropriate essential", + "name": "All operand arguments to type-generic macros in shall have an appropriate essential type", "precision": "high", "severity": "error", "short_name": "TgMathArgumentWithInvalidEssentialType", @@ -29,9 +29,9 @@ }, "queries": [ { - "description": "All operand arguments to any multi-argument type-generic macros in shall have the same standard type", + "description": "All operand arguments to any multi-argument type-generic macros in shall have the same standard type.", "kind": "problem", - "name": "All operand arguments to any multi-argument type-generic macros in shall have the same", + "name": "Operand arguments for an invocation of a type-generic macro shall have the same standard type", "precision": "high", "severity": "error", "short_name": "TgMathArgumentsWithDifferingStandardType", From e30b3c34dcd9defdba2adc5dea814be68e2c585e Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 11 Mar 2025 22:12:53 -0700 Subject: [PATCH 299/628] Implement final MISRA 2023 rule amendments --- amendments.csv | 9 +- ...dLocalObjectAddressCopiedToGlobalObject.ql | 39 ++++ .../ExceptionHandlingFeaturesOfFenvhUsed.ql | 26 ++- c/misra/test/rules/DIR-4-9/test.c | 1 + .../EmergentLanguageFeaturesUsed.expected | 1 - ...ObjectAddressCopiedToGlobalObject.expected | 4 + ...calObjectAddressCopiedToGlobalObject.qlref | 1 + c/misra/test/rules/RULE-18-6/test.c | 169 ++++++++++++++++++ ...eptionHandlingFeaturesOfFenvhUsed.expected | 28 +-- c/misra/test/rules/RULE-21-12/test.c | 9 +- .../2025-03-11-various-misra-amendments.md | 8 + .../src/codingstandards/cpp/Emergent.qll | 4 - .../cpp/IrreplaceableFunctionLikeMacro.qll | 6 + .../cpp/exclusions/c/Pointers1.qll | 17 ++ ...ddressOfAutoStorageObjectToOtherObject.qll | 2 +- rule_packages/c/Pointers1.json | 12 ++ 16 files changed, 303 insertions(+), 33 deletions(-) create mode 100644 c/misra/src/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql create mode 100644 c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.expected create mode 100644 c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.qlref create mode 100644 c/misra/test/rules/RULE-18-6/test.c create mode 100644 change_notes/2025-03-11-various-misra-amendments.md diff --git a/amendments.csv b/amendments.csv index 6049525515..b496790f07 100644 --- a/amendments.csv +++ b/amendments.csv @@ -1,8 +1,8 @@ language,standard,amendment,rule_id,supportable,implementation_category,implemented,difficulty c,MISRA-C-2012,Amendment3,DIR-4-6,Yes,Expand,Yes,Easy -c,MISRA-C-2012,Amendment3,DIR-4-9,Yes,Refine,No,Easy +c,MISRA-C-2012,Amendment3,DIR-4-9,Yes,Refine,Yes,Easy c,MISRA-C-2012,Amendment3,DIR-4-11,Yes,Refine,No,Import -c,MISRA-C-2012,Amendment3,RULE-1-4,Yes,Replace,No,Easy +c,MISRA-C-2012,Amendment3,RULE-1-4,Yes,Replace,Yes,Easy c,MISRA-C-2012,Amendment3,RULE-10-1,Yes,Replace,Yes,Easy c,MISRA-C-2012,Amendment3,RULE-10-3,Yes,Refine,Yes,Easy c,MISRA-C-2012,Amendment3,RULE-10-4,Yes,Refine,Yes,Import @@ -10,11 +10,11 @@ c,MISRA-C-2012,Amendment3,RULE-10-5,Yes,Expand,Yes,Easy c,MISRA-C-2012,Amendment3,RULE-10-7,Yes,Refine,Yes,Import c,MISRA-C-2012,Amendment3,RULE-10-8,Yes,Refine,Yes,Import c,MISRA-C-2012,Amendment3,RULE-21-11,Yes,Clarification,Yes,Import -c,MISRA-C-2012,Amendment3,RULE-21-12,Yes,Replace,No,Easy +c,MISRA-C-2012,Amendment3,RULE-21-12,Yes,Replace,Yes,Easy c,MISRA-C-2012,Amendment4,RULE-11-3,Yes,Expand,No,Easy c,MISRA-C-2012,Amendment4,RULE-11-8,Yes,Expand,No,Easy c,MISRA-C-2012,Amendment4,RULE-13-2,Yes,Expand,No,Very Hard -c,MISRA-C-2012,Amendment4,RULE-18-6,Yes,Expand,No,Medium +c,MISRA-C-2012,Amendment4,RULE-18-6,Yes,Expand,Yes,Medium c,MISRA-C-2012,Amendment4,RULE-18-8,Yes,Split,Yes,Easy c,MISRA-C-2012,Amendment4,RULE-2-2,Yes,Clarification,Yes,Import c,MISRA-C-2012,Amendment4,RULE-2-7,Yes,Clarification,Yes,Import @@ -26,7 +26,6 @@ c,MISRA-C-2012,Amendment4,RULE-10-1,Yes,Clarification,Yes,Import c,MISRA-C-2012,Amendment4,RULE-18-3,Yes,Clarification,Yes,Import c,MISRA-C-2012,Amendment4,RULE-1-4,Yes,Replace,No,Easy c,MISRA-C-2012,Amendment4,RULE-9-1,Yes,Refine,No,Easy -c,MISRA-C-2012,Amendment4,RULE-9-2,Yes,Refine,No,Import c,MISRA-C-2012,Corrigendum2,DIR-4-10,Yes,Clarification,Yes,Import c,MISRA-C-2012,Corrigendum2,RULE-7-4,Yes,Refine,No,Easy c,MISRA-C-2012,Corrigendum2,RULE-8-2,Yes,Clarification,Yes,Import diff --git a/c/misra/src/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql b/c/misra/src/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql new file mode 100644 index 0000000000..6a520447d1 --- /dev/null +++ b/c/misra/src/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql @@ -0,0 +1,39 @@ +/** + * @id c/misra/thread-local-object-address-copied-to-global-object + * @name RULE-18-6: The address of an object with thread-local storage shall not be copied to a global object + * @description Storing the address of a thread-local object in a global object will result in + * undefined behavior if the address is accessed after the relevant thread is + * terminated. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-18-6 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.Objects +import codingstandards.cpp.Concurrency + +from AssignExpr assignment, Element threadLocal, ObjectIdentity static +where + not isExcluded(assignment, Pointers1Package::threadLocalObjectAddressCopiedToGlobalObjectQuery()) and + assignment.getLValue() = static.getASubobjectAccess() and + static.getStorageDuration().isStatic() and + ( + exists(ObjectIdentity threadLocalObj | + threadLocal = threadLocalObj and + assignment.getRValue() = threadLocalObj.getASubobjectAddressExpr() and + threadLocalObj.getStorageDuration().isThread() + ) + or + exists(TSSGetFunctionCall getCall | + threadLocal = getCall.getKey() and + assignment.getRValue() = getCall + ) + ) +select assignment, "Thread local object $@ address copied to static object $@.", + threadLocal.getLocation(), threadLocal.toString(), static.getLocation(), static.toString() diff --git a/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql b/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql index 33da2f5d03..c70e71ea1a 100644 --- a/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql +++ b/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql @@ -18,7 +18,8 @@ import codingstandards.c.misra class FPExceptionHandlingFunction extends Function { FPExceptionHandlingFunction() { this.hasName([ - "feclearexcept", "fegetexceptflag", "feraiseexcept", "fesetexceptflag", "fetestexcept" + "feclearexcept", "fegetexceptflag", "feraiseexcept", "fesetexceptflag", "fetestexcept", + "fesetenv", "feupdateenv", "fesetround" ]) and this.getFile().getBaseName() = "fenv.h" } @@ -33,22 +34,29 @@ class FPExceptionHandlingMacro extends Macro { } } -from Locatable call, string name, string kind +from Locatable element, string name, string message where - not isExcluded(call, BannedPackage::exceptionHandlingFeaturesOfFenvhUsedQuery()) and + not isExcluded(element, BannedPackage::exceptionHandlingFeaturesOfFenvhUsedQuery()) and ( + exists(Include include | + include.getIncludedFile().getBaseName() = "fenv.h" and + message = "Include of banned header" and + name = "fenv.h" and + element = include + ) + or exists(FPExceptionHandlingFunction f | - call = f.getACallToThisFunction() and + element = f.getACallToThisFunction() and name = f.getName() and - kind = "function" + message = "Call to banned function" ) or exists(FPExceptionHandlingMacro m | - call = m.getAnInvocation() and + element = m.getAnInvocation() and name = m.getName() and - kind = "macro" and + message = "Expansion of banned macro" and // Exclude macro invocations expanded from other macro invocations from macros in fenv.h. - not call.(MacroInvocation).getParentInvocation().getMacro().getFile().getBaseName() = "fenv.h" + not element.(MacroInvocation).getParentInvocation().getMacro().getFile().getBaseName() = "fenv.h" ) ) -select call, "Call to banned " + kind + " " + name + "." +select element, message + " '" + name + "'." diff --git a/c/misra/test/rules/DIR-4-9/test.c b/c/misra/test/rules/DIR-4-9/test.c index 50e6bdb042..c91e1a15a2 100644 --- a/c/misra/test/rules/DIR-4-9/test.c +++ b/c/misra/test/rules/DIR-4-9/test.c @@ -10,6 +10,7 @@ #define MACRO8(x) "NOP" // COMPLIANT #define MACRO9() printf_custom("output = %d", 7) // NON_COMPLIANT #define MACRO10(x) // COMPLIANT +#define MACRO11(x) _Generic((x), int: 1, default: 0) // COMPLIANT #define MY_ASSERT(X) assert(X) // NON_COMPLIANT[FALSE_NEGATIVE] const char a1[MACRO2(1, 1) + 6]; diff --git a/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected b/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected index 04c0e1bbd6..b0bbc467aa 100644 --- a/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected +++ b/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected @@ -1,6 +1,5 @@ | test.c:2:1:2:22 | #include | Usage of emergent language feature. | | test.c:4:1:4:20 | #include | Usage of emergent language feature. | -| test.c:6:1:6:49 | #define MACRO(x) _Generic((x), int : 0, long : 1) | Usage of emergent language feature. | | test.c:7:1:7:32 | #define __STDC_WANT_LIB_EXT1__ 1 | Usage of emergent language feature. | | test.c:12:26:12:40 | atomic_new_type | Usage of emergent language feature. | | test.c:17:15:17:15 | i | Usage of emergent language feature. | diff --git a/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.expected b/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.expected new file mode 100644 index 0000000000..99c5a91645 --- /dev/null +++ b/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.expected @@ -0,0 +1,4 @@ +| test.c:29:3:29:10 | ... = ... | Thread local object $@ address copied to static object $@. | test.c:8:19:8:20 | test.c:8:19:8:20 | t1 | test.c:12:6:12:7 | test.c:12:6:12:7 | g2 | +| test.c:55:3:55:14 | ... = ... | Thread local object $@ address copied to static object $@. | test.c:10:17:10:18 | test.c:10:17:10:18 | t3 | test.c:13:3:13:4 | test.c:13:3:13:4 | g3 | +| test.c:152:3:152:21 | ... = ... | Thread local object $@ address copied to static object $@. | test.c:152:16:152:20 | test.c:152:16:152:20 | & ... | test.c:12:6:12:7 | test.c:12:6:12:7 | g2 | +| test.c:155:3:155:23 | ... = ... | Thread local object $@ address copied to static object $@. | test.c:155:18:155:22 | test.c:155:18:155:22 | & ... | test.c:13:3:13:4 | test.c:13:3:13:4 | g3 | diff --git a/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.qlref b/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.qlref new file mode 100644 index 0000000000..90cdd7a43f --- /dev/null +++ b/c/misra/test/rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.qlref @@ -0,0 +1 @@ +rules/RULE-18-6/ThreadLocalObjectAddressCopiedToGlobalObject.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-18-6/test.c b/c/misra/test/rules/RULE-18-6/test.c new file mode 100644 index 0000000000..13b1070397 --- /dev/null +++ b/c/misra/test/rules/RULE-18-6/test.c @@ -0,0 +1,169 @@ +#include + +typedef struct { + int *p; + int m +} s; + +_Thread_local int t1; +_Thread_local int *t2; +_Thread_local s t3; +int g1; +int *g2; +s g3; + +void f1() { + // Regular object accesses + t1 = t1; // COMPLIANT + t1 = *t2; // COMPLIANT + t1 = g1; // COMPLIANT + t1 = *g2; // COMPLIANT + g1 = t1; // COMPLIANT + g1 = *t2; // COMPLIANT + g1 = g1; // COMPLIANT + g1 = *g2; // COMPLIANT + t2 = &t1; // COMPLIANT + t2 = t2; // COMPLIANT + t2 = &g1; // COMPLIANT + t2 = g2; // COMPLIANT + g2 = &t1; // NON-COMPLIANT + g2 = t2; // COMPLIANT + g2 = &g1; // COMPLIANT + g2 = g2; // COMPLIANT + *t2 = t1; // COMPLIANT + *t2 = *t2; // COMPLIANT + *t2 = g1; // COMPLIANT + *t2 = *g2; // COMPLIANT + *g2 = t1; // COMPLIANT + *g2 = *t2; // COMPLIANT + *g2 = g1; // COMPLIANT + *g2 = *g2; // COMPLIANT + + // Subobject accesses + t3.m = t3.m; // COMPLIANT + t3.m = *t3.p; // COMPLIANT + t3.m = g3.m; // COMPLIANT + t3.m = *g3.p; // COMPLIANT + g3.m = t3.m; // COMPLIANT + g3.m = *t3.p; // COMPLIANT + g3.m = g3.m; // COMPLIANT + g3.m = *g3.p; // COMPLIANT + t3.p = &t3.m; // COMPLIANT + t3.p = t3.p; // COMPLIANT + t3.p = &g3.m; // COMPLIANT + t3.p = g3.p; // COMPLIANT + g3.p = &t3.m; // NON-COMPLIANT + g3.p = t3.p; // COMPLIANT + g3.p = &g3.m; // COMPLIANT + g3.p = g3.p; // COMPLIANT + *t3.p = t3.m; // COMPLIANT + *t3.p = *t3.p; // COMPLIANT + *t3.p = g3.m; // COMPLIANT + *t3.p = *g3.p; // COMPLIANT + *g3.p = t3.m; // COMPLIANT + *g3.p = *t3.p; // COMPLIANT + *g3.p = g3.m; // COMPLIANT + *g3.p = *g3.p; // COMPLIANT + + // Storing values in locals (automatic storage duration) + int l1; + int *l2; + s l3; + + l1 = l1; // COMPLIANT + l1 = *l2; // COMPLIANT + l1 = l3.m; // COMPLIANT + l1 = *l3.p; // COMPLIANT + l1 = t1; // COMPLIANT + l1 = *t2; // COMPLIANT + l1 = t3.m; // COMPLIANT + l1 = *t3.p; // COMPLIANT + l1 = g1; // COMPLIANT + l1 = *g2; // COMPLIANT + l1 = g3.m; // COMPLIANT + l1 = *g3.p; // COMPLIANT + l2 = &l1; // COMPLIANT + l2 = l2; // COMPLIANT + l2 = &l3.m; // COMPLIANT + l2 = l3.p; // COMPLIANT + l2 = &t1; // COMPLIANT + l2 = t2; // COMPLIANT + l2 = &t3.m; // COMPLIANT + l2 = t3.p; // COMPLIANT + l2 = &g1; // COMPLIANT + l2 = g2; // COMPLIANT + l2 = &g3.m; // COMPLIANT + l2 = g3.p; // COMPLIANT + *l2 = l1; // COMPLIANT + *l2 = *l2; // COMPLIANT + *l2 = l3.m; // COMPLIANT + *l2 = *l3.p; // COMPLIANT + *l2 = t1; // COMPLIANT + *l2 = *t2; // COMPLIANT + *l2 = t3.m; // COMPLIANT + *l2 = *t3.p; // COMPLIANT + *l2 = g1; // COMPLIANT + *l2 = *g2; // COMPLIANT + *l2 = g3.m; // COMPLIANT + *l2 = *g3.p; // COMPLIANT + l3.m = l1; // COMPLIANT + l3.m = *l2; // COMPLIANT + l3.m = l3.m; // COMPLIANT + l3.m = *l3.p; // COMPLIANT + l3.m = t1; // COMPLIANT + l3.m = *t2; // COMPLIANT + l3.m = t3.m; // COMPLIANT + l3.m = *t3.p; // COMPLIANT + l3.m = g1; // COMPLIANT + l3.m = *g2; // COMPLIANT + l3.m = g3.m; // COMPLIANT + l3.m = *g3.p; // COMPLIANT + l3.p = &l1; // COMPLIANT + l3.p = l2; // COMPLIANT + l3.p = &l3.m; // COMPLIANT + l3.p = l3.p; // COMPLIANT + l3.p = &t1; // COMPLIANT + l3.p = t2; // COMPLIANT + l3.p = &t3.m; // COMPLIANT + l3.p = t3.p; // COMPLIANT + l3.p = &g1; // COMPLIANT + l3.p = g2; // COMPLIANT + l3.p = &g3.m; // COMPLIANT + l3.p = g3.p; // COMPLIANT + *l3.p = l1; // COMPLIANT + *l3.p = *l2; // COMPLIANT + *l3.p = l3.m; // COMPLIANT + *l3.p = *l3.p; // COMPLIANT + *l3.p = t1; // COMPLIANT + *l3.p = *t2; // COMPLIANT + *l3.p = t3.m; // COMPLIANT + *l3.p = *t3.p; // COMPLIANT + *l3.p = g1; // COMPLIANT + *l3.p = *g2; // COMPLIANT + *l3.p = g3.m; // COMPLIANT + *l3.p = *g3.p; // COMPLIANT + + // Storing local values in globals is covered by the shared query. +} + +tss_t tss1; +void f2() { + g1 = *(int *)tss_get(&tss1); // COMPLIANT + g2 = tss_get(&tss1); // NON-COMPLIANT + *g2 = *(int *)tss_get(&tss1); // COMPLIANT + g3.m = *(int *)tss_get(&tss1); // COMPLIANT + g3.p = tss_get(&tss1); // NON-COMPLIANT + *g3.p = *(int *)tss_get(&tss1); // COMPLIANT + g1 = ((s *)tss_get(&tss1))->m; // COMPLIANT + g1 = *((s *)tss_get(&tss1))->p; // COMPLIANT + g2 = &((s *)tss_get(&tss1))->m; // NON-COMPLIANT[false negative] + g2 = *((s *)tss_get(&tss1))->p; // COMPLIANT + *g2 = ((s *)tss_get(&tss1))->m; // COMPLIANT + *g2 = *((s *)tss_get(&tss1))->p; // COMPLIANT + g3.m = ((s *)tss_get(&tss1))->m; // COMPLIANT + g3.m = *((s *)tss_get(&tss1))->p; // COMPLIANT + g3.p = &((s *)tss_get(&tss1))->m; // NON-COMPLIANT[false negative] + g3.p = *((s *)tss_get(&tss1))->p; // COMPLIANT + *g3.p = ((s *)tss_get(&tss1))->m; // COMPLIANT + *g3.p = *((s *)tss_get(&tss1))->p; // COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.expected b/c/misra/test/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.expected index 747b25a2c1..8032bf38cc 100644 --- a/c/misra/test/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.expected +++ b/c/misra/test/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.expected @@ -1,12 +1,16 @@ -| test.c:4:11:4:23 | call to feclearexcept | Call to banned function feclearexcept. | -| test.c:4:25:4:34 | FE_INVALID | Call to banned macro FE_INVALID. | -| test.c:6:3:6:17 | call to fegetexceptflag | Call to banned function fegetexceptflag. | -| test.c:6:24:6:36 | FE_ALL_EXCEPT | Call to banned macro FE_ALL_EXCEPT. | -| test.c:7:3:7:15 | call to feraiseexcept | Call to banned function feraiseexcept. | -| test.c:7:17:7:28 | FE_DIVBYZERO | Call to banned macro FE_DIVBYZERO. | -| test.c:8:3:8:15 | call to feraiseexcept | Call to banned function feraiseexcept. | -| test.c:8:17:8:27 | FE_OVERFLOW | Call to banned macro FE_OVERFLOW. | -| test.c:9:3:9:17 | call to fesetexceptflag | Call to banned function fesetexceptflag. | -| test.c:9:24:9:36 | FE_ALL_EXCEPT | Call to banned macro FE_ALL_EXCEPT. | -| test.c:10:3:10:14 | call to fetestexcept | Call to banned function fetestexcept. | -| test.c:10:16:10:27 | FE_UNDERFLOW | Call to banned macro FE_UNDERFLOW. | +| test.c:2:1:2:17 | #include | Include of banned header 'fenv.h'. | +| test.c:6:11:6:23 | call to feclearexcept | Call to banned function 'feclearexcept'. | +| test.c:6:25:6:34 | FE_INVALID | Expansion of banned macro 'FE_INVALID'. | +| test.c:8:3:8:17 | call to fegetexceptflag | Call to banned function 'fegetexceptflag'. | +| test.c:8:24:8:36 | FE_ALL_EXCEPT | Expansion of banned macro 'FE_ALL_EXCEPT'. | +| test.c:9:3:9:15 | call to feraiseexcept | Call to banned function 'feraiseexcept'. | +| test.c:9:17:9:28 | FE_DIVBYZERO | Expansion of banned macro 'FE_DIVBYZERO'. | +| test.c:10:3:10:15 | call to feraiseexcept | Call to banned function 'feraiseexcept'. | +| test.c:10:17:10:27 | FE_OVERFLOW | Expansion of banned macro 'FE_OVERFLOW'. | +| test.c:11:3:11:17 | call to fesetexceptflag | Call to banned function 'fesetexceptflag'. | +| test.c:11:24:11:36 | FE_ALL_EXCEPT | Expansion of banned macro 'FE_ALL_EXCEPT'. | +| test.c:12:3:12:14 | call to fetestexcept | Call to banned function 'fetestexcept'. | +| test.c:12:16:12:27 | FE_UNDERFLOW | Expansion of banned macro 'FE_UNDERFLOW'. | +| test.c:15:3:15:10 | call to fesetenv | Call to banned function 'fesetenv'. | +| test.c:16:3:16:13 | call to feupdateenv | Call to banned function 'feupdateenv'. | +| test.c:17:3:17:12 | call to fesetround | Call to banned function 'fesetround'. | diff --git a/c/misra/test/rules/RULE-21-12/test.c b/c/misra/test/rules/RULE-21-12/test.c index ae4d90a402..9a049c9ed8 100644 --- a/c/misra/test/rules/RULE-21-12/test.c +++ b/c/misra/test/rules/RULE-21-12/test.c @@ -1,4 +1,6 @@ +// NON_COMPLIANT: Cannot #include fenv.h. #include + void f2(); void f1() { int i = feclearexcept(FE_INVALID); // NON_COMPLIANT @@ -8,5 +10,10 @@ void f1() { feraiseexcept(FE_OVERFLOW); // NON_COMPLIANT fesetexceptflag(&i2, FE_ALL_EXCEPT); // NON_COMPLIANT fetestexcept(FE_UNDERFLOW); // NON_COMPLIANT - f2(); // COMPLIANT + fenv_t env; + fegetenv(&env); + fesetenv(&env); // NON_COMPLIANT + feupdateenv(&env); // NON_COMPLIANT + fesetround(0); // NON_COMPLIANT + f2(); // COMPLIANT } diff --git a/change_notes/2025-03-11-various-misra-amendments.md b/change_notes/2025-03-11-various-misra-amendments.md new file mode 100644 index 0000000000..99acdcc63a --- /dev/null +++ b/change_notes/2025-03-11-various-misra-amendments.md @@ -0,0 +1,8 @@ + - `DIR-4-9` - `FunctionOverFunctionLikeMacro.ql`: + - Macros with `_Generic` now no longer reported. + - `RULE-1-4` - `EmergentLanguageFeaturesUsed.ql`: + - Ban on usage of `_Generics` removed. + - `RULE-18-6` - `ThreadLocalObjectAddressCopiedToGlobalObject.ql`: + - New query added to detect thread local objects assigned to static storage duration objects. + - `RULE-21-12` - `ExceptionHandlingFeaturesOfFenvhUsed.ql`: + - Added reports for `#include`ing "fenv.h", and for using `fesetenv`, `feupdatenv`, and `fesetround`. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Emergent.qll b/cpp/common/src/codingstandards/cpp/Emergent.qll index 506d024bc9..3b3fbbaebd 100644 --- a/cpp/common/src/codingstandards/cpp/Emergent.qll +++ b/cpp/common/src/codingstandards/cpp/Emergent.qll @@ -30,8 +30,4 @@ module C11 { getBody() = "1" } } - - class GenericMacro extends EmergentLanguageFeature, Macro { - GenericMacro() { getBody().indexOf("_Generic") = 0 } - } } diff --git a/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll b/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll index af62cacfd3..e3d6df7e50 100644 --- a/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll +++ b/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll @@ -56,3 +56,9 @@ private class FunctionLikeMacroWithOperatorArgument extends IrreplaceableFunctio ) } } + +private class GenericMacro extends IrreplaceableFunctionLikeMacro { + GenericMacro() { + getBody().matches("%_Generic%") + } +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll index e35f0f3a88..725fe46904 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Pointers1.qll @@ -19,6 +19,7 @@ newtype Pointers1Query = TDoNotUseAdditionOrSubtractionOperatorsOnPointersQuery() or TNoMoreThanTwoLevelsOfPointerNestingInDeclarationsQuery() or TAutomaticStorageObjectAddressCopiedToOtherObjectQuery() or + TThreadLocalObjectAddressCopiedToGlobalObjectQuery() or TObjectWithNoPointerDereferenceShouldBeOpaqueQuery() or TPointerShouldPointToConstTypeWhenPossibleQuery() @@ -158,6 +159,15 @@ predicate isPointers1QueryMetadata(Query query, string queryId, string ruleId, s ruleId = "RULE-18-6" and category = "required" or + query = + // `Query` instance for the `threadLocalObjectAddressCopiedToGlobalObject` query + Pointers1Package::threadLocalObjectAddressCopiedToGlobalObjectQuery() and + queryId = + // `@id` for the `threadLocalObjectAddressCopiedToGlobalObject` query + "c/misra/thread-local-object-address-copied-to-global-object" and + ruleId = "RULE-18-6" and + category = "required" + or query = // `Query` instance for the `objectWithNoPointerDereferenceShouldBeOpaque` query Pointers1Package::objectWithNoPointerDereferenceShouldBeOpaqueQuery() and @@ -283,6 +293,13 @@ module Pointers1Package { TQueryC(TPointers1PackageQuery(TAutomaticStorageObjectAddressCopiedToOtherObjectQuery())) } + Query threadLocalObjectAddressCopiedToGlobalObjectQuery() { + //autogenerate `Query` type + result = + // `Query` type for `threadLocalObjectAddressCopiedToGlobalObject` query + TQueryC(TPointers1PackageQuery(TThreadLocalObjectAddressCopiedToGlobalObjectQuery())) + } + Query objectWithNoPointerDereferenceShouldBeOpaqueQuery() { //autogenerate `Query` type result = diff --git a/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll b/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll index 1b22fd5c3b..214f8e9aba 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll @@ -54,4 +54,4 @@ query predicate problems(Expr use, string message, Expr source, string srcStr) { srcStr = "parameter" ) ) -} +} \ No newline at end of file diff --git a/rule_packages/c/Pointers1.json b/rule_packages/c/Pointers1.json index 5f53d15702..1b54fc1fb6 100644 --- a/rule_packages/c/Pointers1.json +++ b/rule_packages/c/Pointers1.json @@ -305,6 +305,18 @@ "correctness", "external/misra/c/2012/third-edition-first-revision" ] + }, + { + "description": "Storing the address of a thread-local object in a global object will result in undefined behavior if the address is accessed after the relevant thread is terminated.", + "kind": "problem", + "name": "The address of an object with thread-local storage shall not be copied to a global object", + "precision": "very-high", + "severity": "error", + "short_name": "ThreadLocalObjectAddressCopiedToGlobalObject", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] } ], "title": "The address of an object with automatic storage shall not be copied to another object that persists after the first object has ceased to exist" From f363371916d4e8aecf6540597c07985648d01dc0 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 11 Mar 2025 22:22:30 -0700 Subject: [PATCH 300/628] Update generic test expectation offsets post formatting --- ...ectionDoesntDependOnMacroArgument.expected | 6 +- ...ricSelectionNotExpandedFromAMacro.expected | 2 +- ...ectionNotFromMacroWithSideEffects.expected | 6 +- ...nericWithoutNonDefaultAssociation.expected | 4 +- ...icAssociationWithUnselectableType.expected | 26 +-- ...faultSelectionForPointerInGeneric.expected | 168 +++++++++--------- ...ressionWithIncorrectEssentialType.expected | 8 +- ...lidGenericMacroArgumentEvaluation.expected | 24 +-- ...ultGenericSelectionNotFirstOrLast.expected | 8 +- 9 files changed, 126 insertions(+), 126 deletions(-) diff --git a/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.expected b/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.expected index 2534e47012..a903827391 100644 --- a/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.expected +++ b/c/misra/test/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.expected @@ -1,3 +1,3 @@ -| test.c:2:1:2:30 | #define M1 _Generic(1, int: 1) | Generic macro M1 uses controlling expr 1, which doesn't match any macro parameter. | -| test.c:4:1:4:33 | #define M2(X) _Generic(1, int: X) | Generic macro M2 uses controlling expr 1, which doesn't match any macro parameter. | -| test.c:18:1:18:38 | #define M9(X) g(_Generic((Y), int: 1)) | Generic macro M9 uses controlling expr (Y), which doesn't match any macro parameter. | +| test.c:2:1:2:31 | #define M1 _Generic(1, int : 1) | Generic macro M1 uses controlling expr 1, which doesn't match any macro parameter. | +| test.c:4:1:4:34 | #define M2(X) _Generic(1, int : X) | Generic macro M2 uses controlling expr 1, which doesn't match any macro parameter. | +| test.c:18:1:18:39 | #define M9(X) g(_Generic((Y), int : 1)) | Generic macro M9 uses controlling expr (Y), which doesn't match any macro parameter. | diff --git a/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.expected b/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.expected index 476a9320b8..aa3516354e 100644 --- a/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.expected +++ b/c/misra/test/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.expected @@ -1 +1 @@ -| test.c:21:3:21:21 | _Generic | Generic expression with controlling expression $@ is not expanded froma macro | test.c:21:12:21:12 | 1 | 1 | +| test.c:21:3:21:22 | _Generic | Generic expression with controlling expression $@ is not expanded froma macro | test.c:21:12:21:12 | 1 | 1 | diff --git a/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.expected b/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.expected index 1abcb4f2bb..b0a970bbcf 100644 --- a/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.expected +++ b/c/misra/test/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.expected @@ -1,3 +1,3 @@ -| test.c:4:1:4:37 | #define M2(X) _Generic((X)++, int: 1) | Generic selection macro M2 contains a side effect '... ++', which is not from macro invocation arguments. | test.c:4:1:4:37 | #define M2(X) _Generic((X)++, int: 1) | (ignored) | -| test.c:7:1:7:38 | #define M3(X) _Generic(l1++, int: (X)) | Generic selection macro M3 contains a side effect '... ++', which is not from macro invocation arguments. | test.c:7:1:7:38 | #define M3(X) _Generic(l1++, int: (X)) | (ignored) | -| test.c:42:1:44:24 | #define M5(X) static volatile l ## X; _Generic(l ## X, int: 1) | Generic selection in macro M5 contains an invocation-dependent side effect which is not from macro invocation arguments, for example $@. | test.c:47:3:47:7 | _Generic | side effect 'la' | +| test.c:4:1:4:38 | #define M2(X) _Generic((X)++, int : 1) | Generic selection macro M2 contains a side effect '... ++', which is not from macro invocation arguments. | test.c:4:1:4:38 | #define M2(X) _Generic((X)++, int : 1) | (ignored) | +| test.c:7:1:7:39 | #define M3(X) _Generic(l1++, int : (X)) | Generic selection macro M3 contains a side effect '... ++', which is not from macro invocation arguments. | test.c:7:1:7:39 | #define M3(X) _Generic(l1++, int : (X)) | (ignored) | +| test.c:42:1:44:25 | #define M5(X) static volatile l ## X; _Generic(l ## X, int : 1) | Generic selection in macro M5 contains an invocation-dependent side effect which is not from macro invocation arguments, for example $@. | test.c:47:3:47:7 | _Generic | side effect 'la' | diff --git a/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.expected b/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.expected index 50d6277e84..6a56026947 100644 --- a/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.expected +++ b/c/misra/test/rules/RULE-23-3/GenericWithoutNonDefaultAssociation.expected @@ -1,2 +1,2 @@ -| test.c:2:1:2:35 | #define M1 _Generic(1, default: 1); | Generic selection contains no non-default association. | -| test.c:14:3:14:25 | _Generic | Generic selection contains no non-default association. | +| test.c:2:1:2:36 | #define M1 _Generic(1, default : 1); | Generic selection contains no non-default association. | +| test.c:14:3:14:26 | _Generic | Generic selection contains no non-default association. | diff --git a/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.expected b/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.expected index 27030fc768..132bb82979 100644 --- a/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.expected +++ b/c/misra/test/rules/RULE-23-4/GenericAssociationWithUnselectableType.expected @@ -1,13 +1,13 @@ -| test.c:11:18:11:18 | 1 | Generic selection uses unselectable type 'const int', due to qualifiers removed'. | test.c:11:18:11:18 | 1 | side effect | -| test.c:12:21:12:21 | 1 | Generic selection uses unselectable type 'volatile int', due to qualifiers removed'. | test.c:12:21:12:21 | 1 | side effect | -| test.c:13:20:13:20 | 1 | Generic selection uses unselectable type '_Atomic(int)', due to qualifiers removed'. | test.c:13:20:13:20 | 1 | side effect | -| test.c:16:27:16:27 | 1 | Generic selection uses unselectable type 'const volatile int', due to qualifiers removed'. | test.c:16:27:16:27 | 1 | side effect | -| test.c:18:18:18:18 | 1 | Generic selection uses unselectable type '(unnamed class/struct/union)', due to containing an anonymous struct or union type'. | test.c:18:18:18:18 | 1 | side effect | -| test.c:19:20:19:20 | 1 | Generic selection uses unselectable type 'struct *', due to containing an anonymous struct or union type'. | test.c:19:20:19:20 | 1 | side effect | -| test.c:24:17:24:17 | 1 | Generic selection uses unselectable type '(unnamed class/struct/union)', due to containing an anonymous struct or union type'. | test.c:24:17:24:17 | 1 | side effect | -| test.c:25:19:25:19 | 1 | Generic selection uses unselectable type 'union *', due to containing an anonymous struct or union type'. | test.c:25:19:25:19 | 1 | side effect | -| test.c:31:15:31:15 | 1 | Generic selection uses unselectable type 'int[3]', due to array-to-pointer decay'. | test.c:31:15:31:15 | 1 | side effect | -| test.c:40:1:40:53 | #define M1(X) _Generic((X), const int: 1, default: 0) | Generic in macro M1 has unselectable type 'const int', due to qualifiers removed. | test.c:40:1:40:53 | #define M1(X) _Generic((X), const int: 1, default: 0) | (ignored) | -| test.c:42:1:42:46 | #define M2(X) _Generic(1, X[3]: 1, default: 0) | Generic in macro M2 has an invocation-dependent unselectable type, for example $@. | test.c:49:3:49:10 | 1 | 'char[3]', due to array-to-pointer decay | -| test.c:52:3:52:15 | M3(X) | Generic resulting from invocation of macro $@ contains an unselectable type 'const int', due to qualifiers removed. | test.c:44:1:44:43 | #define M3(X) _Generic(1, X: 1, default: 0) | M3 | -| test.c:64:18:64:18 | 1 | Generic selection uses unselectable type 'const_int', due to qualifiers removed'. | test.c:64:18:64:18 | 1 | side effect | +| test.c:11:24:11:24 | 1 | Generic selection uses unselectable type 'const int', due to qualifiers removed'. | test.c:11:24:11:24 | 1 | side effect | +| test.c:12:27:12:27 | 1 | Generic selection uses unselectable type 'volatile int', due to qualifiers removed'. | test.c:12:27:12:27 | 1 | side effect | +| test.c:13:26:13:26 | 1 | Generic selection uses unselectable type '_Atomic(int)', due to qualifiers removed'. | test.c:13:26:13:26 | 1 | side effect | +| test.c:16:33:16:33 | 1 | Generic selection uses unselectable type 'const volatile int', due to qualifiers removed'. | test.c:16:33:16:33 | 1 | side effect | +| test.c:18:24:18:24 | 1 | Generic selection uses unselectable type '(unnamed class/struct/union)', due to containing an anonymous struct or union type'. | test.c:18:24:18:24 | 1 | side effect | +| test.c:19:26:19:26 | 1 | Generic selection uses unselectable type 'struct *', due to containing an anonymous struct or union type'. | test.c:19:26:19:26 | 1 | side effect | +| test.c:24:23:24:23 | 1 | Generic selection uses unselectable type '(unnamed class/struct/union)', due to containing an anonymous struct or union type'. | test.c:24:23:24:23 | 1 | side effect | +| test.c:25:25:25:25 | 1 | Generic selection uses unselectable type 'union *', due to containing an anonymous struct or union type'. | test.c:25:25:25:25 | 1 | side effect | +| test.c:31:21:31:21 | 1 | Generic selection uses unselectable type 'int[3]', due to array-to-pointer decay'. | test.c:31:21:31:21 | 1 | side effect | +| test.c:40:1:40:55 | #define M1(X) _Generic((X), const int : 1, default : 0) | Generic in macro M1 has unselectable type 'const int', due to qualifiers removed. | test.c:40:1:40:55 | #define M1(X) _Generic((X), const int : 1, default : 0) | (ignored) | +| test.c:42:1:42:48 | #define M2(X) _Generic(1, X[3] : 1, default : 0) | Generic in macro M2 has an invocation-dependent unselectable type, for example $@. | test.c:49:3:49:10 | 1 | 'char[3]', due to array-to-pointer decay | +| test.c:52:3:52:15 | M3(X) | Generic resulting from invocation of macro $@ contains an unselectable type 'const int', due to qualifiers removed. | test.c:44:1:44:45 | #define M3(X) _Generic(1, X : 1, default : 0) | M3 | +| test.c:64:24:64:24 | 1 | Generic selection uses unselectable type 'const_int', due to qualifiers removed'. | test.c:64:24:64:24 | 1 | side effect | diff --git a/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.expected b/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.expected index 994d55968c..3ed6b3f26b 100644 --- a/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.expected +++ b/c/misra/test/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.expected @@ -1,84 +1,84 @@ -| test.c:41:3:41:44 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:41:3:41:44 | _Generic | | -| test.c:42:3:42:47 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to volatile int *. | test.c:42:3:42:47 | _Generic | | -| test.c:43:3:43:53 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile int *. | test.c:43:3:43:53 | _Generic | | -| test.c:44:3:44:39 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:44:3:44:39 | _Generic | | -| test.c:45:3:45:45 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const void *. | test.c:45:3:45:45 | _Generic | | -| test.c:46:3:46:54 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile void *. | test.c:46:3:46:54 | _Generic | | -| test.c:48:3:48:38 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:48:3:48:38 | _Generic | | -| test.c:50:3:50:39 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to void *. | test.c:50:3:50:39 | _Generic | | -| test.c:51:3:51:45 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const void *. | test.c:51:3:51:45 | _Generic | | -| test.c:52:3:52:54 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile void *. | test.c:52:3:52:54 | _Generic | | -| test.c:57:3:57:53 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile int *. | test.c:57:3:57:53 | _Generic | | -| test.c:59:3:59:38 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to int *. | test.c:59:3:59:38 | _Generic | | -| test.c:61:3:61:53 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile int *. | test.c:61:3:61:53 | _Generic | | -| test.c:62:3:62:39 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to void *. | test.c:62:3:62:39 | _Generic | | -| test.c:63:3:63:54 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile void *. | test.c:63:3:63:54 | _Generic | | -| test.c:69:3:69:38 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to int *. | test.c:69:3:69:38 | _Generic | | -| test.c:70:3:70:44 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const int *. | test.c:70:3:70:44 | _Generic | | -| test.c:71:3:71:47 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to volatile int *. | test.c:71:3:71:47 | _Generic | | -| test.c:73:3:73:39 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to void *. | test.c:73:3:73:39 | _Generic | | -| test.c:74:3:74:45 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const void *. | test.c:74:3:74:45 | _Generic | | -| test.c:75:3:75:54 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const volatile void *. | test.c:75:3:75:54 | _Generic | | -| test.c:77:3:77:38 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to int *. | test.c:77:3:77:38 | _Generic | | -| test.c:78:3:78:44 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const int *. | test.c:78:3:78:44 | _Generic | | -| test.c:79:3:79:47 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to volatile int *. | test.c:79:3:79:47 | _Generic | | -| test.c:80:3:80:53 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const volatile int *. | test.c:80:3:80:53 | _Generic | | -| test.c:82:3:82:45 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const void *. | test.c:82:3:82:45 | _Generic | | -| test.c:83:3:83:54 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const volatile void *. | test.c:83:3:83:54 | _Generic | | -| test.c:85:3:85:38 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to int *. | test.c:85:3:85:38 | _Generic | | -| test.c:86:3:86:44 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to const int *. | test.c:86:3:86:44 | _Generic | | -| test.c:87:3:87:53 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to const volatile int *. | test.c:87:3:87:53 | _Generic | | -| test.c:88:3:88:39 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to void *. | test.c:88:3:88:39 | _Generic | | -| test.c:90:3:90:54 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to const volatile void *. | test.c:90:3:90:54 | _Generic | | -| test.c:94:3:94:38 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to int *. | test.c:94:3:94:38 | _Generic | | -| test.c:95:3:95:44 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to const int *. | test.c:95:3:95:44 | _Generic | | -| test.c:96:3:96:47 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to volatile int *. | test.c:96:3:96:47 | _Generic | | -| test.c:97:3:97:53 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to const volatile int *. | test.c:97:3:97:53 | _Generic | | -| test.c:98:3:98:39 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to void *. | test.c:98:3:98:39 | _Generic | | -| test.c:99:3:99:45 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to const void *. | test.c:99:3:99:45 | _Generic | | -| test.c:119:3:119:45 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:119:3:119:45 | _Generic | | -| test.c:120:3:120:48 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to volatile int *. | test.c:120:3:120:48 | _Generic | | -| test.c:121:3:121:54 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile int *. | test.c:121:3:121:54 | _Generic | | -| test.c:122:3:122:40 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:122:3:122:40 | _Generic | | -| test.c:123:3:123:46 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const void *. | test.c:123:3:123:46 | _Generic | | -| test.c:124:3:124:55 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile void *. | test.c:124:3:124:55 | _Generic | | -| test.c:126:3:126:39 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:126:3:126:39 | _Generic | | -| test.c:128:3:128:40 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to void *. | test.c:128:3:128:40 | _Generic | | -| test.c:129:3:129:46 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const void *. | test.c:129:3:129:46 | _Generic | | -| test.c:130:3:130:55 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile void *. | test.c:130:3:130:55 | _Generic | | -| test.c:135:3:135:54 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile int *. | test.c:135:3:135:54 | _Generic | | -| test.c:137:3:137:39 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to int *. | test.c:137:3:137:39 | _Generic | | -| test.c:139:3:139:54 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile int *. | test.c:139:3:139:54 | _Generic | | -| test.c:140:3:140:40 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to void *. | test.c:140:3:140:40 | _Generic | | -| test.c:141:3:141:55 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile void *. | test.c:141:3:141:55 | _Generic | | -| test.c:147:3:147:39 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to int *. | test.c:147:3:147:39 | _Generic | | -| test.c:148:3:148:45 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const int *. | test.c:148:3:148:45 | _Generic | | -| test.c:149:3:149:48 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to volatile int *. | test.c:149:3:149:48 | _Generic | | -| test.c:151:3:151:40 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to void *. | test.c:151:3:151:40 | _Generic | | -| test.c:152:3:152:46 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const void *. | test.c:152:3:152:46 | _Generic | | -| test.c:153:3:153:55 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const volatile void *. | test.c:153:3:153:55 | _Generic | | -| test.c:156:3:156:45 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:156:3:156:45 | _Generic | | -| test.c:157:3:157:48 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to volatile int *. | test.c:157:3:157:48 | _Generic | | -| test.c:158:3:158:54 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile int *. | test.c:158:3:158:54 | _Generic | | -| test.c:159:3:159:40 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:159:3:159:40 | _Generic | | -| test.c:160:3:160:46 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const void *. | test.c:160:3:160:46 | _Generic | | -| test.c:161:3:161:55 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile void *. | test.c:161:3:161:55 | _Generic | | -| test.c:163:3:163:39 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:163:3:163:39 | _Generic | | -| test.c:165:3:165:40 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to void *. | test.c:165:3:165:40 | _Generic | | -| test.c:166:3:166:46 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const void *. | test.c:166:3:166:46 | _Generic | | -| test.c:167:3:167:55 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile void *. | test.c:167:3:167:55 | _Generic | | -| test.c:172:3:172:54 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile int *. | test.c:172:3:172:54 | _Generic | | -| test.c:180:3:180:48 | _Generic | Generic matched default selection, as controlling argument type int(*)[3] does not undergo pointer conversion to int(*const)[3]. | test.c:180:3:180:48 | _Generic | | -| test.c:188:3:191:18 | _Generic | Generic matched default selection, as controlling argument type int(*)[3] does not undergo pointer conversion to int(*const)[3]. | test.c:188:3:191:18 | _Generic | | -| test.c:200:3:200:47 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to int *. | test.c:200:3:200:47 | _Generic | | -| test.c:201:3:201:47 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:201:3:201:47 | _Generic | | -| test.c:215:3:215:44 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:215:3:215:44 | _Generic | | -| test.c:216:3:216:46 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int_t *. | test.c:216:3:216:46 | _Generic | | -| test.c:217:3:217:42 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to c_int_t *. | test.c:217:3:217:42 | _Generic | | -| test.c:221:3:221:45 | _Generic | Generic matched default selection, as controlling argument type int_t * does not undergo pointer conversion to const int *. | test.c:221:3:221:45 | _Generic | | -| test.c:222:3:222:47 | _Generic | Generic matched default selection, as controlling argument type int_t * does not undergo pointer conversion to const int_t *. | test.c:222:3:222:47 | _Generic | | -| test.c:223:3:223:43 | _Generic | Generic matched default selection, as controlling argument type int_t * does not undergo pointer conversion to c_int_t *. | test.c:223:3:223:43 | _Generic | | -| test.c:225:3:225:38 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:225:3:225:38 | _Generic | | -| test.c:226:3:226:40 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int_t *. | test.c:226:3:226:40 | _Generic | | -| test.c:231:3:231:39 | _Generic | Generic matched default selection, as controlling argument type c_int_t * does not undergo pointer conversion to int *. | test.c:231:3:231:39 | _Generic | | -| test.c:232:3:232:41 | _Generic | Generic matched default selection, as controlling argument type c_int_t * does not undergo pointer conversion to int_t *. | test.c:232:3:232:41 | _Generic | | +| test.c:41:3:41:46 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:41:3:41:46 | _Generic | | +| test.c:42:3:42:49 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to volatile int *. | test.c:42:3:42:49 | _Generic | | +| test.c:43:3:43:55 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile int *. | test.c:43:3:43:55 | _Generic | | +| test.c:44:3:44:41 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:44:3:44:41 | _Generic | | +| test.c:45:3:45:47 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const void *. | test.c:45:3:45:47 | _Generic | | +| test.c:46:3:46:56 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile void *. | test.c:46:3:46:56 | _Generic | | +| test.c:48:3:48:40 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:48:3:48:40 | _Generic | | +| test.c:50:3:50:41 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to void *. | test.c:50:3:50:41 | _Generic | | +| test.c:51:3:51:47 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const void *. | test.c:51:3:51:47 | _Generic | | +| test.c:52:3:52:56 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile void *. | test.c:52:3:52:56 | _Generic | | +| test.c:57:3:57:55 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile int *. | test.c:57:3:57:55 | _Generic | | +| test.c:59:3:59:40 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to int *. | test.c:59:3:59:40 | _Generic | | +| test.c:61:3:61:55 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile int *. | test.c:61:3:61:55 | _Generic | | +| test.c:62:3:62:41 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to void *. | test.c:62:3:62:41 | _Generic | | +| test.c:63:3:63:56 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile void *. | test.c:63:3:63:56 | _Generic | | +| test.c:69:3:69:40 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to int *. | test.c:69:3:69:40 | _Generic | | +| test.c:70:3:70:46 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const int *. | test.c:70:3:70:46 | _Generic | | +| test.c:71:3:71:49 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to volatile int *. | test.c:71:3:71:49 | _Generic | | +| test.c:73:3:73:41 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to void *. | test.c:73:3:73:41 | _Generic | | +| test.c:74:3:74:47 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const void *. | test.c:74:3:74:47 | _Generic | | +| test.c:75:3:75:56 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const volatile void *. | test.c:75:3:75:56 | _Generic | | +| test.c:77:3:77:40 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to int *. | test.c:77:3:77:40 | _Generic | | +| test.c:78:3:78:46 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const int *. | test.c:78:3:78:46 | _Generic | | +| test.c:79:3:79:49 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to volatile int *. | test.c:79:3:79:49 | _Generic | | +| test.c:80:3:80:55 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const volatile int *. | test.c:80:3:80:55 | _Generic | | +| test.c:82:3:82:47 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const void *. | test.c:82:3:82:47 | _Generic | | +| test.c:83:3:83:56 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to const volatile void *. | test.c:83:3:83:56 | _Generic | | +| test.c:85:3:85:40 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to int *. | test.c:85:3:85:40 | _Generic | | +| test.c:86:3:86:46 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to const int *. | test.c:86:3:86:46 | _Generic | | +| test.c:87:3:87:55 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to const volatile int *. | test.c:87:3:87:55 | _Generic | | +| test.c:88:3:88:41 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to void *. | test.c:88:3:88:41 | _Generic | | +| test.c:90:3:90:56 | _Generic | Generic matched default selection, as controlling argument type const void * does not undergo pointer conversion to const volatile void *. | test.c:90:3:90:56 | _Generic | | +| test.c:94:3:94:40 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to int *. | test.c:94:3:94:40 | _Generic | | +| test.c:95:3:95:46 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to const int *. | test.c:95:3:95:46 | _Generic | | +| test.c:96:3:96:49 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to volatile int *. | test.c:96:3:96:49 | _Generic | | +| test.c:97:3:97:55 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to const volatile int *. | test.c:97:3:97:55 | _Generic | | +| test.c:98:3:98:41 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to void *. | test.c:98:3:98:41 | _Generic | | +| test.c:99:3:99:47 | _Generic | Generic matched default selection, as controlling argument type const volatile void * does not undergo pointer conversion to const void *. | test.c:99:3:99:47 | _Generic | | +| test.c:119:3:119:47 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:119:3:119:47 | _Generic | | +| test.c:120:3:120:50 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to volatile int *. | test.c:120:3:120:50 | _Generic | | +| test.c:121:3:121:56 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile int *. | test.c:121:3:121:56 | _Generic | | +| test.c:122:3:122:42 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:122:3:122:42 | _Generic | | +| test.c:123:3:123:48 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const void *. | test.c:123:3:123:48 | _Generic | | +| test.c:124:3:124:57 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile void *. | test.c:124:3:124:57 | _Generic | | +| test.c:126:3:126:41 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:126:3:126:41 | _Generic | | +| test.c:128:3:128:42 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to void *. | test.c:128:3:128:42 | _Generic | | +| test.c:129:3:129:48 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const void *. | test.c:129:3:129:48 | _Generic | | +| test.c:130:3:130:57 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile void *. | test.c:130:3:130:57 | _Generic | | +| test.c:135:3:135:56 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile int *. | test.c:135:3:135:56 | _Generic | | +| test.c:137:3:137:41 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to int *. | test.c:137:3:137:41 | _Generic | | +| test.c:139:3:139:56 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile int *. | test.c:139:3:139:56 | _Generic | | +| test.c:140:3:140:42 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to void *. | test.c:140:3:140:42 | _Generic | | +| test.c:141:3:141:57 | _Generic | Generic matched default selection, as controlling argument type volatile int * does not undergo pointer conversion to const volatile void *. | test.c:141:3:141:57 | _Generic | | +| test.c:147:3:147:41 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to int *. | test.c:147:3:147:41 | _Generic | | +| test.c:148:3:148:47 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const int *. | test.c:148:3:148:47 | _Generic | | +| test.c:149:3:149:50 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to volatile int *. | test.c:149:3:149:50 | _Generic | | +| test.c:151:3:151:42 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to void *. | test.c:151:3:151:42 | _Generic | | +| test.c:152:3:152:48 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const void *. | test.c:152:3:152:48 | _Generic | | +| test.c:153:3:153:57 | _Generic | Generic matched default selection, as controlling argument type const volatile int * does not undergo pointer conversion to const volatile void *. | test.c:153:3:153:57 | _Generic | | +| test.c:156:3:156:47 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:156:3:156:47 | _Generic | | +| test.c:157:3:157:50 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to volatile int *. | test.c:157:3:157:50 | _Generic | | +| test.c:158:3:158:56 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile int *. | test.c:158:3:158:56 | _Generic | | +| test.c:159:3:159:42 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:159:3:159:42 | _Generic | | +| test.c:160:3:160:48 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const void *. | test.c:160:3:160:48 | _Generic | | +| test.c:161:3:161:57 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const volatile void *. | test.c:161:3:161:57 | _Generic | | +| test.c:163:3:163:41 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:163:3:163:41 | _Generic | | +| test.c:165:3:165:42 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to void *. | test.c:165:3:165:42 | _Generic | | +| test.c:166:3:166:48 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const void *. | test.c:166:3:166:48 | _Generic | | +| test.c:167:3:167:57 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile void *. | test.c:167:3:167:57 | _Generic | | +| test.c:172:3:172:56 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to const volatile int *. | test.c:172:3:172:56 | _Generic | | +| test.c:180:3:180:50 | _Generic | Generic matched default selection, as controlling argument type int(*)[3] does not undergo pointer conversion to int(*const)[3]. | test.c:180:3:180:50 | _Generic | | +| test.c:188:3:192:16 | _Generic | Generic matched default selection, as controlling argument type int(*)[3] does not undergo pointer conversion to int(*const)[3]. | test.c:188:3:192:16 | _Generic | | +| test.c:201:3:201:49 | _Generic | Generic matched default selection, as controlling argument type void * does not undergo pointer conversion to int *. | test.c:201:3:201:49 | _Generic | | +| test.c:202:3:202:49 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to void *. | test.c:202:3:202:49 | _Generic | | +| test.c:216:3:216:46 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int *. | test.c:216:3:216:46 | _Generic | | +| test.c:217:3:217:48 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to const int_t *. | test.c:217:3:217:48 | _Generic | | +| test.c:218:3:218:44 | _Generic | Generic matched default selection, as controlling argument type int * does not undergo pointer conversion to c_int_t *. | test.c:218:3:218:44 | _Generic | | +| test.c:222:3:222:47 | _Generic | Generic matched default selection, as controlling argument type int_t * does not undergo pointer conversion to const int *. | test.c:222:3:222:47 | _Generic | | +| test.c:223:3:223:49 | _Generic | Generic matched default selection, as controlling argument type int_t * does not undergo pointer conversion to const int_t *. | test.c:223:3:223:49 | _Generic | | +| test.c:224:3:224:45 | _Generic | Generic matched default selection, as controlling argument type int_t * does not undergo pointer conversion to c_int_t *. | test.c:224:3:224:45 | _Generic | | +| test.c:226:3:226:40 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int *. | test.c:226:3:226:40 | _Generic | | +| test.c:227:3:227:42 | _Generic | Generic matched default selection, as controlling argument type const int * does not undergo pointer conversion to int_t *. | test.c:227:3:227:42 | _Generic | | +| test.c:232:3:232:41 | _Generic | Generic matched default selection, as controlling argument type c_int_t * does not undergo pointer conversion to int *. | test.c:232:3:232:41 | _Generic | | +| test.c:233:3:233:43 | _Generic | Generic matched default selection, as controlling argument type c_int_t * does not undergo pointer conversion to int_t *. | test.c:233:3:233:43 | _Generic | | diff --git a/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.expected b/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.expected index 1cdcc82698..4f02d039ce 100644 --- a/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.expected +++ b/c/misra/test/rules/RULE-23-6/GenericExpressionWithIncorrectEssentialType.expected @@ -1,4 +1,4 @@ -| test.c:11:3:11:8 | _Generic | Controlling expression in generic macro $@ has standard type (unnamed enum), which doesn't match its essential type (unnamed enum). | test.c:6:1:6:71 | #define M1(X) _Generic((X), int: 1, unsigned int: 1, short: 2, long: 3) | M1 | -| test.c:15:3:15:13 | _Generic | Controlling expression in generic macro $@ has standard type int, which doesn't match its essential type short. | test.c:6:1:6:71 | #define M1(X) _Generic((X), int: 1, unsigned int: 1, short: 2, long: 3) | M1 | -| test.c:18:3:18:23 | _Generic | Controlling expression in generic has standard type int, which doesn't match its essential type char. | test.c:18:3:18:23 | _Generic | | -| test.c:19:3:19:53 | _Generic | Controlling expression in generic has standard type int, which doesn't match its essential type short. | test.c:19:3:19:53 | _Generic | | +| test.c:11:3:11:8 | _Generic | Controlling expression in generic macro $@ has standard type (unnamed enum), which doesn't match its essential type (unnamed enum). | test.c:6:1:6:75 | #define M1(X) _Generic((X), int : 1, unsigned int : 1, short : 2, long : 3) | M1 | +| test.c:15:3:15:13 | _Generic | Controlling expression in generic macro $@ has standard type int, which doesn't match its essential type short. | test.c:6:1:6:75 | #define M1(X) _Generic((X), int : 1, unsigned int : 1, short : 2, long : 3) | M1 | +| test.c:18:3:18:24 | _Generic | Controlling expression in generic has standard type int, which doesn't match its essential type char. | test.c:18:3:18:24 | _Generic | | +| test.c:19:3:19:55 | _Generic | Controlling expression in generic has standard type int, which doesn't match its essential type short. | test.c:19:3:19:55 | _Generic | | diff --git a/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.expected b/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.expected index 57eecd6be8..47a8acce92 100644 --- a/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.expected +++ b/c/misra/test/rules/RULE-23-7/InvalidGenericMacroArgumentEvaluation.expected @@ -1,12 +1,12 @@ -| test.c:9:1:9:51 | #define M3(X) _Generic((X), int: f1(X), default: 0) | Generic macro M3 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 2. | -| test.c:10:1:10:61 | #define M4(X) (X) + _Generic((X), int: f1(X), default: f1(X)) | Generic macro M4 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | -| test.c:11:1:11:61 | #define M5(X) _Generic((X), int: f1(X), default: f1(X)) + (X) | Generic macro M5 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | -| test.c:12:1:12:63 | #define M6(X) _Generic((X), int: f1((X) + (X)), default: f1(X)) | Generic macro M6 may have unexpected behavior from side effects in parameter X, as it is expanded in generic selection 1 more than once. | -| test.c:21:1:21:36 | #define M9(X) _Generic((X), int: f1) | Generic macro M9 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 1. | -| test.c:23:1:23:40 | #define M10(X) _Generic((X), int: f1(1)) | Generic macro M10 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 1. | -| test.c:32:1:32:58 | #define M12(X) _Generic((X) + (X), int: f1(X), default: 1) | Generic macro M12 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 2. | -| test.c:33:1:33:68 | #define M13(X) _Generic((X) + (X), int: f1(X), default: f1(X)) + (X) | Generic macro M13 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | -| test.c:43:1:43:77 | #define M17(X,Y) _Generic((X) + (Y), int: f2((X), (Y)), default: f2((X), 1)) | Generic macro M17 may have unexpected behavior from side effects in parameter Y, as it is not expanded in generic selection 2. | -| test.c:67:1:67:78 | #define M26(X) _Generic((X), int: IGNORE_2ND(X, X), default: IGNORE_2ND(X, X)) | Generic macro M26 may have unexpected behavior from side effects in parameter X, as it is expanded in generic selection 1 more than once. | -| test.c:67:1:67:78 | #define M26(X) _Generic((X), int: IGNORE_2ND(X, X), default: IGNORE_2ND(X, X)) | Generic macro M26 may have unexpected behavior from side effects in parameter X, as it is expanded in generic selection 2 more than once. | -| test.c:68:1:68:75 | #define M27(X) _Generic((X), int: f1(IGNORE(X)), default: f1(IGNORE(X)))(X) | Generic macro M27 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | +| test.c:9:1:9:53 | #define M3(X) _Generic((X), int : f1(X), default : 0) | Generic macro M3 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 2. | +| test.c:10:1:10:63 | #define M4(X) (X) + _Generic((X), int : f1(X), default : f1(X)) | Generic macro M4 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | +| test.c:11:1:11:63 | #define M5(X) _Generic((X), int : f1(X), default : f1(X)) + (X) | Generic macro M5 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | +| test.c:12:1:12:65 | #define M6(X) _Generic((X), int : f1((X) + (X)), default : f1(X)) | Generic macro M6 may have unexpected behavior from side effects in parameter X, as it is expanded in generic selection 1 more than once. | +| test.c:21:1:21:37 | #define M9(X) _Generic((X), int : f1) | Generic macro M9 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 1. | +| test.c:23:1:23:41 | #define M10(X) _Generic((X), int : f1(1)) | Generic macro M10 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 1. | +| test.c:32:1:32:60 | #define M12(X) _Generic((X) + (X), int : f1(X), default : 1) | Generic macro M12 may have unexpected behavior from side effects in parameter X, as it is not expanded in generic selection 2. | +| test.c:33:1:33:70 | #define M13(X) _Generic((X) + (X), int : f1(X), default : f1(X)) + (X) | Generic macro M13 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | +| test.c:43:1:43:79 | #define M17(X,Y) _Generic((X) + (Y), int : f2((X), (Y)), default : f2((X), 1)) | Generic macro M17 may have unexpected behavior from side effects in parameter Y, as it is not expanded in generic selection 2. | +| test.c:68:1:68:80 | #define M26(X) _Generic((X), int : IGNORE_2ND(X, X), default : IGNORE_2ND(X, X)) | Generic macro M26 may have unexpected behavior from side effects in parameter X, as it is expanded in generic selection 1 more than once. | +| test.c:68:1:68:80 | #define M26(X) _Generic((X), int : IGNORE_2ND(X, X), default : IGNORE_2ND(X, X)) | Generic macro M26 may have unexpected behavior from side effects in parameter X, as it is expanded in generic selection 2 more than once. | +| test.c:69:1:69:77 | #define M27(X) _Generic((X), int : f1(IGNORE(X)), default : f1(IGNORE(X)))(X) | Generic macro M27 may have unexpected behavior from side effects in parameter X, as it is expanded outside the generic selection and inside the generic selection. | diff --git a/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.expected b/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.expected index 5951834d00..fb407e2ff1 100644 --- a/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.expected +++ b/c/misra/test/rules/RULE-23-8/DefaultGenericSelectionNotFirstOrLast.expected @@ -1,4 +1,4 @@ -| test.c:11:1:11:64 | #define M4(X) _Generic((X), int: 1, default: 0, unsigned int: 2) | Generic macro M4 has default as 2nd association, which is not first or last. | test.c:11:1:11:64 | #define M4(X) _Generic((X), int: 1, default: 0, unsigned int: 2) | (ignored) | -| test.c:17:1:17:60 | #define M5(__VA_ARGS__...) _Generic(0, __VA_ARGS__, default: 0, int: 1) | Generic macro M5 has a default association which is not first or last, for example $@. | test.c:28:5:28:23 | _Generic | 2nd | -| test.c:34:5:34:27 | M6(__VA_ARGS__...) | Generic macro $@, in this expansion, has default as 2nd association, which is not first or last. | test.c:19:1:19:48 | #define M6(__VA_ARGS__...) _Generic(0, __VA_ARGS__, int: 1) | M6 | -| test.c:44:5:44:52 | _Generic | Generic has default as 2nd association, which is not first or last. | test.c:44:5:44:52 | _Generic | | +| test.c:11:1:11:67 | #define M4(X) _Generic((X), int : 1, default : 0, unsigned int : 2) | Generic macro M4 has default as 2nd association, which is not first or last. | test.c:11:1:11:67 | #define M4(X) _Generic((X), int : 1, default : 0, unsigned int : 2) | (ignored) | +| test.c:17:1:17:62 | #define M5(__VA_ARGS__...) _Generic(0, __VA_ARGS__, default : 0, int : 1) | Generic macro M5 has a default association which is not first or last, for example $@. | test.c:30:3:30:22 | _Generic | 2nd | +| test.c:37:3:37:27 | M6(__VA_ARGS__...) | Generic macro $@, in this expansion, has default as 2nd association, which is not first or last. | test.c:19:1:19:49 | #define M6(__VA_ARGS__...) _Generic(0, __VA_ARGS__, int : 1) | M6 | +| test.c:48:3:48:53 | _Generic | Generic has default as 2nd association, which is not first or last. | test.c:48:3:48:53 | _Generic | | From a1142f3b4ef9e4768f5ffa5ea13025c92dcf2bf2 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 12 Mar 2025 11:38:15 -0700 Subject: [PATCH 301/628] reformat (and reformat generic with clang-format 11) --- .../rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql | 3 ++- c/misra/test/rules/DIR-4-9/test.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql b/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql index c70e71ea1a..b8d17de8aa 100644 --- a/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql +++ b/c/misra/src/rules/RULE-21-12/ExceptionHandlingFeaturesOfFenvhUsed.ql @@ -56,7 +56,8 @@ where name = m.getName() and message = "Expansion of banned macro" and // Exclude macro invocations expanded from other macro invocations from macros in fenv.h. - not element.(MacroInvocation).getParentInvocation().getMacro().getFile().getBaseName() = "fenv.h" + not element.(MacroInvocation).getParentInvocation().getMacro().getFile().getBaseName() = + "fenv.h" ) ) select element, message + " '" + name + "'." diff --git a/c/misra/test/rules/DIR-4-9/test.c b/c/misra/test/rules/DIR-4-9/test.c index c91e1a15a2..304c4bd004 100644 --- a/c/misra/test/rules/DIR-4-9/test.c +++ b/c/misra/test/rules/DIR-4-9/test.c @@ -10,7 +10,7 @@ #define MACRO8(x) "NOP" // COMPLIANT #define MACRO9() printf_custom("output = %d", 7) // NON_COMPLIANT #define MACRO10(x) // COMPLIANT -#define MACRO11(x) _Generic((x), int: 1, default: 0) // COMPLIANT +#define MACRO11(x) _Generic((x), int : 1, default : 0) // COMPLIANT #define MY_ASSERT(X) assert(X) // NON_COMPLIANT[FALSE_NEGATIVE] const char a1[MACRO2(1, 1) + 6]; From fd9fc0daf28ef5d8ecae6e065f25729ce2bbb2b5 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 12 Mar 2025 11:41:17 -0700 Subject: [PATCH 302/628] format IrreplaceableFunctionLikeMacro.qll --- .../codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll b/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll index e3d6df7e50..8daf129622 100644 --- a/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll +++ b/cpp/common/src/codingstandards/cpp/IrreplaceableFunctionLikeMacro.qll @@ -58,7 +58,5 @@ private class FunctionLikeMacroWithOperatorArgument extends IrreplaceableFunctio } private class GenericMacro extends IrreplaceableFunctionLikeMacro { - GenericMacro() { - getBody().matches("%_Generic%") - } -} \ No newline at end of file + GenericMacro() { getBody().matches("%_Generic%") } +} From fbbb19d74d534f680989888ac887f13b295b46f4 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 12 Mar 2025 11:44:17 -0700 Subject: [PATCH 303/628] Readd removed newline --- .../DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll b/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll index 214f8e9aba..1b22fd5c3b 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotcopyaddressofautostorageobjecttootherobject/DoNotCopyAddressOfAutoStorageObjectToOtherObject.qll @@ -54,4 +54,4 @@ query predicate problems(Expr use, string message, Expr source, string srcStr) { srcStr = "parameter" ) ) -} \ No newline at end of file +} From 855310353f8f206cf0134c16d1b2b0a7852fad1c Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 12 Mar 2025 12:47:47 -0700 Subject: [PATCH 304/628] regenerate query metadata --- .../RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.ql | 2 +- .../rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.ql b/c/misra/src/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.ql index 966b948d81..ec4631ef1b 100644 --- a/c/misra/src/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.ql +++ b/c/misra/src/rules/RULE-22-15/ThreadResourceDisposedBeforeThreadsJoined.ql @@ -2,7 +2,7 @@ * @id c/misra/thread-resource-disposed-before-threads-joined * @name RULE-22-15: Thread synchronization objects and thread-specific storage pointers shall not be disposed unsafely * @description Thread synchronization objects and thread-specific storage pointers shall not be - * destroyed until after all threads accessing them have terminated + * destroyed until after all threads accessing them have terminated. * @kind problem * @precision medium * @problem.severity error diff --git a/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql b/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql index 5b848f9e1e..4b70a21527 100644 --- a/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql +++ b/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql @@ -10,7 +10,7 @@ * correctness * concurrency * external/misra/c/2012/amendment4 - * audit + * external/misra/audit * external/misra/obligation/required */ From 433b887be461f785761ad1de2510d0f1f25363eb Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 12 Mar 2025 16:15:38 -0700 Subject: [PATCH 305/628] Address feedback --- c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql | 1 - rule_packages/c/SideEffects3.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql b/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql index 68f00be15f..c7fdde4539 100644 --- a/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql +++ b/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql @@ -37,7 +37,6 @@ class AtomicAccessInFullExpressionOrdering extends Ordering::Configuration { * Note, it may be accessed directly, or by passing its address into the std atomic functions. */ class AtomicVariableAccess extends VariableAccess { - pragma[noinline] AtomicVariableAccess() { getTarget().getType().hasSpecifier("atomic") } /* Get the `atomic_()` call this VarAccess occurs in. */ diff --git a/rule_packages/c/SideEffects3.json b/rule_packages/c/SideEffects3.json index 369f5db9ee..1ff29ec166 100644 --- a/rule_packages/c/SideEffects3.json +++ b/rule_packages/c/SideEffects3.json @@ -20,7 +20,7 @@ { "description": "The value of an atomic variable shall not depend on evaluation order and interleaving of threads.", "kind": "problem", - "name": "The value of an atomic variable depend on its evaluation order and interleave of threads", + "name": "The value of an atomic variable shall not depend on the evaluation order of interleaved threads", "precision": "very-high", "severity": "error", "short_name": "UnsequencedAtomicReads", From 79a1ca36b2295694857f3dacfc66297da6e8e943 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 12 Mar 2025 16:22:33 -0700 Subject: [PATCH 306/628] Regenerate query metadata --- c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql b/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql index c7fdde4539..b5e17fc934 100644 --- a/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql +++ b/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql @@ -1,6 +1,6 @@ /** * @id c/misra/unsequenced-atomic-reads - * @name RULE-13-2: The value of an atomic variable depend on its evaluation order and interleave of threads + * @name RULE-13-2: The value of an atomic variable shall not depend on the evaluation order of interleaved threads * @description The value of an atomic variable shall not depend on evaluation order and * interleaving of threads. * @kind problem From d70ea29a5e31cca97e6a2600fa994e4b5cc13bd0 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 12 Mar 2025 17:35:21 -0700 Subject: [PATCH 307/628] Address feedback --- .../AtomicQualifierAppliedToVoid.ql | 31 +++++++++++++++---- .../AtomicQualifierAppliedToVoid.expected | 5 +++ c/misra/test/rules/RULE-11-10/test.c | 12 ++++++- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/c/misra/src/rules/RULE-11-10/AtomicQualifierAppliedToVoid.ql b/c/misra/src/rules/RULE-11-10/AtomicQualifierAppliedToVoid.ql index d867241518..6440e84070 100644 --- a/c/misra/src/rules/RULE-11-10/AtomicQualifierAppliedToVoid.ql +++ b/c/misra/src/rules/RULE-11-10/AtomicQualifierAppliedToVoid.ql @@ -23,14 +23,33 @@ class AtomicVoidType extends Type { } } -Type getNestedType(Type root) { - result = root +predicate usesAtomicVoid(Type root) { + root instanceof AtomicVoidType or - exists(DerivedType derived | derived = root | result = getNestedType(derived.getBaseType())) + usesAtomicVoid(root.(DerivedType).getBaseType()) + or + usesAtomicVoid(root.(RoutineType).getReturnType()) + or + usesAtomicVoid(root.(RoutineType).getAParameterType()) + or + usesAtomicVoid(root.(FunctionPointerType).getReturnType()) + or + usesAtomicVoid(root.(FunctionPointerType).getAParameterType()) + or + usesAtomicVoid(root.(TypedefType).getBaseType()) +} + +class ExplicitType extends Type { + Element getDeclaration(string description) { + result.(DeclarationEntry).getType() = this and description = result.(DeclarationEntry).getName() + or + result.(CStyleCast).getType() = this and description = "Cast" + } } -from DeclarationEntry decl, AtomicVoidType atomicVoid +from Element decl, ExplicitType explicitType, string elementDescription where not isExcluded(decl, Declarations9Package::atomicQualifierAppliedToVoidQuery()) and - atomicVoid = getNestedType(decl.getType()) -select decl, decl.getName() + " declared with an atomic void type." + decl = explicitType.getDeclaration(elementDescription) and + usesAtomicVoid(explicitType) +select decl, elementDescription + " declared with an atomic void type." diff --git a/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected b/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected index e3a6746ae7..d38aac6455 100644 --- a/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected +++ b/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected @@ -1,3 +1,8 @@ | test.c:3:15:3:16 | definition of g3 | g3 declared with an atomic void type. | | test.c:10:17:10:18 | definition of m3 | m3 declared with an atomic void type. | | test.c:15:22:15:23 | definition of p2 | p2 declared with an atomic void type. | +| test.c:20:23:20:24 | declaration of f2 | f2 declared with an atomic void type. | +| test.c:21:25:21:26 | declaration of f3 | f3 declared with an atomic void type. | +| test.c:22:14:22:15 | declaration of f4 | f4 declared with an atomic void type. | +| test.c:23:16:23:17 | declaration of f5 | f5 declared with an atomic void type. | +| test.c:27:3:27:19 | (_Atomic(void) *)... | Cast declared with an atomic void type. | diff --git a/c/misra/test/rules/RULE-11-10/test.c b/c/misra/test/rules/RULE-11-10/test.c index e030345dde..cd95891865 100644 --- a/c/misra/test/rules/RULE-11-10/test.c +++ b/c/misra/test/rules/RULE-11-10/test.c @@ -15,4 +15,14 @@ void f(_Atomic int p1, // COMPLIANT _Atomic void *p2 // NON_COMPLIANT // _Atomic void p3[] // doesn't compile, even though it perhaps should as // it is adjusted to void*. -) {} \ No newline at end of file +) {} + +typedef _Atomic void *f2(void); // NON_COMPLIANT +typedef _Atomic void *(*f3)(void); // NON_COMPLIANT +typedef void f4(_Atomic void *); // NON_COMPLIANT +typedef void (*f5)(_Atomic void *); // NON_COMPLIANT + +void f6() { + (void *)0; // COMPLIANT + (_Atomic void *)0; // NON_COMPLIANT +} \ No newline at end of file From db1061ecdaf9c55c5c324c50a4a4c47b92050332 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 13 Mar 2025 10:06:12 -0700 Subject: [PATCH 308/628] Update codeql warning source location expectations --- .../test/rules/RULE-13-2/UnsequencedAtomicReads.expected | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected index 2231a83735..897dd68f30 100644 --- a/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected +++ b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected @@ -1,5 +1,5 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:87,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:87,67-75) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:87,5-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:86,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:86,67-75) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:86,5-18) | test.c:44:12:44:18 | ... + ... | Atomic variable $@ has a $@ that is unsequenced with $@. | test.c:42:15:42:16 | a1 | a1 | test.c:44:12:44:13 | a1 | previous read | test.c:44:17:44:18 | a1 | another read | | test.c:46:3:46:37 | ... + ... | Atomic variable $@ has a $@ that is unsequenced with $@. | test.c:42:15:42:16 | a1 | a1 | test.c:46:16:46:17 | a1 | previous read | test.c:46:35:46:36 | a1 | another read | From 7e8ba849c90c960e9a5c38620d130ed5400679e2 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 13 Mar 2025 10:14:22 -0700 Subject: [PATCH 309/628] Fix merge --- rules.csv | 5 ----- 1 file changed, 5 deletions(-) diff --git a/rules.csv b/rules.csv index 0ea6db3c53..3f7961b630 100644 --- a/rules.csv +++ b/rules.csv @@ -677,13 +677,8 @@ c,MISRA-C-2012,RULE-9-2,Yes,Required,,,The initializer for an aggregate or union c,MISRA-C-2012,RULE-9-3,Yes,Required,,,Arrays shall not be partially initialized,,Memory1,Medium, c,MISRA-C-2012,RULE-9-4,Yes,Required,,,An element of an object shall not be initialized more than once,,Memory1,Medium, c,MISRA-C-2012,RULE-9-5,No,Required,,,Where designated initializers are used to initialize an array object the size of the array shall be specified explicitly,,,Medium, -<<<<<<< HEAD c,MISRA-C-2012,RULE-9-6,Yes,Required,,,An initializer using chained designators shall not contain initializers without designators,,Declarations10,Hard, -c,MISRA-C-2012,RULE-9-7,Yes,Mandatory,,,Atomic objects shall be appropriately initialized before being accessed,,Concurrency6,Hard, -======= -c,MISRA-C-2012,RULE-9-6,Yes,Required,,,An initializer using chained designators shall not contain initializers without designators,,Declarations9,Hard, c,MISRA-C-2012,RULE-9-7,Yes,Mandatory,,,Atomic objects shall be appropriately initialized before being accessed,,Concurrency7,Hard, ->>>>>>> origin/main c,MISRA-C-2012,RULE-10-1,Yes,Required,,,Operands shall not be of an inappropriate essential type,,EssentialTypes,Hard, c,MISRA-C-2012,RULE-10-2,Yes,Required,,,Expressions of essentially character type shall not be used inappropriately in addition and subtraction operations,,EssentialTypes,Medium, c,MISRA-C-2012,RULE-10-3,Yes,Required,,,The value of an expression shall not be assigned to an object with a narrower essential type or of a different essential type category,,EssentialTypes,Hard, From f1944dbc9cefc94550e4e1b390e14f3fa91a2833 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 13 Mar 2025 10:16:31 -0700 Subject: [PATCH 310/628] Format cast test cases --- c/misra/test/rules/RULE-11-10/test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/misra/test/rules/RULE-11-10/test.c b/c/misra/test/rules/RULE-11-10/test.c index cd95891865..8f8e837b66 100644 --- a/c/misra/test/rules/RULE-11-10/test.c +++ b/c/misra/test/rules/RULE-11-10/test.c @@ -23,6 +23,6 @@ typedef void f4(_Atomic void *); // NON_COMPLIANT typedef void (*f5)(_Atomic void *); // NON_COMPLIANT void f6() { - (void *)0; // COMPLIANT + (void *)0; // COMPLIANT (_Atomic void *)0; // NON_COMPLIANT } \ No newline at end of file From 66d7f2bb1230a731fd339b65c5e2044bc13eeb34 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 14 Mar 2025 14:38:56 -0700 Subject: [PATCH 311/628] Don't report '//*comment' in RULE-3-1 --- .../RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql | 2 +- .../CharacterSequencesAndUsedWithinAComment.expected | 1 + c/misra/test/rules/RULE-3-1/test.c | 6 ++++++ ...24-12-13-implement-misra-c-amendment4-rule-amendments.md | 3 ++- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql b/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql index 58d449a59b..af05bfe4bc 100644 --- a/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql +++ b/c/misra/src/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.ql @@ -43,7 +43,7 @@ where not isExcluded(comment, SyntaxPackage::characterSequencesAndUsedWithinACommentQuery()) and ( exists(IllegalCommentSequence c | illegalSequence = c | - comment.getContents().indexOf(illegalSequence) > 0 + comment.getContents().indexOf(illegalSequence) > 1 ) or exists(IllegalCCommentRegexp c | illegalSequence = c.getDescription() | diff --git a/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected b/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected index 5008fb100d..3c4cab00b1 100644 --- a/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected +++ b/c/misra/test/rules/RULE-3-1/CharacterSequencesAndUsedWithinAComment.expected @@ -3,3 +3,4 @@ | test.c:21:1:21:7 | // /* | Comment contains an illegal sequence '/*' | | test.c:30:1:30:27 | /* https://github.com // */ | Comment contains an illegal sequence '//' | | test.c:33:1:33:60 | /* a://b, a://b., ://a.b, a://b., a://.b, ://, a://, ://b */ | Comment contains an illegal sequence '//' | +| test.c:42:1:42:8 | ///* foo | Comment contains an illegal sequence '/*' | diff --git a/c/misra/test/rules/RULE-3-1/test.c b/c/misra/test/rules/RULE-3-1/test.c index ad61fd0f91..fd7a6574dd 100644 --- a/c/misra/test/rules/RULE-3-1/test.c +++ b/c/misra/test/rules/RULE-3-1/test.c @@ -35,4 +35,10 @@ // COMPLIANT // https://github.com +// COMPLIANT +//* foo + +// NON_COMPLIANT +///* foo + void f(){} \ No newline at end of file diff --git a/change_notes/2024-12-13-implement-misra-c-amendment4-rule-amendments.md b/change_notes/2024-12-13-implement-misra-c-amendment4-rule-amendments.md index a8fbd282d8..b168ccaf78 100644 --- a/change_notes/2024-12-13-implement-misra-c-amendment4-rule-amendments.md +++ b/change_notes/2024-12-13-implement-misra-c-amendment4-rule-amendments.md @@ -7,4 +7,5 @@ - `RULE-13-2` - `UnsequencedAtomicReads.ql` - New query to find expressions which read an atomic variable more than once between sequence points, to address new case from MISRA-C 2012 Amendment 4. - `RULE-3-1` - `CharacterSequencesAndUsedWithinAComment.ql` - - Add exception allowing URLs inside of cpp-style `/* ... */` comments, in compliance with MISRA-C 2012 Amendment 4 \ No newline at end of file + - Add exception allowing URLs inside of cpp-style `/* ... */` comments, in compliance with MISRA-C 2012 Amendment 4. + - No longer report cases of `//*some comment` in this rule. \ No newline at end of file From c55a173fae2d1d2fd1d4b15616d9cdd61acff3cc Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 14 Mar 2025 17:36:13 -0700 Subject: [PATCH 312/628] First round of feedback --- ...025-1-04-misra-c-technical-corrigenda-2.md | 2 +- ...nterArithmeticToAddressDifferentArrays.qll | 23 +++++++++++++------ .../test.cpp | 12 +++++++--- rule_packages/c/Statements5.json | 3 +++ 4 files changed, 29 insertions(+), 11 deletions(-) diff --git a/change_notes/2025-1-04-misra-c-technical-corrigenda-2.md b/change_notes/2025-1-04-misra-c-technical-corrigenda-2.md index be037074f6..6849951810 100644 --- a/change_notes/2025-1-04-misra-c-technical-corrigenda-2.md +++ b/change_notes/2025-1-04-misra-c-technical-corrigenda-2.md @@ -1,6 +1,6 @@ - `RULE-8-3` - `DeclarationsOfAFunctionSameNameAndType.ql`: - Implement new exception, unnamed parameters are not covered by this rule. - - `RULE-10-2` - `AdditionSubtractionOnEssentiallCharType.ql`: + - `RULE-10-2` - `AdditionSubtractionOnEssentiallyCharType.ql`: - Disallow `+` and `-` operations with an essentially char type and other types larger than int type. - Note, this change affects the essential type of such expressions, which may affect other essential types rules. - `RULE-18-1`, `M5-0-16` - `PointerAndDerivedPointerMustAddressSameArray.ql`, `PointerAndDerivedPointerAccessDifferentArray.ql`: diff --git a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll index 5a45ff703e..2b11291293 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll @@ -104,6 +104,16 @@ class CastedToBytePointer extends ArrayLikeAccess, Conversion { } } + predicate pointerRecastBarrier(DataFlow::Node barrier) { + // Casting to a differently sized pointer + exists(CStyleCast cast, Expr casted | + cast.getExpr() = casted and casted = barrier.asConvertedExpr() + | + not casted.getType().(PointerType).getBaseType().getSize() = + cast.getType().(PointerType).getBaseType().getSize() + ) + } + /** * A data-flow configuration that tracks access to an array to type to an array index expression. * This is used to determine possible pointer to array creations. @@ -111,7 +121,11 @@ class CastedToBytePointer extends ArrayLikeAccess, Conversion { module ByteArrayToArrayExprConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node source) { exists(CastedToBytePointer a | a.getNode() = source) } - // TODO: casting to different size pointed-to-type invalidates + predicate isBarrier(DataFlow::Node barrier) { + // Casting to a differently sized pointer invalidates this analysis. + pointerRecastBarrier(barrier) + } + predicate isSink(DataFlow::Node sink) { exists(ArrayExpr c | c.getArrayBase() = sink.asExpr()) } } @@ -126,12 +140,7 @@ module ArrayToArrayExprConfig implements DataFlow::ConfigSig { predicate isBarrier(DataFlow::Node barrier) { // Casting to a differently sized pointer invalidates this analysis. - exists(CStyleCast cast, Expr casted | - cast.getExpr() = casted and casted = barrier.asConvertedExpr() - | - not casted.getType().(PointerType).getBaseType().getSize() = - cast.getType().(PointerType).getBaseType().getSize() - ) + pointerRecastBarrier(barrier) } predicate isSink(DataFlow::Node sink) { exists(ArrayExpr c | c.getArrayBase() = sink.asExpr()) } diff --git a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp index 3a86d7963e..d9874bfb29 100644 --- a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp +++ b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/test.cpp @@ -40,8 +40,14 @@ void f1() { void *p22 = &p21[0]; // COMPLIANT void *p23 = &p21[100]; // NON_COMPLIANT[FALSE_NEGATIVE] + // Casting a byte pointer to a differently sized type that isn't char + // invalidates analysis + long *p24 = (long *)p15; + void *p25 = &p24[0]; // COMPLIANT + void *p26 = &p24[100]; // NON_COMPLIANT[FALSE_NEGATIVE] + // Void pointers have size zero and can't be analyzed. - void *p24 = 0; - unsigned char *p25 = (unsigned char *)p24; - void *p26 = &p25[100]; // COMPLIANT + void *p27 = 0; + unsigned char *p28 = (unsigned char *)p27; + void *p29 = &p28[100]; // COMPLIANT } \ No newline at end of file diff --git a/rule_packages/c/Statements5.json b/rule_packages/c/Statements5.json index 329819b61f..03380f4897 100644 --- a/rule_packages/c/Statements5.json +++ b/rule_packages/c/Statements5.json @@ -20,6 +20,9 @@ ] } ], + "implementation_scope": { + "description": "Not all invariant logical expressions which contain dynamic values are detected to be invariant, for instance, `x < 3 && x > 5` where x does not have a statically known value." + }, "title": "Controlling expressions shall not be invariant" }, "RULE-15-5": { From fb6eaaa9eed6d8d377849af6ef47aa17eec7d524 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 14 Mar 2025 17:56:28 -0700 Subject: [PATCH 313/628] Format --- ...interArithmeticToAddressDifferentArrays.qll | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll index 2b11291293..2b788ea6fb 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll @@ -104,15 +104,15 @@ class CastedToBytePointer extends ArrayLikeAccess, Conversion { } } - predicate pointerRecastBarrier(DataFlow::Node barrier) { - // Casting to a differently sized pointer - exists(CStyleCast cast, Expr casted | - cast.getExpr() = casted and casted = barrier.asConvertedExpr() - | - not casted.getType().(PointerType).getBaseType().getSize() = - cast.getType().(PointerType).getBaseType().getSize() - ) - } +predicate pointerRecastBarrier(DataFlow::Node barrier) { + // Casting to a differently sized pointer + exists(CStyleCast cast, Expr casted | + cast.getExpr() = casted and casted = barrier.asConvertedExpr() + | + not casted.getType().(PointerType).getBaseType().getSize() = + cast.getType().(PointerType).getBaseType().getSize() + ) +} /** * A data-flow configuration that tracks access to an array to type to an array index expression. From 6acd87740d00f8130b944a08674ec7b5525c19c3 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 14 Mar 2025 18:02:51 -0700 Subject: [PATCH 314/628] Format essentialTypes --- .../src/codingstandards/c/misra/EssentialTypes.qll | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll index 05bfef87fa..de6d43e2c5 100644 --- a/c/misra/src/codingstandards/c/misra/EssentialTypes.qll +++ b/c/misra/src/codingstandards/c/misra/EssentialTypes.qll @@ -357,8 +357,9 @@ class EssentialBinaryOperationSubjectToUsualConversions extends EssentialExpr, B */ class EssentialAddExpr extends EssentialBinaryOperationSubjectToUsualConversions, AddExpr { override Type getEssentialType() { - exists(Type otherOperandType, - EssentialTypeCategory operandTypeCategory, EssentialTypeCategory otherOperandTypeCategory, int intTypeSize + exists( + Type otherOperandType, EssentialTypeCategory operandTypeCategory, + EssentialTypeCategory otherOperandTypeCategory, int intTypeSize | operandTypeCategory = getEssentialTypeCategory(getEssentialType(getAnOperand())) and otherOperandType = getEssentialType(getAnOperand()) and @@ -381,10 +382,8 @@ class EssentialAddExpr extends EssentialBinaryOperationSubjectToUsualConversions class EssentialSubExpr extends EssentialBinaryOperationSubjectToUsualConversions, SubExpr { override Type getEssentialType() { exists( - EssentialTypeCategory leftEssentialTypeCategory, - Type rightEssentialType, - EssentialTypeCategory rightEssentialTypeCategory, - int intTypeSize + EssentialTypeCategory leftEssentialTypeCategory, Type rightEssentialType, + EssentialTypeCategory rightEssentialTypeCategory, int intTypeSize | leftEssentialTypeCategory = getEssentialTypeCategory(getEssentialType(getLeftOperand())) and rightEssentialType = getEssentialType(getRightOperand()) and From 3e6cf77c8f653d50776c9f0afc54c5abcc818ef5 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 17 Mar 2025 17:24:37 -0700 Subject: [PATCH 315/628] Update cast to byte pointer getName() --- ...DoNotUsePointerArithmeticToAddressDifferentArrays.qll | 9 +-------- ...UsePointerArithmeticToAddressDifferentArrays.expected | 4 ++-- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll index 2b788ea6fb..5d3a7e1cda 100644 --- a/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll +++ b/cpp/common/src/codingstandards/cpp/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.qll @@ -80,14 +80,7 @@ class CastedToBytePointer extends ArrayLikeAccess, Conversion { override Element getElement() { result = this } - override string getName() { - result = "cast to btye pointer " + this.toString() - or - exists(Cast cast | - cast.getExpr() = this and - result = cast.getType().(PointerType).getBaseType().toString() - ) - } + override string getName() { result = "cast to byte pointer" } override int getSize() { result = size } diff --git a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected index 5bb4881b81..31ff47e55c 100644 --- a/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected +++ b/cpp/common/test/rules/donotusepointerarithmetictoaddressdifferentarrays/DoNotUsePointerArithmeticToAddressDifferentArrays.expected @@ -4,5 +4,5 @@ | test.cpp:11:8:11:11 | ... -- | Array pointer p7 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | | test.cpp:12:8:12:9 | p3 | Array pointer p8 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | | test.cpp:25:15:25:21 | & ... | Array pointer p14 points 1 element past the end of $@. | test.cpp:2:7:2:8 | l1 | l1 | -| test.cpp:30:15:30:21 | & ... | Array pointer p17 points 1 element past the end of $@. | test.cpp:28:24:28:42 | (unsigned char *)... | cast to btye pointer (unsigned char *)... | -| test.cpp:35:15:35:21 | & ... | Array pointer p20 points 1 element past the end of $@. | test.cpp:33:24:33:43 | (unsigned char *)... | cast to btye pointer (unsigned char *)... | +| test.cpp:30:15:30:21 | & ... | Array pointer p17 points 1 element past the end of $@. | test.cpp:28:24:28:42 | (unsigned char *)... | cast to byte pointer | +| test.cpp:35:15:35:21 | & ... | Array pointer p20 points 1 element past the end of $@. | test.cpp:33:24:33:43 | (unsigned char *)... | cast to byte pointer | From ded47aa1e71b16ac85be2acdaddfe5777fd2c508 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 20 Mar 2025 15:32:02 -0700 Subject: [PATCH 316/628] Address feedback --- .../PossibleMisuseOfUndetectedInfinity.ql | 35 +++--- .../DIR-4-15/PossibleMisuseOfUndetectedNaN.ql | 95 ++++------------ ...ossibleMisuseOfUndetectedInfinity.expected | 52 ++++----- .../PossibleMisuseOfUndetectedNaN.expected | 64 +++++------ .../src/codingstandards/cpp/FloatingPoint.qll | 72 ++++++++++++- .../cpp/RestrictedRangeAnalysis.qll | 101 +++++++++++------- .../cpp/exclusions/c/FloatingTypes2.qll | 2 +- .../UncheckedRangeDomainPoleErrors.qll | 53 +-------- .../generate_rules/coding_standards_utils.py | 4 +- 9 files changed, 230 insertions(+), 248 deletions(-) diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql index 3d54b4f829..812e9fe1e2 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql @@ -87,7 +87,6 @@ module InvalidInfinityUsage implements DataFlow::ConfigSig { class InvalidInfinityUsage extends DataFlow::Node { string description; - string infinityDescription; InvalidInfinityUsage() { // Case 2: NaNs and infinities shall not be cast to integers @@ -95,22 +94,18 @@ class InvalidInfinityUsage extends DataFlow::Node { asExpr() = c.getUnconverted() and c.getExpr().getType() instanceof FloatingPointType and c.getType() instanceof IntegralType and - description = "$@ casted to integer." and - infinityDescription = "Possibly infinite float value" + description = "cast to integer." ) or // Case 3: Infinities shall not underflow or otherwise produce finite values exists(BinaryOperation op | asExpr() = op.getRightOperand() and op.getOperator() = "/" and - description = "Division operation may silently underflow and produce zero, as the divisor $@." and - infinityDescription = "may be an infinite float value" + description = "divisor, which would silently underflow and produce zero." ) } string getDescription() { result = description } - - string getInfinityDescription() { result = infinityDescription } } module InvalidInfinityFlow = DataFlow::Global; @@ -119,7 +114,8 @@ import InvalidInfinityFlow::PathGraph from Element elem, InvalidInfinityFlow::PathNode source, InvalidInfinityFlow::PathNode sink, - InvalidInfinityUsage usage, Expr sourceExpr, Element extra, string extraString + InvalidInfinityUsage usage, Expr sourceExpr, string sourceString, Function function, + string computedInFunction where elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and not InvalidInfinityFlow::PathGraph::edges(_, source, _, _) and @@ -129,19 +125,18 @@ where not usage.asExpr().isFromTemplateInstantiation(_) and usage = sink.getNode() and sourceExpr = source.getNode().asExpr() and + function = sourceExpr.getEnclosingFunction() and InvalidInfinityFlow::flow(source.getNode(), usage) and ( if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() - then - extraString = - usage.getInfinityDescription() + " computed in function " + - sourceExpr.getEnclosingFunction().getName() and - extra = sourceExpr.getEnclosingFunction() - else ( - extra = sourceExpr and - if sourceExpr instanceof DivExpr - then extraString = usage.getInfinityDescription() + " from division by zero" - else extraString = usage.getInfinityDescription() - ) + then computedInFunction = "computed in function $@ " + else computedInFunction = "" + ) and + ( + if sourceExpr instanceof DivExpr + then sourceString = "from division by zero" + else sourceString = sourceExpr.toString() ) -select elem, source, sink, usage.getDescription(), extra, extraString +select elem, source, sink, + "Possibly infinite float value $@ " + computedInFunction + "flows to " + usage.getDescription(), + sourceExpr, sourceString, function, function.getName() diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql index 2835a454d9..e1b6762ada 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql @@ -1,5 +1,5 @@ /** - * @id c/misra/possible-misuse-of-undetected-na-n + * @id c/misra/possible-misuse-of-undetected-nan * @name DIR-4-15: Evaluation of floating-point expressions shall not lead to the undetected generation of NaNs * @description Evaluation of floating-point expressions shall not lead to the undetected generation * of NaNs. @@ -23,58 +23,6 @@ import semmle.code.cpp.dataflow.new.DataFlow import semmle.code.cpp.dataflow.new.TaintTracking import semmle.code.cpp.controlflow.Dominance -bindingset[name] -Function getMathVariants(string name) { result.hasGlobalOrStdName([name, name + "f", name + "l"]) } - -predicate hasDomainError(FunctionCall fc, string description) { - exists(Function functionWithDomainError | fc.getTarget() = functionWithDomainError | - functionWithDomainError = [getMathVariants(["acos", "asin", "atanh"])] and - not ( - RestrictedRangeAnalysis::upperBound(fc.getArgument(0)) <= 1.0 and - RestrictedRangeAnalysis::lowerBound(fc.getArgument(0)) >= -1.0 - ) and - description = - "the argument has a range " + RestrictedRangeAnalysis::lowerBound(fc.getArgument(0)) + "..." + - RestrictedRangeAnalysis::upperBound(fc.getArgument(0)) + - " which is outside the domain of this function (-1.0...1.0)" - or - functionWithDomainError = getMathVariants(["atan2", "pow"]) and - ( - exprMayEqualZero(fc.getArgument(0)) and - exprMayEqualZero(fc.getArgument(1)) and - description = "both arguments are equal to zero" - ) - or - functionWithDomainError = getMathVariants("pow") and - ( - RestrictedRangeAnalysis::upperBound(fc.getArgument(0)) < 0.0 and - RestrictedRangeAnalysis::upperBound(fc.getArgument(1)) < 0.0 and - description = "both arguments are less than zero" - ) - or - functionWithDomainError = getMathVariants("acosh") and - RestrictedRangeAnalysis::upperBound(fc.getArgument(0)) < 1.0 and - description = "argument is less than 1" - or - //pole error is the same as domain for logb and tgamma (but not ilogb - no pole error exists) - functionWithDomainError = getMathVariants(["ilogb", "logb", "tgamma"]) and - exprMayEqualZero(fc.getArgument(0)) and - description = "argument is equal to zero" - or - functionWithDomainError = getMathVariants(["log", "log10", "log2", "sqrt"]) and - RestrictedRangeAnalysis::upperBound(fc.getArgument(0)) < 0.0 and - description = "argument is negative" - or - functionWithDomainError = getMathVariants("log1p") and - RestrictedRangeAnalysis::upperBound(fc.getArgument(0)) < -1.0 and - description = "argument is less than 1" - or - functionWithDomainError = getMathVariants("fmod") and - exprMayEqualZero(fc.getArgument(1)) and - description = "y is 0" - ) -} - abstract class PotentiallyNaNExpr extends Expr { abstract string getReason(); } @@ -82,7 +30,7 @@ abstract class PotentiallyNaNExpr extends Expr { class DomainErrorFunctionCall extends FunctionCall, PotentiallyNaNExpr { string reason; - DomainErrorFunctionCall() { hasDomainError(this, reason) } + DomainErrorFunctionCall() { RestrictedDomainError::hasDomainError(this, reason) } override string getReason() { result = reason } } @@ -116,8 +64,13 @@ class InvalidOperationExpr extends BinaryOperation, PotentiallyNaNExpr { or // 7.1.3: multiplication of zero by infinity getOperator() = "*" and - exprMayEqualZero(getAnOperand()) and - exprMayEqualInfinity(getAnOperand(), _) and + exists(Expr zeroOp, Expr infinityOp | + zeroOp = getAnOperand() and + infinityOp = getAnOperand() and + not zeroOp = infinityOp and + exprMayEqualZero(zeroOp) and + exprMayEqualInfinity(infinityOp, _) + ) and reason = "from multiplication of zero by infinity" or // 7.1.4: Division of zero by zero, or infinity by infinity @@ -199,15 +152,13 @@ module InvalidNaNUsage implements DataFlow::ConfigSig { class InvalidNaNUsage extends DataFlow::Node { string description; - string nanDescription; InvalidNaNUsage() { // Case 1: NaNs shall not be compared, except to themselves exists(ComparisonOperation cmp | this.asExpr() = cmp.getAnOperand() and not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand()) and - description = "Comparison involving a $@, which always evaluates to false." and - nanDescription = "possibly NaN float value" + description = "comparison, which would always evaluate to false." ) or // Case 2: NaNs and infinities shall not be cast to integers @@ -215,14 +166,11 @@ class InvalidNaNUsage extends DataFlow::Node { this.asExpr() = c.getUnconverted() and c.getExpr().getType() instanceof FloatingPointType and c.getType() instanceof IntegralType and - description = "$@ casted to integer." and - nanDescription = "Possibly NaN float value" + description = "a cast to integer." ) } string getDescription() { result = description } - - string getNaNDescription() { result = nanDescription } } module InvalidNaNFlow = DataFlow::Global; @@ -231,7 +179,8 @@ import InvalidNaNFlow::PathGraph from Element elem, InvalidNaNFlow::PathNode source, InvalidNaNFlow::PathNode sink, - InvalidNaNUsage usage, Expr sourceExpr, string sourceString, Element extra, string extraString + InvalidNaNUsage usage, Expr sourceExpr, string sourceString, Function function, + string computedInFunction where not InvalidNaNFlow::PathGraph::edges(_, source, _, _) and not InvalidNaNFlow::PathGraph::edges(sink, _, _, _) and @@ -240,18 +189,14 @@ where elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and usage = sink.getNode() and sourceExpr = source.getNode().asExpr() and - sourceString = " (" + source.getNode().asExpr().(PotentiallyNaNExpr).getReason() + ")" and + sourceString = source.getNode().asExpr().(PotentiallyNaNExpr).getReason() and + function = sourceExpr.getEnclosingFunction() and InvalidNaNFlow::flow(source.getNode(), usage) and ( if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() - then - extraString = - usage.getNaNDescription() + sourceString + " computed in function " + - sourceExpr.getEnclosingFunction().getName() and - extra = sourceExpr.getEnclosingFunction() - else ( - extra = sourceExpr and - extraString = usage.getNaNDescription() + sourceString - ) + then computedInFunction = "computed in function $@ " + else computedInFunction = "" ) -select elem, source, sink, usage.getDescription(), extra, extraString +select elem, source, sink, + "Possible NaN value $@ " + computedInFunction + "flows to " + usage.getDescription(), sourceExpr, + sourceString, function, function.getName() diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected index f1f08b5a51..8dd5ac15b8 100644 --- a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected @@ -85,29 +85,29 @@ nodes | test.c:210:23:210:31 | middleInf | semmle.label | middleInf | subpaths #select -| test.c:12:8:12:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:12:8:12:9 | l2 | Division operation may silently underflow and produce zero, as the divisor $@. | test.c:8:14:8:20 | ... / ... | may be an infinite float value from division by zero | -| test.c:13:8:13:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:13:8:13:9 | l3 | Division operation may silently underflow and produce zero, as the divisor $@. | test.c:8:14:8:20 | ... / ... | may be an infinite float value from division by zero | -| test.c:18:8:18:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:18:3:18:9 | l2 | $@ casted to integer. | test.c:8:14:8:20 | ... / ... | Possibly infinite float value from division by zero | -| test.c:19:8:19:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:19:3:19:9 | l3 | $@ casted to integer. | test.c:8:14:8:20 | ... / ... | Possibly infinite float value from division by zero | -| test.c:27:19:27:20 | l2 | test.c:8:14:8:20 | ... / ... | test.c:27:19:27:20 | l2 | Division operation may silently underflow and produce zero, as the divisor $@. | test.c:8:14:8:20 | ... / ... | may be an infinite float value from division by zero | -| test.c:28:19:28:20 | l3 | test.c:8:14:8:20 | ... / ... | test.c:28:19:28:20 | l3 | Division operation may silently underflow and produce zero, as the divisor $@. | test.c:8:14:8:20 | ... / ... | may be an infinite float value from division by zero | -| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | $@ casted to integer. | test.c:31:14:32:15 | ... / ... | Possibly infinite float value from division by zero | -| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | $@ casted to integer. | test.c:61:11:61:17 | ... / ... | Possibly infinite float value from division by zero | -| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | $@ casted to integer. | test.c:66:11:66:19 | ... / ... | Possibly infinite float value from division by zero | -| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | $@ casted to integer. | test.c:72:20:72:28 | ... / ... | Possibly infinite float value from division by zero | -| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | $@ casted to integer. | test.c:75:24:75:32 | ... / ... | Possibly infinite float value from division by zero | -| test.c:79:10:79:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:79:5:79:12 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | -| test.c:87:10:87:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:87:5:87:12 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | -| test.c:91:10:91:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:91:5:91:12 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | -| test.c:93:10:93:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:93:5:93:12 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | -| test.c:99:10:99:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:99:5:99:12 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | -| test.c:105:10:105:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:105:5:105:12 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | -| test.c:111:10:111:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:111:5:111:12 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | -| test.c:114:21:114:23 | l12 | test.c:77:15:77:21 | ... / ... | test.c:114:16:114:23 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | -| test.c:117:28:117:30 | l12 | test.c:77:15:77:21 | ... / ... | test.c:117:23:117:30 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | -| test.c:120:25:120:27 | l12 | test.c:77:15:77:21 | ... / ... | test.c:120:20:120:27 | l12 | $@ casted to integer. | test.c:77:15:77:21 | ... / ... | Possibly infinite float value from division by zero | -| test.c:163:9:164:15 | ... / ... | test.c:163:3:164:16 | ... / ... | test.c:163:3:164:16 | ... / ... | $@ casted to integer. | test.c:163:9:164:15 | ... / ... | Possibly infinite float value from division by zero | -| test.c:175:32:175:32 | p | test.c:189:51:189:59 | ... / ... | test.c:175:27:175:32 | p | $@ casted to integer. | test.c:189:6:189:24 | addInfThenCastToInt | Possibly infinite float value computed in function addInfThenCastToInt | -| test.c:175:32:175:32 | p | test.c:193:13:194:15 | ... / ... | test.c:175:27:175:32 | p | $@ casted to integer. | test.c:192:6:192:7 | f2 | Possibly infinite float value computed in function f2 | -| test.c:175:32:175:32 | p | test.c:204:19:204:27 | ... / ... | test.c:175:27:175:32 | p | $@ casted to integer. | test.c:192:6:192:7 | f2 | Possibly infinite float value computed in function f2 | -| test.c:185:18:185:18 | p | test.c:200:25:200:33 | ... / ... | test.c:185:13:185:18 | p | $@ casted to integer. | test.c:192:6:192:7 | f2 | Possibly infinite float value computed in function f2 | +| test.c:12:8:12:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:12:8:12:9 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:13:8:13:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:13:8:13:9 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:18:8:18:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:18:3:18:9 | l2 | Possibly infinite float value $@ flows to cast to integer. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:19:8:19:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:19:3:19:9 | l3 | Possibly infinite float value $@ flows to cast to integer. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:27:19:27:20 | l2 | test.c:8:14:8:20 | ... / ... | test.c:27:19:27:20 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:28:19:28:20 | l3 | test.c:8:14:8:20 | ... / ... | test.c:28:19:28:20 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Possibly infinite float value $@ flows to cast to integer. | test.c:31:14:32:15 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:61:11:61:17 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:66:11:66:19 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:72:20:72:28 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:75:24:75:32 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:79:10:79:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:79:5:79:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:87:10:87:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:87:5:87:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:91:10:91:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:91:5:91:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:93:10:93:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:93:5:93:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:99:10:99:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:99:5:99:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:105:10:105:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:105:5:105:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:111:10:111:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:111:5:111:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:114:21:114:23 | l12 | test.c:77:15:77:21 | ... / ... | test.c:114:16:114:23 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:117:28:117:30 | l12 | test.c:77:15:77:21 | ... / ... | test.c:117:23:117:30 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:120:25:120:27 | l12 | test.c:77:15:77:21 | ... / ... | test.c:120:20:120:27 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:163:9:164:15 | ... / ... | test.c:163:3:164:16 | ... / ... | test.c:163:3:164:16 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:163:9:164:15 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:175:32:175:32 | p | test.c:189:51:189:59 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:189:51:189:59 | ... / ... | from division by zero | test.c:189:6:189:24 | addInfThenCastToInt | addInfThenCastToInt | +| test.c:175:32:175:32 | p | test.c:193:13:194:15 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:193:13:194:15 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:175:32:175:32 | p | test.c:204:19:204:27 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:204:19:204:27 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:185:18:185:18 | p | test.c:200:25:200:33 | ... / ... | test.c:185:13:185:18 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:200:25:200:33 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected index e0047d9ef7..aeec3c943f 100644 --- a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected @@ -102,35 +102,35 @@ nodes | test.c:211:23:211:31 | middleNaN | semmle.label | middleNaN | subpaths #select -| test.c:36:8:36:9 | l5 | test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | $@ casted to integer. | test.c:27:14:27:20 | ... / ... | Possibly NaN float value (from division of infinity by infinity) | -| test.c:37:8:37:9 | l6 | test.c:28:14:28:20 | ... / ... | test.c:37:3:37:9 | l6 | $@ casted to integer. | test.c:28:14:28:20 | ... / ... | Possibly NaN float value (from division of infinity by infinity) | -| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | $@ casted to integer. | test.c:31:14:32:15 | ... / ... | Possibly NaN float value (from division of zero by zero) | -| test.c:39:8:39:9 | l8 | test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | $@ casted to integer. | test.c:33:14:33:22 | ... / ... | Possibly NaN float value (from division of zero by zero) | -| test.c:46:3:46:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:46:3:46:4 | l5 | Comparison involving a $@, which always evaluates to false. | test.c:27:14:27:20 | ... / ... | possibly NaN float value (from division of infinity by infinity) | -| test.c:47:3:47:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:47:3:47:4 | l5 | Comparison involving a $@, which always evaluates to false. | test.c:27:14:27:20 | ... / ... | possibly NaN float value (from division of infinity by infinity) | -| test.c:48:3:48:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:48:3:48:4 | l5 | Comparison involving a $@, which always evaluates to false. | test.c:27:14:27:20 | ... / ... | possibly NaN float value (from division of infinity by infinity) | -| test.c:49:3:49:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:49:3:49:4 | l5 | Comparison involving a $@, which always evaluates to false. | test.c:27:14:27:20 | ... / ... | possibly NaN float value (from division of infinity by infinity) | -| test.c:50:3:50:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:50:3:50:4 | l5 | Comparison involving a $@, which always evaluates to false. | test.c:27:14:27:20 | ... / ... | possibly NaN float value (from division of infinity by infinity) | -| test.c:51:3:51:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:51:3:51:4 | l5 | Comparison involving a $@, which always evaluates to false. | test.c:27:14:27:20 | ... / ... | possibly NaN float value (from division of infinity by infinity) | -| test.c:52:3:52:4 | l6 | test.c:28:14:28:20 | ... / ... | test.c:52:3:52:4 | l6 | Comparison involving a $@, which always evaluates to false. | test.c:28:14:28:20 | ... / ... | possibly NaN float value (from division of infinity by infinity) | -| test.c:53:3:53:4 | l7 | test.c:31:14:32:15 | ... / ... | test.c:53:3:53:4 | l7 | Comparison involving a $@, which always evaluates to false. | test.c:31:14:32:15 | ... / ... | possibly NaN float value (from division of zero by zero) | -| test.c:54:3:54:4 | l8 | test.c:33:14:33:22 | ... / ... | test.c:54:3:54:4 | l8 | Comparison involving a $@, which always evaluates to false. | test.c:33:14:33:22 | ... / ... | possibly NaN float value (from division of zero by zero) | -| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | $@ casted to integer. | test.c:61:11:61:17 | ... / ... | Possibly NaN float value (from division of zero by zero) | -| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | $@ casted to integer. | test.c:66:11:66:19 | ... / ... | Possibly NaN float value (from division of zero by zero) | -| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | $@ casted to integer. | test.c:72:20:72:28 | ... / ... | Possibly NaN float value (from division of zero by zero) | -| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | $@ casted to integer. | test.c:75:24:75:32 | ... / ... | Possibly NaN float value (from division of zero by zero) | -| test.c:126:10:126:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:126:5:126:12 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | -| test.c:132:10:132:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:132:5:132:12 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | -| test.c:138:10:138:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:138:5:138:12 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | -| test.c:144:10:144:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:144:5:144:12 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | -| test.c:148:10:148:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:148:5:148:12 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | -| test.c:155:25:155:27 | l13 | test.c:122:15:122:21 | ... / ... | test.c:155:20:155:27 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | -| test.c:157:28:157:30 | l13 | test.c:122:15:122:21 | ... / ... | test.c:157:23:157:30 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | -| test.c:158:21:158:23 | l13 | test.c:122:15:122:21 | ... / ... | test.c:158:16:158:23 | l13 | $@ casted to integer. | test.c:122:15:122:21 | ... / ... | Possibly NaN float value (from division of zero by zero) | -| test.c:166:8:166:10 | call to pow | test.c:166:3:166:18 | call to pow | test.c:166:3:166:18 | call to pow | $@ casted to integer. | test.c:166:8:166:10 | call to pow | Possibly NaN float value (both arguments are equal to zero) | -| test.c:171:8:171:11 | call to acos | test.c:171:3:171:15 | call to acos | test.c:171:3:171:15 | call to acos | $@ casted to integer. | test.c:171:8:171:11 | call to acos | Possibly NaN float value (the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0)) | -| test.c:175:32:175:32 | p | test.c:190:51:190:59 | ... / ... | test.c:175:27:175:32 | p | $@ casted to integer. | test.c:190:6:190:24 | addNaNThenCastToInt | Possibly NaN float value (from division of zero by zero) computed in function addNaNThenCastToInt | -| test.c:175:32:175:32 | p | test.c:195:13:195:21 | ... / ... | test.c:175:27:175:32 | p | $@ casted to integer. | test.c:192:6:192:7 | f2 | Possibly NaN float value (from division of zero by zero) computed in function f2 | -| test.c:175:32:175:32 | p | test.c:199:23:199:31 | ... / ... | test.c:175:27:175:32 | p | $@ casted to integer. | test.c:192:6:192:7 | f2 | Possibly NaN float value (from division of zero by zero) computed in function f2 | -| test.c:175:32:175:32 | p | test.c:205:19:205:27 | ... / ... | test.c:175:27:175:32 | p | $@ casted to integer. | test.c:192:6:192:7 | f2 | Possibly NaN float value (from division of zero by zero) computed in function f2 | -| test.c:185:18:185:18 | p | test.c:201:25:201:33 | ... / ... | test.c:185:13:185:18 | p | $@ casted to integer. | test.c:192:6:192:7 | f2 | Possibly NaN float value (from division of zero by zero) computed in function f2 | +| test.c:36:8:36:9 | l5 | test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | Possible NaN value $@ flows to a cast to integer. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:37:8:37:9 | l6 | test.c:28:14:28:20 | ... / ... | test.c:37:3:37:9 | l6 | Possible NaN value $@ flows to a cast to integer. | test.c:28:14:28:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Possible NaN value $@ flows to a cast to integer. | test.c:31:14:32:15 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:39:8:39:9 | l8 | test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | Possible NaN value $@ flows to a cast to integer. | test.c:33:14:33:22 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:46:3:46:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:46:3:46:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:47:3:47:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:47:3:47:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:48:3:48:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:48:3:48:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:49:3:49:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:49:3:49:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:50:3:50:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:50:3:50:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:51:3:51:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:51:3:51:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:52:3:52:4 | l6 | test.c:28:14:28:20 | ... / ... | test.c:52:3:52:4 | l6 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:28:14:28:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:53:3:53:4 | l7 | test.c:31:14:32:15 | ... / ... | test.c:53:3:53:4 | l7 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:31:14:32:15 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:54:3:54:4 | l8 | test.c:33:14:33:22 | ... / ... | test.c:54:3:54:4 | l8 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:33:14:33:22 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:61:11:61:17 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:66:11:66:19 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:72:20:72:28 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:75:24:75:32 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:126:10:126:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:126:5:126:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:132:10:132:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:132:5:132:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:138:10:138:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:138:5:138:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:144:10:144:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:144:5:144:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:148:10:148:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:148:5:148:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:155:25:155:27 | l13 | test.c:122:15:122:21 | ... / ... | test.c:155:20:155:27 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:157:28:157:30 | l13 | test.c:122:15:122:21 | ... / ... | test.c:157:23:157:30 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:158:21:158:23 | l13 | test.c:122:15:122:21 | ... / ... | test.c:158:16:158:23 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:166:8:166:10 | call to pow | test.c:166:3:166:18 | call to pow | test.c:166:3:166:18 | call to pow | Possible NaN value $@ flows to a cast to integer. | test.c:166:8:166:10 | call to pow | both arguments are equal to zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:171:8:171:11 | call to acos | test.c:171:3:171:15 | call to acos | test.c:171:3:171:15 | call to acos | Possible NaN value $@ flows to a cast to integer. | test.c:171:8:171:11 | call to acos | the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0) | test.c:6:6:6:7 | f1 | f1 | +| test.c:175:32:175:32 | p | test.c:190:51:190:59 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:190:51:190:59 | ... / ... | from division of zero by zero | test.c:190:6:190:24 | addNaNThenCastToInt | addNaNThenCastToInt | +| test.c:175:32:175:32 | p | test.c:195:13:195:21 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:195:13:195:21 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:175:32:175:32 | p | test.c:199:23:199:31 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:199:23:199:31 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:175:32:175:32 | p | test.c:205:19:205:27 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:205:19:205:27 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:185:18:185:18 | p | test.c:201:25:201:33 | ... / ... | test.c:185:13:185:18 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:201:25:201:33 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | diff --git a/cpp/common/src/codingstandards/cpp/FloatingPoint.qll b/cpp/common/src/codingstandards/cpp/FloatingPoint.qll index f3ba8dba18..f141214c82 100644 --- a/cpp/common/src/codingstandards/cpp/FloatingPoint.qll +++ b/cpp/common/src/codingstandards/cpp/FloatingPoint.qll @@ -1,5 +1,6 @@ import codeql.util.Boolean import codingstandards.cpp.RestrictedRangeAnalysis +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis as SimpleRangeAnalysis predicate exprMayEqualZero(Expr e) { RestrictedRangeAnalysis::upperBound(e) >= 0 and @@ -254,7 +255,7 @@ class FPClassificationGuard instanceof GuardCondition { ) } - // Helper function, gets base constraint assuming `classifier() == value` or `classifier != value`. + // Helper predicate, gets base constraint assuming `classifier() == value` or `classifier != value`. private FPClassificationConstraint getBaseConstraint(Boolean areEqual, int testResult) { exists(FPClassificationConstraint base | testResult = 0 and @@ -340,3 +341,72 @@ predicate exprMayEqualInfinity(Expr e, Boolean positive) { not guardedNotFPClass(e, TInfinite()) and not e.getType() instanceof IntegralType } + +signature float upperBoundPredicate(Expr e); + +signature float lowerBoundPredicate(Expr e); + +signature predicate exprMayEqualZeroPredicate(Expr e); + +predicate exprMayEqualZeroNaive(Expr e) { + e.getValue().toFloat() = 0 +} + +/** + * Get the math function name variants for the given name, e.g., "acos" has variants "acos", + * "acosf", and "acosl". + */ +Function getMathVariants(string name) { result.hasGlobalOrStdName([name, name + "f", name + "l"]) } + +module DomainError { + predicate hasDomainError(FunctionCall fc, string description) { + exists(Function functionWithDomainError | fc.getTarget() = functionWithDomainError | + functionWithDomainError = [getMathVariants(["acos", "asin", "atanh"])] and + not ( + ub(fc.getArgument(0)) <= 1.0 and + lb(fc.getArgument(0)) >= -1.0 + ) and + description = + "the argument has a range " + lb(fc.getArgument(0)) + "..." + ub(fc.getArgument(0)) + + " which is outside the domain of this function (-1.0...1.0)" + or + functionWithDomainError = getMathVariants(["atan2", "pow"]) and + ( + mayEqualZero(fc.getArgument(0)) and + mayEqualZero(fc.getArgument(1)) and + description = "both arguments are equal to zero" + ) + or + functionWithDomainError = getMathVariants("pow") and + ( + ub(fc.getArgument(0)) < 0.0 and + ub(fc.getArgument(1)) < 0.0 and + description = "both arguments are less than zero" + ) + or + functionWithDomainError = getMathVariants("acosh") and + ub(fc.getArgument(0)) < 1.0 and + description = "argument is less than 1" + or + //pole error is the same as domain for logb and tgamma (but not ilogb - no pole error exists) + functionWithDomainError = getMathVariants(["ilogb", "logb", "tgamma"]) and + fc.getArgument(0).getValue().toFloat() = 0 and + description = "argument is equal to zero" + or + functionWithDomainError = getMathVariants(["log", "log10", "log2", "sqrt"]) and + ub(fc.getArgument(0)) < 0.0 and + description = "argument is negative" + or + functionWithDomainError = getMathVariants("log1p") and + ub(fc.getArgument(0)) < -1.0 and + description = "argument is less than 1" + or + functionWithDomainError = getMathVariants("fmod") and + fc.getArgument(1).getValue().toFloat() = 0 and + description = "y is 0" + ) + } +} + +import DomainError as RestrictedDomainError +import DomainError as SimpleDomainError diff --git a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll index b81f113281..05290b3aaf 100644 --- a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll +++ b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll @@ -2,56 +2,75 @@ import semmle.code.cpp.controlflow.Guards import semmle.code.cpp.valuenumbering.HashCons /** - * A fork of SimpleRangeAnalysis.qll, which is intended to only give - * results with a conservative basis. + * A fork of SimpleRangeAnalysis.qll, which is intended to only give results + * with a conservative basis. Forked from codeql/cpp-all@1.4.2. * - * For instance, since range analysis is local, a function call (e.g. - * `f()`) is given the widest possible range in the original library. In - * this fork, we do not provide any result. + * For instance, since range analysis is local, a function call (e.g. `f()`) is + * given the widest possible range in the original library. In this fork, we do + * not provide any result. * * Original library level doc comment from SimpleRangeAnalysis.qll: * - * Simple range analysis library. Range analysis is usually done as an - * abstract interpretation over the lattice of range values. (A range is a - * pair, containing a lower and upper bound for the value.) The problem - * with this approach is that the lattice is very tall, which means it can - * take an extremely large number of iterations to find the least fixed - * point. This example illustrates the problem: + * > Simple range analysis library. Range analysis is usually done as an + * > abstract interpretation over the lattice of range values. (A range is a + * > pair, containing a lower and upper bound for the value.) The problem + * > with this approach is that the lattice is very tall, which means it can + * > take an extremely large number of iterations to find the least fixed + * > point. This example illustrates the problem: * - * int count = 0; - * for (; p; p = p->next) { - * count = count+1; - * } + * > int count = 0; + * > for (; p; p = p->next) { + * > count = count+1; + * > } * - * The range of 'count' is initially (0,0), then (0,1) on the second - * iteration, (0,2) on the third iteration, and so on until we eventually - * reach maxInt. + * > The range of 'count' is initially (0,0), then (0,1) on the second + * > iteration, (0,2) on the third iteration, and so on until we eventually + * > reach maxInt. * - * This library uses a crude solution to the problem described above: if - * the upper (or lower) bound of an expression might depend recursively on - * itself then we round it up (down for lower bounds) to one of a fixed set - * of values, such as 0, 1, 2, 256, and +Inf. This limits the height of the - * lattice which ensures that the analysis will terminate in a reasonable - * amount of time. This solution is similar to the abstract interpretation - * technique known as 'widening', but it is less precise because we are - * unable to inspect the bounds from the previous iteration of the fixed - * point computation. For example, widening might be able to deduce that - * the lower bound is -11 but we would approximate it to -16. + * > This library uses a crude solution to the problem described above: if + * > the upper (or lower) bound of an expression might depend recursively on + * > itself then we round it up (down for lower bounds) to one of a fixed set + * > of values, such as 0, 1, 2, 256, and +Inf. This limits the height of the + * > lattice which ensures that the analysis will terminate in a reasonable + * > amount of time. This solution is similar to the abstract interpretation + * > technique known as 'widening', but it is less precise because we are + * > unable to inspect the bounds from the previous iteration of the fixed + * > point computation. For example, widening might be able to deduce that + * > the lower bound is -11 but we would approximate it to -16. * - * QL does not allow us to compute an aggregate over a recursive - * sub-expression, so we cannot compute the minimum lower bound and maximum - * upper bound during the recursive phase of the query. Instead, the - * recursive phase computes a set of lower bounds and a set of upper bounds - * for each expression. We compute the minimum lower bound and maximum - * upper bound after the recursion is finished. This is another reason why - * we need to limit the number of bounds per expression, because they will - * all be stored until the recursive phase is finished. + * > QL does not allow us to compute an aggregate over a recursive + * > sub-expression, so we cannot compute the minimum lower bound and maximum + * > upper bound during the recursive phase of the query. Instead, the + * > recursive phase computes a set of lower bounds and a set of upper bounds + * > for each expression. We compute the minimum lower bound and maximum + * > upper bound after the recursion is finished. This is another reason why + * > we need to limit the number of bounds per expression, because they will + * > all be stored until the recursive phase is finished. * - * The ranges are represented using a pair of floating point numbers. This - * is simpler than using integers because floating point numbers cannot - * overflow and wrap. It is also convenient because we can detect overflow - * and negative overflow by looking for bounds that are outside the range - * of the type. + * > The ranges are represented using a pair of floating point numbers. This + * > is simpler than using integers because floating point numbers cannot + * > overflow and wrap. It is also convenient because we can detect overflow + * > and negative overflow by looking for bounds that are outside the range + * > of the type. + * + * The differences between this library and the original are: + * - The `largeValue()` predicate, with a value of 1e15, used in place of + * `exprMaxVal()` and `exprMinVal()` in most places. + * - Support for range analysis extensions removed for simplicity. + * - Additional predicates have been added to check for non-zero values, and guards + * against values equalling zero. + * - Division by a constant value has been added as a supported operations. Division + * is always widened, as support for division introduces examples of significantly + * longer chains of dependent expressions than merely addition and multiplication. + * These long chains can introduce exponential growth in the number of candidate + * bounds, even without recursive binary operations, so widening is always applied. + * - Division operations where the range of the denominator includes zero (and its + * not guarded to be non-zero) and produce infinite upper and/or lower bounds. + * - Support for monotonically increasing and decreasing math functions has been + * added, including `log`, `exp`, `asin`, `atan`, `sinh`, and `sqrt`. If a math + * function increases or decreases monotonically, then the lower or upper bound of + * its input can be used to compute the lower or upper bound of the function call. + * Not all math functions increase or decrease monotonically. */ module RestrictedRangeAnalysis { import cpp diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/FloatingTypes2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/FloatingTypes2.qll index 7cdc6430a3..0dbc6cc22d 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/FloatingTypes2.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/FloatingTypes2.qll @@ -22,7 +22,7 @@ predicate isFloatingTypes2QueryMetadata(Query query, string queryId, string rule FloatingTypes2Package::possibleMisuseOfUndetectedNaNQuery() and queryId = // `@id` for the `possibleMisuseOfUndetectedNaN` query - "c/misra/possible-misuse-of-undetected-na-n" and + "c/misra/possible-misuse-of-undetected-nan" and ruleId = "DIR-4-15" and category = "required" } diff --git a/cpp/common/src/codingstandards/cpp/rules/uncheckedrangedomainpoleerrors/UncheckedRangeDomainPoleErrors.qll b/cpp/common/src/codingstandards/cpp/rules/uncheckedrangedomainpoleerrors/UncheckedRangeDomainPoleErrors.qll index ad93f70bd4..acc7888d2c 100644 --- a/cpp/common/src/codingstandards/cpp/rules/uncheckedrangedomainpoleerrors/UncheckedRangeDomainPoleErrors.qll +++ b/cpp/common/src/codingstandards/cpp/rules/uncheckedrangedomainpoleerrors/UncheckedRangeDomainPoleErrors.qll @@ -4,63 +4,14 @@ import cpp import codingstandards.cpp.CodingStandards +import codingstandards.cpp.FloatingPoint +import codingstandards.cpp.FloatingPoint::SimpleDomainError import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis abstract class UncheckedRangeDomainPoleErrorsSharedQuery extends Query { } Query getQuery() { result instanceof UncheckedRangeDomainPoleErrorsSharedQuery } -bindingset[name] -Function getMathVariants(string name) { result.hasGlobalOrStdName([name, name + "f", name + "l"]) } - -predicate hasDomainError(FunctionCall fc, string description) { - exists(Function functionWithDomainError | fc.getTarget() = functionWithDomainError | - functionWithDomainError = [getMathVariants(["acos", "asin", "atanh"])] and - not ( - upperBound(fc.getArgument(0)) <= 1.0 and - lowerBound(fc.getArgument(0)) >= -1.0 - ) and - description = - "the argument has a range " + lowerBound(fc.getArgument(0)) + "..." + - upperBound(fc.getArgument(0)) + " which is outside the domain of this function (-1.0...1.0)" - or - functionWithDomainError = getMathVariants(["atan2", "pow"]) and - ( - fc.getArgument(0).getValue().toFloat() = 0 and - fc.getArgument(1).getValue().toFloat() = 0 and - description = "both arguments are equal to zero" - ) - or - functionWithDomainError = getMathVariants("pow") and - ( - upperBound(fc.getArgument(0)) < 0.0 and - upperBound(fc.getArgument(1)) < 0.0 and - description = "both arguments are less than zero" - ) - or - functionWithDomainError = getMathVariants("acosh") and - upperBound(fc.getArgument(0)) < 1.0 and - description = "argument is less than 1" - or - //pole error is the same as domain for logb and tgamma (but not ilogb - no pole error exists) - functionWithDomainError = getMathVariants(["ilogb", "logb", "tgamma"]) and - fc.getArgument(0).getValue().toFloat() = 0 and - description = "argument is equal to zero" - or - functionWithDomainError = getMathVariants(["log", "log10", "log2", "sqrt"]) and - upperBound(fc.getArgument(0)) < 0.0 and - description = "argument is negative" - or - functionWithDomainError = getMathVariants("log1p") and - upperBound(fc.getArgument(0)) < -1.0 and - description = "argument is less than 1" - or - functionWithDomainError = getMathVariants("fmod") and - fc.getArgument(1).getValue().toFloat() = 0 and - description = "y is 0" - ) -} - predicate hasRangeError(FunctionCall fc, string description) { exists(Function functionWithRangeError | fc.getTarget() = functionWithRangeError | functionWithRangeError.hasGlobalOrStdName(["abs", "labs", "llabs", "imaxabs"]) and diff --git a/scripts/generate_rules/coding_standards_utils.py b/scripts/generate_rules/coding_standards_utils.py index 6f96460ef7..b0bcd48443 100644 --- a/scripts/generate_rules/coding_standards_utils.py +++ b/scripts/generate_rules/coding_standards_utils.py @@ -19,8 +19,10 @@ def split_camel_case(short_name : str) -> List[str]: """Split a camel case string to a list.""" + # Edge case, turn FooNaNBar into foo-nan-bar instead of foo-na-n-bar by a preprocessing step. + nan_fixed = short_name.replace("NaN", "Nan") matches = re.finditer( - ".+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)", short_name) + ".+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)", nan_fixed) return [m.group(0) for m in matches] From d10783cccb68348dbb43910ed6647867aa9bfdaf Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 20 Mar 2025 17:24:44 -0700 Subject: [PATCH 317/628] Format FloatingPoint.qll --- cpp/common/src/codingstandards/cpp/FloatingPoint.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/FloatingPoint.qll b/cpp/common/src/codingstandards/cpp/FloatingPoint.qll index f141214c82..f5ff2fefca 100644 --- a/cpp/common/src/codingstandards/cpp/FloatingPoint.qll +++ b/cpp/common/src/codingstandards/cpp/FloatingPoint.qll @@ -348,9 +348,7 @@ signature float lowerBoundPredicate(Expr e); signature predicate exprMayEqualZeroPredicate(Expr e); -predicate exprMayEqualZeroNaive(Expr e) { - e.getValue().toFloat() = 0 -} +predicate exprMayEqualZeroNaive(Expr e) { e.getValue().toFloat() = 0 } /** * Get the math function name variants for the given name, e.g., "acos" has variants "acos", @@ -358,7 +356,9 @@ predicate exprMayEqualZeroNaive(Expr e) { */ Function getMathVariants(string name) { result.hasGlobalOrStdName([name, name + "f", name + "l"]) } -module DomainError { +module DomainError< + upperBoundPredicate/1 ub, lowerBoundPredicate/1 lb, exprMayEqualZeroPredicate/1 mayEqualZero> +{ predicate hasDomainError(FunctionCall fc, string description) { exists(Function functionWithDomainError | fc.getTarget() = functionWithDomainError | functionWithDomainError = [getMathVariants(["acos", "asin", "atanh"])] and From 2265ed48d7b8739a4061e12ac601c5d2277e7ef9 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 21 Mar 2025 00:50:52 -0700 Subject: [PATCH 318/628] Address feedback --- c/common/src/codingstandards/c/Generic.qll | 2 +- ...ricSelectionDoesntDependOnMacroArgument.ql | 9 ++-- .../GenericSelectionNotExpandedFromAMacro.ql | 4 +- ...ricSelectionNotFromMacroWithSideEffects.ql | 1 + .../GenericWithoutNonDefaultAssociation.ql | 2 +- ...ectionDoesntDependOnMacroArgument.expected | 6 +-- ...ricSelectionNotExpandedFromAMacro.expected | 2 +- .../codingstandards/cpp/types/Compatible.qll | 51 +------------------ .../cpp/types/SimpleAssignment.qll | 6 +++ 9 files changed, 21 insertions(+), 62 deletions(-) diff --git a/c/common/src/codingstandards/c/Generic.qll b/c/common/src/codingstandards/c/Generic.qll index 784c16778e..1281be5f71 100644 --- a/c/common/src/codingstandards/c/Generic.qll +++ b/c/common/src/codingstandards/c/Generic.qll @@ -115,7 +115,7 @@ class ParsedGenericMacro extends Macro { ) } - string getControllingExprString() { result = getSelectionString(1) } + string getControllingExprString() { result = getSelectionString(1).trim() } bindingset[str, word] private int countWordInString(string word, string str) { diff --git a/c/misra/src/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.ql b/c/misra/src/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.ql index 0dc0e5273a..1a76339f50 100644 --- a/c/misra/src/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.ql +++ b/c/misra/src/rules/RULE-23-1/GenericSelectionDoesntDependOnMacroArgument.ql @@ -19,8 +19,9 @@ import codingstandards.c.Generic from ParsedGenericMacro macro, string ctrlExpr where not isExcluded(macro, GenericsPackage::genericSelectionDoesntDependOnMacroArgumentQuery()) and - ctrlExpr = macro.getControllingExprString().trim() and - not macro.expansionsInsideControllingExpr(_) > 0 + ctrlExpr = macro.getControllingExprString() and + // No parameter exists that is expanded in the controlling expression one or more times + not exists(string parameter | macro.expansionsInsideControllingExpr(parameter) > 0) select macro, - "Generic macro " + macro.getName() + " uses controlling expr " + ctrlExpr + - ", which doesn't match any macro parameter." + "Generic macro " + macro.getName() + " doesn't refer to a macro parameter in controlling expr '" + + ctrlExpr + "'." diff --git a/c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql b/c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql index 540804ffc4..603c44e8e1 100644 --- a/c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql +++ b/c/misra/src/rules/RULE-23-1/GenericSelectionNotExpandedFromAMacro.ql @@ -19,5 +19,5 @@ where not isExcluded(generic, GenericsPackage::genericSelectionNotExpandedFromAMacroQuery()) and ctrlExpr = generic.getControllingExpr() and not exists(MacroInvocation mi | mi.getAGeneratedElement() = generic.getExpr()) -select generic, "Generic expression with controlling expression $@ is not expanded froma macro", - ctrlExpr, ctrlExpr.toString() +select generic, "$@ in generic expression does not expand a macro parameter.", ctrlExpr, + "Controlling expression" diff --git a/c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql b/c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql index 4b1a2d26c3..d7fcb13d76 100644 --- a/c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql +++ b/c/misra/src/rules/RULE-23-2/GenericSelectionNotFromMacroWithSideEffects.ql @@ -72,6 +72,7 @@ module GenericSideEffectReportConfig implements MacroReportConfigSig Date: Mon, 24 Mar 2025 18:30:08 +0000 Subject: [PATCH 319/628] Bump version to 2.44.0-dev --- c/cert/src/qlpack.yml | 2 +- c/cert/test/qlpack.yml | 2 +- c/common/src/qlpack.yml | 2 +- c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- c/misra/test/qlpack.yml | 2 +- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/qlpack.yml | 2 +- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- docs/user_manual.md | 12 ++++++------ 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 8498e9447d..631639301e 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.43.0-dev +version: 2.44.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index 2b44a05fdf..6eaaba1e91 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.43.0-dev +version: 2.44.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 685a3a0144..4c21dc9b18 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.43.0-dev +version: 2.44.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index 8f8486949b..1dbb59b4fd 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.43.0-dev +version: 2.44.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 5b8b1fc0b2..54cda2c1cc 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.43.0-dev +version: 2.44.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index aa5c5d86ae..9148e26b59 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.43.0-dev +version: 2.44.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index 1116e9534d..6d31398b2c 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.43.0-dev +version: 2.44.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index d540b01a32..ff7621c9d1 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.43.0-dev +version: 2.44.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 89b5196f23..f44646cdbe 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.43.0-dev +version: 2.44.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index ceedca4647..c6d57b0d33 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.43.0-dev +version: 2.44.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index ce7e896ced..302955fc78 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards -version: 2.43.0-dev +version: 2.44.0-dev license: MIT dependencies: codeql/cpp-all: 2.1.1 diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index e2201b887e..1f0b830de8 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.43.0-dev +version: 2.44.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 7c104631d1..27e0893ed6 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.43.0-dev +version: 2.44.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index 08bdda24eb..cdf6cbcdea 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.43.0-dev +version: 2.44.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index 73a6e189a3..83188c2748 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.43.0-dev +version: 2.44.0-dev license: MIT dependencies: codeql/cpp-all: 2.1.1 diff --git a/docs/user_manual.md b/docs/user_manual.md index a771aa1cc6..1e14744f80 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -35,14 +35,14 @@ ## Release information -This user manual documents release `2.43.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.44.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: - `coding-standards-codeql-packs-2.37.0-dev.zip`: CodeQL packs that can be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `code-scanning-cpp-query-pack-2.43.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.43.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.43.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.43.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.44.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.44.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.44.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.44.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -667,7 +667,7 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.43.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.44.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | From 642c7373d271bcb46daec0b6baf16d7278df5857 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 25 Mar 2025 00:28:00 -0700 Subject: [PATCH 320/628] Handle bit fields --- ...gMathArgumentsWithDifferingStandardType.ql | 37 ++++++++++++------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql b/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql index 5156d81cef..5267ff98f9 100644 --- a/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql +++ b/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql @@ -16,12 +16,6 @@ import cpp import codingstandards.c.misra import codingstandards.c.TgMath -Expr getFullyExplicitlyConverted(Expr e) { - if e.hasExplicitConversion() - then result = getFullyExplicitlyConverted(e.getExplicitlyConverted()) - else result = e -} - string argTypesString(TgMathInvocation call, int i) { exists(string typeStr | typeStr = getEffectiveStandardType(call.getOperandArgument(i)).toString() and @@ -33,12 +27,28 @@ string argTypesString(TgMathInvocation call, int i) { ) } -predicate promotes(Type type) { type.(IntegralType).getSize() < any(IntType t).getSize() } - -Type integerPromote(Type type) { - promotes(type) and result.(IntType).isSigned() - or - not promotes(type) and result = type +/** + * If the range of values can be represented as a signed int, it is promoted to signed int. + * + * A value may also promote to unsigned int but only if `int` cannot represent the range of + * values. Which basically means only an `unsigned int` promotes to `unsigned int`, so we don't + * need to do anything in this case. + * + * An unsigned int bitfield with fewer than 32 bits is promoted to `int`. + */ +predicate promotesToSignedInt(Expr e) { + exists(int intBits, int intBytes | + intBytes = any(IntType t).getSize() and + intBits = intBytes * 8 and + ( + e.(FieldAccess).getTarget().(BitField).getNumBits() < intBits + or + e.getUnderlyingType().(IntegralType).getSize() < intBytes + ) + ) +} +Type getPromotedType(Expr e) { + if promotesToSignedInt(e) then result.(IntType).isSigned() else result = e.getUnderlyingType() } Type canonicalize(Type type) { @@ -48,8 +58,7 @@ Type canonicalize(Type type) { } Type getEffectiveStandardType(Expr e) { - result = - canonicalize(integerPromote(getFullyExplicitlyConverted(e).getType().stripTopLevelSpecifiers())) + result = canonicalize(getPromotedType(e.getExplicitlyConverted())) } from TgMathInvocation call, Type firstType From 952253de73853bb7a291672a7909698d81f76817 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 25 Mar 2025 00:30:09 -0700 Subject: [PATCH 321/628] Format SimpleAssignment.qll --- cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll b/cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll index a38939c9ea..4f7a85c80a 100644 --- a/cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll +++ b/cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll @@ -1,9 +1,10 @@ /** * Helper predicates related to C11/C17 constraints on simple assignment between two types. - * + * * Currently only a subset of the constraints are implemented, specifically those * related to pointer types. */ + import codingstandards.cpp.types.LvalueConversion import codingstandards.cpp.types.Compatible From f268604d7d3920dad7c3546c60d56e90152ef6f5 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 25 Mar 2025 00:31:41 -0700 Subject: [PATCH 322/628] Update regex --- c/common/src/codingstandards/c/Generic.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/common/src/codingstandards/c/Generic.qll b/c/common/src/codingstandards/c/Generic.qll index 1281be5f71..19d5aad443 100644 --- a/c/common/src/codingstandards/c/Generic.qll +++ b/c/common/src/codingstandards/c/Generic.qll @@ -2,7 +2,7 @@ import cpp import codingstandards.cpp.Macro import codingstandards.cpp.MatchingParenthesis -string genericRegexp() { result = ".*_Generic\\s*\\(\\s*(.+),.*" } +string genericRegexp() { result = "\\b_Generic\\s*\\(\\s*(.+),.*" } bindingset[input] string deparenthesize(string input) { From 94bad29caacbeb653fe3adc34ea62d2008a316b4 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 25 Mar 2025 00:32:46 -0700 Subject: [PATCH 323/628] Format --- .../RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql b/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql index 5267ff98f9..81209c8565 100644 --- a/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql +++ b/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql @@ -29,11 +29,11 @@ string argTypesString(TgMathInvocation call, int i) { /** * If the range of values can be represented as a signed int, it is promoted to signed int. - * + * * A value may also promote to unsigned int but only if `int` cannot represent the range of * values. Which basically means only an `unsigned int` promotes to `unsigned int`, so we don't * need to do anything in this case. - * + * * An unsigned int bitfield with fewer than 32 bits is promoted to `int`. */ predicate promotesToSignedInt(Expr e) { @@ -47,6 +47,7 @@ predicate promotesToSignedInt(Expr e) { ) ) } + Type getPromotedType(Expr e) { if promotesToSignedInt(e) then result.(IntType).isSigned() else result = e.getUnderlyingType() } From 6245f7210e709e205b21e092e2cd907689cdd638 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 25 Mar 2025 00:34:09 -0700 Subject: [PATCH 324/628] Format --- cpp/common/src/codingstandards/cpp/types/Compatible.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll index fb8bf46aad..d6f65126e8 100644 --- a/cpp/common/src/codingstandards/cpp/types/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -369,4 +369,4 @@ private class FunctionType extends Type { result = this.(RoutineType).getParameterType(i) or result = this.(FunctionPointerIshType).getParameterType(i) } -} \ No newline at end of file +} From 2045a44bd4aef7968ddc589004ee3d3ccd6d2bc7 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 26 Mar 2025 11:43:00 +0000 Subject: [PATCH 325/628] Restore deleted deviations suppression query --- .../deviations/DeviationsSuppression.qhelp | 12 ++ .../cpp/deviations/DeviationsSuppression.ql | 120 ++++++++++++++++++ .../DeviationsSuppression.expected | 7 + .../DeviationsSuppression.qlref | 1 + 4 files changed, 140 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.qhelp create mode 100644 cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql create mode 100644 cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected create mode 100644 cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.qlref diff --git a/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.qhelp b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.qhelp new file mode 100644 index 0000000000..0bf3a3a71b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.qhelp @@ -0,0 +1,12 @@ + + + +

    This query generates suppression information for rules that have an associated deviation record.

    +
    + +
  • + MISRA Compliance 2020 document: + Chapter 4.2 (page 12) - Deviations. +
  • +
    +
    \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql new file mode 100644 index 0000000000..9035b7d288 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql @@ -0,0 +1,120 @@ +/** + * @name Deviation suppression + * @description Generates information about files and locations where certain alerts should be considered suppressed by deviations. + * @kind alert-suppression + * @id cpp/coding-standards/deviation-suppression + */ + +import cpp +import Deviations + +/** Holds if `lineNumber` is an indexed line number in file `f`. */ +private predicate isLineNumber(File f, int lineNumber) { + exists(Location l | l.getFile() = f | + l.getStartLine() = lineNumber + or + l.getEndLine() = lineNumber + ) +} + +/** Gets the last line number in `f`. */ +private int getLastLineNumber(File f) { result = max(int lineNumber | isLineNumber(f, lineNumber)) } + +/** Gets the last column number on the last line of `f`. */ +int getLastColumnNumber(File f) { + result = + max(Location l | + l.getFile() = f and + l.getEndLine() = getLastLineNumber(f) + | + l.getEndColumn() + ) +} + +newtype TDeviationScope = + TDeviationRecordFileScope(DeviationRecord dr, File file) { + exists(string deviationPath | + dr.isDeviated(_, deviationPath) and + file.getRelativePath().prefix(deviationPath.length()) = deviationPath + ) + } or + TDeviationRecordCommentScope(DeviationRecord dr, Comment c) { c = dr.getACodeIdentifierComment() } + +/** A deviation scope. */ +class DeviationScope extends TDeviationScope { + /** Gets the location at which this deviation was defined. */ + abstract Locatable getDeviationDefinitionLocation(); + + /** Gets the Query being deviated. */ + abstract Query getQuery(); + + abstract string toString(); + + abstract predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ); +} + +/** A deviation scope derived from a "path" entry in a `DeviationRecord`. */ +class DeviationRecordFileScope extends DeviationScope, TDeviationRecordFileScope { + private DeviationRecord getDeviationRecord() { this = TDeviationRecordFileScope(result, _) } + + override Locatable getDeviationDefinitionLocation() { result = getDeviationRecord() } + + private File getFile() { this = TDeviationRecordFileScope(_, result) } + + override Query getQuery() { result = getDeviationRecord().getQuery() } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + // In an ideal world, we would produce a URL here that informed the AlertSuppression code that + // the whole file was suppressed. However, experimentation suggestions the alert suppression + // code only works with locations with lines and columns, so we generate a location that covers + // the whole "indexed" file, by finding the location indexed in the database with the latest + // line and column number. + exists(File f | f = getFile() | + f.getLocation().hasLocationInfo(filepath, _, _, _, _) and + startline = 1 and + startcolumn = 1 and + endline = getLastLineNumber(f) and + endcolumn = getLastColumnNumber(f) + ) + } + + override string toString() { + result = "Deviation of " + getDeviationRecord().getQuery() + " for " + getFile() + "." + } +} + +/** + * A deviation scope derived from a comment corresponding to a "code-identifier" entry for a + * `DeviationRecord`. + */ +class DeviationRecordCommentScope extends DeviationScope, TDeviationRecordCommentScope { + private DeviationRecord getDeviationRecord() { this = TDeviationRecordCommentScope(result, _) } + + private Comment getComment() { this = TDeviationRecordCommentScope(_, result) } + + override Locatable getDeviationDefinitionLocation() { result = getDeviationRecord() } + + override Query getQuery() { result = getDeviationRecord().getQuery() } + + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + getComment().getLocation().hasLocationInfo(filepath, startline, _, endline, endcolumn) and + startcolumn = 1 + } + + override string toString() { + result = + "Deviation of " + getDeviationRecord().getQuery() + " for comment " + getComment() + "." + } +} + +from DeviationScope deviationScope +select deviationScope.getDeviationDefinitionLocation(), // suppression comment + "// lgtm[" + deviationScope.getQuery().getQueryId() + "]", // text of suppression comment (excluding delimiters) + "lgtm[" + deviationScope.getQuery().getQueryId() + "]", // text of suppression annotation + deviationScope // scope of suppression diff --git a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected new file mode 100644 index 0000000000..50ceb35b9d --- /dev/null +++ b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected @@ -0,0 +1,7 @@ +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:12:1:12:58 | Deviation of cpp/autosar/type-long-double-used for comment // a-0-4-2-deviation COMPLIANT[DEVIATED]. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/unused-return-value] | lgtm[cpp/autosar/unused-return-value] | nested/nested2/test2.h:1:1:6:1 | Deviation of cpp/autosar/unused-return-value for nested/nested2/test2.h. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | coding-standards.xml:1:1:17:19 | Deviation of cpp/autosar/useless-assignment for coding-standards.xml. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | main.cpp:1:1:14:1 | Deviation of cpp/autosar/useless-assignment for main.cpp. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/coding-standards.xml:1:1:13:19 | Deviation of cpp/autosar/useless-assignment for nested/coding-standards.xml. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/nested2/test2.h:1:1:6:1 | Deviation of cpp/autosar/useless-assignment for nested/nested2/test2.h. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/test.h:1:1:6:1 | Deviation of cpp/autosar/useless-assignment for nested/test.h. | diff --git a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.qlref b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.qlref new file mode 100644 index 0000000000..6268ee7342 --- /dev/null +++ b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.qlref @@ -0,0 +1 @@ +codingstandards/cpp/deviations/DeviationsSuppression.ql \ No newline at end of file From 1e4011f73443b8b080385dcea3a3abce7f2b7858 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 26 Mar 2025 11:46:30 +0000 Subject: [PATCH 326/628] Add change note. --- change_notes/2025-03-26-deviations-suppression.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 change_notes/2025-03-26-deviations-suppression.md diff --git a/change_notes/2025-03-26-deviations-suppression.md b/change_notes/2025-03-26-deviations-suppression.md new file mode 100644 index 0000000000..5dcb5e8dba --- /dev/null +++ b/change_notes/2025-03-26-deviations-suppression.md @@ -0,0 +1 @@ + - The `DeviationsSuppression.ql` query has been restored after being incorrectly deleted in a previous release. \ No newline at end of file From 6b9dc41a53e8840cd0c8aaa07dfe6b0cb9600d08 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 26 Mar 2025 23:40:27 -0700 Subject: [PATCH 327/628] Feedback --- change_notes/2025-03-11-various-misra-amendments.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/change_notes/2025-03-11-various-misra-amendments.md b/change_notes/2025-03-11-various-misra-amendments.md index 99acdcc63a..19783fe803 100644 --- a/change_notes/2025-03-11-various-misra-amendments.md +++ b/change_notes/2025-03-11-various-misra-amendments.md @@ -5,4 +5,5 @@ - `RULE-18-6` - `ThreadLocalObjectAddressCopiedToGlobalObject.ql`: - New query added to detect thread local objects assigned to static storage duration objects. - `RULE-21-12` - `ExceptionHandlingFeaturesOfFenvhUsed.ql`: - - Added reports for `#include`ing "fenv.h", and for using `fesetenv`, `feupdatenv`, and `fesetround`. \ No newline at end of file + - Added reports for `#include`ing "fenv.h", and for using `fesetenv`, `feupdatenv`, and `fesetround`. + - Report message altered to handle new cases. \ No newline at end of file From dae8162b31cc8914a8662513854b1370492e8a0c Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 27 Mar 2025 00:48:07 -0700 Subject: [PATCH 328/628] Address feedback --- c/common/src/codingstandards/c/SubObjects.qll | 35 ++++++++++++++ .../GlobalInitializationAnalysis.qll | 4 +- .../DIR-5-1/PossibleDataRaceBetweenThreads.ql | 40 +++++++++------- .../InvalidOperationOnUnlockedMutex.ql | 2 +- ...NonRecursiveMutexRecursivelyLockedAudit.ql | 4 +- ...onditionVariableUsedWithMultipleMutexes.ql | 2 +- .../ThreadStorageNotInitializedBeforeUse.ql | 2 +- .../PossibleDataRaceBetweenThreads.expected | 48 +++++++++---------- c/misra/test/rules/RULE-22-14/test.c | 12 +++++ .../InvalidOperationOnUnlockedMutex.expected | 32 ++++++------- ...ursiveMutexRecursivelyLockedAudit.expected | 12 ++--- ...onVariableUsedWithMultipleMutexes.expected | 4 +- ...eadStorageNotInitializedBeforeUse.expected | 10 ++-- .../cpp/concurrency/LockingOperation.qll | 23 ++++----- rule_packages/c/Concurrency9.json | 2 +- 15 files changed, 140 insertions(+), 92 deletions(-) diff --git a/c/common/src/codingstandards/c/SubObjects.qll b/c/common/src/codingstandards/c/SubObjects.qll index 282b0fb5eb..66f15cd18c 100644 --- a/c/common/src/codingstandards/c/SubObjects.qll +++ b/c/common/src/codingstandards/c/SubObjects.qll @@ -1,3 +1,31 @@ +/** + * A library that expands upon the `Objects.qll` library, to support nested "Objects" such as + * `x.y.z` or `x[i][j]` within an object `x`. + * + * Objects in C are values in memory, that have a type and a storage duration. In the case of + * array objects and struct objects, the object will contain other objects. The these subobjects + * will share properties of the root object such as storage duration. This library can be used to, + * for instance, find all usages of a struct member to ensure that member is initialized before it + * is used. + * + * To use this library, select `SubObject` and find its usages in the AST via `getAnAccess()` (to + * find usages of the subobject by value) or `getAnAddressOfExpr()` (to find usages of the object + * by address). + * + * Note that a struct or array object may contain a pointer. In this case, the pointer itself is + * a subobject of the struct or array object, but the object that the pointer points to is not. + * This is because the pointed-to object does not necessarily have the same storage duration, + * lifetime, or linkage as the pointer and the object containing the pointer. + * + * Note as well that `getAnAccess()` on an array subobject will return all accesses to the array, + * not just accesses to a particular index. For this reason, `SubObject` exposes the predicate + * `isPrecise()`. If a subobject is precise, that means all results of `getAnAccess()` will + * definitely refer to the same object in memory. If it is not precise, the different accesses + * may refer to the same or different objects in memory. For instance, `x[i].y` and `x[j].y` are + * the same object if `i` and `j` are the same, but they are different objects if `i` and `j` are + * different. + */ + import codingstandards.c.Objects newtype TSubObject = @@ -70,6 +98,8 @@ class SubObject extends TSubObject { exists(MemberVariable m | this = TObjectMember(_, m) and result = m.getAnAccess() and + // Only consider `DotFieldAccess`es, not `PointerFieldAccess`es, as the latter + // are not subobjects of the root object: result.(DotFieldAccess).getQualifier() = getParent().getAnAccess() ) or @@ -79,6 +109,11 @@ class SubObject extends TSubObject { AddressOfExpr getAnAddressOfExpr() { result.getOperand() = this.getAnAccess() } + /** + * Get the "root" object identity to which this subobject belongs. For instance, in the + * expression `x.y.z`, the root object is `x`. This subobject will share properties with the root + * object such as storage duration, lifetime, and linkage. + */ ObjectIdentity getRootIdentity() { exists(ObjectIdentity i | this = TObjectRoot(i) and diff --git a/c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll b/c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll index 90d0a4630a..2906883ae9 100644 --- a/c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll +++ b/c/common/src/codingstandards/c/initialization/GlobalInitializationAnalysis.qll @@ -7,7 +7,9 @@ signature module GlobalInitializationAnalysisConfigSig { /** A function which is not called or started as a thread */ default predicate isRootFunction(Function f) { not exists(Function f2 | f2.calls(f)) and - not f instanceof ThreadedFunction + not f instanceof ThreadedFunction and + // Exclude functions which are used as function pointers. + not exists(FunctionAccess access | f = access.getTarget()) } ObjectIdentity getAnInitializedObject(Expr e); diff --git a/c/misra/src/rules/DIR-5-1/PossibleDataRaceBetweenThreads.ql b/c/misra/src/rules/DIR-5-1/PossibleDataRaceBetweenThreads.ql index 443dc284fd..edf3705a9b 100644 --- a/c/misra/src/rules/DIR-5-1/PossibleDataRaceBetweenThreads.ql +++ b/c/misra/src/rules/DIR-5-1/PossibleDataRaceBetweenThreads.ql @@ -47,7 +47,7 @@ class NonReentrantOperation extends TNonReentrantOperation { ) } - Expr getARead() { + Expr getAReadExpr() { exists(SubObject object | this = TReadWrite(object) and result = object.getAnAccess() @@ -56,7 +56,7 @@ class NonReentrantOperation extends TNonReentrantOperation { this = TStdFunctionCall(result) } - Expr getAWrite() { + Expr getAWriteExpr() { exists(SubObject object, Assignment assignment | this = TReadWrite(object) and result = assignment and @@ -94,16 +94,20 @@ class NonReentrantOperation extends TNonReentrantOperation { class WritingThread extends ThreadedFunction { NonReentrantOperation aWriteObject; - Expr aWrite; + Expr aWriteExpr; WritingThread() { - aWrite = aWriteObject.getAWrite() and - this.calls*(aWrite.getEnclosingFunction()) and - not aWrite instanceof LockProtectedControlFlowNode and - not aWrite.getEnclosingFunction().getName().matches(["%init%", "%boot%", "%start%"]) + aWriteExpr = aWriteObject.getAWriteExpr() and + // This function directly contains the write expression, or transitively calls the function + // that contains the write expression. + this.calls*(aWriteExpr.getEnclosingFunction()) and + // The write isn't synchronized with a mutex or condition object. + not aWriteExpr instanceof LockProtectedControlFlowNode and + // The write doesn't seem to be during a special initialization phase of the program. + not aWriteExpr.getEnclosingFunction().getName().matches(["%init%", "%boot%", "%start%"]) } - Expr getAWrite() { result = aWrite } + Expr getAWriteExpr() { result = aWriteExpr } } class ReadingThread extends ThreadedFunction { @@ -111,22 +115,22 @@ class ReadingThread extends ThreadedFunction { ReadingThread() { exists(NonReentrantOperation op | - aReadExpr = op.getARead() and + aReadExpr = op.getAReadExpr() and this.calls*(aReadExpr.getEnclosingFunction()) and not aReadExpr instanceof LockProtectedControlFlowNode ) } - Expr getARead() { result = aReadExpr } + Expr getAReadExpr() { result = aReadExpr } } predicate mayBeDataRace(Expr write, Expr read, NonReentrantOperation operation) { exists(WritingThread wt | - wt.getAWrite() = write and - write = operation.getAWrite() and + wt.getAWriteExpr() = write and + write = operation.getAWriteExpr() and exists(ReadingThread rt | - read = rt.getARead() and - read = operation.getARead() and + read = rt.getAReadExpr() and + read = operation.getAReadExpr() and ( wt.isMultiplySpawned() or not wt = rt @@ -141,18 +145,18 @@ from where not isExcluded(write, Concurrency9Package::possibleDataRaceBetweenThreadsQuery()) and mayBeDataRace(write, read, operation) and - wt = min(WritingThread f | f.getAWrite() = write | f order by f.getName()) and - rt = min(ReadingThread f | f.getARead() = read | f order by f.getName()) and + wt = min(WritingThread f | f.getAWriteExpr() = write | f order by f.getName()) and + rt = min(ReadingThread f | f.getAReadExpr() = read | f order by f.getName()) and writeString = operation.getWriteString() and readString = operation.getReadString() and if wt.isMultiplySpawned() then message = "Threaded " + writeString + - " $@ not synchronized, for example from thread function $@ spawned from a loop." + " $@ not synchronized from thread function $@ spawned from a loop." else message = "Threaded " + writeString + - " $@, for example from thread function $@, not synchronized with $@, for example from thread function $@." + " $@ from thread function $@ is not synchronized with $@ from thread function $@." select write, message, operation.getSourceElement(), operation.toString(), wt, wt.getName(), read, "concurrent " + readString, rt, rt.getName() diff --git a/c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql b/c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql index 7c0b86f145..252b4a7d9f 100644 --- a/c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql +++ b/c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql @@ -64,5 +64,5 @@ where not isExcluded(operation, Concurrency9Package::invalidOperationOnUnlockedMutexQuery()) and mutex = operation.getMutex() and not DominatingSet::isDominatedByBehavior(operation) -select operation, "Invalid operation on mutex '$@' not locked by the current thread", +select operation, "Invalid operation on mutex '$@' not locked by the current thread.", mutex.getRootIdentity(), mutex.toString() diff --git a/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql b/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql index 4b70a21527..d242f75f57 100644 --- a/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql +++ b/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql @@ -2,7 +2,7 @@ * @id c/misra/non-recursive-mutex-recursively-locked-audit * @name RULE-22-18: (Audit) Non-recursive mutexes shall not be recursively locked * @description Mutex that may be initialized without mtx_recursive shall not be locked by a thread - * that has previous may havec locked it. + * that may have previously locked it. * @kind problem * @precision high * @problem.severity error @@ -57,4 +57,4 @@ where isTrackableMutex(lockCall, true) or isTrackableMutex(coveredByLock, true) ) -select n, "Mutex locked after previous $@.", coveredByLock, "already locked" +select n, "Mutex locked after it was already $@.", coveredByLock, "previously locked" diff --git a/c/misra/src/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.ql b/c/misra/src/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.ql index afa2556646..0d5aa5399f 100644 --- a/c/misra/src/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.ql +++ b/c/misra/src/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.ql @@ -64,6 +64,6 @@ where useOne = firstCallForConditionMutex(cond, mutexOne) and useTwo = firstCallForConditionMutex(cond, mutexOne) select useOne, - "Condition variable $@ associated with multiple mutexes, operation uses mutex $@ while $@ uses other mutex $@", + "Condition variable $@ associated with multiple mutexes, operation uses mutex $@ while $@ uses other mutex $@.", cond.getRootIdentity(), cond.toString(), mutexOne.getRootIdentity(), mutexOne.toString(), useTwo, "another operation", mutexTwo.getRootIdentity(), mutexTwo.toString() diff --git a/c/misra/src/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.ql b/c/misra/src/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.ql index 652b5d1f8c..1edf4aa9c3 100644 --- a/c/misra/src/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.ql +++ b/c/misra/src/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.ql @@ -40,5 +40,5 @@ where not isExcluded(objUse, Concurrency9Package::threadStorageNotInitializedBeforeUseQuery()) and InitAnalysis::uninitializedFrom(objUse, obj, callRoot) select objUse, - "Thread specific storage pointer '$@' possibly used before initialization, from entry point function '$@'.", + "Thread specific storage pointer '$@' used before initialization from entry point function '$@'.", obj, obj.toString(), callRoot, callRoot.getName() diff --git a/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.expected b/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.expected index 3f32b09d5c..e1c0e9389d 100644 --- a/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.expected +++ b/c/misra/test/rules/DIR-5-1/PossibleDataRaceBetweenThreads.expected @@ -1,24 +1,24 @@ -| test.c:31:3:31:8 | ... = ... | Threaded write to object $@, for example from thread function $@, not synchronized with $@, for example from thread function $@. | test.c:11:5:11:6 | g2 | g2 | test.c:30:6:30:29 | single_thread4_writes_g2 | single_thread4_writes_g2 | test.c:27:3:27:4 | g2 | concurrent read operation | test.c:26:6:26:28 | single_thread3_reads_g2 | single_thread3_reads_g2 | -| test.c:35:3:35:8 | ... = ... | Threaded write to object $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:12:5:12:6 | g3 | g3 | test.c:34:6:34:27 | many_thread5_writes_g3 | many_thread5_writes_g3 | test.c:35:3:35:4 | g3 | concurrent read operation | test.c:34:6:34:27 | many_thread5_writes_g3 | many_thread5_writes_g3 | -| test.c:71:3:71:11 | ... = ... | Threaded write to object $@, for example from thread function $@, not synchronized with $@, for example from thread function $@. | test.c:68:3:68:4 | g7 | g7.m1 | test.c:70:6:70:33 | single_thread11_writes_g7_m1 | single_thread11_writes_g7_m1 | test.c:75:6:75:7 | m1 | concurrent read operation | test.c:74:6:74:33 | single_thread12_writes_g7_m1 | single_thread12_writes_g7_m1 | -| test.c:75:3:75:11 | ... = ... | Threaded write to object $@, for example from thread function $@, not synchronized with $@, for example from thread function $@. | test.c:68:3:68:4 | g7 | g7.m1 | test.c:74:6:74:33 | single_thread12_writes_g7_m1 | single_thread12_writes_g7_m1 | test.c:71:6:71:7 | m1 | concurrent read operation | test.c:70:6:70:33 | single_thread11_writes_g7_m1 | single_thread11_writes_g7_m1 | -| test.c:79:3:79:11 | call to setlocale | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:79:3:79:11 | call to setlocale | setlocale | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:79:3:79:11 | call to setlocale | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:80:3:80:8 | call to tmpnam | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:80:3:80:8 | call to tmpnam | tmpnam | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:80:3:80:8 | call to tmpnam | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:81:3:81:6 | call to rand | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:81:3:81:6 | call to rand | rand | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:81:3:81:6 | call to rand | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:82:3:82:7 | call to srand | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:82:3:82:7 | call to srand | srand | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:82:3:82:7 | call to srand | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:83:3:83:8 | call to getenv | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:83:3:83:8 | call to getenv | getenv | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:83:3:83:8 | call to getenv | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:84:3:84:10 | call to getenv_s | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:84:3:84:10 | call to getenv_s | getenv_s | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:84:3:84:10 | call to getenv_s | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:86:3:86:10 | call to strerror | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:86:3:86:10 | call to strerror | strerror | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:86:3:86:10 | call to strerror | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:87:3:87:9 | call to asctime | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:87:3:87:9 | call to asctime | asctime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:87:3:87:9 | call to asctime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:88:3:88:7 | call to ctime | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:88:3:88:7 | call to ctime | ctime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:88:3:88:7 | call to ctime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:89:3:89:8 | call to gmtime | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:89:3:89:8 | call to gmtime | gmtime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:89:3:89:8 | call to gmtime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:90:3:90:11 | call to localtime | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:90:3:90:11 | call to localtime | localtime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:90:3:90:11 | call to localtime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:91:3:91:10 | call to mbrtoc16 | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:91:3:91:10 | call to mbrtoc16 | mbrtoc16 | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:91:3:91:10 | call to mbrtoc16 | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:92:3:92:10 | call to mbrtoc32 | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:92:3:92:10 | call to mbrtoc32 | mbrtoc32 | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:92:3:92:10 | call to mbrtoc32 | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:93:3:93:10 | call to c16rtomb | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:93:3:93:10 | call to c16rtomb | c16rtomb | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:93:3:93:10 | call to c16rtomb | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:94:3:94:10 | call to c32rtomb | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:94:3:94:10 | call to c32rtomb | c32rtomb | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:94:3:94:10 | call to c32rtomb | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:95:3:95:8 | call to mbrlen | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:95:3:95:8 | call to mbrlen | mbrlen | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:95:3:95:8 | call to mbrlen | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:96:3:96:9 | call to mbrtowc | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:96:3:96:9 | call to mbrtowc | mbrtowc | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:96:3:96:9 | call to mbrtowc | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:97:3:97:9 | call to wcrtomb | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:97:3:97:9 | call to wcrtomb | wcrtomb | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:97:3:97:9 | call to wcrtomb | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:98:3:98:11 | call to mbsrtowcs | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:98:3:98:11 | call to mbsrtowcs | mbsrtowcs | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:98:3:98:11 | call to mbsrtowcs | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | -| test.c:99:3:99:11 | call to wcsrtombs | Threaded call to non-reentrant function $@ not synchronized, for example from thread function $@ spawned from a loop. | test.c:99:3:99:11 | call to wcsrtombs | wcsrtombs | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:99:3:99:11 | call to wcsrtombs | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:31:3:31:8 | ... = ... | Threaded write to object $@ from thread function $@ is not synchronized with $@ from thread function $@. | test.c:11:5:11:6 | g2 | g2 | test.c:30:6:30:29 | single_thread4_writes_g2 | single_thread4_writes_g2 | test.c:27:3:27:4 | g2 | concurrent read operation | test.c:26:6:26:28 | single_thread3_reads_g2 | single_thread3_reads_g2 | +| test.c:35:3:35:8 | ... = ... | Threaded write to object $@ not synchronized from thread function $@ spawned from a loop. | test.c:12:5:12:6 | g3 | g3 | test.c:34:6:34:27 | many_thread5_writes_g3 | many_thread5_writes_g3 | test.c:35:3:35:4 | g3 | concurrent read operation | test.c:34:6:34:27 | many_thread5_writes_g3 | many_thread5_writes_g3 | +| test.c:71:3:71:11 | ... = ... | Threaded write to object $@ from thread function $@ is not synchronized with $@ from thread function $@. | test.c:68:3:68:4 | g7 | g7.m1 | test.c:70:6:70:33 | single_thread11_writes_g7_m1 | single_thread11_writes_g7_m1 | test.c:75:6:75:7 | m1 | concurrent read operation | test.c:74:6:74:33 | single_thread12_writes_g7_m1 | single_thread12_writes_g7_m1 | +| test.c:75:3:75:11 | ... = ... | Threaded write to object $@ from thread function $@ is not synchronized with $@ from thread function $@. | test.c:68:3:68:4 | g7 | g7.m1 | test.c:74:6:74:33 | single_thread12_writes_g7_m1 | single_thread12_writes_g7_m1 | test.c:71:6:71:7 | m1 | concurrent read operation | test.c:70:6:70:33 | single_thread11_writes_g7_m1 | single_thread11_writes_g7_m1 | +| test.c:79:3:79:11 | call to setlocale | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:79:3:79:11 | call to setlocale | setlocale | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:79:3:79:11 | call to setlocale | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:80:3:80:8 | call to tmpnam | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:80:3:80:8 | call to tmpnam | tmpnam | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:80:3:80:8 | call to tmpnam | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:81:3:81:6 | call to rand | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:81:3:81:6 | call to rand | rand | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:81:3:81:6 | call to rand | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:82:3:82:7 | call to srand | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:82:3:82:7 | call to srand | srand | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:82:3:82:7 | call to srand | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:83:3:83:8 | call to getenv | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:83:3:83:8 | call to getenv | getenv | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:83:3:83:8 | call to getenv | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:84:3:84:10 | call to getenv_s | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:84:3:84:10 | call to getenv_s | getenv_s | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:84:3:84:10 | call to getenv_s | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:86:3:86:10 | call to strerror | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:86:3:86:10 | call to strerror | strerror | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:86:3:86:10 | call to strerror | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:87:3:87:9 | call to asctime | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:87:3:87:9 | call to asctime | asctime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:87:3:87:9 | call to asctime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:88:3:88:7 | call to ctime | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:88:3:88:7 | call to ctime | ctime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:88:3:88:7 | call to ctime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:89:3:89:8 | call to gmtime | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:89:3:89:8 | call to gmtime | gmtime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:89:3:89:8 | call to gmtime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:90:3:90:11 | call to localtime | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:90:3:90:11 | call to localtime | localtime | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:90:3:90:11 | call to localtime | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:91:3:91:10 | call to mbrtoc16 | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:91:3:91:10 | call to mbrtoc16 | mbrtoc16 | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:91:3:91:10 | call to mbrtoc16 | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:92:3:92:10 | call to mbrtoc32 | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:92:3:92:10 | call to mbrtoc32 | mbrtoc32 | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:92:3:92:10 | call to mbrtoc32 | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:93:3:93:10 | call to c16rtomb | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:93:3:93:10 | call to c16rtomb | c16rtomb | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:93:3:93:10 | call to c16rtomb | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:94:3:94:10 | call to c32rtomb | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:94:3:94:10 | call to c32rtomb | c32rtomb | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:94:3:94:10 | call to c32rtomb | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:95:3:95:8 | call to mbrlen | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:95:3:95:8 | call to mbrlen | mbrlen | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:95:3:95:8 | call to mbrlen | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:96:3:96:9 | call to mbrtowc | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:96:3:96:9 | call to mbrtowc | mbrtowc | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:96:3:96:9 | call to mbrtowc | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:97:3:97:9 | call to wcrtomb | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:97:3:97:9 | call to wcrtomb | wcrtomb | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:97:3:97:9 | call to wcrtomb | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:98:3:98:11 | call to mbsrtowcs | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:98:3:98:11 | call to mbsrtowcs | mbsrtowcs | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:98:3:98:11 | call to mbsrtowcs | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | +| test.c:99:3:99:11 | call to wcsrtombs | Threaded call to non-reentrant function $@ not synchronized from thread function $@ spawned from a loop. | test.c:99:3:99:11 | call to wcsrtombs | wcsrtombs | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | test.c:99:3:99:11 | call to wcsrtombs | concurrent call to non-reentrant function | test.c:78:6:78:43 | many_thread13_calls_nonreentrant_funcs | many_thread13_calls_nonreentrant_funcs | diff --git a/c/misra/test/rules/RULE-22-14/test.c b/c/misra/test/rules/RULE-22-14/test.c index d8f1770ad8..c664a08dc3 100644 --- a/c/misra/test/rules/RULE-22-14/test.c +++ b/c/misra/test/rules/RULE-22-14/test.c @@ -143,4 +143,16 @@ void invalid_mtx_init_types() { mtx_init(&m, mtx_plain & mtx_recursive); // NON-COMPLIANT mtx_init(&m, mtx_plain * mtx_recursive); // NON-COMPLIANT mtx_init(&m, -1); // NON-COMPLIANT +} + +void function_pointer_uses_global_mutexes() { + // If the function has been used as a function pointer, we don't attempt to + // analyze this. + mtx_lock(&g1); // COMPLIANT + mtx_lock(&g2.m1); // COMPLIANT + mtx_lock(g3); // COMPLIANT +} + +void take_function_pointer() { + void (*f)(void) = function_pointer_uses_global_mutexes; } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.expected b/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.expected index 76d3ac1ba1..254d55adc2 100644 --- a/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.expected +++ b/c/misra/test/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.expected @@ -1,16 +1,16 @@ -| test.c:19:3:19:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:11:9:11:10 | l1 | l1 | -| test.c:20:3:20:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:11:9:11:10 | l1 | l1 | -| test.c:25:3:25:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:14:5:14:6 | l2 | l2.m1 | -| test.c:26:3:26:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:14:5:14:6 | l2 | l2.m1 | -| test.c:31:3:31:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:3:7:3:8 | g1 | g1 | -| test.c:32:3:32:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:3:7:3:8 | g1 | g1 | -| test.c:37:3:37:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:6:3:6:4 | g2 | g2.m1 | -| test.c:38:3:38:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:6:3:6:4 | g2 | g2.m1 | -| test.c:47:3:47:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:11:9:11:10 | l1 | l1 | -| test.c:48:3:48:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:14:5:14:6 | l2 | l2.m1 | -| test.c:49:3:49:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:3:7:3:8 | g1 | g1 | -| test.c:50:3:50:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread | test.c:6:3:6:4 | g2 | g2.m1 | -| test.c:51:3:51:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:11:9:11:10 | l1 | l1 | -| test.c:52:3:52:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:14:5:14:6 | l2 | l2.m1 | -| test.c:53:3:53:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:3:7:3:8 | g1 | g1 | -| test.c:54:3:54:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread | test.c:6:3:6:4 | g2 | g2.m1 | +| test.c:19:3:19:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:11:9:11:10 | l1 | l1 | +| test.c:20:3:20:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:11:9:11:10 | l1 | l1 | +| test.c:25:3:25:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:14:5:14:6 | l2 | l2.m1 | +| test.c:26:3:26:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:14:5:14:6 | l2 | l2.m1 | +| test.c:31:3:31:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:3:7:3:8 | g1 | g1 | +| test.c:32:3:32:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:3:7:3:8 | g1 | g1 | +| test.c:37:3:37:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:6:3:6:4 | g2 | g2.m1 | +| test.c:38:3:38:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:6:3:6:4 | g2 | g2.m1 | +| test.c:47:3:47:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:11:9:11:10 | l1 | l1 | +| test.c:48:3:48:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:14:5:14:6 | l2 | l2.m1 | +| test.c:49:3:49:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:3:7:3:8 | g1 | g1 | +| test.c:50:3:50:10 | call to cnd_wait | Invalid operation on mutex '$@' not locked by the current thread. | test.c:6:3:6:4 | g2 | g2.m1 | +| test.c:51:3:51:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:11:9:11:10 | l1 | l1 | +| test.c:52:3:52:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:14:5:14:6 | l2 | l2.m1 | +| test.c:53:3:53:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:3:7:3:8 | g1 | g1 | +| test.c:54:3:54:12 | call to mtx_unlock | Invalid operation on mutex '$@' not locked by the current thread. | test.c:6:3:6:4 | g2 | g2.m1 | diff --git a/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.expected b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.expected index 8f359c90f8..e268f5367e 100644 --- a/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.expected +++ b/c/misra/test/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.expected @@ -1,6 +1,6 @@ -| test.c:44:3:44:10 | call to mtx_lock | Mutex locked after previous $@. | test.c:43:3:43:10 | call to mtx_lock | already locked | -| test.c:49:3:49:10 | call to mtx_lock | Mutex locked after previous $@. | test.c:48:3:48:10 | call to mtx_lock | already locked | -| test.c:54:3:54:10 | call to mtx_lock | Mutex locked after previous $@. | test.c:53:3:53:10 | call to mtx_lock | already locked | -| test.c:59:3:59:10 | call to mtx_lock | Mutex locked after previous $@. | test.c:58:3:58:10 | call to mtx_lock | already locked | -| test.c:76:3:76:10 | call to mtx_lock | Mutex locked after previous $@. | test.c:75:3:75:10 | call to mtx_lock | already locked | -| test.c:81:3:81:10 | call to mtx_lock | Mutex locked after previous $@. | test.c:80:3:80:10 | call to mtx_lock | already locked | +| test.c:44:3:44:10 | call to mtx_lock | Mutex locked after it was already $@. | test.c:43:3:43:10 | call to mtx_lock | previously locked | +| test.c:49:3:49:10 | call to mtx_lock | Mutex locked after it was already $@. | test.c:48:3:48:10 | call to mtx_lock | previously locked | +| test.c:54:3:54:10 | call to mtx_lock | Mutex locked after it was already $@. | test.c:53:3:53:10 | call to mtx_lock | previously locked | +| test.c:59:3:59:10 | call to mtx_lock | Mutex locked after it was already $@. | test.c:58:3:58:10 | call to mtx_lock | previously locked | +| test.c:76:3:76:10 | call to mtx_lock | Mutex locked after it was already $@. | test.c:75:3:75:10 | call to mtx_lock | previously locked | +| test.c:81:3:81:10 | call to mtx_lock | Mutex locked after it was already $@. | test.c:80:3:80:10 | call to mtx_lock | previously locked | diff --git a/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.expected b/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.expected index ee9dff0be2..c9785067c6 100644 --- a/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.expected +++ b/c/misra/test/rules/RULE-22-19/ConditionVariableUsedWithMultipleMutexes.expected @@ -1,2 +1,2 @@ -| test.c:19:3:19:10 | call to cnd_wait | Condition variable $@ associated with multiple mutexes, operation uses mutex $@ while $@ uses other mutex $@ | test.c:16:9:16:12 | cnd1 | cnd1 | test.c:17:9:17:12 | mtx1 | mtx1 | test.c:19:3:19:10 | call to cnd_wait | another operation | test.c:18:9:18:12 | mtx2 | mtx2 | -| test.c:41:3:41:10 | call to cnd_wait | Condition variable $@ associated with multiple mutexes, operation uses mutex $@ while $@ uses other mutex $@ | test.c:37:7:37:11 | gcnd1 | gcnd1 | test.c:38:7:38:11 | gmtx1 | gmtx1 | test.c:41:3:41:10 | call to cnd_wait | another operation | test.c:39:7:39:11 | gmtx2 | gmtx2 | +| test.c:19:3:19:10 | call to cnd_wait | Condition variable $@ associated with multiple mutexes, operation uses mutex $@ while $@ uses other mutex $@. | test.c:16:9:16:12 | cnd1 | cnd1 | test.c:17:9:17:12 | mtx1 | mtx1 | test.c:19:3:19:10 | call to cnd_wait | another operation | test.c:18:9:18:12 | mtx2 | mtx2 | +| test.c:41:3:41:10 | call to cnd_wait | Condition variable $@ associated with multiple mutexes, operation uses mutex $@ while $@ uses other mutex $@. | test.c:37:7:37:11 | gcnd1 | gcnd1 | test.c:38:7:38:11 | gmtx1 | gmtx1 | test.c:41:3:41:10 | call to cnd_wait | another operation | test.c:39:7:39:11 | gmtx2 | gmtx2 | diff --git a/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.expected b/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.expected index 9a9b86dfa2..301debd7e8 100644 --- a/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.expected +++ b/c/misra/test/rules/RULE-22-20/ThreadStorageNotInitializedBeforeUse.expected @@ -1,5 +1,5 @@ -| test.c:6:11:6:13 | & ... | Thread specific storage pointer '$@' possibly used before initialization, from entry point function '$@'. | test.c:5:9:5:10 | l1 | l1 | test.c:4:6:4:19 | use_local_mtxs | use_local_mtxs | -| test.c:11:11:11:12 | l4 | Thread specific storage pointer '$@' possibly used before initialization, from entry point function '$@'. | test.c:10:15:10:20 | call to malloc | call to malloc | test.c:16:6:16:31 | root1_calls_use_local_mtxs | root1_calls_use_local_mtxs | -| test.c:25:11:25:13 | & ... | Thread specific storage pointer '$@' possibly used before initialization, from entry point function '$@'. | test.c:22:7:22:8 | g1 | g1 | test.c:24:6:24:28 | root2_uses_global_tss_t | root2_uses_global_tss_t | -| test.c:38:11:38:13 | & ... | Thread specific storage pointer '$@' possibly used before initialization, from entry point function '$@'. | test.c:22:7:22:8 | g1 | g1 | test.c:41:6:41:45 | root4_call_thread_without_initialization | root4_call_thread_without_initialization | -| test.c:58:11:58:13 | & ... | Thread specific storage pointer '$@' possibly used before initialization, from entry point function '$@'. | test.c:56:7:56:8 | g5 | g5 | test.c:67:6:67:50 | root6_spawn_thread_uninitialized_thread_local | root6_spawn_thread_uninitialized_thread_local | +| test.c:6:11:6:13 | & ... | Thread specific storage pointer '$@' used before initialization from entry point function '$@'. | test.c:5:9:5:10 | l1 | l1 | test.c:4:6:4:19 | use_local_mtxs | use_local_mtxs | +| test.c:11:11:11:12 | l4 | Thread specific storage pointer '$@' used before initialization from entry point function '$@'. | test.c:10:15:10:20 | call to malloc | call to malloc | test.c:16:6:16:31 | root1_calls_use_local_mtxs | root1_calls_use_local_mtxs | +| test.c:25:11:25:13 | & ... | Thread specific storage pointer '$@' used before initialization from entry point function '$@'. | test.c:22:7:22:8 | g1 | g1 | test.c:24:6:24:28 | root2_uses_global_tss_t | root2_uses_global_tss_t | +| test.c:38:11:38:13 | & ... | Thread specific storage pointer '$@' used before initialization from entry point function '$@'. | test.c:22:7:22:8 | g1 | g1 | test.c:41:6:41:45 | root4_call_thread_without_initialization | root4_call_thread_without_initialization | +| test.c:58:11:58:13 | & ... | Thread specific storage pointer '$@' used before initialization from entry point function '$@'. | test.c:56:7:56:8 | g5 | g5 | test.c:67:6:67:50 | root6_spawn_thread_uninitialized_thread_local | root6_spawn_thread_uninitialized_thread_local | diff --git a/cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll b/cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll index 1dd753d122..95404b114a 100644 --- a/cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll +++ b/cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll @@ -52,18 +52,11 @@ class CPPMutexFunctionCall extends MutexFunctionCall { VariableAccess var; CPPMutexFunctionCall() { - ( - // the non recursive kinds - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "mutex") or - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "timed_mutex") or - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "shared_timed_mutex") or - // the recursive ones - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_mutex") or - getTarget() - .(MemberFunction) - .getDeclaringType() - .hasQualifiedName("std", "recursive_timed_mutex") - ) and + getTarget() + .(MemberFunction) + .getDeclaringType() + .hasQualifiedName("std", + ["mutex", "timed_mutex", "shared_timed_mutex", "recursive_mutex", "recursive_timed_mutex"]) and var = getQualifier() } @@ -71,8 +64,10 @@ class CPPMutexFunctionCall extends MutexFunctionCall { * Holds if this mutex is a recursive mutex. */ override predicate isRecursive() { - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_mutex") or - getTarget().(MemberFunction).getDeclaringType().hasQualifiedName("std", "recursive_timed_mutex") + getTarget() + .(MemberFunction) + .getDeclaringType() + .hasQualifiedName("std", ["recursive_mutex", "recursive_timed_mutex"]) } /** diff --git a/rule_packages/c/Concurrency9.json b/rule_packages/c/Concurrency9.json index 39c5cc58a8..7a88f4e2ab 100644 --- a/rule_packages/c/Concurrency9.json +++ b/rule_packages/c/Concurrency9.json @@ -82,7 +82,7 @@ ] }, { - "description": "Mutex that may be initialized without mtx_recursive shall not be locked by a thread that has previous may havec locked it.", + "description": "Mutex that may be initialized without mtx_recursive shall not be locked by a thread that may have previously locked it.", "kind": "problem", "name": "(Audit) Non-recursive mutexes shall not be recursively locked", "precision": "high", From 0a6460986a1994659f43927f2bbdcca0b306e020 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 27 Mar 2025 01:40:53 -0700 Subject: [PATCH 329/628] Implement missing amendment for directive 4-11 from misra C 2012 amendment 3 --- amendments.csv | 2 +- ...cisionPeriodicTrigonometricFunctionCall.ql | 43 +++++++++++++ ...PeriodicTrigonometricFunctionCall.expected | 18 ++++++ ...ionPeriodicTrigonometricFunctionCall.qlref | 1 + c/misra/test/rules/DIR-4-11/test.c | 62 +++++++++++++++++++ ...etect-precision-limit-in-trig-functions.md | 2 + .../cpp/exclusions/c/Contracts.qll | 17 +++++ rule_packages/c/Contracts.json | 13 ++++ 8 files changed, 157 insertions(+), 1 deletion(-) create mode 100644 c/misra/src/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.ql create mode 100644 c/misra/test/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.expected create mode 100644 c/misra/test/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.qlref create mode 100644 c/misra/test/rules/DIR-4-11/test.c create mode 100644 change_notes/2025-03-27-detect-precision-limit-in-trig-functions.md diff --git a/amendments.csv b/amendments.csv index 64d2e2e858..9b10149027 100644 --- a/amendments.csv +++ b/amendments.csv @@ -1,7 +1,7 @@ language,standard,amendment,rule_id,supportable,implementation_category,implemented,difficulty c,MISRA-C-2012,Amendment3,DIR-4-6,Yes,Expand,Yes,Easy c,MISRA-C-2012,Amendment3,DIR-4-9,Yes,Refine,No,Easy -c,MISRA-C-2012,Amendment3,DIR-4-11,Yes,Refine,No,Import +c,MISRA-C-2012,Amendment3,DIR-4-11,Yes,Refine,Yes,Import c,MISRA-C-2012,Amendment3,RULE-1-4,Yes,Replace,No,Easy c,MISRA-C-2012,Amendment3,RULE-10-1,Yes,Replace,Yes,Easy c,MISRA-C-2012,Amendment3,RULE-10-3,Yes,Refine,Yes,Easy diff --git a/c/misra/src/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.ql b/c/misra/src/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.ql new file mode 100644 index 0000000000..6a910a1a71 --- /dev/null +++ b/c/misra/src/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.ql @@ -0,0 +1,43 @@ +/** + * @id c/misra/low-precision-periodic-trigonometric-function-call + * @name DIR-4-11: The validity of values passed to trigonometric functions shall be checked + * @description Trigonometric periodic functions have significantly less precision when called with + * large floating-point values. + * @kind problem + * @precision high + * @problem.severity warning + * @tags external/misra/id/dir-4-11 + * correctness + * external/misra/c/2012/third-edition-first-revision + * external/misra/c/2012/amendment3 + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis + +float getMaxAllowedAbsoluteValue(FloatingPointType t, string description) { + if t.getSize() <= 4 + then ( + // Per MISRA, assume k=1 for float types. + result = 3.15 and description = "pi" + ) else ( + // Allow k=10 for doubles, as the standard allows for a larger range depending on the + // implementation, application, and precision goals. + result = 10 * 3.15 and description = "10 * pi" + ) +} + +from FunctionCall fc, Expr argument, float maxValue, float maxAllowedValue, string maxAllowedStr +where + not isExcluded(fc, ContractsPackage::lowPrecisionPeriodicTrigonometricFunctionCallQuery()) and + fc.getTarget().getName() = ["sin", "cos", "tan"] and + argument = fc.getArgument(0) and + maxValue = rank[1](float bound | bound = [lowerBound(argument), upperBound(argument)].abs()) and + maxAllowedValue = getMaxAllowedAbsoluteValue(argument.getType(), maxAllowedStr) and + maxValue > maxAllowedValue +select fc, + "Call to periodic trigonometric function " + fc.getTarget().getName() + + " with maximum argument absolute value of " + maxValue.toString() + + ", which exceeds the recommended " + "maximum of " + maxAllowedStr + "." diff --git a/c/misra/test/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.expected b/c/misra/test/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.expected new file mode 100644 index 0000000000..d5d5892975 --- /dev/null +++ b/c/misra/test/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.expected @@ -0,0 +1,18 @@ +| test.c:32:5:32:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. | +| test.c:33:5:33:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. | +| test.c:34:5:34:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. | +| test.c:38:5:38:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. | +| test.c:39:5:39:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. | +| test.c:40:5:40:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 31.4, which exceeds the recommended maximum of pi. | +| test.c:49:5:49:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. | +| test.c:50:5:50:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. | +| test.c:51:5:51:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. | +| test.c:52:5:52:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. | +| test.c:53:5:53:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. | +| test.c:54:5:54:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. | +| test.c:55:5:55:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. | +| test.c:56:5:56:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. | +| test.c:57:5:57:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 314, which exceeds the recommended maximum of pi. | +| test.c:58:5:58:7 | call to sin | Call to periodic trigonometric function sin with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. | +| test.c:59:5:59:7 | call to cos | Call to periodic trigonometric function cos with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. | +| test.c:60:5:60:7 | call to tan | Call to periodic trigonometric function tan with maximum argument absolute value of 314, which exceeds the recommended maximum of 10 * pi. | diff --git a/c/misra/test/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.qlref b/c/misra/test/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.qlref new file mode 100644 index 0000000000..f7bd11b44d --- /dev/null +++ b/c/misra/test/rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.qlref @@ -0,0 +1 @@ +rules/DIR-4-11/LowPrecisionPeriodicTrigonometricFunctionCall.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-11/test.c b/c/misra/test/rules/DIR-4-11/test.c new file mode 100644 index 0000000000..dac34860ff --- /dev/null +++ b/c/misra/test/rules/DIR-4-11/test.c @@ -0,0 +1,62 @@ +#include +void f(int x) { + float f1 = 0.0f; + double d1 = 0.0f; + sin(f1); // COMPLIANT + cos(f1); // COMPLIANT + tan(f1); // COMPLIANT + sin(d1); // COMPLIANT + cos(d1); // COMPLIANT + tan(d1); // COMPLIANT + + if (x < 10) { + f1 += 3.14; + d1 += 3.14; + sin(f1); // COMPLIANT + cos(f1); // COMPLIANT + tan(f1); // COMPLIANT + sin(d1); // COMPLIANT + cos(d1); // COMPLIANT + tan(d1); // COMPLIANT + sin(-f1); // COMPLIANT + cos(-f1); // COMPLIANT + tan(-f1); // COMPLIANT + sin(-d1); // COMPLIANT + cos(-d1); // COMPLIANT + tan(-d1); // COMPLIANT + } + + if (x < 20) { + f1 = 3.14 * 10; + d1 = 3.14 * 10; + sin(f1); // NON-COMPLIANT + cos(f1); // NON-COMPLIANT + tan(f1); // NON-COMPLIANT + sin(d1); // COMPLIANT + cos(d1); // COMPLIANT + tan(d1); // COMPLIANT + sin(-f1); // NON-COMPLIANT + cos(-f1); // NON-COMPLIANT + tan(-f1); // NON-COMPLIANT + sin(-d1); // COMPLIANT + cos(-d1); // COMPLIANT + tan(-d1); // COMPLIANT + } + + if (x < 30) { + f1 = 3.14 * 100; + d1 = 3.14 * 100; + sin(f1); // NON-COMPLIANT + cos(f1); // NON-COMPLIANT + tan(f1); // NON-COMPLIANT + sin(d1); // NON-COMPLIANT + cos(d1); // NON-COMPLIANT + tan(d1); // NON-COMPLIANT + sin(-f1); // NON-COMPLIANT + cos(-f1); // NON-COMPLIANT + tan(-f1); // NON-COMPLIANT + sin(-d1); // NON-COMPLIANT + cos(-d1); // NON-COMPLIANT + tan(-d1); // NON-COMPLIANT + } +} \ No newline at end of file diff --git a/change_notes/2025-03-27-detect-precision-limit-in-trig-functions.md b/change_notes/2025-03-27-detect-precision-limit-in-trig-functions.md new file mode 100644 index 0000000000..914b25a2a2 --- /dev/null +++ b/change_notes/2025-03-27-detect-precision-limit-in-trig-functions.md @@ -0,0 +1,2 @@ + - `DIR-4-11` - `LowPrecisionPeriodicTrigonometricFunctionCall.ql`: + - New query within rule added to detect calls to periodic trigonometric functions with values outside of pi*k for k that depends on implementation and application precision goals, assuming k=1 for 32 bit floating types and k=10 for 64 bit floating types. diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts.qll index 32a44a4355..174e7769b7 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Contracts.qll @@ -6,6 +6,7 @@ import codingstandards.cpp.exclusions.RuleMetadata newtype ContractsQuery = TDoNotViolateInLineLinkageConstraintsQuery() or TCheckMathLibraryFunctionParametersQuery() or + TLowPrecisionPeriodicTrigonometricFunctionCallQuery() or TFunctionErrorInformationUntestedQuery() predicate isContractsQueryMetadata(Query query, string queryId, string ruleId, string category) { @@ -27,6 +28,15 @@ predicate isContractsQueryMetadata(Query query, string queryId, string ruleId, s ruleId = "DIR-4-11" and category = "required" or + query = + // `Query` instance for the `lowPrecisionPeriodicTrigonometricFunctionCall` query + ContractsPackage::lowPrecisionPeriodicTrigonometricFunctionCallQuery() and + queryId = + // `@id` for the `lowPrecisionPeriodicTrigonometricFunctionCall` query + "c/misra/low-precision-periodic-trigonometric-function-call" and + ruleId = "DIR-4-11" and + category = "required" + or query = // `Query` instance for the `functionErrorInformationUntested` query ContractsPackage::functionErrorInformationUntestedQuery() and @@ -52,6 +62,13 @@ module ContractsPackage { TQueryC(TContractsPackageQuery(TCheckMathLibraryFunctionParametersQuery())) } + Query lowPrecisionPeriodicTrigonometricFunctionCallQuery() { + //autogenerate `Query` type + result = + // `Query` type for `lowPrecisionPeriodicTrigonometricFunctionCall` query + TQueryC(TContractsPackageQuery(TLowPrecisionPeriodicTrigonometricFunctionCallQuery())) + } + Query functionErrorInformationUntestedQuery() { //autogenerate `Query` type result = diff --git a/rule_packages/c/Contracts.json b/rule_packages/c/Contracts.json index 40bf3d8b0b..e7db6fff86 100644 --- a/rule_packages/c/Contracts.json +++ b/rule_packages/c/Contracts.json @@ -44,6 +44,19 @@ "implementation_scope": { "description": "This query identifies possible domain, pole and range errors on a selection of C standard library fuctions from math.h." } + }, + { + "description": "Trigonometric periodic functions have significantly less precision when called with large floating-point values.", + "kind": "problem", + "name": "The validity of values passed to trigonometric functions shall be checked", + "precision": "high", + "severity": "warning", + "short_name": "LowPrecisionPeriodicTrigonometricFunctionCall", + "tags": [ + "correctness", + "external/misra/c/2012/third-edition-first-revision", + "external/misra/c/2012/amendment3" + ] } ], "title": "The validity of values passed to library functions shall be checked" From 00defddfa6abde09164a9b7860026fe4f497b076 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 27 Mar 2025 10:05:09 -0700 Subject: [PATCH 330/628] Fix typo --- .../RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql | 4 ++-- rule_packages/c/Concurrency9.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql b/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql index d242f75f57..7e002585b6 100644 --- a/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql +++ b/c/misra/src/rules/RULE-22-18/NonRecursiveMutexRecursivelyLockedAudit.ql @@ -1,8 +1,8 @@ /** * @id c/misra/non-recursive-mutex-recursively-locked-audit * @name RULE-22-18: (Audit) Non-recursive mutexes shall not be recursively locked - * @description Mutex that may be initialized without mtx_recursive shall not be locked by a thread - * that may have previously locked it. + * @description Mutexes that may be initialized without mtx_recursive shall not be locked by a + * thread that may have previously locked it. * @kind problem * @precision high * @problem.severity error diff --git a/rule_packages/c/Concurrency9.json b/rule_packages/c/Concurrency9.json index 7a88f4e2ab..6ae1df8173 100644 --- a/rule_packages/c/Concurrency9.json +++ b/rule_packages/c/Concurrency9.json @@ -82,7 +82,7 @@ ] }, { - "description": "Mutex that may be initialized without mtx_recursive shall not be locked by a thread that may have previously locked it.", + "description": "Mutexes that may be initialized without mtx_recursive shall not be locked by a thread that may have previously locked it.", "kind": "problem", "name": "(Audit) Non-recursive mutexes shall not be recursively locked", "precision": "high", From 35cfb0f1e1e57a71a3a1d9537903a7c16aab304e Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sat, 29 Mar 2025 15:54:57 -0700 Subject: [PATCH 331/628] Add additional CERT-C rules to rules.csv --- rules.csv | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rules.csv b/rules.csv index 3f7961b630..2db1d7a66d 100644 --- a/rules.csv +++ b/rules.csv @@ -515,6 +515,7 @@ c,CERT-C,ERR30-C,Yes,Rule,,,Take care when reading errno,M19-3-1,Contracts4,Hard c,CERT-C,ERR32-C,Yes,Rule,,,Do not rely on indeterminate values of errno,,Contracts5,Hard, c,CERT-C,ERR33-C,Yes,Rule,,,Detect and handle standard library errors,MEM52-CPP,Contracts5,Hard, c,CERT-C,ERR34-C,OutOfScope,Rule,,,Detect errors when converting a string to a number,,,, +c,CERT-C,EXP16-C,Yes,Rule,,,Do not compare function pointers to constant values,,Expressions2,Medium, c,CERT-C,EXP30-C,Yes,Rule,,,Do not depend on the order of evaluation for side effects,EXP50-CPP,SideEffects1,Easy, c,CERT-C,EXP32-C,Yes,Rule,,,Do not access a volatile object through a nonvolatile reference,,Pointers3,Easy, c,CERT-C,EXP33-C,Yes,Rule,,,Do not read uninitialized memory,EXP53-CPP,InvalidMemory1,Import, @@ -530,6 +531,8 @@ c,CERT-C,EXP44-C,Yes,Rule,,,"Do not rely on side effects in operands to sizeof, c,CERT-C,EXP45-C,Yes,Rule,,,Do not perform assignments in selection statements,M6-2-1,SideEffects1,Medium, c,CERT-C,EXP46-C,Yes,Rule,,,Do not use a bitwise operator with a Boolean-like operand,,Expressions,Easy, c,CERT-C,EXP47-C,OutOfScope,Rule,,,Do not call va_arg with an argument of the incorrect type,,,, +c,CERT-C,FIO03-C,Yes,Rule,,,Do not make assumptions about fopen() and file creation,,IO5,Hard, +c,CERT-C,FIO21-C,Yes,Rule,,,Do not create temporary files in shared directories,,IO5,Easy, c,CERT-C,FIO30-C,Yes,Rule,,,Exclude user input from format strings,A27-0-1,IO1,Import, c,CERT-C,FIO32-C,Yes,Rule,,,Do not perform operations on devices that are only appropriate for files,,IO3,Medium, c,CERT-C,FIO34-C,Yes,Rule,,,Distinguish between characters read from a file and EOF or WEOF,,IO1,Hard, @@ -569,7 +572,7 @@ c,CERT-C,MSC38-C,Yes,Rule,,,Do not treat a predefined identifier as an object if c,CERT-C,MSC39-C,Yes,Rule,,,Do not call va_arg() on a va_list that has an indeterminate value,,Contracts7,Hard, c,CERT-C,MSC40-C,Yes,Rule,,,Do not violate constraints,,Contracts,Very Hard, c,CERT-C,MSC41-C,OutOfScope,Rule,,,Never hard code sensitive information,,,, -c,CERT-C,POS30-C,OutOfScope,Rule,,,Use the readlink() function properly,,,, +c,CERT-C,POS30-C,Yes,Rule,,,Use the readlink() function properly,,IO5,Hard, c,CERT-C,POS34-C,OutOfScope,Rule,,,Do not call putenv() with a pointer to an automatic variable as the argument,,,, c,CERT-C,POS35-C,OutOfScope,Rule,,,Avoid race conditions while checking for the existence of a symbolic link,,,, c,CERT-C,POS36-C,OutOfScope,Rule,,,Observe correct revocation order while relinquishing privileges,,,, From c25018fce4f419e5e770b8804fbd483b9705ccd3 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 31 Mar 2025 20:42:42 +0100 Subject: [PATCH 332/628] Re-add DeviationsSuppression.ql This is required for our reporting scripts. Changes implemented to support reporting of locations and messages for new deviation formats. --- .../deviations/CodeIdentifierDeviation.qll | 49 +++++++++++++++++-- .../cpp/deviations/DeviationsSuppression.ql | 25 ++++++---- .../DeviationsSuppression.expected | 2 +- 3 files changed, 60 insertions(+), 16 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll index 310a2b678b..4b2f03cf98 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -226,8 +226,8 @@ class DeviationAttribute extends StdAttribute { DeviationRecord getADeviationRecord() { result = record } - pragma[nomagic] - Element getASuppressedElement() { + /** Gets the element to which this attribute was applied. */ + Element getPrimarySuppressedElement() { result.(Type).getAnAttribute() = this or result.(Stmt).getAnAttribute() = this @@ -235,6 +235,11 @@ class DeviationAttribute extends StdAttribute { result.(Variable).getAnAttribute() = this or result.(Function).getAnAttribute() = this + } + + pragma[nomagic] + Element getASuppressedElement() { + result = this.getPrimarySuppressedElement() or result.(Expr).getEnclosingStmt() = this.getASuppressedElement() or @@ -336,26 +341,60 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { ) } + predicate hasLocationInfo( + string filepath, int suppressedLine, int suppressedColumn, int endline, int endcolumn + ) { + exists(Comment commentMarker | + this = TSingleLineDeviation(_, commentMarker, filepath, suppressedLine) and + suppressedColumn = 1 and + endline = suppressedLine + | + if commentMarker instanceof DeviationEndOfLineMarker + then endcolumn = commentMarker.(DeviationEndOfLineMarker).getLocation().getEndColumn() + else + // Find the last column for a location on the next line + endcolumn = + max(Location l | + l.hasLocationInfo(filepath, _, _, _, _) and + l.getEndLine() = suppressedLine + | + l.getEndColumn() + ) + ) + or + this = TMultiLineDeviation(_, _, _, filepath, suppressedLine, endline) and + suppressedColumn = 1 and + endcolumn = 1 + or + exists(DeviationAttribute attribute | + this = TCodeIdentifierDeviation(_, attribute) and + attribute + .getPrimarySuppressedElement() + .getLocation() + .hasLocationInfo(filepath, suppressedLine, suppressedColumn, endline, endcolumn) + ) + } + string toString() { exists(string filepath | exists(int suppressedLine | this = TSingleLineDeviation(_, _, filepath, suppressedLine) and result = - "Deviation record " + getADeviationRecord() + " applied to " + filepath + " Line " + + "Deviation of " + getADeviationRecord().getQuery() + " applied to " + filepath + " Line " + suppressedLine ) or exists(int suppressedStartLine, int suppressedEndLine | this = TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedEndLine) and result = - "Deviation record " + getADeviationRecord() + " applied to " + filepath + " Line" + + "Deviation of " + getADeviationRecord().getQuery() + " applied to " + filepath + " Line " + suppressedStartLine + ":" + suppressedEndLine ) ) or exists(DeviationAttribute attribute | this = TCodeIdentifierDeviation(_, attribute) and - result = "Deviation record " + getADeviationRecord() + " applied to " + attribute + result = "Deviation of " + getADeviationRecord().getQuery() + " applied to " + attribute ) } } diff --git a/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql index 9035b7d288..f29c068983 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql +++ b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql @@ -38,7 +38,9 @@ newtype TDeviationScope = file.getRelativePath().prefix(deviationPath.length()) = deviationPath ) } or - TDeviationRecordCommentScope(DeviationRecord dr, Comment c) { c = dr.getACodeIdentifierComment() } + TDeviationRecordCodeIdentiferDeviationScope(DeviationRecord dr, CodeIdentifierDeviation c) { + c = dr.getACodeIdentifierDeviation() + } /** A deviation scope. */ class DeviationScope extends TDeviationScope { @@ -91,10 +93,16 @@ class DeviationRecordFileScope extends DeviationScope, TDeviationRecordFileScope * A deviation scope derived from a comment corresponding to a "code-identifier" entry for a * `DeviationRecord`. */ -class DeviationRecordCommentScope extends DeviationScope, TDeviationRecordCommentScope { - private DeviationRecord getDeviationRecord() { this = TDeviationRecordCommentScope(result, _) } +class DeviationRecordCommentScope extends DeviationScope, + TDeviationRecordCodeIdentiferDeviationScope +{ + private DeviationRecord getDeviationRecord() { + this = TDeviationRecordCodeIdentiferDeviationScope(result, _) + } - private Comment getComment() { this = TDeviationRecordCommentScope(_, result) } + private CodeIdentifierDeviation getCodeIdentifierDeviation() { + this = TDeviationRecordCodeIdentiferDeviationScope(_, result) + } override Locatable getDeviationDefinitionLocation() { result = getDeviationRecord() } @@ -103,14 +111,11 @@ class DeviationRecordCommentScope extends DeviationScope, TDeviationRecordCommen override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - getComment().getLocation().hasLocationInfo(filepath, startline, _, endline, endcolumn) and - startcolumn = 1 + getCodeIdentifierDeviation() + .hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } - override string toString() { - result = - "Deviation of " + getDeviationRecord().getQuery() + " for comment " + getComment() + "." - } + override string toString() { result = getCodeIdentifierDeviation().toString() } } from DeviationScope deviationScope diff --git a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected index 50ceb35b9d..1d8a87d359 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected +++ b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected @@ -1,4 +1,4 @@ -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:12:1:12:58 | Deviation of cpp/autosar/type-long-double-used for comment // a-0-4-2-deviation COMPLIANT[DEVIATED]. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:12:1:12:58 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 12 | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/unused-return-value] | lgtm[cpp/autosar/unused-return-value] | nested/nested2/test2.h:1:1:6:1 | Deviation of cpp/autosar/unused-return-value for nested/nested2/test2.h. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | coding-standards.xml:1:1:17:19 | Deviation of cpp/autosar/useless-assignment for coding-standards.xml. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | main.cpp:1:1:14:1 | Deviation of cpp/autosar/useless-assignment for main.cpp. | From ddd28e6dc4274c3c1ce1ee313ed3692c28ce7744 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 31 Mar 2025 20:47:06 +0100 Subject: [PATCH 333/628] Test new deviation formats for DeviationSuppressions.ql --- .../DeviationsSuppression.expected | 6 ++++- .../deviations_report_deviated/main.cpp | 25 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected index 1d8a87d359..73f564c13c 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected +++ b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected @@ -1,7 +1,11 @@ | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:12:1:12:58 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 12 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:14:1:14:65 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 14 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:18:1:18:40 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 18 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:21:1:27:1 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 21:27 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:29:1:35:1 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 29:35 | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/unused-return-value] | lgtm[cpp/autosar/unused-return-value] | nested/nested2/test2.h:1:1:6:1 | Deviation of cpp/autosar/unused-return-value for nested/nested2/test2.h. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | coding-standards.xml:1:1:17:19 | Deviation of cpp/autosar/useless-assignment for coding-standards.xml. | -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | main.cpp:1:1:14:1 | Deviation of cpp/autosar/useless-assignment for main.cpp. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | main.cpp:1:1:39:1 | Deviation of cpp/autosar/useless-assignment for main.cpp. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/coding-standards.xml:1:1:13:19 | Deviation of cpp/autosar/useless-assignment for nested/coding-standards.xml. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/nested2/test2.h:1:1:6:1 | Deviation of cpp/autosar/useless-assignment for nested/nested2/test2.h. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/test.h:1:1:6:1 | Deviation of cpp/autosar/useless-assignment for nested/test.h. | diff --git a/cpp/common/test/deviations/deviations_report_deviated/main.cpp b/cpp/common/test/deviations/deviations_report_deviated/main.cpp index c59dea5609..7891faea18 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/main.cpp +++ b/cpp/common/test/deviations/deviations_report_deviated/main.cpp @@ -10,5 +10,30 @@ int main(int argc, char **argv) { getX(); // NON_COMPLIANT long double d1; // NON_COMPLIANT (A0-4-2) long double d2; // a-0-4-2-deviation COMPLIANT[DEVIATED] + + long double d3; // codeql::autosar_deviation(a-0-4-2-deviation) + // COMPLIANT[DEVIATED] + long double d4; // NON_COMPLIANT (A0-4-2) + // codeql::autosar_deviation_next_line(a-0-4-2-deviation) + long double d5; // COMPLIANT[DEVIATED] + long double d6; // NON_COMPLIANT (A0-4-2) + + // codeql::autosar_deviation_begin(a-0-4-2-deviation) + long double d7; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d8; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d9; // COMPLIANT[DEVIATED] + // codeql::autosar_deviation_end(a-0-4-2-deviation) + long double d10; // NON_COMPLIANT (A0-4-2) + // codeql::autosar_deviation_begin(a-0-4-2-deviation) + long double d11; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d12; // COMPLIANT[DEVIATED] + getX(); // NON_COMPLIANT (A0-1-2) + long double d13; // COMPLIANT[DEVIATED] + // codeql::autosar_deviation_end(a-0-4-2-deviation) + long double d14; // NON_COMPLIANT (A0-4-2) + getX(); // NON_COMPLIANT (A0-1-2) return 0; } \ No newline at end of file From e7b53b27d540dac4213f6dfeef26f3a8174988ea Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 31 Mar 2025 20:39:32 -0700 Subject: [PATCH 334/628] Implement Rule-1-4's rule amendment from Amendment4 (also amended in Amdt3) --- amendments.csv | 2 +- .../EmergentLanguageFeaturesUsed.expected | 6 ------ c/misra/test/rules/RULE-1-4/test.c | 12 ++++++------ ...mics-threads-and-threadlocals-in-misra-c.md | 2 ++ .../src/codingstandards/cpp/Emergent.qll | 18 ------------------ 5 files changed, 9 insertions(+), 31 deletions(-) create mode 100644 change_notes/2025-03-31-allow-atomics-threads-and-threadlocals-in-misra-c.md diff --git a/amendments.csv b/amendments.csv index 1e774bc0c3..7bcc65327c 100644 --- a/amendments.csv +++ b/amendments.csv @@ -24,7 +24,7 @@ c,MISRA-C-2012,Amendment4,RULE-8-9,Yes,Clarification,Yes,Import c,MISRA-C-2012,Amendment4,RULE-9-4,Yes,Clarification,Yes,Import c,MISRA-C-2012,Amendment4,RULE-10-1,Yes,Clarification,Yes,Import c,MISRA-C-2012,Amendment4,RULE-18-3,Yes,Clarification,Yes,Import -c,MISRA-C-2012,Amendment4,RULE-1-4,Yes,Replace,No,Easy +c,MISRA-C-2012,Amendment4,RULE-1-4,Yes,Replace,Yes,Easy c,MISRA-C-2012,Amendment4,RULE-9-1,Yes,Refine,Yes,Easy c,MISRA-C-2012,Corrigendum2,DIR-4-10,Yes,Clarification,Yes,Import c,MISRA-C-2012,Corrigendum2,RULE-7-4,Yes,Refine,Yes,Easy diff --git a/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected b/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected index b0bbc467aa..3f63a6c26c 100644 --- a/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected +++ b/c/misra/test/rules/RULE-1-4/EmergentLanguageFeaturesUsed.expected @@ -1,7 +1 @@ -| test.c:2:1:2:22 | #include | Usage of emergent language feature. | -| test.c:4:1:4:20 | #include | Usage of emergent language feature. | | test.c:7:1:7:32 | #define __STDC_WANT_LIB_EXT1__ 1 | Usage of emergent language feature. | -| test.c:12:26:12:40 | atomic_new_type | Usage of emergent language feature. | -| test.c:17:15:17:15 | i | Usage of emergent language feature. | -| test.c:24:27:24:28 | i3 | Usage of emergent language feature. | -| test.c:25:28:25:29 | i4 | Usage of emergent language feature. | diff --git a/c/misra/test/rules/RULE-1-4/test.c b/c/misra/test/rules/RULE-1-4/test.c index 81d609f052..5bea219b54 100644 --- a/c/misra/test/rules/RULE-1-4/test.c +++ b/c/misra/test/rules/RULE-1-4/test.c @@ -1,15 +1,15 @@ #include //COMPLIANT -#include //NON_COMPLIANT +#include //COMPLIANT #include //COMPLIANT -#include //NON_COMPLIANT +#include //COMPLIANT -#define MACRO(x) _Generic((x), int : 0, long : 1) // NON_COMPLIANT +#define MACRO(x) _Generic((x), int : 0, long : 1) // COMPLIANT #define __STDC_WANT_LIB_EXT1__ 1 // NON_COMPLIANT _Noreturn void f0(); // COMPLIANT typedef int new_type; // COMPLIANT -typedef _Atomic new_type atomic_new_type; // NON_COMPLIANT +typedef _Atomic new_type atomic_new_type; // COMPLIANT void f(int p) { int i0 = _Generic(p, int : 0, long : 1); // COMPLIANT @@ -21,6 +21,6 @@ void f(int p) { int a = _Alignof(int); // COMPLIANT int a1 = alignof(int); // COMPLIANT - static thread_local int i3; // NON_COMPLIANT - static _Thread_local int i4; // NON_COMPLIANT + static thread_local int i3; // COMPLIANT + static _Thread_local int i4; // COMPLIANT } \ No newline at end of file diff --git a/change_notes/2025-03-31-allow-atomics-threads-and-threadlocals-in-misra-c.md b/change_notes/2025-03-31-allow-atomics-threads-and-threadlocals-in-misra-c.md new file mode 100644 index 0000000000..b59e04610f --- /dev/null +++ b/change_notes/2025-03-31-allow-atomics-threads-and-threadlocals-in-misra-c.md @@ -0,0 +1,2 @@ + - `RULE-1-4` - `EmergentLanguageFeaturesUsed.ql`: + - Allow usage of atomics, `thread.h`, and `_Thread_local` as per Misra C 2012 Amendment 4. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Emergent.qll b/cpp/common/src/codingstandards/cpp/Emergent.qll index 3b3fbbaebd..30f1df58e4 100644 --- a/cpp/common/src/codingstandards/cpp/Emergent.qll +++ b/cpp/common/src/codingstandards/cpp/Emergent.qll @@ -6,24 +6,6 @@ import cpp module C11 { abstract class EmergentLanguageFeature extends Element { } - class AtomicVariableSpecifier extends EmergentLanguageFeature, Variable { - AtomicVariableSpecifier() { - getType().(DerivedType).getBaseType*().getASpecifier().getName() = "atomic" - } - } - - class AtomicDeclaration extends EmergentLanguageFeature, Declaration { - AtomicDeclaration() { getASpecifier().getName() = "atomic" } - } - - class ThreadLocalDeclaration extends EmergentLanguageFeature, Declaration { - ThreadLocalDeclaration() { getASpecifier().getName() = "is_thread_local" } - } - - class EmergentHeader extends EmergentLanguageFeature, Include { - EmergentHeader() { getIncludedFile().getBaseName() = ["stdatomic.h", "threads.h"] } - } - class LibExt1Macro extends EmergentLanguageFeature, Macro { LibExt1Macro() { getName() = "__STDC_WANT_LIB_EXT1__" and From 24d743593ee429a50b81dd8f526f0d1ee603529a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 04:34:06 +0000 Subject: [PATCH 335/628] Bump actions/create-github-app-token from 1 to 2 Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 1 to 2. - [Release notes](https://github.com/actions/create-github-app-token/releases) - [Commits](https://github.com/actions/create-github-app-token/compare/v1...v2) --- updated-dependencies: - dependency-name: actions/create-github-app-token dependency-version: '2' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/dispatch-matrix-test-on-comment.yml | 2 +- .github/workflows/dispatch-release-performance-check.yml | 2 +- .github/workflows/finalize-release.yml | 2 +- .github/workflows/prepare-release.yml | 2 +- .github/workflows/update-release.yml | 2 +- .github/workflows/validate-release.yml | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/dispatch-matrix-test-on-comment.yml b/.github/workflows/dispatch-matrix-test-on-comment.yml index 964fb7e9f3..972cabdb89 100644 --- a/.github/workflows/dispatch-matrix-test-on-comment.yml +++ b/.github/workflows/dispatch-matrix-test-on-comment.yml @@ -19,7 +19,7 @@ jobs: - name: Generate token id: generate-token - uses: actions/create-github-app-token@v1 + uses: actions/create-github-app-token@v2 with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} diff --git a/.github/workflows/dispatch-release-performance-check.yml b/.github/workflows/dispatch-release-performance-check.yml index a8df297f7d..5886bb2ea8 100644 --- a/.github/workflows/dispatch-release-performance-check.yml +++ b/.github/workflows/dispatch-release-performance-check.yml @@ -19,7 +19,7 @@ jobs: - name: Generate token id: generate-token - uses: actions/create-github-app-token@v1 + uses: actions/create-github-app-token@v2 with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} diff --git a/.github/workflows/finalize-release.yml b/.github/workflows/finalize-release.yml index a7ccc0375e..b3a96f32d3 100644 --- a/.github/workflows/finalize-release.yml +++ b/.github/workflows/finalize-release.yml @@ -103,7 +103,7 @@ jobs: - name: Generate token if: env.HOTFIX_RELEASE == 'false' id: generate-token - uses: actions/create-github-app-token@v1 + uses: actions/create-github-app-token@v2 with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 19dbe1adbd..75e297d42e 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -143,7 +143,7 @@ jobs: - name: Generate token id: generate-token - uses: actions/create-github-app-token@v1 + uses: actions/create-github-app-token@v2 with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} diff --git a/.github/workflows/update-release.yml b/.github/workflows/update-release.yml index 4f779d0841..e3b8045514 100644 --- a/.github/workflows/update-release.yml +++ b/.github/workflows/update-release.yml @@ -43,7 +43,7 @@ jobs: - name: Generate token id: generate-token - uses: actions/create-github-app-token@v1 + uses: actions/create-github-app-token@v2 with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} diff --git a/.github/workflows/validate-release.yml b/.github/workflows/validate-release.yml index 63aa9e90e3..cd7d27f6fa 100644 --- a/.github/workflows/validate-release.yml +++ b/.github/workflows/validate-release.yml @@ -40,7 +40,7 @@ jobs: steps: - name: Generate token id: generate-token - uses: actions/create-github-app-token@v1 + uses: actions/create-github-app-token@v2 with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} @@ -108,7 +108,7 @@ jobs: steps: - name: Generate token id: generate-token - uses: actions/create-github-app-token@v1 + uses: actions/create-github-app-token@v2 with: app-id: ${{ vars.AUTOMATION_APP_ID }} private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }} From 4623f33542c09fbc1d2fa38833a2d0a337489602 Mon Sep 17 00:00:00 2001 From: Michael R Fairhurst Date: Tue, 8 Apr 2025 22:15:40 +0000 Subject: [PATCH 336/628] First pass at addressing cross-compiler compatibility in MISRA 2023. Handles clang findings and gcc findings. Many issues were merely updates to the test cases, however, additional work has been done to properly handle tgmath.h and stdatomic.h macros across gcc and clang results. --- c/common/src/codingstandards/c/TgMath.qll | 59 +++- .../functionnoreturnattributecondition/test.c | 2 +- .../rules/RULE-13-2/UnsequencedAtomicReads.ql | 50 ++- .../TgMathArgumentWithInvalidEssentialType.ql | 11 +- ...gMathArgumentsWithDifferingStandardType.ql | 6 +- .../RULE-21-25/InvalidMemoryOrderArgument.ql | 76 +--- .../RULE-9-7/UninitializedAtomicObject.ql | 6 +- c/misra/test/rules/DIR-5-1/test.c | 2 +- c/misra/test/rules/DIR-5-3/test.c | 2 +- ...eOfObsoleteMacroAtomicVarInit.expected.gcc | 1 + ...tomicQualifierAppliedToVoid.expected.clang | 0 c/misra/test/rules/RULE-11-10/test.c.clang | 28 ++ ...egateObjectDirectlyAccessed.expected.clang | 0 c/misra/test/rules/RULE-12-6/test.c | 6 +- c/misra/test/rules/RULE-12-6/test.c.clang | 89 +++++ .../RULE-13-2/UnsequencedAtomicReads.expected | 6 +- .../UnsequencedAtomicReads.expected.gcc | 5 + c/misra/test/rules/RULE-17-11/test.c | 2 +- c/misra/test/rules/RULE-18-10/test.c | 6 +- c/misra/test/rules/RULE-18-8/test.c | 2 +- ...ointerConversionOfTemporaryObject.expected | 6 +- ...eSubscriptedWithTemporaryLifetime.expected | 14 +- c/misra/test/rules/RULE-18-9/test.c | 5 +- ...hArgumentWithInvalidEssentialType.expected | 2 + ...entWithInvalidEssentialType.expected.clang | 76 ++++ ...umentWithInvalidEssentialType.expected.gcc | 79 +++++ c/misra/test/rules/RULE-21-22/test.c | 6 + c/misra/test/rules/RULE-21-22/test.c.clang | 329 ++++++++++++++++++ c/misra/test/rules/RULE-21-22/test.c.gcc | 329 ++++++++++++++++++ ...tsWithDifferingStandardType.expected.clang | 139 ++++++++ ...entsWithDifferingStandardType.expected.gcc | 139 ++++++++ .../InvalidMemoryOrderArgument.expected | 142 ++++---- .../InvalidMemoryOrderArgument.expected.gcc | 106 ++++++ c/misra/test/rules/RULE-21-25/test.c | 19 +- c/misra/test/rules/RULE-21-26/test.c | 2 +- c/misra/test/rules/RULE-22-16/test.c | 2 +- ...fObjectWithUnmatchedAlignment.expected.gcc | 20 +- c/misra/test/rules/RULE-9-7/test.c | 4 +- ...ss-compiler-compatibility-in-misra-2023.md | 12 + .../src/codingstandards/cpp/FloatingPoint.qll | 3 +- .../cpp/StdFunctionOrMacro.qll | 138 ++++++-- 41 files changed, 1698 insertions(+), 233 deletions(-) create mode 100644 c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected.gcc create mode 100644 c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected.clang create mode 100644 c/misra/test/rules/RULE-11-10/test.c.clang create mode 100644 c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected.clang create mode 100644 c/misra/test/rules/RULE-12-6/test.c.clang create mode 100644 c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected.gcc create mode 100644 c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected.clang create mode 100644 c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected.gcc create mode 100644 c/misra/test/rules/RULE-21-22/test.c.clang create mode 100644 c/misra/test/rules/RULE-21-22/test.c.gcc create mode 100644 c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected.clang create mode 100644 c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected.gcc create mode 100644 c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected.gcc create mode 100644 change_notes/2025-04-08-address-cross-compiler-compatibility-in-misra-2023.md diff --git a/c/common/src/codingstandards/c/TgMath.qll b/c/common/src/codingstandards/c/TgMath.qll index 36c47fb5a2..8d68cd2574 100644 --- a/c/common/src/codingstandards/c/TgMath.qll +++ b/c/common/src/codingstandards/c/TgMath.qll @@ -1,21 +1,38 @@ import cpp -private string getATgMathMacroName(boolean allowComplex) { +private string getATgMathMacroName(boolean allowComplex, int numberOfParameters) { allowComplex = true and + numberOfParameters = 1 and result = [ "acos", "acosh", "asin", "asinh", "atan", "atanh", "carg", "cimag", "conj", "cos", "cosh", - "cproj", "creal", "exp", "fabs", "log", "pow", "sin", "sinh", "sqrt", "tan", "tanh" + "cproj", "creal", "exp", "fabs", "log", "sin", "sinh", "sqrt", "tan", "tanh" + ] + or + allowComplex = true and + numberOfParameters = 2 and + result = "pow" + or + allowComplex = false and + numberOfParameters = 1 and + result = + [ + "cbrt", "ceil", "erf", "erfc", "exp2", "expm1", "floor", "ilogb", "lgamma", "llrint", + "llround", "log10", "log1p", "log2", "logb", "lrint", "lround", "nearbyint", "rint", "round", + "tgamma", "trunc", ] or allowComplex = false and + numberOfParameters = 2 and result = [ - "atan2", "cbrt", "ceil", "copysign", "erf", "erfc", "exp2", "expm1", "fdim", "floor", "fma", - "fmax", "fmin", "fmod", "frexp", "hypot", "ilogb", "ldexp", "lgamma", "llrint", "llround", - "log10", "log1p", "log2", "logb", "lrint", "lround", "nearbyint", "nextafter", "nexttoward", - "remainder", "remquo", "rint", "round", "scalbn", "scalbln", "tgamma", "trunc", + "atan2", "copysign", "fdim", "fmax", "fmin", "fmod", "frexp", "hypot", "ldexp", "nextafter", + "nexttoward", "remainder", "scalbn", "scalbln" ] + or + allowComplex = false and + numberOfParameters = 3 and + result = ["fma", "remquo"] } private predicate hasOutputArgument(string macroName, int index) { @@ -27,19 +44,41 @@ private predicate hasOutputArgument(string macroName, int index) { class TgMathInvocation extends MacroInvocation { Call call; boolean allowComplex; + int numberOfParameters; TgMathInvocation() { - this.getMacro().getName() = getATgMathMacroName(allowComplex) and + this.getMacro().getName() = getATgMathMacroName(allowComplex, numberOfParameters) and call = getBestCallInExpansion(this) } + /** Account for extra parameters added by gcc */ + private int getParameterOffset() { + // Gcc calls look something like: `__builtin_tgmath(cosf, cosd, cosl, arg)`, in this example + // there is a parameter offset of 3, so `getOperandArgument(0)` is equivalent to + // `call.getArgument(3)`. + result = call.getNumberOfArguments() - numberOfParameters + } + Expr getOperandArgument(int i) { - result = call.getArgument(i) and - not hasOutputArgument(call.getTarget().getName(), i) + i >= 0 and + result = call.getArgument(i + getParameterOffset()) and + //i in [0..numberOfParameters - 1] and + not hasOutputArgument(getMacro().getName(), i) + } + + /** Get all explicit conversions, except those added by clang in the macro body */ + Expr getExplicitlyConvertedOperandArgument(int i) { + exists(Expr explicitConv | + explicitConv = getOperandArgument(i).getExplicitlyConverted() and + // clang explicitly casts most arguments, but not some integer arguments such as in `scalbn`. + if call.getTarget().getName().matches("__tg_%") and explicitConv instanceof Conversion + then result = explicitConv.(Conversion).getExpr() + else result = explicitConv + ) } int getNumberOfOperandArguments() { - result = call.getNumberOfArguments() - count(int i | hasOutputArgument(getMacroName(), i)) + result = numberOfParameters - count(int i | hasOutputArgument(getMacroName(), i)) } Expr getAnOperandArgument() { result = getOperandArgument(_) } diff --git a/c/common/test/rules/functionnoreturnattributecondition/test.c b/c/common/test/rules/functionnoreturnattributecondition/test.c index 1b0ba759e1..c13654a8e0 100644 --- a/c/common/test/rules/functionnoreturnattributecondition/test.c +++ b/c/common/test/rules/functionnoreturnattributecondition/test.c @@ -77,7 +77,7 @@ _Noreturn void test_noreturn_f10(int i) { // COMPLIANT case 4: thrd_exit(0); break; - default: + default:; jmp_buf jb; longjmp(jb, 0); } diff --git a/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql b/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql index b5e17fc934..86756668a8 100644 --- a/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql +++ b/c/misra/src/rules/RULE-13-2/UnsequencedAtomicReads.ql @@ -17,6 +17,7 @@ import semmle.code.cpp.dataflow.TaintTracking import codingstandards.c.misra import codingstandards.c.Ordering import codingstandards.c.orderofevaluation.VariableAccessOrdering +import codingstandards.cpp.StdFunctionOrMacro class AtomicAccessInFullExpressionOrdering extends Ordering::Configuration { AtomicAccessInFullExpressionOrdering() { this = "AtomicAccessInFullExpressionOrdering" } @@ -24,8 +25,8 @@ class AtomicAccessInFullExpressionOrdering extends Ordering::Configuration { override predicate isCandidate(Expr e1, Expr e2) { exists(AtomicVariableAccess a, AtomicVariableAccess b, FullExpr e | a = e1 and b = e2 | a.getTarget() = b.getTarget() and - a.(ConstituentExpr).getFullExpr() = e and - b.(ConstituentExpr).getFullExpr() = e and + a.getARead().(ConstituentExpr).getFullExpr() = e and + b.getARead().(ConstituentExpr).getFullExpr() = e and not a = b ) } @@ -39,13 +40,32 @@ class AtomicAccessInFullExpressionOrdering extends Ordering::Configuration { class AtomicVariableAccess extends VariableAccess { AtomicVariableAccess() { getTarget().getType().hasSpecifier("atomic") } - /* Get the `atomic_()` call this VarAccess occurs in. */ - FunctionCall getAtomicFunctionCall() { - exists(AddressOfExpr addrParent, FunctionCall fc | - fc.getTarget().getName().matches("__c11_atomic%") and + /* Get the `atomic_load()` call this VarAccess occurs in. */ + Expr getAtomicFunctionRead() { + exists(AddressOfExpr addrParent, AtomicReadOrWriteCall fc | + fc.getName().matches("atomic_load%") and + // StdFunctionOrMacro arguments are not necessarily reliable, so we look for any AddressOfExpr + // that is an argument to a call to `atomic_load`. addrParent = fc.getArgument(0) and addrParent.getAnOperand() = this and - result = fc + result = fc.getExpr() + ) + } + + /* Get the `atomic_store()` call this VarAccess occurs in. */ + Expr getAtomicFunctionWrite(Expr storedValue) { + exists(AddressOfExpr addrParent, AtomicReadOrWriteCall fc | + addrParent = fc.getArgument(0) and + addrParent.getAnOperand() = this and + result = fc.getExpr() and + ( + fc.getName().matches(["%store%", "%exchange%", "%fetch_%"]) and + not fc.getName().matches("%compare%") and + storedValue = fc.getArgument(1) + or + fc.getName().matches(["%compare%"]) and + storedValue = fc.getArgument(2) + ) ) } @@ -53,7 +73,7 @@ class AtomicVariableAccess extends VariableAccess { * Gets an assigned expr, either in the form `x = ` or `atomic_store(&x, )`. */ Expr getAnAssignedExpr() { - result = getAtomicFunctionCall().getArgument(1) + exists(getAtomicFunctionWrite(result)) or exists(AssignExpr assign | assign.getLValue() = this and @@ -65,7 +85,7 @@ class AtomicVariableAccess extends VariableAccess { * Gets the expression holding this variable access, either in the form `x` or `atomic_read(&x)`. */ Expr getARead() { - result = getAtomicFunctionCall() + result = getAtomicFunctionRead() or result = this } @@ -73,11 +93,17 @@ class AtomicVariableAccess extends VariableAccess { from AtomicAccessInFullExpressionOrdering config, FullExpr e, Variable v, AtomicVariableAccess va1, - AtomicVariableAccess va2 + AtomicVariableAccess va2, Expr va1Read, Expr va2Read where not isExcluded(e, SideEffects3Package::unsequencedAtomicReadsQuery()) and - e = va1.(ConstituentExpr).getFullExpr() and - config.isUnsequenced(va1, va2) and + va1Read = va1.getARead() and + va2Read = va2.getARead() and + e = va1Read.(ConstituentExpr).getFullExpr() and + // Careful here. The `VariableAccess` in a pair of atomic function calls may not be unsequenced, + // for instance in gcc where atomic functions expand to StmtExprs, which have clear sequences. + // In this case, the result of `getARead()` for a pair of atomic function calls may be + // unsequenced even though the `VariableAccess`es within those calls are not. + config.isUnsequenced(va1Read, va2Read) and v = va1.getTarget() and v = va2.getTarget() and // Exclude cases where the variable is assigned a value tainted by the other variable access. diff --git a/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql b/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql index 2105567d04..3c918c10d3 100644 --- a/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql +++ b/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql @@ -34,14 +34,17 @@ string getAllowedTypesString(TgMathInvocation call) { else result = "essentially signed, unsigned, or real floating type" } -from TgMathInvocation call, Expr arg, int argIndex, Type type, EssentialTypeCategory category +from TgMathInvocation call, Expr convertedArg, Expr unconverted, int argIndex, Type type, EssentialTypeCategory category where not isExcluded(call, EssentialTypes2Package::tgMathArgumentWithInvalidEssentialTypeQuery()) and - arg = call.getOperandArgument(argIndex) and - type = getEssentialType(arg) and + // We must handle conversions specially, as clang inserts casts in the macro body we want to ignore. + convertedArg = call.getExplicitlyConvertedOperandArgument(argIndex) and + unconverted = convertedArg.getUnconverted() and + // Do not use `convertedArg.getEssentialType()`, as that is affected by clang's casts in the macro body. + type = getEssentialTypeBeforeConversions(convertedArg) and category = getEssentialTypeCategory(type) and not category = getAnAllowedEssentialTypeCategory(call) -select arg, +select unconverted, "Argument " + (argIndex + 1) + " provided to type-generic macro '" + call.getMacroName() + "' has " + category.toString().toLowerCase() + ", which is not " + getAllowedTypesString(call) + "." diff --git a/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql b/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql index 81209c8565..1a19249982 100644 --- a/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql +++ b/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql @@ -59,14 +59,14 @@ Type canonicalize(Type type) { } Type getEffectiveStandardType(Expr e) { - result = canonicalize(getPromotedType(e.getExplicitlyConverted())) + result = canonicalize(getPromotedType(e)) } from TgMathInvocation call, Type firstType where not isExcluded(call, EssentialTypes2Package::tgMathArgumentsWithDifferingStandardTypeQuery()) and - firstType = getEffectiveStandardType(call.getAnOperandArgument()) and - not forall(Expr arg | arg = call.getAnOperandArgument() | + firstType = getEffectiveStandardType(call.getExplicitlyConvertedOperandArgument(0)) and + not forall(Expr arg | arg = call.getExplicitlyConvertedOperandArgument(_) | firstType = getEffectiveStandardType(arg) ) select call, diff --git a/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql b/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql index 92ec2694b3..a7b599316a 100644 --- a/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql +++ b/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql @@ -14,11 +14,23 @@ import cpp import codingstandards.c.misra +import codingstandards.cpp.StdFunctionOrMacro import semmle.code.cpp.dataflow.new.DataFlow +class MemoryOrderEnum extends Enum { + MemoryOrderEnum() { + this.hasGlobalOrStdName("memory_order") + or + exists(TypedefType t | + t.getName() = "memory_order" and + t.getBaseType() = this + ) + } +} + /* A member of the set of memory orders defined in the `memory_order` enum */ class MemoryOrder extends EnumConstant { - MemoryOrder() { getDeclaringEnum().getName() = "memory_order" } + MemoryOrder() { getDeclaringEnum() instanceof MemoryOrderEnum } int getIntValue() { result = getValue().toInt() } } @@ -49,59 +61,6 @@ class MemoryOrderConstantExpr extends Expr { string getMemoryOrderString() { result = ord.getName() } } -/** - * A `stdatomic.h` function which accepts a `memory_order` value as a parameter. - */ -class MemoryOrderedStdAtomicFunction extends Function { - int orderParamIdx; - - MemoryOrderedStdAtomicFunction() { - exists(int baseParamIdx, int baseParams, string prefix, string regex, string basename | - regex = "__(c11_)?atomic_([a-z_]+)" and - prefix = getName().regexpCapture(regex, 1) and - basename = "atomic_" + getName().regexpCapture(regex, 2) + ["", "_explicit"] and - ( - basename in ["atomic_thread_fence", "atomic_signal_fence"] and - baseParamIdx = 0 and - baseParams = 1 - or - basename in ["atomic_load", "atomic_flag_clear", "atomic_flag_test_and_set"] and - baseParamIdx = 1 and - baseParams = 2 - or - basename in [ - "atomic_store", "atomic_fetch_" + ["add", "sub", "or", "xor", "and"], "atomic_exchange" - ] and - baseParamIdx = 2 and - baseParams = 3 - or - basename in ["atomic_compare_exchange_" + ["strong", "weak"]] and - baseParamIdx = [3, 4] and - baseParams = 5 - ) and - ( - // GCC case, may have one or two inserted parameters, e.g.: - // __atomic_load(8, &repr->a, &desired, order) - // or - // __atomic_load_8(&repr->a, &desired, order) - prefix = "" and - exists(int extraParams | - extraParams = getNumberOfParameters() - baseParams and - extraParams >= 0 and - orderParamIdx = baseParamIdx + extraParams - ) - or - // Clang case, no inserted parameters: - // __c11_atomic_load(object, order) - prefix = "c11_" and - orderParamIdx = baseParamIdx - ) - ) - } - - int getOrderParameterIdx() { result = orderParamIdx } -} - module MemoryOrderFlowConfig implements DataFlow::ConfigSig { predicate isSource(DataFlow::Node node) { // Direct usage of memory order constant @@ -118,9 +77,8 @@ module MemoryOrderFlowConfig implements DataFlow::ConfigSig { } predicate isSink(DataFlow::Node node) { - exists(FunctionCall fc | - node.asExpr() = - fc.getArgument(fc.getTarget().(MemoryOrderedStdAtomicFunction).getOrderParameterIdx()) + exists(AtomicallySequencedCall call | + call.getAMemoryOrderArgument() = node.asExpr() ) } } @@ -140,7 +98,7 @@ string describeMemoryOrderNode(DataFlow::Node node) { } from - Expr argument, Function function, string value, MemoryOrderFlow::PathNode source, + Expr argument, AtomicallySequencedCall function, string value, MemoryOrderFlow::PathNode source, MemoryOrderFlow::PathNode sink where not isExcluded(argument, Concurrency6Package::invalidMemoryOrderArgumentQuery()) and @@ -149,6 +107,6 @@ where value = describeMemoryOrderNode(source.getNode()) and // Double check that we didn't find flow from something equivalent to the allowed value. not value = any(AllowedMemoryOrder e).getName() and - function.getACallToThisFunction().getAnArgument() = argument + function.getAMemoryOrderArgument() = argument select argument, source, sink, "Invalid memory order '$@' in call to function '$@'.", value, value, function, function.getName() diff --git a/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql b/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql index dfb096189f..5f7fb803d6 100644 --- a/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql +++ b/c/misra/src/rules/RULE-9-7/UninitializedAtomicObject.ql @@ -31,7 +31,11 @@ class ThreadSpawningFunction extends Function { } class AtomicInitAddressOfExpr extends AddressOfExpr { - AtomicInitAddressOfExpr() { exists(AtomicInitCall c | this = c.getArgument(0)) } + AtomicInitAddressOfExpr() { + // StdFunctionOrMacro arguments are not necessarily reliable, so we look for any AddressOfExpr + // that is an argument to a call to `atomic_init`. + exists(AtomicInitCall c | this = c.getAnArgument()) + } } ControlFlowNode getARequiredInitializationPoint(LocalScopeVariable v) { diff --git a/c/misra/test/rules/DIR-5-1/test.c b/c/misra/test/rules/DIR-5-1/test.c index 5e568cc95c..5f392105e6 100644 --- a/c/misra/test/rules/DIR-5-1/test.c +++ b/c/misra/test/rules/DIR-5-1/test.c @@ -99,7 +99,7 @@ void many_thread13_calls_nonreentrant_funcs(void *p) { wcsrtombs(NULL, NULL, 0, NULL); // NON-COMPLIANT } -void main() { +int main(int argc, char *argv[]) { thrd_t single_thread1; thrd_t many_thread2; thrd_t single_thread3; diff --git a/c/misra/test/rules/DIR-5-3/test.c b/c/misra/test/rules/DIR-5-3/test.c index ebdf53cfb4..16eb580276 100644 --- a/c/misra/test/rules/DIR-5-3/test.c +++ b/c/misra/test/rules/DIR-5-3/test.c @@ -14,7 +14,7 @@ void func_called_from_main(void); void make_threads_called_from_func_called_from_main(void); void make_threads_called_from_main_pthread_thrd(void); -void main() { +int main(int argc, char *argv[]) { thrd_create(&g1, &thrd_func, NULL); // COMPLIANT pthread_create(&g2, NULL, &pthread_func, NULL); // COMPLIANT diff --git a/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected.gcc b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected.gcc new file mode 100644 index 0000000000..cb8e72ff0f --- /dev/null +++ b/c/misra/test/rules/RULE-1-5/UseOfObsoleteMacroAtomicVarInit.expected.gcc @@ -0,0 +1 @@ +| test.c:29:18:29:36 | ATOMIC_VAR_INIT(VALUE) | Usage of macro ATOMIC_VAR_INIT() is declared obscelescent in C18, and discouraged in earlier C versions. | diff --git a/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected.clang b/c/misra/test/rules/RULE-11-10/AtomicQualifierAppliedToVoid.expected.clang new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/test/rules/RULE-11-10/test.c.clang b/c/misra/test/rules/RULE-11-10/test.c.clang new file mode 100644 index 0000000000..c30368a48d --- /dev/null +++ b/c/misra/test/rules/RULE-11-10/test.c.clang @@ -0,0 +1,28 @@ +// _Atomic void g1; // doesn't compile +_Atomic int g2; // COMPLIANT +// _Atomic void *g3; // NON_COMPLIANT +// _Atomic void g4[]; // doesn't compile +void *_Atomic g5; // COMPLIANT + +struct { + _Atomic int m1; // COMPLIANT + // _Atomic void m2; // doesn't compile + // _Atomic void *m3; // NON_COMPLIANT + void *_Atomic m4; // COMPLIANT +} s1; + +void f(_Atomic int p1 // COMPLIANT + // _Atomic void *p2 // NON_COMPLIANT + // _Atomic void p3[] // doesn't compile, even though it perhaps should as + // it is adjusted to void*. +) {} + +// typedef _Atomic void *f2(void); // NON_COMPLIANT +// typedef _Atomic void *(*f3)(void); // NON_COMPLIANT +// typedef void f4(_Atomic void *); // NON_COMPLIANT +// typedef void (*f5)(_Atomic void *); // NON_COMPLIANT + +void f6() { + (void *)0; // COMPLIANT + // (_Atomic void *)0; // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected.clang b/c/misra/test/rules/RULE-12-6/AtomicAggregateObjectDirectlyAccessed.expected.clang new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/test/rules/RULE-12-6/test.c b/c/misra/test/rules/RULE-12-6/test.c index 0281e6b0d8..74d9de2fca 100644 --- a/c/misra/test/rules/RULE-12-6/test.c +++ b/c/misra/test/rules/RULE-12-6/test.c @@ -28,8 +28,8 @@ void f1() { atomic_store(&s1_atomic_ptr, l2); // COMPLIANT // Undefined behavior, but not banned by this rule. - memset(&atomic_s1, sizeof(atomic_s1), 0); // COMPLIANT - memset(ptr_atomic_s1, sizeof(*ptr_atomic_s1), 0); // COMPLIANT + memset(&atomic_s1, 0, sizeof(atomic_s1)); // COMPLIANT + memset(ptr_atomic_s1, 0, sizeof(*ptr_atomic_s1)); // COMPLIANT // OK: whole loads and stores are protected from data-races. takeCopy(atomic_s1); // COMPLIANT @@ -53,7 +53,7 @@ void f1() { // All OK: not an atomic struct, but rather an atomic pointer to non-atomic // struct. - memset(s1_atomic_ptr, sizeof(*s1_atomic_ptr), 0); // COMPLIANT + memset(s1_atomic_ptr, 0, sizeof(*s1_atomic_ptr)); // COMPLIANT takeCopy(*s1_atomic_ptr); // COMPLIANT *s1_atomic_ptr = (s1){0}; // COMPLIANT s1_atomic_ptr = l2; // COMPLIANT diff --git a/c/misra/test/rules/RULE-12-6/test.c.clang b/c/misra/test/rules/RULE-12-6/test.c.clang new file mode 100644 index 0000000000..83ad24cdb5 --- /dev/null +++ b/c/misra/test/rules/RULE-12-6/test.c.clang @@ -0,0 +1,89 @@ +#include "stdatomic.h" +#include "string.h" + +typedef struct s1 { + int x; +} s1; + +_Atomic s1 atomic_s1; +// A non-atomic pointer to an atomic s1 +_Atomic s1 *ptr_atomic_s1; +// An atomic pointer to a non-atomic s1 +s1 *_Atomic s1_atomic_ptr; + +_Atomic int g3; + +void takeCopy(s1 p1); + +void f1() { + s1 l1; + s1 *l2; + l1 = atomic_load(&atomic_s1); // COMPLIANT + l1 = atomic_load(ptr_atomic_s1); // COMPLIANT + l2 = atomic_load(&s1_atomic_ptr); // COMPLIANT + l1.x = 4; // COMPLIANT + l2->x = 4; // COMPLIANT + atomic_store(&atomic_s1, l1); // COMPLIANT + atomic_store(ptr_atomic_s1, l1); // COMPLIANT + atomic_store(&s1_atomic_ptr, l2); // COMPLIANT + + // Undefined behavior, but not banned by this rule. + memset(&atomic_s1, 0, sizeof(atomic_s1)); // COMPLIANT + memset(ptr_atomic_s1, 0, sizeof(*ptr_atomic_s1)); // COMPLIANT + + // OK: whole loads and stores are protected from data-races. + takeCopy(atomic_s1); // COMPLIANT + takeCopy(*ptr_atomic_s1); // COMPLIANT + atomic_s1 = (s1){0}; // COMPLIANT + *ptr_atomic_s1 = (s1){0}; // COMPLIANT + atomic_s1 = *l2; // COMPLIANT + ptr_atomic_s1 = l2; // COMPLIANT + + // Banned: circumvents data-race protection, results in UB. + // atomic_s1.x; // NON-COMPLIANT + // ptr_atomic_s1->x; // NON-COMPLIANT + // atomic_s1.x = 0; // NON-COMPLIANT + // ptr_atomic_s1->x = 0; // NON-COMPLIANT + + // OK: not evaluated. + sizeof(atomic_s1); // COMPLIANT + sizeof(ptr_atomic_s1); // COMPLIANT + // sizeof(atomic_s1.x); // COMPLIANT + // sizeof(ptr_atomic_s1->x); // COMPLIANT + + // All OK: not an atomic struct, but rather an atomic pointer to non-atomic + // struct. + memset(s1_atomic_ptr, 0, sizeof(*s1_atomic_ptr)); // COMPLIANT + takeCopy(*s1_atomic_ptr); // COMPLIANT + *s1_atomic_ptr = (s1){0}; // COMPLIANT + s1_atomic_ptr = l2; // COMPLIANT + s1_atomic_ptr->x; // COMPLIANT + + // Atomic specifier hidden behind a typedef, still atomic: + typedef _Atomic s1 atomic_s1; + atomic_s1 l3; + // l3.x; // NON_COMPLIANT + + // Worst case scenario: a typedef of a volatile const pointer to an atomic + // typedef type. + typedef atomic_s1 *volatile const atomic_s1_specified_ptr; + atomic_s1_specified_ptr l4; + // (l4)->x; // NON_COMPLIANT +} + +#define NOOP(x) (x) +#define DOT_FIELD_ACCESS_X(v) (v).x +#define POINTER_FIELD_ACCESS_X(v) (v)->x +#define GET_X_ATOMIC_S1() atomic_s1.x +#define GET_X_PTR_ATOMIC_S1() atomic_s1.x + +void f2() { + // Banned UB with user macros: + // NOOP(atomic_s1.x); // NON-COMPLIANT + // DOT_FIELD_ACCESS_X(atomic_s1); // NON-COMPLIANT + // POINTER_FIELD_ACCESS_X(ptr_atomic_s1); // NON-COMPLIANT + // GET_X_ATOMIC_S1(); // NON-COMPLIANT + // GET_X_PTR_ATOMIC_S1(); // NON-COMPLIANT + // GET_X_ATOMIC_S1() = 0; // NON-COMPLIANT + // GET_X_PTR_ATOMIC_S1() = 0; // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected index 897dd68f30..4fa06eb069 100644 --- a/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected +++ b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected @@ -1,5 +1,5 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:86,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:86,67-75) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:86,5-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:112,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:112,67-75) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:112,5-18) | test.c:44:12:44:18 | ... + ... | Atomic variable $@ has a $@ that is unsequenced with $@. | test.c:42:15:42:16 | a1 | a1 | test.c:44:12:44:13 | a1 | previous read | test.c:44:17:44:18 | a1 | another read | | test.c:46:3:46:37 | ... + ... | Atomic variable $@ has a $@ that is unsequenced with $@. | test.c:42:15:42:16 | a1 | a1 | test.c:46:16:46:17 | a1 | previous read | test.c:46:35:46:36 | a1 | another read | diff --git a/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected.gcc b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected.gcc new file mode 100644 index 0000000000..ccfb4e6a7b --- /dev/null +++ b/c/misra/test/rules/RULE-13-2/UnsequencedAtomicReads.expected.gcc @@ -0,0 +1,5 @@ +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:112,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:112,67-75) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (UnsequencedAtomicReads.ql:112,5-18) +| test.c:44:12:44:18 | ... + ... | Atomic variable $@ has a $@ that is unsequenced with $@. | test.c:42:15:42:16 | a1 | a1 | test.c:44:12:44:13 | a1 | previous read | test.c:44:17:44:18 | a1 | another read | +| test.c:46:15:46:17 | & ... | Atomic variable $@ has a $@ that is unsequenced with $@. | test.c:42:15:42:16 | a1 | a1 | test.c:46:16:46:17 | a1 | previous read | test.c:46:35:46:36 | a1 | another read | diff --git a/c/misra/test/rules/RULE-17-11/test.c b/c/misra/test/rules/RULE-17-11/test.c index 7baaea5821..73227accb9 100644 --- a/c/misra/test/rules/RULE-17-11/test.c +++ b/c/misra/test/rules/RULE-17-11/test.c @@ -86,7 +86,7 @@ __attribute__((noreturn)) void test_noreturn_f13(int i) { // COMPLIANT // Allowed by exception. It is undefined behavior for main() to be declared with // noreturn. -int main(char **argv, int argc) { // COMPLIANT +int main(int argc, char *argv[]) { // COMPLIANT abort(); } diff --git a/c/misra/test/rules/RULE-18-10/test.c b/c/misra/test/rules/RULE-18-10/test.c index 645943733d..b5906a3039 100644 --- a/c/misra/test/rules/RULE-18-10/test.c +++ b/c/misra/test/rules/RULE-18-10/test.c @@ -58,9 +58,9 @@ void f1( // Unknown array length types: int p21[], // COMPLIANT - int p22[][], // COMPLIANT + int p22[][2], // COMPLIANT int (*p23)[], // COMPLIANT - int (*p24)[2][], // COMPLIANT + // int (*p24)[2][], // doesn't compile int (*p25)[][2], // COMPLIANT // VLA types that are rewritten as pointers: @@ -73,7 +73,7 @@ void f1( int(*l2)[3]; // COMPLIANT int(*l3)[p0]; // NON-COMPLIANT - int l6[10] = p23; + int l6[10]; // A pointer to a VMT may be declared `static`. static int(*l4)[p0]; // NON-COMPLIANT diff --git a/c/misra/test/rules/RULE-18-8/test.c b/c/misra/test/rules/RULE-18-8/test.c index e6e038049c..7d6a1400d6 100644 --- a/c/misra/test/rules/RULE-18-8/test.c +++ b/c/misra/test/rules/RULE-18-8/test.c @@ -29,7 +29,7 @@ void f1(int n, // Pointers to variably-modified types are not VLAs. int p2[n][n], int p3[], // array of unknown length is converted to pointer - int p4[][] // array of unknown length are not VLAs. + int p4[][n] // array of unknown length are not VLAs. ) {} struct s { diff --git a/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected b/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected index 34bec03490..cf741ed16c 100644 --- a/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected +++ b/c/misra/test/rules/RULE-18-9/ArrayToPointerConversionOfTemporaryObject.expected @@ -25,6 +25,6 @@ | test.c:90:3:90:36 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:90:3:90:8 | call to get_s2 | call to get_s2 | | test.c:91:15:91:42 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:91:15:91:20 | call to get_s2 | call to get_s2 | | test.c:92:15:92:48 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:92:15:92:20 | call to get_s2 | call to get_s2 | -| test.c:111:15:111:33 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:111:16:111:22 | ... = ... | ... = ... | -| test.c:113:15:113:37 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:113:16:113:26 | ... ? ... : ... | ... ? ... : ... | -| test.c:114:15:114:31 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:114:16:114:20 | ... , ... | ... , ... | +| test.c:114:15:114:27 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:112:9:112:11 | arr | arr | test.c:114:16:114:22 | ... = ... | ... = ... | +| test.c:116:15:116:37 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:116:16:116:26 | ... ? ... : ... | ... ? ... : ... | +| test.c:117:15:117:31 | array to pointer conversion | Array to pointer conversion of array $@ from temporary object $@. | test.c:3:13:3:21 | const_arr | const_arr | test.c:117:16:117:20 | ... , ... | ... , ... | diff --git a/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected b/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected index 19604e2092..4c961ee994 100644 --- a/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected +++ b/c/misra/test/rules/RULE-18-9/ModifiableLValueSubscriptedWithTemporaryLifetime.expected @@ -5,11 +5,11 @@ | test.c:84:5:84:19 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:84:14:84:16 | arr | arr | test.c:84:5:84:10 | call to get_s1 | call to get_s1 | | test.c:93:3:93:27 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:93:22:93:24 | arr | arr | test.c:93:3:93:8 | call to get_s2 | call to get_s2 | | test.c:94:3:94:27 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:94:22:94:24 | arr | arr | test.c:94:3:94:8 | call to get_s2 | call to get_s2 | -| test.c:137:3:137:23 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:137:12:137:20 | arr_union | arr_union | test.c:137:3:137:8 | call to get_s3 | call to get_s3 | -| test.c:138:3:138:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:138:12:138:21 | arr_struct | arr_struct | test.c:138:3:138:8 | call to get_s3 | call to get_s3 | -| test.c:139:3:139:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:139:12:139:21 | arr_struct | arr_struct | test.c:139:3:139:8 | call to get_s3 | call to get_s3 | -| test.c:140:3:140:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:140:12:140:21 | arr_struct | arr_struct | test.c:140:3:140:8 | call to get_s3 | call to get_s3 | +| test.c:140:3:140:23 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:140:12:140:20 | arr_union | arr_union | test.c:140:3:140:8 | call to get_s3 | call to get_s3 | | test.c:141:3:141:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:141:12:141:21 | arr_struct | arr_struct | test.c:141:3:141:8 | call to get_s3 | call to get_s3 | -| test.c:142:4:142:25 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:142:13:142:22 | arr_struct | arr_struct | test.c:142:4:142:9 | call to get_s3 | call to get_s3 | -| test.c:146:3:146:19 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:146:12:146:16 | arr2d | arr2d | test.c:146:3:146:8 | call to get_s3 | call to get_s3 | -| test.c:147:4:147:20 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:147:13:147:17 | arr2d | arr2d | test.c:147:4:147:9 | call to get_s3 | call to get_s3 | +| test.c:142:3:142:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:142:12:142:21 | arr_struct | arr_struct | test.c:142:3:142:8 | call to get_s3 | call to get_s3 | +| test.c:143:3:143:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:143:12:143:21 | arr_struct | arr_struct | test.c:143:3:143:8 | call to get_s3 | call to get_s3 | +| test.c:144:3:144:24 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:144:12:144:21 | arr_struct | arr_struct | test.c:144:3:144:8 | call to get_s3 | call to get_s3 | +| test.c:145:4:145:25 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:145:13:145:22 | arr_struct | arr_struct | test.c:145:4:145:9 | call to get_s3 | call to get_s3 | +| test.c:149:3:149:19 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:149:12:149:16 | arr2d | arr2d | test.c:149:3:149:8 | call to get_s3 | call to get_s3 | +| test.c:150:4:150:20 | access to array | Modifiable lvalue produced by subscripting array member $@ of temporary lifetime object $@ | test.c:150:13:150:17 | arr2d | arr2d | test.c:150:4:150:9 | call to get_s3 | call to get_s3 | diff --git a/c/misra/test/rules/RULE-18-9/test.c b/c/misra/test/rules/RULE-18-9/test.c index f2fb44fdc9..d5eb5ec35e 100644 --- a/c/misra/test/rules/RULE-18-9/test.c +++ b/c/misra/test/rules/RULE-18-9/test.c @@ -108,7 +108,10 @@ void f(void) { get_s2_ptr()->member_s1.arr[0] = 1; // COMPLIANT // Other types of non-lvalue types - use_int_ptr((l1 = l1).const_arr); // NON-COMPLIANT + struct { + int arr[10]; + } l3; + use_int_ptr((l3 = l3).arr); // NON-COMPLIANT use_int_ptr(((struct s1)l1).const_arr); // NON-COMPLIANT[FALSE_NEGATIVE] use_int_ptr((1 ? l1 : l1).const_arr); // NON-COMPLIANT use_int_ptr((0, l1).const_arr); // NON-COMPLIANT diff --git a/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected index 7c30f68204..46e4e8f5c8 100644 --- a/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected +++ b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected @@ -130,3 +130,5 @@ | test.c:303:14:303:15 | cf | Argument 2 provided to type-generic macro 'scalbln' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | | test.c:309:10:309:11 | cf | Argument 1 provided to type-generic macro 'tgamma' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | | test.c:310:9:310:10 | cf | Argument 1 provided to type-generic macro 'trunc' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | +| test.c:325:14:325:14 | i | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:328:20:328:20 | c | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | diff --git a/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected.clang b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected.clang new file mode 100644 index 0000000000..313438ea6c --- /dev/null +++ b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected.clang @@ -0,0 +1,76 @@ +| test.c:29:7:29:7 | c | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:40:7:40:7 | e | Argument 1 provided to type-generic macro 'cos' has essentially enum type, which is not essentially signed, unsigned, or floating type. | +| test.c:41:7:41:7 | b | Argument 1 provided to type-generic macro 'cos' has essentially boolean type, which is not essentially signed, unsigned, or floating type. | +| test.c:156:8:156:8 | c | Argument 1 provided to type-generic macro 'acos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:157:9:157:9 | c | Argument 1 provided to type-generic macro 'acosh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:158:8:158:8 | c | Argument 1 provided to type-generic macro 'asin' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:159:9:159:9 | c | Argument 1 provided to type-generic macro 'asinh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:160:9:160:9 | c | Argument 1 provided to type-generic macro 'atan2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:161:12:161:12 | c | Argument 2 provided to type-generic macro 'atan2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:162:9:162:9 | c | Argument 1 provided to type-generic macro 'atanh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:163:8:163:8 | c | Argument 1 provided to type-generic macro 'carg' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:164:8:164:8 | c | Argument 1 provided to type-generic macro 'ceil' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:165:9:165:9 | c | Argument 1 provided to type-generic macro 'cimag' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:166:8:166:8 | c | Argument 1 provided to type-generic macro 'conj' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:167:15:167:15 | c | Argument 2 provided to type-generic macro 'copysign' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:168:12:168:12 | c | Argument 1 provided to type-generic macro 'copysign' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:169:8:169:8 | c | Argument 1 provided to type-generic macro 'cosh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:170:9:170:9 | c | Argument 1 provided to type-generic macro 'cproj' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:171:9:171:9 | c | Argument 1 provided to type-generic macro 'creal' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:172:7:172:7 | c | Argument 1 provided to type-generic macro 'erf' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:173:8:173:8 | c | Argument 1 provided to type-generic macro 'erfc' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:174:7:174:7 | c | Argument 1 provided to type-generic macro 'exp' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:175:8:175:8 | c | Argument 1 provided to type-generic macro 'exp2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:176:9:176:9 | c | Argument 1 provided to type-generic macro 'expm1' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:177:8:177:8 | c | Argument 1 provided to type-generic macro 'fabs' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:178:8:178:8 | c | Argument 1 provided to type-generic macro 'fdim' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:179:11:179:11 | c | Argument 2 provided to type-generic macro 'fdim' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:180:9:180:9 | c | Argument 1 provided to type-generic macro 'floor' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:181:7:181:7 | c | Argument 1 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:182:10:182:10 | c | Argument 2 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:183:13:183:13 | c | Argument 3 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:184:8:184:8 | c | Argument 1 provided to type-generic macro 'fmax' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:185:11:185:11 | c | Argument 2 provided to type-generic macro 'fmax' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:186:8:186:8 | c | Argument 1 provided to type-generic macro 'fmin' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:187:11:187:11 | c | Argument 2 provided to type-generic macro 'fmin' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:188:8:188:8 | c | Argument 1 provided to type-generic macro 'fmod' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:189:11:189:11 | c | Argument 2 provided to type-generic macro 'fmod' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:191:9:191:9 | c | Argument 1 provided to type-generic macro 'hypot' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:192:12:192:12 | c | Argument 2 provided to type-generic macro 'hypot' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:193:9:193:9 | c | Argument 1 provided to type-generic macro 'ilogb' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:194:9:194:9 | c | Argument 1 provided to type-generic macro 'ldexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:195:12:195:12 | c | Argument 2 provided to type-generic macro 'ldexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:196:10:196:10 | c | Argument 1 provided to type-generic macro 'lgamma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:197:10:197:10 | c | Argument 1 provided to type-generic macro 'llrint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:198:11:198:11 | c | Argument 1 provided to type-generic macro 'llround' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:199:7:199:7 | c | Argument 1 provided to type-generic macro 'log' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:200:9:200:9 | c | Argument 1 provided to type-generic macro 'log10' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:201:9:201:9 | c | Argument 1 provided to type-generic macro 'log1p' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:202:8:202:8 | c | Argument 1 provided to type-generic macro 'log2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:203:8:203:8 | c | Argument 1 provided to type-generic macro 'logb' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:204:9:204:9 | c | Argument 1 provided to type-generic macro 'lrint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:205:10:205:10 | c | Argument 1 provided to type-generic macro 'lround' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:206:13:206:13 | c | Argument 1 provided to type-generic macro 'nearbyint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:207:13:207:13 | c | Argument 1 provided to type-generic macro 'nextafter' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:208:16:208:16 | c | Argument 2 provided to type-generic macro 'nextafter' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:209:14:209:14 | c | Argument 1 provided to type-generic macro 'nexttoward' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:210:17:210:17 | c | Argument 2 provided to type-generic macro 'nexttoward' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:211:7:211:7 | c | Argument 1 provided to type-generic macro 'pow' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:212:10:212:10 | c | Argument 2 provided to type-generic macro 'pow' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:213:13:213:13 | c | Argument 1 provided to type-generic macro 'remainder' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:214:16:214:16 | c | Argument 2 provided to type-generic macro 'remainder' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:217:8:217:8 | c | Argument 1 provided to type-generic macro 'rint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:218:9:218:9 | c | Argument 1 provided to type-generic macro 'round' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:219:10:219:10 | c | Argument 1 provided to type-generic macro 'scalbn' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:220:13:220:13 | c | Argument 2 provided to type-generic macro 'scalbn' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:221:11:221:11 | c | Argument 1 provided to type-generic macro 'scalbln' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:222:14:222:14 | c | Argument 2 provided to type-generic macro 'scalbln' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:223:7:223:7 | c | Argument 1 provided to type-generic macro 'sin' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:224:8:224:8 | c | Argument 1 provided to type-generic macro 'sinh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:225:8:225:8 | c | Argument 1 provided to type-generic macro 'sqrt' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:226:7:226:7 | c | Argument 1 provided to type-generic macro 'tan' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:227:8:227:8 | c | Argument 1 provided to type-generic macro 'tanh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:228:10:228:10 | c | Argument 1 provided to type-generic macro 'tgamma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:229:9:229:9 | c | Argument 1 provided to type-generic macro 'trunc' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:325:14:325:14 | i | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:328:20:328:20 | c | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | diff --git a/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected.gcc b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected.gcc new file mode 100644 index 0000000000..79b070ae84 --- /dev/null +++ b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected.gcc @@ -0,0 +1,79 @@ +| test.c:29:7:29:7 | c | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:40:7:40:7 | e | Argument 1 provided to type-generic macro 'cos' has essentially enum type, which is not essentially signed, unsigned, or floating type. | +| test.c:41:7:41:7 | b | Argument 1 provided to type-generic macro 'cos' has essentially boolean type, which is not essentially signed, unsigned, or floating type. | +| test.c:156:8:156:8 | c | Argument 1 provided to type-generic macro 'acos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:157:9:157:9 | c | Argument 1 provided to type-generic macro 'acosh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:158:8:158:8 | c | Argument 1 provided to type-generic macro 'asin' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:159:9:159:9 | c | Argument 1 provided to type-generic macro 'asinh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:160:9:160:9 | c | Argument 1 provided to type-generic macro 'atan2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:161:12:161:12 | c | Argument 2 provided to type-generic macro 'atan2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:162:9:162:9 | c | Argument 1 provided to type-generic macro 'atanh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:163:8:163:8 | c | Argument 1 provided to type-generic macro 'carg' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:164:8:164:8 | c | Argument 1 provided to type-generic macro 'ceil' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:165:9:165:9 | c | Argument 1 provided to type-generic macro 'cimag' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:166:8:166:8 | c | Argument 1 provided to type-generic macro 'conj' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:167:15:167:15 | c | Argument 2 provided to type-generic macro 'copysign' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:168:12:168:12 | c | Argument 1 provided to type-generic macro 'copysign' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:169:8:169:8 | c | Argument 1 provided to type-generic macro 'cosh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:170:9:170:9 | c | Argument 1 provided to type-generic macro 'cproj' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:171:9:171:9 | c | Argument 1 provided to type-generic macro 'creal' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:172:7:172:7 | c | Argument 1 provided to type-generic macro 'erf' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:173:8:173:8 | c | Argument 1 provided to type-generic macro 'erfc' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:174:7:174:7 | c | Argument 1 provided to type-generic macro 'exp' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:175:8:175:8 | c | Argument 1 provided to type-generic macro 'exp2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:176:9:176:9 | c | Argument 1 provided to type-generic macro 'expm1' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:177:8:177:8 | c | Argument 1 provided to type-generic macro 'fabs' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:178:8:178:8 | c | Argument 1 provided to type-generic macro 'fdim' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:179:11:179:11 | c | Argument 2 provided to type-generic macro 'fdim' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:180:9:180:9 | c | Argument 1 provided to type-generic macro 'floor' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:181:7:181:7 | c | Argument 1 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:182:10:182:10 | c | Argument 2 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:183:13:183:13 | c | Argument 3 provided to type-generic macro 'fma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:184:8:184:8 | c | Argument 1 provided to type-generic macro 'fmax' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:185:11:185:11 | c | Argument 2 provided to type-generic macro 'fmax' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:186:8:186:8 | c | Argument 1 provided to type-generic macro 'fmin' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:187:11:187:11 | c | Argument 2 provided to type-generic macro 'fmin' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:188:8:188:8 | c | Argument 1 provided to type-generic macro 'fmod' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:189:11:189:11 | c | Argument 2 provided to type-generic macro 'fmod' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:190:9:190:9 | c | Argument 1 provided to type-generic macro 'frexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:191:9:191:9 | c | Argument 1 provided to type-generic macro 'hypot' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:192:12:192:12 | c | Argument 2 provided to type-generic macro 'hypot' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:193:9:193:9 | c | Argument 1 provided to type-generic macro 'ilogb' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:194:9:194:9 | c | Argument 1 provided to type-generic macro 'ldexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:195:12:195:12 | c | Argument 2 provided to type-generic macro 'ldexp' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:196:10:196:10 | c | Argument 1 provided to type-generic macro 'lgamma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:197:10:197:10 | c | Argument 1 provided to type-generic macro 'llrint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:198:11:198:11 | c | Argument 1 provided to type-generic macro 'llround' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:199:7:199:7 | c | Argument 1 provided to type-generic macro 'log' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:200:9:200:9 | c | Argument 1 provided to type-generic macro 'log10' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:201:9:201:9 | c | Argument 1 provided to type-generic macro 'log1p' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:202:8:202:8 | c | Argument 1 provided to type-generic macro 'log2' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:203:8:203:8 | c | Argument 1 provided to type-generic macro 'logb' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:204:9:204:9 | c | Argument 1 provided to type-generic macro 'lrint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:205:10:205:10 | c | Argument 1 provided to type-generic macro 'lround' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:206:13:206:13 | c | Argument 1 provided to type-generic macro 'nearbyint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:207:13:207:13 | c | Argument 1 provided to type-generic macro 'nextafter' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:208:16:208:16 | c | Argument 2 provided to type-generic macro 'nextafter' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:209:14:209:14 | c | Argument 1 provided to type-generic macro 'nexttoward' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:210:17:210:17 | c | Argument 2 provided to type-generic macro 'nexttoward' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:211:7:211:7 | c | Argument 1 provided to type-generic macro 'pow' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:212:10:212:10 | c | Argument 2 provided to type-generic macro 'pow' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:213:13:213:13 | c | Argument 1 provided to type-generic macro 'remainder' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:214:16:214:16 | c | Argument 2 provided to type-generic macro 'remainder' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:215:10:215:10 | c | Argument 1 provided to type-generic macro 'remquo' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:216:13:216:13 | c | Argument 2 provided to type-generic macro 'remquo' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:217:8:217:8 | c | Argument 1 provided to type-generic macro 'rint' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:218:9:218:9 | c | Argument 1 provided to type-generic macro 'round' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:219:10:219:10 | c | Argument 1 provided to type-generic macro 'scalbn' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:220:13:220:13 | c | Argument 2 provided to type-generic macro 'scalbn' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:221:11:221:11 | c | Argument 1 provided to type-generic macro 'scalbln' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:222:14:222:14 | c | Argument 2 provided to type-generic macro 'scalbln' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:223:7:223:7 | c | Argument 1 provided to type-generic macro 'sin' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:224:8:224:8 | c | Argument 1 provided to type-generic macro 'sinh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:225:8:225:8 | c | Argument 1 provided to type-generic macro 'sqrt' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:226:7:226:7 | c | Argument 1 provided to type-generic macro 'tan' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:227:8:227:8 | c | Argument 1 provided to type-generic macro 'tanh' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:228:10:228:10 | c | Argument 1 provided to type-generic macro 'tgamma' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:229:9:229:9 | c | Argument 1 provided to type-generic macro 'trunc' has essentially character type, which is not essentially signed, unsigned, or real floating type. | +| test.c:325:14:325:14 | i | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:328:20:328:20 | c | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | diff --git a/c/misra/test/rules/RULE-21-22/test.c b/c/misra/test/rules/RULE-21-22/test.c index cc456c17fb..66c889d168 100644 --- a/c/misra/test/rules/RULE-21-22/test.c +++ b/c/misra/test/rules/RULE-21-22/test.c @@ -320,4 +320,10 @@ void f1() { remquo(i, i, 0); // COMPLIANT remquo(i, i, 'c' - 'c'); // COMPLIANT remquo(i, i, c); // COMPLIANT + + /* Test casts */ + cos((char) i); // NON-COMPLIANT + cos((int) c); // COMPLIANT + cos((int) (char) i); // COMPLIANT + cos((char) (int) c); // NON-COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-22/test.c.clang b/c/misra/test/rules/RULE-21-22/test.c.clang new file mode 100644 index 0000000000..d28576e058 --- /dev/null +++ b/c/misra/test/rules/RULE-21-22/test.c.clang @@ -0,0 +1,329 @@ +#include +#include +#include +#include + +void f1() { + int i = 0; + unsigned int ui = 0; + short s = 0; + unsigned short us = 0; + char c = 0; + unsigned char uc = 0; + signed char sc = 0; + long l = 0; + unsigned long ul = 0; + float f = 0.0f; + float _Complex cf = 0.0f + 0.0f * I; + double d = 0.0; + char *p = 0; + void *vp = 0; + uintptr_t uip = p; + enum { e1 } e = e1; + bool b = true; + + cos(i); // COMPLIANT + cos(ui); // COMPLIANT + cos(s); // COMPLIANT + cos(us); // COMPLIANT + cos(c); // NON-COMPLIANT + cos(uc); // COMPLIANT + cos(sc); // COMPLIANT + cos(l); // COMPLIANT + cos(ul); // COMPLIANT + cos(f); // COMPLIANT + cos(cf); // COMPLIANT + cos(d); // COMPLIANT + // cos(p); // Doesn't compile + // cos(vp); // Doesn't compile + cos(uip); // COMPLIANT + cos(e); // NON-COMPLIANT + cos(b); // NON-COMPLIANT + cos(1); // COMPLIANT + cos(1.1f); // COMPLIANT + cos('a'); // NON-COMPLIANT[false negative] + + /** + * Int, float, and complex allowed: + */ + acos(i); // COMPLIANT + acos(f); // COMPLIANT + acosh(i); // COMPLIANT + acosh(f); // COMPLIANT + asin(i); // COMPLIANT + asin(f); // COMPLIANT + asinh(i); // COMPLIANT + asinh(f); // COMPLIANT + atan(i); // COMPLIANT + atan(f); // COMPLIANT + atan2(i, i); // COMPLIANT + atan2(f, f); // COMPLIANT + atanh(i); // COMPLIANT + atanh(f); // COMPLIANT + carg(i); // COMPLIANT + carg(f); // COMPLIANT + cbrt(i); // COMPLIANT + cbrt(f); // COMPLIANT + ceil(i); // COMPLIANT + ceil(f); // COMPLIANT + cimag(i); // COMPLIANT + cimag(f); // COMPLIANT + conj(i); // COMPLIANT + conj(f); // COMPLIANT + copysign(i, i); // COMPLIANT + copysign(f, f); // COMPLIANT + cos(i); // COMPLIANT + cos(f); // COMPLIANT + cosh(i); // COMPLIANT + cosh(f); // COMPLIANT + cproj(i); // COMPLIANT + cproj(f); // COMPLIANT + creal(i); // COMPLIANT + creal(f); // COMPLIANT + erf(i); // COMPLIANT + erf(f); // COMPLIANT + erfc(i); // COMPLIANT + erfc(f); // COMPLIANT + exp(i); // COMPLIANT + exp(f); // COMPLIANT + exp2(i); // COMPLIANT + exp2(f); // COMPLIANT + expm1(i); // COMPLIANT + expm1(f); // COMPLIANT + fabs(i); // COMPLIANT + fabs(f); // COMPLIANT + fdim(i, i); // COMPLIANT + fdim(f, f); // COMPLIANT + floor(i); // COMPLIANT + floor(f); // COMPLIANT + fma(i, i, i); // COMPLIANT + fma(f, f, f); // COMPLIANT + fmax(i, i); // COMPLIANT + fmax(f, f); // COMPLIANT + fmin(i, i); // COMPLIANT + fmin(f, f); // COMPLIANT + fmod(i, i); // COMPLIANT + fmod(f, f); // COMPLIANT + frexp(i, &i); // COMPLIANT + frexp(f, &p); // COMPLIANT + hypot(i, i); // COMPLIANT + hypot(f, f); // COMPLIANT + ilogb(i); // COMPLIANT + ilogb(f); // COMPLIANT + llrint(i); // COMPLIANT + llrint(f); // COMPLIANT + ldexp(i, i); // COMPLIANT + ldexp(f, f); // COMPLIANT + lgamma(i); // COMPLIANT + lgamma(f); // COMPLIANT + llround(i); // COMPLIANT + llround(f); // COMPLIANT + log(i); // COMPLIANT + log(f); // COMPLIANT + pow(i, i); // COMPLIANT + pow(f, f); // COMPLIANT + remainder(i, i); // COMPLIANT + remainder(f, f); // COMPLIANT + remquo(i, i, &i); // COMPLIANT + remquo(f, f, &f); // COMPLIANT + rint(i); // COMPLIANT + rint(f); // COMPLIANT + round(i); // COMPLIANT + round(f); // COMPLIANT + scalbn(i, i); // COMPLIANT + scalbn(f, f); // COMPLIANT + scalbln(i, i); // COMPLIANT + scalbln(f, f); // COMPLIANT + sin(i); // COMPLIANT + sin(f); // COMPLIANT + sin(cf); // COMPLIANT + sinh(i); // COMPLIANT + sinh(f); // COMPLIANT + sqrt(i); // COMPLIANT + sqrt(f); // COMPLIANT + tan(i); // COMPLIANT + tan(f); // COMPLIANT + tanh(i); // COMPLIANT + tanh(f); // COMPLIANT + tgamma(i); // COMPLIANT + tgamma(f); // COMPLIANT + trunc(i); // COMPLIANT + trunc(f); // COMPLIANT + + /** + * Char not allowed: + */ + acos(c); // NON-COMPLIANT + acosh(c); // NON-COMPLIANT + asin(c); // NON-COMPLIANT + asinh(c); // NON-COMPLIANT + atan2(c, i); // NON-COMPLIANT + atan2(i, c); // NON-COMPLIANT + atanh(c); // NON-COMPLIANT + carg(c); // NON-COMPLIANT + ceil(c); // NON-COMPLIANT + cimag(c); // NON-COMPLIANT + conj(c); // NON-COMPLIANT + copysign(i, c); // NON-COMPLIANT + copysign(c, i); // NON-COMPLIANT + cosh(c); // NON-COMPLIANT + cproj(c); // NON-COMPLIANT + creal(c); // NON-COMPLIANT + erf(c); // NON-COMPLIANT + erfc(c); // NON-COMPLIANT + exp(c); // NON-COMPLIANT + exp2(c); // NON-COMPLIANT + expm1(c); // NON-COMPLIANT + fabs(c); // NON-COMPLIANT + fdim(c, i); // NON-COMPLIANT + fdim(i, c); // NON-COMPLIANT + floor(c); // NON-COMPLIANT + fma(c, i, i); // NON-COMPLIANT + fma(i, c, i); // NON-COMPLIANT + fma(i, i, c); // NON-COMPLIANT + fmax(c, i); // NON-COMPLIANT + fmax(i, c); // NON-COMPLIANT + fmin(c, i); // NON-COMPLIANT + fmin(i, c); // NON-COMPLIANT + fmod(c, i); // NON-COMPLIANT + fmod(i, c); // NON-COMPLIANT + //frexp(c, i); // NON-COMPLIANT + hypot(c, i); // NON-COMPLIANT + hypot(i, c); // NON-COMPLIANT + ilogb(c); // NON-COMPLIANT + ldexp(c, i); // NON-COMPLIANT + ldexp(i, c); // NON-COMPLIANT + lgamma(c); // NON-COMPLIANT + llrint(c); // NON-COMPLIANT + llround(c); // NON-COMPLIANT + log(c); // NON-COMPLIANT + log10(c); // NON-COMPLIANT + log1p(c); // NON-COMPLIANT + log2(c); // NON-COMPLIANT + logb(c); // NON-COMPLIANT + lrint(c); // NON-COMPLIANT + lround(c); // NON-COMPLIANT + nearbyint(c); // NON-COMPLIANT + nextafter(c, i); // NON-COMPLIANT + nextafter(i, c); // NON-COMPLIANT + nexttoward(c, i); // NON-COMPLIANT + nexttoward(i, c); // NON-COMPLIANT + pow(c, i); // NON-COMPLIANT + pow(i, c); // NON-COMPLIANT + remainder(c, i); // NON-COMPLIANT + remainder(i, c); // NON-COMPLIANT + //remquo(c, i, i); // NON-COMPLIANT + //remquo(i, c, i); // NON-COMPLIANT + rint(c); // NON-COMPLIANT + round(c); // NON-COMPLIANT + scalbn(c, i); // NON-COMPLIANT + scalbn(i, c); // NON-COMPLIANT + scalbln(c, i); // NON-COMPLIANT + scalbln(i, c); // NON-COMPLIANT + sin(c); // NON-COMPLIANT + sinh(c); // NON-COMPLIANT + sqrt(c); // NON-COMPLIANT + tan(c); // NON-COMPLIANT + tanh(c); // NON-COMPLIANT + tgamma(c); // NON-COMPLIANT + trunc(c); // NON-COMPLIANT + + /** + * Complex types allowed in some calls, not others: + */ + acos(cf); // COMPLIANT + acosh(cf); // COMPLIANT + asin(cf); // COMPLIANT + asinh(cf); // COMPLIANT + atan(cf); // COMPLIANT + //atan2(cf, i); // NON-COMPLIANT + //atan2(i, cf); // NON-COMPLIANT + atanh(cf); // COMPLIANT + carg(cf); // COMPLIANT + //cbrt(cf); // NON-COMPLIANT + //ceil(cf); // NON-COMPLIANT + cimag(cf); // COMPLIANT + conj(cf); // COMPLIANT + //copysign(i, cf); // NON-COMPLIANT + //copysign(cf, i); // NON-COMPLIANT + //copysign(i, cf); // NON-COMPLIANT + cos(cf); // COMPLIANT + cosh(cf); // COMPLIANT + cproj(cf); // COMPLIANT + creal(cf); // COMPLIANT + //erf(cf); // NON-COMPLIANT + //erfc(cf); // NON-COMPLIANT + exp(cf); // COMPLIANT + //exp2(cf); // NON-COMPLIANT + //expm1(cf); // NON-COMPLIANT + fabs(cf); // COMPLIANT + //fdim(cf, i); // NON-COMPLIANT + //fdim(i, cf); // NON-COMPLIANT + //floor(cf); // NON-COMPLIANT + //fma(cf, i, i); // NON-COMPLIANT + //fma(i, cf, i); // NON-COMPLIANT + //fma(i, i, cf); // NON-COMPLIANT + //fmax(cf, i); // NON-COMPLIANT + //fmax(i, cf); // NON-COMPLIANT + //fmin(cf, i); // NON-COMPLIANT + //fmin(i, cf); // NON-COMPLIANT + //fmod(cf, i); // NON-COMPLIANT + //fmod(i, cf); // NON-COMPLIANT + //frexp(cf, i); // NON-COMPLIANT + //hypot(cf, i); // NON-COMPLIANT + //hypot(i, cf); // NON-COMPLIANT + //ilogb(cf); // NON-COMPLIANT + //ldexp(cf, i); // NON-COMPLIANT + //ldexp(i, cf); // NON-COMPLIANT + //lgamma(cf); // NON-COMPLIANT + //llrint(cf); // NON-COMPLIANT + //llround(cf); // NON-COMPLIANT + log(cf); // COMPLIANT + //log10(cf); // NON-COMPLIANT + //log1p(cf); // NON-COMPLIANT + //log2(cf); // NON-COMPLIANT + //logb(cf); // NON-COMPLIANT + //lrint(cf); // NON-COMPLIANT + //lround(cf); // NON-COMPLIANT + //nearbyint(cf); // NON-COMPLIANT + //nextafter(cf, i); // NON-COMPLIANT + //nextafter(i, cf); // NON-COMPLIANT + //nexttoward(cf, i); // NON-COMPLIANT + //nexttoward(i, cf); // NON-COMPLIANT + pow(cf, cf); // COMPLIANT + //remainder(cf, i); // NON-COMPLIANT + //remainder(i, cf); // NON-COMPLIANT + //remquo(cf, i, i); // NON-COMPLIANT + //remquo(i, cf, i); // NON-COMPLIANT + //rint(cf); // NON-COMPLIANT + //round(cf); // NON-COMPLIANT + //scalbn(cf, i); // NON-COMPLIANT + //scalbn(i, cf); // NON-COMPLIANT + //scalbln(cf, i); // NON-COMPLIANT + //scalbln(i, cf); // NON-COMPLIANT + sin(cf); // COMPLIANT + sinh(cf); // COMPLIANT + sqrt(cf); // COMPLIANT + tan(cf); // COMPLIANT + tanh(cf); // COMPLIANT + //tgamma(cf); // NON-COMPLIANT + //trunc(cf); // NON-COMPLIANT + + /* Test output arguments thoroughly */ + frexp(i, &i); // COMPLIANT + frexp(i, vp); // COMPLIANT + frexp(i, 0); // COMPLIANT + frexp(i, 'c' - 'c'); // COMPLIANT + //frexp(i, c); // COMPLIANT + remquo(i, i, &i); // COMPLIANT + remquo(i, i, vp); // COMPLIANT + remquo(i, i, 0); // COMPLIANT + remquo(i, i, 'c' - 'c'); // COMPLIANT + //remquo(i, i, c); // COMPLIANT + + /* Test casts */ + cos((char) i); // NON-COMPLIANT + cos((int) c); // COMPLIANT + cos((int) (char) i); // COMPLIANT + cos((char) (int) c); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-22/test.c.gcc b/c/misra/test/rules/RULE-21-22/test.c.gcc new file mode 100644 index 0000000000..4661a0b4f7 --- /dev/null +++ b/c/misra/test/rules/RULE-21-22/test.c.gcc @@ -0,0 +1,329 @@ +#include +#include +#include +#include + +void f1() { + int i = 0; + unsigned int ui = 0; + short s = 0; + unsigned short us = 0; + char c = 0; + unsigned char uc = 0; + signed char sc = 0; + long l = 0; + unsigned long ul = 0; + float f = 0.0f; + float _Complex cf = 0.0f + 0.0f * I; + double d = 0.0; + char *p = 0; + void *vp = 0; + uintptr_t uip = p; + enum { e1 } e = e1; + bool b = true; + + cos(i); // COMPLIANT + cos(ui); // COMPLIANT + cos(s); // COMPLIANT + cos(us); // COMPLIANT + cos(c); // NON-COMPLIANT + cos(uc); // COMPLIANT + cos(sc); // COMPLIANT + cos(l); // COMPLIANT + cos(ul); // COMPLIANT + cos(f); // COMPLIANT + cos(cf); // COMPLIANT + cos(d); // COMPLIANT + // cos(p); // Doesn't compile + // cos(vp); // Doesn't compile + cos(uip); // COMPLIANT + cos(e); // NON-COMPLIANT + cos(b); // NON-COMPLIANT + cos(1); // COMPLIANT + cos(1.1f); // COMPLIANT + cos('a'); // NON-COMPLIANT[false negative] + + /** + * Int, float, and complex allowed: + */ + acos(i); // COMPLIANT + acos(f); // COMPLIANT + acosh(i); // COMPLIANT + acosh(f); // COMPLIANT + asin(i); // COMPLIANT + asin(f); // COMPLIANT + asinh(i); // COMPLIANT + asinh(f); // COMPLIANT + atan(i); // COMPLIANT + atan(f); // COMPLIANT + atan2(i, i); // COMPLIANT + atan2(f, f); // COMPLIANT + atanh(i); // COMPLIANT + atanh(f); // COMPLIANT + carg(i); // COMPLIANT + carg(f); // COMPLIANT + cbrt(i); // COMPLIANT + cbrt(f); // COMPLIANT + ceil(i); // COMPLIANT + ceil(f); // COMPLIANT + cimag(i); // COMPLIANT + cimag(f); // COMPLIANT + conj(i); // COMPLIANT + conj(f); // COMPLIANT + copysign(i, i); // COMPLIANT + copysign(f, f); // COMPLIANT + cos(i); // COMPLIANT + cos(f); // COMPLIANT + cosh(i); // COMPLIANT + cosh(f); // COMPLIANT + cproj(i); // COMPLIANT + cproj(f); // COMPLIANT + creal(i); // COMPLIANT + creal(f); // COMPLIANT + erf(i); // COMPLIANT + erf(f); // COMPLIANT + erfc(i); // COMPLIANT + erfc(f); // COMPLIANT + exp(i); // COMPLIANT + exp(f); // COMPLIANT + exp2(i); // COMPLIANT + exp2(f); // COMPLIANT + expm1(i); // COMPLIANT + expm1(f); // COMPLIANT + fabs(i); // COMPLIANT + fabs(f); // COMPLIANT + fdim(i, i); // COMPLIANT + fdim(f, f); // COMPLIANT + floor(i); // COMPLIANT + floor(f); // COMPLIANT + fma(i, i, i); // COMPLIANT + fma(f, f, f); // COMPLIANT + fmax(i, i); // COMPLIANT + fmax(f, f); // COMPLIANT + fmin(i, i); // COMPLIANT + fmin(f, f); // COMPLIANT + fmod(i, i); // COMPLIANT + fmod(f, f); // COMPLIANT + frexp(i, &i); // COMPLIANT + frexp(f, &p); // COMPLIANT + hypot(i, i); // COMPLIANT + hypot(f, f); // COMPLIANT + ilogb(i); // COMPLIANT + ilogb(f); // COMPLIANT + llrint(i); // COMPLIANT + llrint(f); // COMPLIANT + ldexp(i, i); // COMPLIANT + ldexp(f, f); // COMPLIANT + lgamma(i); // COMPLIANT + lgamma(f); // COMPLIANT + llround(i); // COMPLIANT + llround(f); // COMPLIANT + log(i); // COMPLIANT + log(f); // COMPLIANT + pow(i, i); // COMPLIANT + pow(f, f); // COMPLIANT + remainder(i, i); // COMPLIANT + remainder(f, f); // COMPLIANT + remquo(i, i, &i); // COMPLIANT + remquo(f, f, &f); // COMPLIANT + rint(i); // COMPLIANT + rint(f); // COMPLIANT + round(i); // COMPLIANT + round(f); // COMPLIANT + scalbn(i, i); // COMPLIANT + scalbn(f, f); // COMPLIANT + scalbln(i, i); // COMPLIANT + scalbln(f, f); // COMPLIANT + sin(i); // COMPLIANT + sin(f); // COMPLIANT + sin(cf); // COMPLIANT + sinh(i); // COMPLIANT + sinh(f); // COMPLIANT + sqrt(i); // COMPLIANT + sqrt(f); // COMPLIANT + tan(i); // COMPLIANT + tan(f); // COMPLIANT + tanh(i); // COMPLIANT + tanh(f); // COMPLIANT + tgamma(i); // COMPLIANT + tgamma(f); // COMPLIANT + trunc(i); // COMPLIANT + trunc(f); // COMPLIANT + + /** + * Char not allowed: + */ + acos(c); // NON-COMPLIANT + acosh(c); // NON-COMPLIANT + asin(c); // NON-COMPLIANT + asinh(c); // NON-COMPLIANT + atan2(c, i); // NON-COMPLIANT + atan2(i, c); // NON-COMPLIANT + atanh(c); // NON-COMPLIANT + carg(c); // NON-COMPLIANT + ceil(c); // NON-COMPLIANT + cimag(c); // NON-COMPLIANT + conj(c); // NON-COMPLIANT + copysign(i, c); // NON-COMPLIANT + copysign(c, i); // NON-COMPLIANT + cosh(c); // NON-COMPLIANT + cproj(c); // NON-COMPLIANT + creal(c); // NON-COMPLIANT + erf(c); // NON-COMPLIANT + erfc(c); // NON-COMPLIANT + exp(c); // NON-COMPLIANT + exp2(c); // NON-COMPLIANT + expm1(c); // NON-COMPLIANT + fabs(c); // NON-COMPLIANT + fdim(c, i); // NON-COMPLIANT + fdim(i, c); // NON-COMPLIANT + floor(c); // NON-COMPLIANT + fma(c, i, i); // NON-COMPLIANT + fma(i, c, i); // NON-COMPLIANT + fma(i, i, c); // NON-COMPLIANT + fmax(c, i); // NON-COMPLIANT + fmax(i, c); // NON-COMPLIANT + fmin(c, i); // NON-COMPLIANT + fmin(i, c); // NON-COMPLIANT + fmod(c, i); // NON-COMPLIANT + fmod(i, c); // NON-COMPLIANT + frexp(c, i); // NON-COMPLIANT + hypot(c, i); // NON-COMPLIANT + hypot(i, c); // NON-COMPLIANT + ilogb(c); // NON-COMPLIANT + ldexp(c, i); // NON-COMPLIANT + ldexp(i, c); // NON-COMPLIANT + lgamma(c); // NON-COMPLIANT + llrint(c); // NON-COMPLIANT + llround(c); // NON-COMPLIANT + log(c); // NON-COMPLIANT + log10(c); // NON-COMPLIANT + log1p(c); // NON-COMPLIANT + log2(c); // NON-COMPLIANT + logb(c); // NON-COMPLIANT + lrint(c); // NON-COMPLIANT + lround(c); // NON-COMPLIANT + nearbyint(c); // NON-COMPLIANT + nextafter(c, i); // NON-COMPLIANT + nextafter(i, c); // NON-COMPLIANT + nexttoward(c, i); // NON-COMPLIANT + nexttoward(i, c); // NON-COMPLIANT + pow(c, i); // NON-COMPLIANT + pow(i, c); // NON-COMPLIANT + remainder(c, i); // NON-COMPLIANT + remainder(i, c); // NON-COMPLIANT + remquo(c, i, i); // NON-COMPLIANT + remquo(i, c, i); // NON-COMPLIANT + rint(c); // NON-COMPLIANT + round(c); // NON-COMPLIANT + scalbn(c, i); // NON-COMPLIANT + scalbn(i, c); // NON-COMPLIANT + scalbln(c, i); // NON-COMPLIANT + scalbln(i, c); // NON-COMPLIANT + sin(c); // NON-COMPLIANT + sinh(c); // NON-COMPLIANT + sqrt(c); // NON-COMPLIANT + tan(c); // NON-COMPLIANT + tanh(c); // NON-COMPLIANT + tgamma(c); // NON-COMPLIANT + trunc(c); // NON-COMPLIANT + + /** + * Complex types allowed in some calls, not others: + */ + acos(cf); // COMPLIANT + acosh(cf); // COMPLIANT + asin(cf); // COMPLIANT + asinh(cf); // COMPLIANT + atan(cf); // COMPLIANT + //atan2(cf, i); // NON-COMPLIANT + //atan2(i, cf); // NON-COMPLIANT + atanh(cf); // COMPLIANT + carg(cf); // COMPLIANT + //cbrt(cf); // NON-COMPLIANT + //ceil(cf); // NON-COMPLIANT + cimag(cf); // COMPLIANT + conj(cf); // COMPLIANT + //copysign(i, cf); // NON-COMPLIANT + //copysign(cf, i); // NON-COMPLIANT + //copysign(i, cf); // NON-COMPLIANT + cos(cf); // COMPLIANT + cosh(cf); // COMPLIANT + cproj(cf); // COMPLIANT + creal(cf); // COMPLIANT + //erf(cf); // NON-COMPLIANT + //erfc(cf); // NON-COMPLIANT + exp(cf); // COMPLIANT + //exp2(cf); // NON-COMPLIANT + //expm1(cf); // NON-COMPLIANT + fabs(cf); // COMPLIANT + //fdim(cf, i); // NON-COMPLIANT + //fdim(i, cf); // NON-COMPLIANT + //floor(cf); // NON-COMPLIANT + //fma(cf, i, i); // NON-COMPLIANT + //fma(i, cf, i); // NON-COMPLIANT + //fma(i, i, cf); // NON-COMPLIANT + //fmax(cf, i); // NON-COMPLIANT + //fmax(i, cf); // NON-COMPLIANT + //fmin(cf, i); // NON-COMPLIANT + //fmin(i, cf); // NON-COMPLIANT + //fmod(cf, i); // NON-COMPLIANT + //fmod(i, cf); // NON-COMPLIANT + //frexp(cf, i); // NON-COMPLIANT + //hypot(cf, i); // NON-COMPLIANT + //hypot(i, cf); // NON-COMPLIANT + //ilogb(cf); // NON-COMPLIANT + //ldexp(cf, i); // NON-COMPLIANT + //ldexp(i, cf); // NON-COMPLIANT + //lgamma(cf); // NON-COMPLIANT + //llrint(cf); // NON-COMPLIANT + //llround(cf); // NON-COMPLIANT + log(cf); // COMPLIANT + //log10(cf); // NON-COMPLIANT + //log1p(cf); // NON-COMPLIANT + //log2(cf); // NON-COMPLIANT + //logb(cf); // NON-COMPLIANT + //lrint(cf); // NON-COMPLIANT + //lround(cf); // NON-COMPLIANT + //nearbyint(cf); // NON-COMPLIANT + //nextafter(cf, i); // NON-COMPLIANT + //nextafter(i, cf); // NON-COMPLIANT + //nexttoward(cf, i); // NON-COMPLIANT + //nexttoward(i, cf); // NON-COMPLIANT + pow(cf, cf); // COMPLIANT + //remainder(cf, i); // NON-COMPLIANT + //remainder(i, cf); // NON-COMPLIANT + //remquo(cf, i, i); // NON-COMPLIANT + //remquo(i, cf, i); // NON-COMPLIANT + //rint(cf); // NON-COMPLIANT + //round(cf); // NON-COMPLIANT + //scalbn(cf, i); // NON-COMPLIANT + //scalbn(i, cf); // NON-COMPLIANT + //scalbln(cf, i); // NON-COMPLIANT + //scalbln(i, cf); // NON-COMPLIANT + sin(cf); // COMPLIANT + sinh(cf); // COMPLIANT + sqrt(cf); // COMPLIANT + tan(cf); // COMPLIANT + tanh(cf); // COMPLIANT + //tgamma(cf); // NON-COMPLIANT + //trunc(cf); // NON-COMPLIANT + + /* Test output arguments thoroughly */ + frexp(i, &i); // COMPLIANT + frexp(i, vp); // COMPLIANT + frexp(i, 0); // COMPLIANT + frexp(i, 'c' - 'c'); // COMPLIANT + frexp(i, c); // COMPLIANT + remquo(i, i, &i); // COMPLIANT + remquo(i, i, vp); // COMPLIANT + remquo(i, i, 0); // COMPLIANT + remquo(i, i, 'c' - 'c'); // COMPLIANT + remquo(i, i, c); // COMPLIANT + + /* Test casts */ + cos((char) i); // NON-COMPLIANT + cos((int) c); // COMPLIANT + cos((int) (char) i); // COMPLIANT + cos((char) (int) c); // NON-COMPLIANT +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected.clang b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected.clang new file mode 100644 index 0000000000..e6ad5c62e4 --- /dev/null +++ b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected.clang @@ -0,0 +1,139 @@ +| test.c:95:3:95:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:96:3:96:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:97:3:97:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:98:3:98:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:99:3:99:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:100:3:100:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:101:3:101:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:102:3:102:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:103:3:103:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:104:3:104:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:105:3:105:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:106:3:106:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:107:3:107:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:108:3:108:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:109:3:109:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:110:3:110:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:111:3:111:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:112:3:112:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:113:3:113:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:114:3:114:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:121:3:121:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:122:3:122:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:123:3:123:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:124:3:124:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:125:3:125:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:126:3:126:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:127:3:127:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:128:3:128:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:131:3:131:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:132:3:132:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:133:3:133:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:134:3:134:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:135:3:135:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:136:3:136:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:137:3:137:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:138:3:138:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:139:3:139:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:140:3:140:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:141:3:141:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:142:3:142:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:143:3:143:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:144:3:144:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:145:3:145:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:146:3:146:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:147:3:147:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:148:3:148:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:149:3:149:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:150:3:150:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:151:3:151:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:152:3:152:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:153:3:153:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:154:3:154:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:155:3:155:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:156:3:156:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:157:3:157:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:158:3:158:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:159:3:159:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:160:3:160:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:161:3:161:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:162:3:162:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:165:3:165:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:166:3:166:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:167:3:167:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:168:3:168:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:169:3:169:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:170:3:170:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:171:3:171:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:172:3:172:17 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:175:3:175:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (float, double). | +| test.c:176:3:176:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (float, long double). | +| test.c:177:3:177:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (double, float). | +| test.c:178:3:178:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (double, long double). | +| test.c:179:3:179:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long double, float). | +| test.c:180:3:180:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long double, double). | +| test.c:183:3:183:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:184:3:184:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:185:3:185:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:186:3:186:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:187:3:187:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:188:3:188:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:189:3:189:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:190:3:190:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:191:3:191:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:192:3:192:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:193:3:193:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:194:3:194:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:195:3:195:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:196:3:196:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:197:3:197:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:198:3:198:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:199:3:199:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:200:3:200:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:201:3:201:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:202:3:202:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:203:3:203:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:204:3:204:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:205:3:205:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:206:3:206:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:207:3:207:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:208:3:208:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:209:3:209:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:210:3:210:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:211:3:211:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:212:3:212:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:213:3:213:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, float). | +| test.c:214:3:214:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, double). | +| test.c:215:3:215:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long double). | +| test.c:216:3:216:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, float). | +| test.c:217:3:217:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, double). | +| test.c:218:3:218:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long double). | +| test.c:219:3:219:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, float). | +| test.c:220:3:220:13 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, double). | +| test.c:221:3:221:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, long double). | +| test.c:222:3:222:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, float). | +| test.c:223:3:223:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, double). | +| test.c:224:3:224:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, long double). | +| test.c:225:3:225:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, float). | +| test.c:226:3:226:14 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, double). | +| test.c:227:3:227:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long double). | +| test.c:228:3:228:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, float). | +| test.c:229:3:229:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, double). | +| test.c:230:3:230:16 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long double). | +| test.c:235:3:235:15 | atan2(__x,__y) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:242:3:242:16 | copysign(__x,__y) | Call to type-generic macro 'copysign' has arguments with differing standard types (int, float). | +| test.c:245:3:245:12 | fdim(__x,__y) | Call to type-generic macro 'fdim' has arguments with differing standard types (int, float). | +| test.c:248:3:248:14 | fma(__x,__y,__z) | Call to type-generic macro 'fma' has arguments with differing standard types (float, int, int). | +| test.c:249:3:249:14 | fma(__x,__y,__z) | Call to type-generic macro 'fma' has arguments with differing standard types (int, float, int). | +| test.c:250:3:250:14 | fma(__x,__y,__z) | Call to type-generic macro 'fma' has arguments with differing standard types (int, int, float). | +| test.c:253:3:253:12 | fmax(__x,__y) | Call to type-generic macro 'fmax' has arguments with differing standard types (int, float). | +| test.c:256:3:256:12 | fmin(__x,__y) | Call to type-generic macro 'fmin' has arguments with differing standard types (int, float). | +| test.c:259:3:259:12 | fmod(__x,__y) | Call to type-generic macro 'fmod' has arguments with differing standard types (int, float). | +| test.c:262:3:262:13 | hypot(__x,__y) | Call to type-generic macro 'hypot' has arguments with differing standard types (int, float). | +| test.c:265:3:265:13 | ldexp(__x,__y) | Call to type-generic macro 'ldexp' has arguments with differing standard types (int, float). | +| test.c:268:3:268:17 | nextafter(__x,__y) | Call to type-generic macro 'nextafter' has arguments with differing standard types (int, float). | +| test.c:271:3:271:18 | nexttoward(__x,__y) | Call to type-generic macro 'nexttoward' has arguments with differing standard types (int, float). | +| test.c:274:3:274:17 | remainder(__x,__y) | Call to type-generic macro 'remainder' has arguments with differing standard types (int, float). | +| test.c:277:3:277:17 | remquo(__x,__y,__z) | Call to type-generic macro 'remquo' has arguments with differing standard types (int, float). | +| test.c:280:3:280:15 | scalbln(__x,__y) | Call to type-generic macro 'scalbln' has arguments with differing standard types (int, float). | +| test.c:283:3:283:14 | scalbn(__x,__y) | Call to type-generic macro 'scalbn' has arguments with differing standard types (int, float). | diff --git a/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected.gcc b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected.gcc new file mode 100644 index 0000000000..f8c610f8c2 --- /dev/null +++ b/c/misra/test/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.expected.gcc @@ -0,0 +1,139 @@ +| test.c:95:3:95:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:96:3:96:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:97:3:97:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:98:3:98:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:99:3:99:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:100:3:100:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:101:3:101:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:102:3:102:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:103:3:103:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:104:3:104:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:105:3:105:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:106:3:106:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:107:3:107:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:108:3:108:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:109:3:109:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:110:3:110:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:111:3:111:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:112:3:112:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:113:3:113:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:114:3:114:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned int). | +| test.c:121:3:121:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:122:3:122:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:123:3:123:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:124:3:124:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:125:3:125:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:126:3:126:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:127:3:127:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:128:3:128:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:131:3:131:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:132:3:132:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:133:3:133:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:134:3:134:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:135:3:135:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:136:3:136:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:137:3:137:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:138:3:138:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:139:3:139:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:140:3:140:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:141:3:141:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:142:3:142:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:143:3:143:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:144:3:144:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:145:3:145:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:146:3:146:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:147:3:147:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:148:3:148:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long). | +| test.c:149:3:149:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:150:3:150:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long). | +| test.c:151:3:151:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:152:3:152:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:153:3:153:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, int). | +| test.c:154:3:154:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned int). | +| test.c:155:3:155:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:156:3:156:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, unsigned long). | +| test.c:157:3:157:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:158:3:158:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, unsigned long). | +| test.c:159:3:159:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:160:3:160:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:161:3:161:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, int). | +| test.c:162:3:162:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, unsigned int). | +| test.c:165:3:165:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:166:3:166:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:167:3:167:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:168:3:168:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, unsigned long). | +| test.c:169:3:169:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:170:3:170:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:171:3:171:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:172:3:172:17 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long). | +| test.c:175:3:175:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (float, double). | +| test.c:176:3:176:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (float, long double). | +| test.c:177:3:177:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (double, float). | +| test.c:178:3:178:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (double, long double). | +| test.c:179:3:179:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long double, float). | +| test.c:180:3:180:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long double, double). | +| test.c:183:3:183:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:184:3:184:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:185:3:185:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:186:3:186:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:187:3:187:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:188:3:188:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:189:3:189:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:190:3:190:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:191:3:191:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:192:3:192:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:193:3:193:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:194:3:194:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:195:3:195:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:196:3:196:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:197:3:197:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:198:3:198:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:199:3:199:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:200:3:200:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:201:3:201:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:202:3:202:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:203:3:203:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:204:3:204:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:205:3:205:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:206:3:206:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:207:3:207:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:208:3:208:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:209:3:209:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:210:3:210:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:211:3:211:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, double). | +| test.c:212:3:212:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, long double). | +| test.c:213:3:213:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, float). | +| test.c:214:3:214:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, double). | +| test.c:215:3:215:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long double). | +| test.c:216:3:216:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, float). | +| test.c:217:3:217:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, double). | +| test.c:218:3:218:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned int, long double). | +| test.c:219:3:219:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, float). | +| test.c:220:3:220:13 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, double). | +| test.c:221:3:221:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, long double). | +| test.c:222:3:222:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, float). | +| test.c:223:3:223:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, double). | +| test.c:224:3:224:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (long, long double). | +| test.c:225:3:225:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, float). | +| test.c:226:3:226:14 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, double). | +| test.c:227:3:227:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long double). | +| test.c:228:3:228:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, float). | +| test.c:229:3:229:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, double). | +| test.c:230:3:230:16 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (unsigned long, long double). | +| test.c:235:3:235:15 | atan2(Val1,Val2) | Call to type-generic macro 'atan2' has arguments with differing standard types (int, float). | +| test.c:242:3:242:16 | copysign(Val1,Val2) | Call to type-generic macro 'copysign' has arguments with differing standard types (int, float). | +| test.c:245:3:245:12 | fdim(Val1,Val2) | Call to type-generic macro 'fdim' has arguments with differing standard types (int, float). | +| test.c:248:3:248:14 | fma(Val1,Val2,Val3) | Call to type-generic macro 'fma' has arguments with differing standard types (float, int, int). | +| test.c:249:3:249:14 | fma(Val1,Val2,Val3) | Call to type-generic macro 'fma' has arguments with differing standard types (int, float, int). | +| test.c:250:3:250:14 | fma(Val1,Val2,Val3) | Call to type-generic macro 'fma' has arguments with differing standard types (int, int, float). | +| test.c:253:3:253:12 | fmax(Val1,Val2) | Call to type-generic macro 'fmax' has arguments with differing standard types (int, float). | +| test.c:256:3:256:12 | fmin(Val1,Val2) | Call to type-generic macro 'fmin' has arguments with differing standard types (int, float). | +| test.c:259:3:259:12 | fmod(Val1,Val2) | Call to type-generic macro 'fmod' has arguments with differing standard types (int, float). | +| test.c:262:3:262:13 | hypot(Val1,Val2) | Call to type-generic macro 'hypot' has arguments with differing standard types (int, float). | +| test.c:265:3:265:13 | ldexp(Val1,Val2) | Call to type-generic macro 'ldexp' has arguments with differing standard types (int, float). | +| test.c:268:3:268:17 | nextafter(Val1,Val2) | Call to type-generic macro 'nextafter' has arguments with differing standard types (int, float). | +| test.c:271:3:271:18 | nexttoward(Val1,Val2) | Call to type-generic macro 'nexttoward' has arguments with differing standard types (int, float). | +| test.c:274:3:274:17 | remainder(Val1,Val2) | Call to type-generic macro 'remainder' has arguments with differing standard types (int, float). | +| test.c:277:3:277:17 | remquo(Val1,Val2,Val3) | Call to type-generic macro 'remquo' has arguments with differing standard types (int, float). | +| test.c:280:3:280:15 | scalbln(Val1,Val2) | Call to type-generic macro 'scalbln' has arguments with differing standard types (int, float). | +| test.c:283:3:283:14 | scalbn(Val1,Val2) | Call to type-generic macro 'scalbn' has arguments with differing standard types (int, float). | diff --git a/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected index 967621d71f..0b17405a0e 100644 --- a/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected +++ b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected @@ -1,33 +1,33 @@ edges -| test.c:4:5:4:6 | *g2 | test.c:53:33:53:34 | g2 | provenance | | -| test.c:4:5:4:6 | *g2 | test.c:54:29:54:30 | g2 | provenance | | -| test.c:4:5:4:6 | *g2 | test.c:55:42:55:43 | g2 | provenance | | -| test.c:4:5:4:6 | *g2 | test.c:56:35:56:36 | g2 | provenance | | -| test.c:4:5:4:6 | *g2 | test.c:57:36:57:37 | g2 | provenance | | -| test.c:4:5:4:6 | *g2 | test.c:58:54:58:55 | g2 | provenance | | -| test.c:4:5:4:6 | *g2 | test.c:59:58:59:59 | g2 | provenance | | -| test.c:4:5:4:6 | *g2 | test.c:60:52:60:53 | g2 | provenance | | -| test.c:4:5:4:6 | *g2 | test.c:61:56:61:57 | g2 | provenance | | -| test.c:4:5:4:6 | *g2 | test.c:62:37:62:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:54:33:54:34 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:55:29:55:30 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:56:42:56:43 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:57:35:57:36 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:58:36:58:37 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:59:56:59:57 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:60:60:60:61 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:61:54:61:55 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:62:58:62:59 | g2 | provenance | | | test.c:4:5:4:6 | *g2 | test.c:63:37:63:38 | g2 | provenance | | -| test.c:4:5:4:6 | *g2 | test.c:64:36:64:37 | g2 | provenance | | -| test.c:4:5:4:6 | *g2 | test.c:65:37:65:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:64:37:64:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:65:36:65:37 | g2 | provenance | | | test.c:4:5:4:6 | *g2 | test.c:66:37:66:38 | g2 | provenance | | -| test.c:4:5:4:6 | *g2 | test.c:67:23:67:24 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:67:37:67:38 | g2 | provenance | | | test.c:4:5:4:6 | *g2 | test.c:68:23:68:24 | g2 | provenance | | -| test.c:4:5:4:6 | *g2 | test.c:71:23:71:24 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:69:23:69:24 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:72:23:72:24 | g2 | provenance | | | test.c:4:10:4:29 | memory_order_relaxed | test.c:4:5:4:6 | *g2 | provenance | | | test.c:4:10:4:29 | memory_order_relaxed | test.c:4:10:4:29 | memory_order_relaxed | provenance | | -| test.c:5:5:5:6 | *g3 | test.c:72:23:72:24 | g3 | provenance | | +| test.c:5:5:5:6 | *g3 | test.c:73:23:73:24 | g3 | provenance | | | test.c:5:10:5:29 | memory_order_acquire | test.c:5:5:5:6 | *g3 | provenance | | | test.c:5:10:5:29 | memory_order_acquire | test.c:5:10:5:29 | memory_order_acquire | provenance | | -| test.c:6:5:6:6 | *g4 | test.c:73:23:73:24 | g4 | provenance | | +| test.c:6:5:6:6 | *g4 | test.c:74:23:74:24 | g4 | provenance | | | test.c:6:10:6:29 | memory_order_consume | test.c:6:5:6:6 | *g4 | provenance | | | test.c:6:10:6:29 | memory_order_consume | test.c:6:10:6:29 | memory_order_consume | provenance | | -| test.c:7:5:7:6 | *g5 | test.c:74:23:74:24 | g5 | provenance | | +| test.c:7:5:7:6 | *g5 | test.c:75:23:75:24 | g5 | provenance | | | test.c:7:10:7:29 | memory_order_acq_rel | test.c:7:5:7:6 | *g5 | provenance | | | test.c:7:10:7:29 | memory_order_acq_rel | test.c:7:10:7:29 | memory_order_acq_rel | provenance | | -| test.c:8:5:8:6 | *g6 | test.c:75:23:75:24 | g6 | provenance | | +| test.c:8:5:8:6 | *g6 | test.c:76:23:76:24 | g6 | provenance | | | test.c:8:10:8:29 | memory_order_release | test.c:8:5:8:6 | *g6 | provenance | | | test.c:8:10:8:29 | memory_order_release | test.c:8:10:8:29 | memory_order_release | provenance | | nodes @@ -46,61 +46,61 @@ nodes | test.c:8:5:8:6 | *g6 | semmle.label | *g6 | | test.c:8:10:8:29 | memory_order_release | semmle.label | memory_order_release | | test.c:8:10:8:29 | memory_order_release | semmle.label | memory_order_release | -| test.c:16:29:16:48 | memory_order_relaxed | semmle.label | memory_order_relaxed | -| test.c:17:29:17:48 | memory_order_acquire | semmle.label | memory_order_acquire | -| test.c:18:29:18:48 | memory_order_consume | semmle.label | memory_order_consume | -| test.c:19:29:19:48 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | -| test.c:20:29:20:48 | memory_order_release | semmle.label | memory_order_release | -| test.c:53:33:53:34 | g2 | semmle.label | g2 | -| test.c:54:29:54:30 | g2 | semmle.label | g2 | -| test.c:55:42:55:43 | g2 | semmle.label | g2 | -| test.c:56:35:56:36 | g2 | semmle.label | g2 | -| test.c:57:36:57:37 | g2 | semmle.label | g2 | -| test.c:58:54:58:55 | g2 | semmle.label | g2 | -| test.c:59:58:59:59 | g2 | semmle.label | g2 | -| test.c:60:52:60:53 | g2 | semmle.label | g2 | -| test.c:61:56:61:57 | g2 | semmle.label | g2 | -| test.c:62:37:62:38 | g2 | semmle.label | g2 | +| test.c:17:29:17:48 | memory_order_relaxed | semmle.label | memory_order_relaxed | +| test.c:18:29:18:48 | memory_order_acquire | semmle.label | memory_order_acquire | +| test.c:19:29:19:48 | memory_order_consume | semmle.label | memory_order_consume | +| test.c:20:29:20:48 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | +| test.c:21:29:21:48 | memory_order_release | semmle.label | memory_order_release | +| test.c:54:33:54:34 | g2 | semmle.label | g2 | +| test.c:55:29:55:30 | g2 | semmle.label | g2 | +| test.c:56:42:56:43 | g2 | semmle.label | g2 | +| test.c:57:35:57:36 | g2 | semmle.label | g2 | +| test.c:58:36:58:37 | g2 | semmle.label | g2 | +| test.c:59:56:59:57 | g2 | semmle.label | g2 | +| test.c:60:60:60:61 | g2 | semmle.label | g2 | +| test.c:61:54:61:55 | g2 | semmle.label | g2 | +| test.c:62:58:62:59 | g2 | semmle.label | g2 | | test.c:63:37:63:38 | g2 | semmle.label | g2 | -| test.c:64:36:64:37 | g2 | semmle.label | g2 | -| test.c:65:37:65:38 | g2 | semmle.label | g2 | +| test.c:64:37:64:38 | g2 | semmle.label | g2 | +| test.c:65:36:65:37 | g2 | semmle.label | g2 | | test.c:66:37:66:38 | g2 | semmle.label | g2 | -| test.c:67:23:67:24 | g2 | semmle.label | g2 | +| test.c:67:37:67:38 | g2 | semmle.label | g2 | | test.c:68:23:68:24 | g2 | semmle.label | g2 | -| test.c:71:23:71:24 | g2 | semmle.label | g2 | -| test.c:72:23:72:24 | g3 | semmle.label | g3 | -| test.c:73:23:73:24 | g4 | semmle.label | g4 | -| test.c:74:23:74:24 | g5 | semmle.label | g5 | -| test.c:75:23:75:24 | g6 | semmle.label | g6 | -| test.c:79:23:79:23 | 1 | semmle.label | 1 | -| test.c:80:23:80:25 | 100 | semmle.label | 100 | +| test.c:69:23:69:24 | g2 | semmle.label | g2 | +| test.c:72:23:72:24 | g2 | semmle.label | g2 | +| test.c:73:23:73:24 | g3 | semmle.label | g3 | +| test.c:74:23:74:24 | g4 | semmle.label | g4 | +| test.c:75:23:75:24 | g5 | semmle.label | g5 | +| test.c:76:23:76:24 | g6 | semmle.label | g6 | +| test.c:80:23:80:23 | 1 | semmle.label | 1 | +| test.c:81:23:81:25 | 100 | semmle.label | 100 | subpaths #select -| test.c:16:29:16:48 | memory_order_relaxed | test.c:16:29:16:48 | memory_order_relaxed | test.c:16:29:16:48 | memory_order_relaxed | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_load | __c11_atomic_load | -| test.c:17:29:17:48 | memory_order_acquire | test.c:17:29:17:48 | memory_order_acquire | test.c:17:29:17:48 | memory_order_acquire | Invalid memory order '$@' in call to function '$@'. | memory_order_acquire | memory_order_acquire | file://:0:0:0:0 | __c11_atomic_load | __c11_atomic_load | -| test.c:18:29:18:48 | memory_order_consume | test.c:18:29:18:48 | memory_order_consume | test.c:18:29:18:48 | memory_order_consume | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | file://:0:0:0:0 | __c11_atomic_load | __c11_atomic_load | -| test.c:19:29:19:48 | memory_order_acq_rel | test.c:19:29:19:48 | memory_order_acq_rel | test.c:19:29:19:48 | memory_order_acq_rel | Invalid memory order '$@' in call to function '$@'. | memory_order_acq_rel | memory_order_acq_rel | file://:0:0:0:0 | __c11_atomic_load | __c11_atomic_load | -| test.c:20:29:20:48 | memory_order_release | test.c:20:29:20:48 | memory_order_release | test.c:20:29:20:48 | memory_order_release | Invalid memory order '$@' in call to function '$@'. | memory_order_release | memory_order_release | file://:0:0:0:0 | __c11_atomic_load | __c11_atomic_load | -| test.c:53:33:53:34 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:53:33:53:34 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_store | __c11_atomic_store | -| test.c:54:29:54:30 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:54:29:54:30 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_load | __c11_atomic_load | -| test.c:55:42:55:43 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:55:42:55:43 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_exchange | __c11_atomic_exchange | -| test.c:56:35:56:36 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:56:35:56:36 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_store | __c11_atomic_store | -| test.c:57:36:57:37 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:57:36:57:37 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_exchange | __c11_atomic_exchange | -| test.c:58:54:58:55 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:58:54:58:55 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_compare_exchange_strong | __c11_atomic_compare_exchange_strong | -| test.c:59:58:59:59 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:59:58:59:59 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_compare_exchange_strong | __c11_atomic_compare_exchange_strong | -| test.c:60:52:60:53 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:60:52:60:53 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_compare_exchange_weak | __c11_atomic_compare_exchange_weak | -| test.c:61:56:61:57 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:61:56:61:57 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_compare_exchange_weak | __c11_atomic_compare_exchange_weak | -| test.c:62:37:62:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:62:37:62:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_fetch_add | __c11_atomic_fetch_add | -| test.c:63:37:63:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:63:37:63:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_fetch_sub | __c11_atomic_fetch_sub | -| test.c:64:36:64:37 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:64:36:64:37 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_fetch_or | __c11_atomic_fetch_or | -| test.c:65:37:65:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:65:37:65:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_fetch_xor | __c11_atomic_fetch_xor | -| test.c:66:37:66:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:66:37:66:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_fetch_and | __c11_atomic_fetch_and | -| test.c:67:23:67:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:67:23:67:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | -| test.c:68:23:68:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:68:23:68:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_signal_fence | __c11_atomic_signal_fence | -| test.c:71:23:71:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:71:23:71:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | -| test.c:72:23:72:24 | g3 | test.c:5:10:5:29 | memory_order_acquire | test.c:72:23:72:24 | g3 | Invalid memory order '$@' in call to function '$@'. | memory_order_acquire | memory_order_acquire | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | -| test.c:73:23:73:24 | g4 | test.c:6:10:6:29 | memory_order_consume | test.c:73:23:73:24 | g4 | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | -| test.c:74:23:74:24 | g5 | test.c:7:10:7:29 | memory_order_acq_rel | test.c:74:23:74:24 | g5 | Invalid memory order '$@' in call to function '$@'. | memory_order_acq_rel | memory_order_acq_rel | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | -| test.c:75:23:75:24 | g6 | test.c:8:10:8:29 | memory_order_release | test.c:75:23:75:24 | g6 | Invalid memory order '$@' in call to function '$@'. | memory_order_release | memory_order_release | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | -| test.c:79:23:79:23 | 1 | test.c:79:23:79:23 | 1 | test.c:79:23:79:23 | 1 | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | -| test.c:80:23:80:25 | 100 | test.c:80:23:80:25 | 100 | test.c:80:23:80:25 | 100 | Invalid memory order '$@' in call to function '$@'. | 100 | 100 | file://:0:0:0:0 | __c11_atomic_thread_fence | __c11_atomic_thread_fence | +| test.c:17:29:17:48 | memory_order_relaxed | test.c:17:29:17:48 | memory_order_relaxed | test.c:17:29:17:48 | memory_order_relaxed | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:18:29:18:48 | memory_order_acquire | test.c:18:29:18:48 | memory_order_acquire | test.c:18:29:18:48 | memory_order_acquire | Invalid memory order '$@' in call to function '$@'. | memory_order_acquire | memory_order_acquire | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:19:29:19:48 | memory_order_consume | test.c:19:29:19:48 | memory_order_consume | test.c:19:29:19:48 | memory_order_consume | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:20:29:20:48 | memory_order_acq_rel | test.c:20:29:20:48 | memory_order_acq_rel | test.c:20:29:20:48 | memory_order_acq_rel | Invalid memory order '$@' in call to function '$@'. | memory_order_acq_rel | memory_order_acq_rel | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:21:29:21:48 | memory_order_release | test.c:21:29:21:48 | memory_order_release | test.c:21:29:21:48 | memory_order_release | Invalid memory order '$@' in call to function '$@'. | memory_order_release | memory_order_release | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:54:33:54:34 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:54:33:54:34 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_store_explicit | +| test.c:55:29:55:30 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:55:29:55:30 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:56:42:56:43 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:56:42:56:43 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_flag_test_and_set_explicit | +| test.c:57:35:57:36 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:57:35:57:36 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_flag_clear_explicit | +| test.c:58:36:58:37 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:58:36:58:37 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_exchange_explicit | +| test.c:59:56:59:57 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:59:56:59:57 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_strong_explicit | +| test.c:60:60:60:61 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:60:60:60:61 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_strong_explicit | +| test.c:61:54:61:55 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:61:54:61:55 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_weak_explicit | +| test.c:62:58:62:59 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:62:58:62:59 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_weak_explicit | +| test.c:63:37:63:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:63:37:63:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_add_explicit | +| test.c:64:37:64:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:64:37:64:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_sub_explicit | +| test.c:65:36:65:37 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:65:36:65:37 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_or_explicit | +| test.c:66:37:66:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:66:37:66:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_xor_explicit | +| test.c:67:37:67:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:67:37:67:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_and_explicit | +| test.c:68:23:68:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:68:23:68:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:69:23:69:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:69:23:69:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_signal_fence | +| test.c:72:23:72:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:72:23:72:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:73:23:73:24 | g3 | test.c:5:10:5:29 | memory_order_acquire | test.c:73:23:73:24 | g3 | Invalid memory order '$@' in call to function '$@'. | memory_order_acquire | memory_order_acquire | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:74:23:74:24 | g4 | test.c:6:10:6:29 | memory_order_consume | test.c:74:23:74:24 | g4 | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:75:23:75:24 | g5 | test.c:7:10:7:29 | memory_order_acq_rel | test.c:75:23:75:24 | g5 | Invalid memory order '$@' in call to function '$@'. | memory_order_acq_rel | memory_order_acq_rel | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:76:23:76:24 | g6 | test.c:8:10:8:29 | memory_order_release | test.c:76:23:76:24 | g6 | Invalid memory order '$@' in call to function '$@'. | memory_order_release | memory_order_release | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:80:23:80:23 | 1 | test.c:80:23:80:23 | 1 | test.c:80:23:80:23 | 1 | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:81:23:81:25 | 100 | test.c:81:23:81:25 | 100 | test.c:81:23:81:25 | 100 | Invalid memory order '$@' in call to function '$@'. | 100 | 100 | Invocation of a standard function implemented as a macro | atomic_thread_fence | diff --git a/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected.gcc b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected.gcc new file mode 100644 index 0000000000..db07e0aa33 --- /dev/null +++ b/c/misra/test/rules/RULE-21-25/InvalidMemoryOrderArgument.expected.gcc @@ -0,0 +1,106 @@ +edges +| test.c:4:5:4:6 | *g2 | test.c:54:33:54:34 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:55:29:55:30 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:56:42:56:43 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:57:35:57:36 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:58:36:58:37 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:59:56:59:57 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:60:60:60:61 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:61:54:61:55 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:62:58:62:59 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:63:37:63:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:64:37:64:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:65:36:65:37 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:66:37:66:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:67:37:67:38 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:68:23:68:24 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:69:23:69:24 | g2 | provenance | | +| test.c:4:5:4:6 | *g2 | test.c:72:23:72:24 | g2 | provenance | | +| test.c:4:10:4:29 | memory_order_relaxed | test.c:4:5:4:6 | *g2 | provenance | | +| test.c:4:10:4:29 | memory_order_relaxed | test.c:4:10:4:29 | memory_order_relaxed | provenance | | +| test.c:5:5:5:6 | *g3 | test.c:73:23:73:24 | g3 | provenance | | +| test.c:5:10:5:29 | memory_order_acquire | test.c:5:5:5:6 | *g3 | provenance | | +| test.c:5:10:5:29 | memory_order_acquire | test.c:5:10:5:29 | memory_order_acquire | provenance | | +| test.c:6:5:6:6 | *g4 | test.c:74:23:74:24 | g4 | provenance | | +| test.c:6:10:6:29 | memory_order_consume | test.c:6:5:6:6 | *g4 | provenance | | +| test.c:6:10:6:29 | memory_order_consume | test.c:6:10:6:29 | memory_order_consume | provenance | | +| test.c:7:5:7:6 | *g5 | test.c:75:23:75:24 | g5 | provenance | | +| test.c:7:10:7:29 | memory_order_acq_rel | test.c:7:5:7:6 | *g5 | provenance | | +| test.c:7:10:7:29 | memory_order_acq_rel | test.c:7:10:7:29 | memory_order_acq_rel | provenance | | +| test.c:8:5:8:6 | *g6 | test.c:76:23:76:24 | g6 | provenance | | +| test.c:8:10:8:29 | memory_order_release | test.c:8:5:8:6 | *g6 | provenance | | +| test.c:8:10:8:29 | memory_order_release | test.c:8:10:8:29 | memory_order_release | provenance | | +nodes +| test.c:4:5:4:6 | *g2 | semmle.label | *g2 | +| test.c:4:10:4:29 | memory_order_relaxed | semmle.label | memory_order_relaxed | +| test.c:4:10:4:29 | memory_order_relaxed | semmle.label | memory_order_relaxed | +| test.c:5:5:5:6 | *g3 | semmle.label | *g3 | +| test.c:5:10:5:29 | memory_order_acquire | semmle.label | memory_order_acquire | +| test.c:5:10:5:29 | memory_order_acquire | semmle.label | memory_order_acquire | +| test.c:6:5:6:6 | *g4 | semmle.label | *g4 | +| test.c:6:10:6:29 | memory_order_consume | semmle.label | memory_order_consume | +| test.c:6:10:6:29 | memory_order_consume | semmle.label | memory_order_consume | +| test.c:7:5:7:6 | *g5 | semmle.label | *g5 | +| test.c:7:10:7:29 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | +| test.c:7:10:7:29 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | +| test.c:8:5:8:6 | *g6 | semmle.label | *g6 | +| test.c:8:10:8:29 | memory_order_release | semmle.label | memory_order_release | +| test.c:8:10:8:29 | memory_order_release | semmle.label | memory_order_release | +| test.c:17:3:17:49 | memory_order_relaxed | semmle.label | memory_order_relaxed | +| test.c:18:3:18:49 | memory_order_acquire | semmle.label | memory_order_acquire | +| test.c:19:3:19:49 | memory_order_consume | semmle.label | memory_order_consume | +| test.c:20:3:20:49 | memory_order_acq_rel | semmle.label | memory_order_acq_rel | +| test.c:21:3:21:49 | memory_order_release | semmle.label | memory_order_release | +| test.c:54:33:54:34 | g2 | semmle.label | g2 | +| test.c:55:29:55:30 | g2 | semmle.label | g2 | +| test.c:56:42:56:43 | g2 | semmle.label | g2 | +| test.c:57:35:57:36 | g2 | semmle.label | g2 | +| test.c:58:36:58:37 | g2 | semmle.label | g2 | +| test.c:59:56:59:57 | g2 | semmle.label | g2 | +| test.c:60:60:60:61 | g2 | semmle.label | g2 | +| test.c:61:54:61:55 | g2 | semmle.label | g2 | +| test.c:62:58:62:59 | g2 | semmle.label | g2 | +| test.c:63:37:63:38 | g2 | semmle.label | g2 | +| test.c:64:37:64:38 | g2 | semmle.label | g2 | +| test.c:65:36:65:37 | g2 | semmle.label | g2 | +| test.c:66:37:66:38 | g2 | semmle.label | g2 | +| test.c:67:37:67:38 | g2 | semmle.label | g2 | +| test.c:68:23:68:24 | g2 | semmle.label | g2 | +| test.c:69:23:69:24 | g2 | semmle.label | g2 | +| test.c:72:23:72:24 | g2 | semmle.label | g2 | +| test.c:73:23:73:24 | g3 | semmle.label | g3 | +| test.c:74:23:74:24 | g4 | semmle.label | g4 | +| test.c:75:23:75:24 | g5 | semmle.label | g5 | +| test.c:76:23:76:24 | g6 | semmle.label | g6 | +| test.c:80:23:80:23 | 1 | semmle.label | 1 | +| test.c:81:23:81:25 | 100 | semmle.label | 100 | +subpaths +#select +| test.c:17:3:17:49 | memory_order_relaxed | test.c:17:3:17:49 | memory_order_relaxed | test.c:17:3:17:49 | memory_order_relaxed | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:18:3:18:49 | memory_order_acquire | test.c:18:3:18:49 | memory_order_acquire | test.c:18:3:18:49 | memory_order_acquire | Invalid memory order '$@' in call to function '$@'. | memory_order_acquire | memory_order_acquire | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:19:3:19:49 | memory_order_consume | test.c:19:3:19:49 | memory_order_consume | test.c:19:3:19:49 | memory_order_consume | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:20:3:20:49 | memory_order_acq_rel | test.c:20:3:20:49 | memory_order_acq_rel | test.c:20:3:20:49 | memory_order_acq_rel | Invalid memory order '$@' in call to function '$@'. | memory_order_acq_rel | memory_order_acq_rel | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:21:3:21:49 | memory_order_release | test.c:21:3:21:49 | memory_order_release | test.c:21:3:21:49 | memory_order_release | Invalid memory order '$@' in call to function '$@'. | memory_order_release | memory_order_release | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:54:33:54:34 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:54:33:54:34 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_store_explicit | +| test.c:55:29:55:30 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:55:29:55:30 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_load_explicit | +| test.c:56:42:56:43 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:56:42:56:43 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_flag_test_and_set_explicit | +| test.c:57:35:57:36 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:57:35:57:36 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_flag_clear_explicit | +| test.c:58:36:58:37 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:58:36:58:37 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_exchange_explicit | +| test.c:59:56:59:57 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:59:56:59:57 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_strong_explicit | +| test.c:60:60:60:61 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:60:60:60:61 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_strong_explicit | +| test.c:61:54:61:55 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:61:54:61:55 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_weak_explicit | +| test.c:62:58:62:59 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:62:58:62:59 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_compare_exchange_weak_explicit | +| test.c:63:37:63:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:63:37:63:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_add_explicit | +| test.c:64:37:64:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:64:37:64:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_sub_explicit | +| test.c:65:36:65:37 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:65:36:65:37 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_or_explicit | +| test.c:66:37:66:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:66:37:66:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_xor_explicit | +| test.c:67:37:67:38 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:67:37:67:38 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_fetch_and_explicit | +| test.c:68:23:68:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:68:23:68:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:69:23:69:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:69:23:69:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_signal_fence | +| test.c:72:23:72:24 | g2 | test.c:4:10:4:29 | memory_order_relaxed | test.c:72:23:72:24 | g2 | Invalid memory order '$@' in call to function '$@'. | memory_order_relaxed | memory_order_relaxed | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:73:23:73:24 | g3 | test.c:5:10:5:29 | memory_order_acquire | test.c:73:23:73:24 | g3 | Invalid memory order '$@' in call to function '$@'. | memory_order_acquire | memory_order_acquire | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:74:23:74:24 | g4 | test.c:6:10:6:29 | memory_order_consume | test.c:74:23:74:24 | g4 | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:75:23:75:24 | g5 | test.c:7:10:7:29 | memory_order_acq_rel | test.c:75:23:75:24 | g5 | Invalid memory order '$@' in call to function '$@'. | memory_order_acq_rel | memory_order_acq_rel | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:76:23:76:24 | g6 | test.c:8:10:8:29 | memory_order_release | test.c:76:23:76:24 | g6 | Invalid memory order '$@' in call to function '$@'. | memory_order_release | memory_order_release | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:80:23:80:23 | 1 | test.c:80:23:80:23 | 1 | test.c:80:23:80:23 | 1 | Invalid memory order '$@' in call to function '$@'. | memory_order_consume | memory_order_consume | Invocation of a standard function implemented as a macro | atomic_thread_fence | +| test.c:81:23:81:25 | 100 | test.c:81:23:81:25 | 100 | test.c:81:23:81:25 | 100 | Invalid memory order '$@' in call to function '$@'. | 100 | 100 | Invocation of a standard function implemented as a macro | atomic_thread_fence | diff --git a/c/misra/test/rules/RULE-21-25/test.c b/c/misra/test/rules/RULE-21-25/test.c index d1831785ba..fc9fc67e95 100644 --- a/c/misra/test/rules/RULE-21-25/test.c +++ b/c/misra/test/rules/RULE-21-25/test.c @@ -1,4 +1,4 @@ -#include "stdatomic.h" +#include int g1 = memory_order_seq_cst; int g2 = memory_order_relaxed; @@ -6,6 +6,7 @@ int g3 = memory_order_acquire; int g4 = memory_order_consume; int g5 = memory_order_acq_rel; int g6 = memory_order_release; +int *ptr; void f(int p) { _Atomic int l1; @@ -25,8 +26,8 @@ void f(int p) { atomic_flag_test_and_set(&l2); // COMPLIANT atomic_flag_clear(&l2); // COMPLIANT atomic_exchange(&l1, 0); // COMPLIANT - atomic_compare_exchange_strong(&l1, 0, 1); // COMPLIANT - atomic_compare_exchange_weak(&l1, 0, 1); // COMPLIANT + atomic_compare_exchange_strong(&l1, ptr, 1); // COMPLIANT + atomic_compare_exchange_weak(&l1, ptr, 1); // COMPLIANT atomic_fetch_add(&l1, 0); // COMPLIANT atomic_fetch_sub(&l1, 0); // COMPLIANT atomic_fetch_or(&l1, 0); // COMPLIANT @@ -39,8 +40,8 @@ void f(int p) { atomic_flag_test_and_set_explicit(&l2, g1); // COMPLIANT atomic_flag_clear_explicit(&l2, g1); // COMPLIANT atomic_exchange_explicit(&l1, 0, g1); // COMPLIANT - atomic_compare_exchange_strong_explicit(&l1, 0, 1, g1, g1); // COMPLIANT - atomic_compare_exchange_weak_explicit(&l1, 0, 1, g1, g1); // COMPLIANT + atomic_compare_exchange_strong_explicit(&l1, ptr, 1, g1, g1); // COMPLIANT + atomic_compare_exchange_weak_explicit(&l1, ptr, 1, g1, g1); // COMPLIANT atomic_fetch_add_explicit(&l1, 0, g1); // COMPLIANT atomic_fetch_sub_explicit(&l1, 0, g1); // COMPLIANT atomic_fetch_or_explicit(&l1, 0, g1); // COMPLIANT @@ -55,10 +56,10 @@ void f(int p) { atomic_flag_test_and_set_explicit(&l2, g2); // NON-COMPLIANT atomic_flag_clear_explicit(&l2, g2); // NON-COMPLIANT atomic_exchange_explicit(&l1, 0, g2); // NON-COMPLIANT - atomic_compare_exchange_strong_explicit(&l1, 0, 1, g2, g1); // NON-COMPLIANT - atomic_compare_exchange_strong_explicit(&l1, 0, 1, g1, g2); // NON-COMPLIANT - atomic_compare_exchange_weak_explicit(&l1, 0, 1, g2, g1); // NON-COMPLIANT - atomic_compare_exchange_weak_explicit(&l1, 0, 1, g1, g2); // NON-COMPLIANT + atomic_compare_exchange_strong_explicit(&l1, ptr, 1, g2, g1); // NON-COMPLIANT + atomic_compare_exchange_strong_explicit(&l1, ptr, 1, g1, g2); // NON-COMPLIANT + atomic_compare_exchange_weak_explicit(&l1, ptr, 1, g2, g1); // NON-COMPLIANT + atomic_compare_exchange_weak_explicit(&l1, ptr, 1, g1, g2); // NON-COMPLIANT atomic_fetch_add_explicit(&l1, 0, g2); // NON-COMPLIANT atomic_fetch_sub_explicit(&l1, 0, g2); // NON-COMPLIANT atomic_fetch_or_explicit(&l1, 0, g2); // NON-COMPLIANT diff --git a/c/misra/test/rules/RULE-21-26/test.c b/c/misra/test/rules/RULE-21-26/test.c index d26f9c1f2f..b08f7e54a1 100644 --- a/c/misra/test/rules/RULE-21-26/test.c +++ b/c/misra/test/rules/RULE-21-26/test.c @@ -9,7 +9,7 @@ struct timespec ts = {0, 0}; void doTimeLock(mtx_t *m) { mtx_timedlock(m, &ts); } -void main(void) { +int main(int argc, char *argv[]) { mtx_init(&g1, mtx_plain); mtx_timedlock(&g1, &ts); // NON-COMPLIANT doTimeLock(&g1); // NON-COMPLIANT diff --git a/c/misra/test/rules/RULE-22-16/test.c b/c/misra/test/rules/RULE-22-16/test.c index c97fb3d588..723516509f 100644 --- a/c/misra/test/rules/RULE-22-16/test.c +++ b/c/misra/test/rules/RULE-22-16/test.c @@ -41,7 +41,7 @@ void f6(int p) { goto skipped; } mtx_unlock(&m); -skipped: +skipped:; } void f7(int p) { diff --git a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected.gcc b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected.gcc index f1054946a7..6f3d414214 100644 --- a/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected.gcc +++ b/c/misra/test/rules/RULE-8-15/RedeclarationOfObjectWithUnmatchedAlignment.expected.gcc @@ -1,10 +1,10 @@ -| test.c:11:8:11:15 | alignas(...) | Variable g4 declared with lexically different _Alignof() values '$@' and '$@' | test.c:11:8:11:15 | alignas(...) | 16 | test.c:12:8:12:15 | alignas(...) | 32 | -| test.c:12:8:12:15 | alignas(...) | Variable g4 declared with lexically different _Alignof() values '$@' and '$@' | test.c:12:8:12:15 | alignas(...) | 32 | test.c:11:8:11:15 | alignas(...) | 16 | -| test.c:18:8:18:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@' | test.c:18:8:18:15 | alignas(...) | int | test.c:19:8:19:15 | alignas(...) | 4 | -| test.c:19:8:19:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@' | test.c:19:8:19:15 | alignas(...) | 4 | test.c:18:8:18:15 | alignas(...) | int | -| test.c:22:8:22:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@' | test.c:22:8:22:15 | alignas(...) | ... * ... | test.c:23:8:23:15 | alignas(...) | 32 | -| test.c:23:8:23:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@' | test.c:23:8:23:15 | alignas(...) | 32 | test.c:22:8:22:15 | alignas(...) | ... * ... | -| test.c:28:8:28:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@' | test.c:28:8:28:15 | alignas(...) | ... * ... | test.c:29:8:29:15 | alignas(...) | ... * ... | -| test.c:29:8:29:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@' | test.c:29:8:29:15 | alignas(...) | ... * ... | test.c:28:8:28:15 | alignas(...) | ... * ... | -| test.c:34:8:34:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@' | test.c:34:8:34:15 | alignas(...) | signed int | test.c:35:8:35:15 | alignas(...) | unsigned int | -| test.c:35:8:35:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@' | test.c:35:8:35:15 | alignas(...) | unsigned int | test.c:34:8:34:15 | alignas(...) | signed int | +| test.c:11:8:11:15 | alignas(...) | Variable g4 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:11:8:11:15 | alignas(...) | 16 | test.c:12:8:12:15 | alignas(...) | 32 | +| test.c:12:8:12:15 | alignas(...) | Variable g4 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:12:8:12:15 | alignas(...) | 32 | test.c:11:8:11:15 | alignas(...) | 16 | +| test.c:18:8:18:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:18:8:18:15 | alignas(...) | int | test.c:19:8:19:15 | alignas(...) | 4 | +| test.c:19:8:19:15 | alignas(...) | Variable g6 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:19:8:19:15 | alignas(...) | 4 | test.c:18:8:18:15 | alignas(...) | int | +| test.c:22:8:22:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:22:8:22:15 | alignas(...) | ... * ... | test.c:23:8:23:15 | alignas(...) | 32 | +| test.c:23:8:23:15 | alignas(...) | Variable g7 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:23:8:23:15 | alignas(...) | 32 | test.c:22:8:22:15 | alignas(...) | ... * ... | +| test.c:28:8:28:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:28:8:28:15 | alignas(...) | ... * ... | test.c:29:8:29:15 | alignas(...) | ... * ... | +| test.c:29:8:29:15 | alignas(...) | Variable g9 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:29:8:29:15 | alignas(...) | ... * ... | test.c:28:8:28:15 | alignas(...) | ... * ... | +| test.c:34:8:34:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:34:8:34:15 | alignas(...) | signed int | test.c:35:8:35:15 | alignas(...) | unsigned int | +| test.c:35:8:35:15 | alignas(...) | Variable g11 declared with lexically different _Alignof() values '$@' and '$@'. | test.c:35:8:35:15 | alignas(...) | unsigned int | test.c:34:8:34:15 | alignas(...) | signed int | diff --git a/c/misra/test/rules/RULE-9-7/test.c b/c/misra/test/rules/RULE-9-7/test.c index da367c0bd1..90645f6372 100644 --- a/c/misra/test/rules/RULE-9-7/test.c +++ b/c/misra/test/rules/RULE-9-7/test.c @@ -4,7 +4,7 @@ _Atomic int g1; // COMPLIANT _Atomic int g2 = 0; // COMPLIANT -void f_thread(void *x); +int f_thread(void *x); void f_starts_thread() { thrd_t t; @@ -13,7 +13,7 @@ void f_starts_thread() { void f_may_initialize_argument(void *p1) {} -void main() { +int main(int argc, char *argv[]) { _Atomic int l1 = 1; // COMPLIANT f_starts_thread(); diff --git a/change_notes/2025-04-08-address-cross-compiler-compatibility-in-misra-2023.md b/change_notes/2025-04-08-address-cross-compiler-compatibility-in-misra-2023.md new file mode 100644 index 0000000000..abe4c2bba8 --- /dev/null +++ b/change_notes/2025-04-08-address-cross-compiler-compatibility-in-misra-2023.md @@ -0,0 +1,12 @@ + - `RULE-21-22`, `RULE-21-23` - `TgMathArgumentWithInvalidEssentialType.ql`, `TgMathArgumentsWithDifferingStandardType.ql` + - Change type-generic macro analysis for finding macro parameters to be compatible with gcc, by ignoring early arguments inserted by gcc. + - Change explicit conversion logic to ignore the explicit casts inserted in macro bodies by clang, which previously overruled the argument essential type. + - `RULE-13-2` - `UnsequencedAtomicReads.ql`: + - Handle statement expression implementation of atomic operations in gcc. + - `RULE-21-25` - `InvalidMemoryOrderArgument.ql`: + - Handle case of where the enum `memory_order` is declared via a typedef as an anonymous enum. + - Rewrite how atomically sequenced operations are found; no longer look for builtins or internal functions, instead look for macros with the exact expected name and analyze the macro bodies for the memory sequence parameter. + - `RULE-9-7` - `UninitializedAtomicArgument.ql`: + - Handle gcc case where `atomic_init` is defined is a call to `atomic_store`, and take a more flexible approach to finding the initialized atomic variable. + - `DIR-4-15` - `PossibleMisuseOfUndetectedInfinity.ql`, `PossibleMisuseOfUndetectedNaN.ql`: + - Fix issue when analyzing clang/gcc implementations of floating point classification macros, where analysis incorrectly determined that `x` in `isinf(x)` was guaranteed to be infinite at the call site itself, affecting later analysis involving `x`. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/FloatingPoint.qll b/cpp/common/src/codingstandards/cpp/FloatingPoint.qll index f5ff2fefca..e2a13bd62e 100644 --- a/cpp/common/src/codingstandards/cpp/FloatingPoint.qll +++ b/cpp/common/src/codingstandards/cpp/FloatingPoint.qll @@ -325,7 +325,8 @@ predicate guardedNotFPClass(Expr e, FPClassification cls) { hashCons(checked) = hashCons(e) and guard.controls(e, cmpEq) and guard.constrainsFPClass(checked, constraint, cmpEq) and - constraint.mustNotBe(cls) + constraint.mustNotBe(cls) and + not checked = e ) } diff --git a/cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll b/cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll index 1067b7ad09..ec4873d20e 100644 --- a/cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll +++ b/cpp/common/src/codingstandards/cpp/StdFunctionOrMacro.qll @@ -3,28 +3,21 @@ * implement a function as a macro: the class `StdFunctionOrMacro<...>::Call` matches both std * function calls as well as std function macro expansions. * - * For instance, `atomic_init` may be implemented as a function, but is also implemented as - * `#DEFINE atomic_init(x) __c11_atomic_init(x)` on some platforms. This module aids in finding - * calls to any standard function which may be a macro, and has predefined behavior for - * handling `__c11_*` macros. + * For instance, `atomic_init` may be implemented as a function, but is also implemented as a + * complicated macro on some platforms. This module aids in finding calls to any standard function + * which may be a macro. * * Since a macro can be defined to expand to any expression, we cannot know generally which - * expanded expressions in `f(x, y)` correspond to arguments `x` or `y`. To handle this, the - * following inference options are available: - * - `NoMacroExpansionInference`: Assume any expression in the macro expansion could correspond to - * any macro argument. - * - `C11FunctionWrapperMacro`: Check if the macro expands to a function call prefixed with - * `__c11_` and if so, return the corresponding argument. Otherwise, fall back to - * `NoMacroExpansionInference`. - * - `InferMacroExpansionArguments`: Implement your own logic for inferring the argument. + * expanded expressions in `f(x, y)` correspond to arguments `x` or `y`. To handle this, implement + * the module `InferMacroExpansionArguments`. * - * To use this module, pick one of the above inference strategies, and then create a predicate for - * the name you wish to match. For instance: + * To match a function of a particular name create a predicate for the name you wish to match. For + * instance: * * ```codeql * private string atomicInit() { result = "atomic_init" } * - * from StdFunctionOrMacro::Call c + * from StdFunctionOrMacro::Call c * select c.getArgument(0) * ``` */ @@ -33,7 +26,7 @@ import cpp as cpp private string atomicInit() { result = "atomic_init" } -class AtomicInitCall = StdFunctionOrMacro::Call; +class AtomicInitCall = StdFunctionOrMacro::Call; /** Specify the name of your function as a predicate */ private signature string getName(); @@ -44,15 +37,72 @@ private signature module InferMacroExpansionArguments { cpp::Expr inferArgument(cpp::MacroInvocation mi, int argumentIdx); } -/** Assume macro `f(x, y, ...)` expands to `__c11_f(x, y, ...)`. */ -private module C11FunctionWrapperMacro implements InferMacroExpansionArguments { +private module InferAtomicMacroArgs implements InferMacroExpansionArguments { + bindingset[pattern] + private cpp::Expr getMacroVarInitializer(cpp::MacroInvocation mi, string pattern) { + exists(cpp::VariableDeclarationEntry decl | + mi.getAGeneratedElement() = decl and + decl.getName().matches(pattern) and + result = decl.getDeclaration().getInitializer().getExpr() + ) + } + bindingset[mi, argumentIdx] cpp::Expr inferArgument(cpp::MacroInvocation mi, int argumentIdx) { - exists(cpp::FunctionCall fc | - fc = mi.getExpr() and - fc.getTarget().hasName("__c11_" + mi.getMacroName()) and - result = mi.getExpr().(cpp::FunctionCall).getArgument(argumentIdx) - ) + result = mi.getExpr().(cpp::FunctionCall).getArgument(argumentIdx) + or + if + argumentIdx = 0 and + exists(getMacroVarInitializer(mi, "__atomic_%_ptr")) + then result = getMacroVarInitializer(mi, "__atomic_%_ptr") + else + if + argumentIdx = [1, 2] and + exists(getMacroVarInitializer(mi, "__atomic_%_tmp")) + then result = getMacroVarInitializer(mi, "__atomic_%_tmp") + else + exists(cpp::FunctionCall fc | + fc = mi.getAnExpandedElement() and + fc.getTarget().getName().matches("%atomic_%") and + result = fc.getArgument(argumentIdx) + ) + } +} + +private string atomicReadOrWriteName() { + result = + [ + "atomic_load", + "atomic_store", + "atomic_fetch_" + ["add", "sub", "or", "xor", "and"], + "atomic_exchange", + "atomic_compare_exchange_" + ["strong", "weak"] + ] + ["", "_explicit"] +} + +class AtomicReadOrWriteCall = + StdFunctionOrMacro::Call; + +private string atomicallySequencedName() { + result = + [ + "atomic_thread_fence", + "atomic_signal_fence", + "atomic_flag_clear_explicit", + "atomic_flag_test_and_set_explicit", + ] + or + result = atomicReadOrWriteName() and + result.matches("%_explicit") +} + +/** A `stdatomic.h` function which accepts a `memory_order` value as a parameter. */ +class AtomicallySequencedCall extends StdFunctionOrMacro::Call +{ + cpp::Expr getAMemoryOrderArgument() { + if getName() = "atomic_compare_exchange_" + ["strong", "weak"] + "_explicit" + then result = getArgument(getNumberOfArguments() - [1, 2]) + else result = getArgument(getNumberOfArguments() - 1) } } @@ -66,7 +116,7 @@ private module C11FunctionWrapperMacro implements InferMacroExpansionArguments { * * ```codeql * private string atomicInit() { result = "atomic_init" } - * from StdFunctionOrMacro::Call c + * from StdFunctionOrMacro::Call c * select c.getArgument(0) * ``` */ @@ -99,6 +149,25 @@ private module StdFunctionOrMacro Date: Tue, 8 Apr 2025 22:22:59 +0000 Subject: [PATCH 337/628] Format c tests, c ql files --- .../TgMathArgumentWithInvalidEssentialType.ql | 4 +- ...gMathArgumentsWithDifferingStandardType.ql | 4 +- .../RULE-21-25/InvalidMemoryOrderArgument.ql | 4 +- c/misra/test/rules/RULE-18-10/test.c | 6 +- c/misra/test/rules/RULE-18-8/test.c | 2 +- c/misra/test/rules/RULE-21-22/test.c | 8 +-- c/misra/test/rules/RULE-21-25/test.c | 68 +++++++++---------- 7 files changed, 47 insertions(+), 49 deletions(-) diff --git a/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql b/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql index 3c918c10d3..fc8565ade5 100644 --- a/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql +++ b/c/misra/src/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.ql @@ -34,7 +34,9 @@ string getAllowedTypesString(TgMathInvocation call) { else result = "essentially signed, unsigned, or real floating type" } -from TgMathInvocation call, Expr convertedArg, Expr unconverted, int argIndex, Type type, EssentialTypeCategory category +from + TgMathInvocation call, Expr convertedArg, Expr unconverted, int argIndex, Type type, + EssentialTypeCategory category where not isExcluded(call, EssentialTypes2Package::tgMathArgumentWithInvalidEssentialTypeQuery()) and // We must handle conversions specially, as clang inserts casts in the macro body we want to ignore. diff --git a/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql b/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql index 1a19249982..34d3b62b2c 100644 --- a/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql +++ b/c/misra/src/rules/RULE-21-23/TgMathArgumentsWithDifferingStandardType.ql @@ -58,9 +58,7 @@ Type canonicalize(Type type) { else result = type } -Type getEffectiveStandardType(Expr e) { - result = canonicalize(getPromotedType(e)) -} +Type getEffectiveStandardType(Expr e) { result = canonicalize(getPromotedType(e)) } from TgMathInvocation call, Type firstType where diff --git a/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql b/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql index a7b599316a..684b4e50cb 100644 --- a/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql +++ b/c/misra/src/rules/RULE-21-25/InvalidMemoryOrderArgument.ql @@ -77,9 +77,7 @@ module MemoryOrderFlowConfig implements DataFlow::ConfigSig { } predicate isSink(DataFlow::Node node) { - exists(AtomicallySequencedCall call | - call.getAMemoryOrderArgument() = node.asExpr() - ) + exists(AtomicallySequencedCall call | call.getAMemoryOrderArgument() = node.asExpr()) } } diff --git a/c/misra/test/rules/RULE-18-10/test.c b/c/misra/test/rules/RULE-18-10/test.c index b5906a3039..565b51e8de 100644 --- a/c/misra/test/rules/RULE-18-10/test.c +++ b/c/misra/test/rules/RULE-18-10/test.c @@ -57,9 +57,9 @@ void f1( } p20, // Unknown array length types: - int p21[], // COMPLIANT - int p22[][2], // COMPLIANT - int (*p23)[], // COMPLIANT + int p21[], // COMPLIANT + int p22[][2], // COMPLIANT + int (*p23)[], // COMPLIANT // int (*p24)[2][], // doesn't compile int (*p25)[][2], // COMPLIANT diff --git a/c/misra/test/rules/RULE-18-8/test.c b/c/misra/test/rules/RULE-18-8/test.c index 7d6a1400d6..ea639de271 100644 --- a/c/misra/test/rules/RULE-18-8/test.c +++ b/c/misra/test/rules/RULE-18-8/test.c @@ -28,7 +28,7 @@ void f1(int n, int p1[n], // COMPLIANT // Pointers to variably-modified types are not VLAs. int p2[n][n], - int p3[], // array of unknown length is converted to pointer + int p3[], // array of unknown length is converted to pointer int p4[][n] // array of unknown length are not VLAs. ) {} diff --git a/c/misra/test/rules/RULE-21-22/test.c b/c/misra/test/rules/RULE-21-22/test.c index 66c889d168..970df4fd56 100644 --- a/c/misra/test/rules/RULE-21-22/test.c +++ b/c/misra/test/rules/RULE-21-22/test.c @@ -322,8 +322,8 @@ void f1() { remquo(i, i, c); // COMPLIANT /* Test casts */ - cos((char) i); // NON-COMPLIANT - cos((int) c); // COMPLIANT - cos((int) (char) i); // COMPLIANT - cos((char) (int) c); // NON-COMPLIANT + cos((char)i); // NON-COMPLIANT + cos((int)c); // COMPLIANT + cos((int)(char)i); // COMPLIANT + cos((char)(int)c); // NON-COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/RULE-21-25/test.c b/c/misra/test/rules/RULE-21-25/test.c index fc9fc67e95..d096634d30 100644 --- a/c/misra/test/rules/RULE-21-25/test.c +++ b/c/misra/test/rules/RULE-21-25/test.c @@ -21,52 +21,52 @@ void f(int p) { atomic_load_explicit(&l1, memory_order_release); // NON-COMPLIANT // Implicit values: - atomic_store(&l1, 0); // COMPLIANT - atomic_load(&l1); // COMPLIANT - atomic_flag_test_and_set(&l2); // COMPLIANT - atomic_flag_clear(&l2); // COMPLIANT - atomic_exchange(&l1, 0); // COMPLIANT + atomic_store(&l1, 0); // COMPLIANT + atomic_load(&l1); // COMPLIANT + atomic_flag_test_and_set(&l2); // COMPLIANT + atomic_flag_clear(&l2); // COMPLIANT + atomic_exchange(&l1, 0); // COMPLIANT atomic_compare_exchange_strong(&l1, ptr, 1); // COMPLIANT atomic_compare_exchange_weak(&l1, ptr, 1); // COMPLIANT - atomic_fetch_add(&l1, 0); // COMPLIANT - atomic_fetch_sub(&l1, 0); // COMPLIANT - atomic_fetch_or(&l1, 0); // COMPLIANT - atomic_fetch_xor(&l1, 0); // COMPLIANT - atomic_fetch_and(&l1, 0); // COMPLIANT + atomic_fetch_add(&l1, 0); // COMPLIANT + atomic_fetch_sub(&l1, 0); // COMPLIANT + atomic_fetch_or(&l1, 0); // COMPLIANT + atomic_fetch_xor(&l1, 0); // COMPLIANT + atomic_fetch_and(&l1, 0); // COMPLIANT // Compliant flowed values (one test per sink): - atomic_store_explicit(&l1, 0, g1); // COMPLIANT - atomic_load_explicit(&l1, g1); // COMPLIANT - atomic_flag_test_and_set_explicit(&l2, g1); // COMPLIANT - atomic_flag_clear_explicit(&l2, g1); // COMPLIANT - atomic_exchange_explicit(&l1, 0, g1); // COMPLIANT + atomic_store_explicit(&l1, 0, g1); // COMPLIANT + atomic_load_explicit(&l1, g1); // COMPLIANT + atomic_flag_test_and_set_explicit(&l2, g1); // COMPLIANT + atomic_flag_clear_explicit(&l2, g1); // COMPLIANT + atomic_exchange_explicit(&l1, 0, g1); // COMPLIANT atomic_compare_exchange_strong_explicit(&l1, ptr, 1, g1, g1); // COMPLIANT atomic_compare_exchange_weak_explicit(&l1, ptr, 1, g1, g1); // COMPLIANT - atomic_fetch_add_explicit(&l1, 0, g1); // COMPLIANT - atomic_fetch_sub_explicit(&l1, 0, g1); // COMPLIANT - atomic_fetch_or_explicit(&l1, 0, g1); // COMPLIANT - atomic_fetch_xor_explicit(&l1, 0, g1); // COMPLIANT - atomic_fetch_and_explicit(&l1, 0, g1); // COMPLIANT - atomic_thread_fence(g1); // COMPLIANT - atomic_signal_fence(g1); // COMPLIANT + atomic_fetch_add_explicit(&l1, 0, g1); // COMPLIANT + atomic_fetch_sub_explicit(&l1, 0, g1); // COMPLIANT + atomic_fetch_or_explicit(&l1, 0, g1); // COMPLIANT + atomic_fetch_xor_explicit(&l1, 0, g1); // COMPLIANT + atomic_fetch_and_explicit(&l1, 0, g1); // COMPLIANT + atomic_thread_fence(g1); // COMPLIANT + atomic_signal_fence(g1); // COMPLIANT // Non-compliant flowed values (one test per sink): - atomic_store_explicit(&l1, 0, g2); // NON-COMPLIANT - atomic_load_explicit(&l1, g2); // NON-COMPLIANT - atomic_flag_test_and_set_explicit(&l2, g2); // NON-COMPLIANT - atomic_flag_clear_explicit(&l2, g2); // NON-COMPLIANT - atomic_exchange_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_store_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_load_explicit(&l1, g2); // NON-COMPLIANT + atomic_flag_test_and_set_explicit(&l2, g2); // NON-COMPLIANT + atomic_flag_clear_explicit(&l2, g2); // NON-COMPLIANT + atomic_exchange_explicit(&l1, 0, g2); // NON-COMPLIANT atomic_compare_exchange_strong_explicit(&l1, ptr, 1, g2, g1); // NON-COMPLIANT atomic_compare_exchange_strong_explicit(&l1, ptr, 1, g1, g2); // NON-COMPLIANT atomic_compare_exchange_weak_explicit(&l1, ptr, 1, g2, g1); // NON-COMPLIANT atomic_compare_exchange_weak_explicit(&l1, ptr, 1, g1, g2); // NON-COMPLIANT - atomic_fetch_add_explicit(&l1, 0, g2); // NON-COMPLIANT - atomic_fetch_sub_explicit(&l1, 0, g2); // NON-COMPLIANT - atomic_fetch_or_explicit(&l1, 0, g2); // NON-COMPLIANT - atomic_fetch_xor_explicit(&l1, 0, g2); // NON-COMPLIANT - atomic_fetch_and_explicit(&l1, 0, g2); // NON-COMPLIANT - atomic_thread_fence(g2); // NON-COMPLIANT - atomic_signal_fence(g2); // NON-COMPLIANT + atomic_fetch_add_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_fetch_sub_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_fetch_or_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_fetch_xor_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_fetch_and_explicit(&l1, 0, g2); // NON-COMPLIANT + atomic_thread_fence(g2); // NON-COMPLIANT + atomic_signal_fence(g2); // NON-COMPLIANT // Non-compliant flowed values (one test per source): atomic_thread_fence(g2); // NON-COMPLIANT From b9e1c0b26f1b0cbcb7d9efe38b29a9ea1e520a9a Mon Sep 17 00:00:00 2001 From: Michael R Fairhurst Date: Wed, 9 Apr 2025 03:01:38 +0000 Subject: [PATCH 338/628] Fix 21-22 test expectations --- .../TgMathArgumentWithInvalidEssentialType.expected | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected index 46e4e8f5c8..03dddb8dfe 100644 --- a/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected +++ b/c/misra/test/rules/RULE-21-22/TgMathArgumentWithInvalidEssentialType.expected @@ -130,5 +130,5 @@ | test.c:303:14:303:15 | cf | Argument 2 provided to type-generic macro 'scalbln' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | | test.c:309:10:309:11 | cf | Argument 1 provided to type-generic macro 'tgamma' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | | test.c:310:9:310:10 | cf | Argument 1 provided to type-generic macro 'trunc' has essentially complex floating type, which is not essentially signed, unsigned, or real floating type. | -| test.c:325:14:325:14 | i | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | -| test.c:328:20:328:20 | c | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:325:13:325:13 | i | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | +| test.c:328:18:328:18 | c | Argument 1 provided to type-generic macro 'cos' has essentially character type, which is not essentially signed, unsigned, or floating type. | From 315276902e53b55bfbb6ecd458f04d6a8b4abc27 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 9 Apr 2025 19:25:48 -0700 Subject: [PATCH 339/628] Update obligation level of new CERT-C rules --- rules.csv | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rules.csv b/rules.csv index 2db1d7a66d..68049625e6 100644 --- a/rules.csv +++ b/rules.csv @@ -515,7 +515,7 @@ c,CERT-C,ERR30-C,Yes,Rule,,,Take care when reading errno,M19-3-1,Contracts4,Hard c,CERT-C,ERR32-C,Yes,Rule,,,Do not rely on indeterminate values of errno,,Contracts5,Hard, c,CERT-C,ERR33-C,Yes,Rule,,,Detect and handle standard library errors,MEM52-CPP,Contracts5,Hard, c,CERT-C,ERR34-C,OutOfScope,Rule,,,Detect errors when converting a string to a number,,,, -c,CERT-C,EXP16-C,Yes,Rule,,,Do not compare function pointers to constant values,,Expressions2,Medium, +c,CERT-C,EXP16-C,Yes,Recommendation,,,Do not compare function pointers to constant values,,Expressions2,Medium, c,CERT-C,EXP30-C,Yes,Rule,,,Do not depend on the order of evaluation for side effects,EXP50-CPP,SideEffects1,Easy, c,CERT-C,EXP32-C,Yes,Rule,,,Do not access a volatile object through a nonvolatile reference,,Pointers3,Easy, c,CERT-C,EXP33-C,Yes,Rule,,,Do not read uninitialized memory,EXP53-CPP,InvalidMemory1,Import, @@ -531,8 +531,8 @@ c,CERT-C,EXP44-C,Yes,Rule,,,"Do not rely on side effects in operands to sizeof, c,CERT-C,EXP45-C,Yes,Rule,,,Do not perform assignments in selection statements,M6-2-1,SideEffects1,Medium, c,CERT-C,EXP46-C,Yes,Rule,,,Do not use a bitwise operator with a Boolean-like operand,,Expressions,Easy, c,CERT-C,EXP47-C,OutOfScope,Rule,,,Do not call va_arg with an argument of the incorrect type,,,, -c,CERT-C,FIO03-C,Yes,Rule,,,Do not make assumptions about fopen() and file creation,,IO5,Hard, -c,CERT-C,FIO21-C,Yes,Rule,,,Do not create temporary files in shared directories,,IO5,Easy, +c,CERT-C,FIO03-C,Yes,Recommendation,,,Do not make assumptions about fopen() and file creation,,IO5,Hard, +c,CERT-C,FIO21-C,Yes,Recommendation,,,Do not create temporary files in shared directories,,IO5,Easy, c,CERT-C,FIO30-C,Yes,Rule,,,Exclude user input from format strings,A27-0-1,IO1,Import, c,CERT-C,FIO32-C,Yes,Rule,,,Do not perform operations on devices that are only appropriate for files,,IO3,Medium, c,CERT-C,FIO34-C,Yes,Rule,,,Distinguish between characters read from a file and EOF or WEOF,,IO1,Hard, From 64ad8fb8955f3e749ce61c8aca33c0272657b30d Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 9 Apr 2025 23:30:12 -0700 Subject: [PATCH 340/628] Add new query suites for CERT-C recommendations --- c/cert/src/codeql-suites/cert-c-default.qls | 10 ++++++++++ c/cert/src/codeql-suites/cert-c-recommendation.qls | 10 ++++++++++ c/cert/src/codeql-suites/cert-default.qls | 11 ++--------- c/cert/src/qlpack.yml | 1 + ...5-04-09-new-cert-c-recommendation-query-suite.md | 9 +++++++++ cpp/cert/src/codeql-suites/cert-cpp-default.qls | 9 +++++++++ .../cert-cpp-single-translation-unit.qls | 11 +++++++++++ cpp/cert/src/codeql-suites/cert-default.qls | 11 ++--------- .../codeql-suites/cert-single-translation-unit.qls | 13 ++----------- cpp/cert/src/qlpack.yml | 1 + 10 files changed, 57 insertions(+), 29 deletions(-) create mode 100644 c/cert/src/codeql-suites/cert-c-default.qls create mode 100644 c/cert/src/codeql-suites/cert-c-recommendation.qls create mode 100644 change_notes/2025-04-09-new-cert-c-recommendation-query-suite.md create mode 100644 cpp/cert/src/codeql-suites/cert-cpp-default.qls create mode 100644 cpp/cert/src/codeql-suites/cert-cpp-single-translation-unit.qls diff --git a/c/cert/src/codeql-suites/cert-c-default.qls b/c/cert/src/codeql-suites/cert-c-default.qls new file mode 100644 index 0000000000..348d2f37ae --- /dev/null +++ b/c/cert/src/codeql-suites/cert-c-default.qls @@ -0,0 +1,10 @@ +- description: CERT C 2016 (Default) +- qlpack: codeql/cert-c-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/rule +- exclude: + tags contain: + - external/cert/default-disabled diff --git a/c/cert/src/codeql-suites/cert-c-recommendation.qls b/c/cert/src/codeql-suites/cert-c-recommendation.qls new file mode 100644 index 0000000000..59ac5e9c2d --- /dev/null +++ b/c/cert/src/codeql-suites/cert-c-recommendation.qls @@ -0,0 +1,10 @@ +- description: CERT C 2016 (Recommendations) +- qlpack: codeql/cert-c-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/recommendation +- exclude: + tags contain: + - external/cert/default-disabled diff --git a/c/cert/src/codeql-suites/cert-default.qls b/c/cert/src/codeql-suites/cert-default.qls index 1e11a0afca..c093b31fa7 100644 --- a/c/cert/src/codeql-suites/cert-default.qls +++ b/c/cert/src/codeql-suites/cert-default.qls @@ -1,9 +1,2 @@ -- description: CERT C 2016 (Default) -- qlpack: codeql/cert-c-coding-standards -- include: - kind: - - problem - - path-problem -- exclude: - tags contain: - - external/cert/default-disabled +- description: "DEPRECATED - CERT C 2016 - use cert-c-default.qls instead" +- import: codeql-suites/cert-c-default.qls diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 631639301e..e3664d75b5 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -3,6 +3,7 @@ version: 2.44.0-dev description: CERT C 2016 suites: codeql-suites license: MIT +default-suite-file: codeql-suites/cert-c-default.qls dependencies: codeql/common-c-coding-standards: '*' codeql/cpp-all: 2.1.1 diff --git a/change_notes/2025-04-09-new-cert-c-recommendation-query-suite.md b/change_notes/2025-04-09-new-cert-c-recommendation-query-suite.md new file mode 100644 index 0000000000..910433e351 --- /dev/null +++ b/change_notes/2025-04-09-new-cert-c-recommendation-query-suite.md @@ -0,0 +1,9 @@ + - The following query suites have been added or modified for CERT C: + - A new query suite has been created `cert-c-default.qls` to avoid confusion with the CERT C++ query suites. The `cert-default.qls` suite has been deprecated, and will be removed in a future releases, and is replaced by the `cert-c-default.qls` suite. + - The `cert-c-default.qls` suite has been specified as the default for the pack, and will include our most up-to-date coverage for CERT C. + - One new query suite, `cert-c-recommended.qls` has been added to enable running CERT recommendations (as opposed to rules) that will be added in the future. + - The default query suite, `cert-c-default.qls` has been set to exclude CERT recommendations (as opposed to rules) that will be added in the future. + - The following query suites have been added or modified for CERT C++: + - A new query suite has been created `cert-cpp-default.qls` to avoid confusion with the CERT C query suites. The `cert-default.qls` suite has been deprecated, and will be removed in a future releases, and is replaced by the `cert-cpp-default.qls` suite. + - The `cert-cpp-default.qls` suite has been specified as the default for the pack, and will include our most up-to-date coverage for CERT C. + - A new query suite has been created `cert-cpp-single-translation-unit.qls` to avoid confusion with the CERT C query suites. The `cert-single-translation-unit.qls` suite has been deprecated, and will be removed in a future releases, and is replaced by the `cert-cpp-single-translation-unit.qls` suite. \ No newline at end of file diff --git a/cpp/cert/src/codeql-suites/cert-cpp-default.qls b/cpp/cert/src/codeql-suites/cert-cpp-default.qls new file mode 100644 index 0000000000..e9211246b1 --- /dev/null +++ b/cpp/cert/src/codeql-suites/cert-cpp-default.qls @@ -0,0 +1,9 @@ +- description: CERT C++ 2016 (Default) +- qlpack: codeql/cert-cpp-coding-standards +- include: + kind: + - problem + - path-problem +- exclude: + tags contain: + - external/cert/default-disabled diff --git a/cpp/cert/src/codeql-suites/cert-cpp-single-translation-unit.qls b/cpp/cert/src/codeql-suites/cert-cpp-single-translation-unit.qls new file mode 100644 index 0000000000..2f09815e0d --- /dev/null +++ b/cpp/cert/src/codeql-suites/cert-cpp-single-translation-unit.qls @@ -0,0 +1,11 @@ +- description: CERT C++ 2016 (Single Translation Unit) +- qlpack: codeql/cert-cpp-coding-standards +- include: + kind: + - problem + - path-problem + tags contain: + - scope/single-translation-unit +- exclude: + tags contain: + - external/cert/default-disabled diff --git a/cpp/cert/src/codeql-suites/cert-default.qls b/cpp/cert/src/codeql-suites/cert-default.qls index e9211246b1..66599b60fb 100644 --- a/cpp/cert/src/codeql-suites/cert-default.qls +++ b/cpp/cert/src/codeql-suites/cert-default.qls @@ -1,9 +1,2 @@ -- description: CERT C++ 2016 (Default) -- qlpack: codeql/cert-cpp-coding-standards -- include: - kind: - - problem - - path-problem -- exclude: - tags contain: - - external/cert/default-disabled +- description: "DEPRECATED - CERT C++ 2016 - use cert-cpp-default.qls instead" +- import: codeql-suites/cert-cpp-default.qls \ No newline at end of file diff --git a/cpp/cert/src/codeql-suites/cert-single-translation-unit.qls b/cpp/cert/src/codeql-suites/cert-single-translation-unit.qls index 2f09815e0d..4966648394 100644 --- a/cpp/cert/src/codeql-suites/cert-single-translation-unit.qls +++ b/cpp/cert/src/codeql-suites/cert-single-translation-unit.qls @@ -1,11 +1,2 @@ -- description: CERT C++ 2016 (Single Translation Unit) -- qlpack: codeql/cert-cpp-coding-standards -- include: - kind: - - problem - - path-problem - tags contain: - - scope/single-translation-unit -- exclude: - tags contain: - - external/cert/default-disabled +- description: "DEPRECATED - CERT C++ 2016 (Single Translation Unit) - use cert-cpp-single-translation-unit.qls instead" +- import: codeql-suites/cert-cpp-single-translation-unit.qls \ No newline at end of file diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index f44646cdbe..97976d30cd 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -3,6 +3,7 @@ version: 2.44.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT +default-suite-file: codeql-suites/cert-cpp-default.qls dependencies: codeql/cpp-all: 2.1.1 codeql/common-cpp-coding-standards: '*' From 8843822ec1b46b0a913edfc5a5f7372d1e4752a8 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 10 Apr 2025 08:45:07 -0700 Subject: [PATCH 341/628] Add 'recommendation' to CERT schema --- schemas/rule-package.schema.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/schemas/rule-package.schema.json b/schemas/rule-package.schema.json index b4f729afe2..f9f65d679c 100644 --- a/schemas/rule-package.schema.json +++ b/schemas/rule-package.schema.json @@ -94,7 +94,8 @@ "obligation": { "type": "string", "enum": [ - "rule" + "rule", + "recommendation" ] } }, From d39ec8d75696f4d5ee0493f97b55102f47d5da52 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 10 Apr 2025 09:25:26 -0700 Subject: [PATCH 342/628] Fix, move 'recommendation' from CERT-C++ to CERT-C in schema --- schemas/rule-package.schema.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/schemas/rule-package.schema.json b/schemas/rule-package.schema.json index f9f65d679c..f8c3f028e3 100644 --- a/schemas/rule-package.schema.json +++ b/schemas/rule-package.schema.json @@ -94,8 +94,7 @@ "obligation": { "type": "string", "enum": [ - "rule", - "recommendation" + "rule" ] } }, @@ -142,7 +141,8 @@ "obligation": { "type": "string", "enum": [ - "rule" + "rule", + "recommendation" ] } }, From 14bd93788a59b7265a730626fe44178b0f56d8a1 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 30 Mar 2025 18:30:36 -0700 Subject: [PATCH 343/628] Update cert-help-extraction.py to support CERT-C optional (recommendation) rules --- scripts/help/cert-help-extraction.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/scripts/help/cert-help-extraction.py b/scripts/help/cert-help-extraction.py index 6bd1abccd5..f785b0955f 100755 --- a/scripts/help/cert-help-extraction.py +++ b/scripts/help/cert-help-extraction.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 from argparse import ArgumentParser +from typing import Generator import tempfile import re import urllib.request @@ -23,6 +24,7 @@ CERT_WIKI = "https://wiki.sei.cmu.edu/" RULES_LIST_C = "/confluence/display/c/2+Rules" +RECOMMENDED_LIST_C = "/confluence/display/c/3+Recommendations" RULES_LIST_CPP = "/confluence/display/cplusplus/2+Rules" cache_path = script_path.parent / '.cache' @@ -47,16 +49,22 @@ def soupify(url: str) -> BeautifulSoup: return BeautifulSoup(content, 'html.parser') - -def get_rules(): - rules = [] - for soup in [soupify(f"{CERT_WIKI}{RULES_LIST_C}"), soupify(f"{CERT_WIKI}{RULES_LIST_CPP}")]: +def get_rule_listings() -> Generator[Tag, None, None]: + for rule_list_id in [RULES_LIST_C, RULES_LIST_CPP]: + soup = soupify(f"{CERT_WIKI}{rule_list_id}") if soup == None: - return None - - rule_listing_start = soup.find( + continue + + yield soup.find( "h1", string="Rule Listing") + soup = soupify(f"{CERT_WIKI}{RECOMMENDED_LIST_C}") + if soup != None: + yield soup.find("h1", string="Recommendation Listing") + +def get_rules(): + rules = [] + for rule_listing_start in get_rule_listings(): for link in rule_listing_start.next_element.next_element.find_all('a'): if '-C' in link.string: rule, title = map(str.strip, link.string.split('.', 1)) @@ -214,6 +222,8 @@ def helper(node): # Fix a broken url present in many CERT-C pages if node.name == 'a' and 'href' in node.attrs and node['href'] == "http://BB. Definitions#vulnerability": node['href'] = "https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability" + elif node.name == 'a' and 'href' in node.attrs and node['href'] == "http://BB. Definitions#unexpected behavior": + node['href'] = "https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior" # Turn relative URLs into absolute URLS elif node.name == 'a' and 'href' in node.attrs and node['href'].startswith("/confluence"): node['href'] = f"{CERT_WIKI}{node['href']}" From d2e638eedab86f076b1cbd04cd81383e09cb5611 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 30 Mar 2025 18:27:49 -0700 Subject: [PATCH 344/628] Implement expressions2 package --- ...CompareFunctionPointersToConstantValues.md | 129 ++++++++++++++++++ ...CompareFunctionPointersToConstantValues.ql | 101 ++++++++++++++ ...eFunctionPointersToConstantValues.expected | 16 +++ ...pareFunctionPointersToConstantValues.qlref | 1 + c/cert/test/rules/EXP16-C/test.c | 113 +++++++++++++++ .../cpp/exclusions/c/Expressions2.qll | 26 ++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + .../codingstandards/cpp/types/Compatible.qll | 19 +-- .../cpp/types/FunctionType.qll | 19 +++ rule_packages/c/Expressions2.json | 23 ++++ 10 files changed, 432 insertions(+), 18 deletions(-) create mode 100644 c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.md create mode 100644 c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql create mode 100644 c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.expected create mode 100644 c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.qlref create mode 100644 c/cert/test/rules/EXP16-C/test.c create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Expressions2.qll create mode 100644 cpp/common/src/codingstandards/cpp/types/FunctionType.qll create mode 100644 rule_packages/c/Expressions2.json diff --git a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.md b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.md new file mode 100644 index 0000000000..b5a7c98bd6 --- /dev/null +++ b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.md @@ -0,0 +1,129 @@ +# EXP16-C: Do not compare function pointers to constant values + +This query implements the CERT-C rule EXP16-C: + +> Do not compare function pointers to constant values + + +## Description + +Comparing a function pointer to a value that is not a null function pointer of the same type will be diagnosed because it typically indicates programmer error and can result in [unexpected behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior). Implicit comparisons will be diagnosed, as well. + +## Noncompliant Code Example + +In this noncompliant code example, the addresses of the POSIX functions `getuid` and `geteuid` are compared for equality to 0. Because no function address shall be null, the first subexpression will always evaluate to false (0), and the second subexpression always to true (nonzero). Consequently, the entire expression will always evaluate to true, leading to a potential security vulnerability. + +```cpp +/* First the options that are allowed only for root */ +if (getuid == 0 || geteuid != 0) { + /* ... */ +} + +``` + +## Noncompliant Code Example + +In this noncompliant code example, the function pointers `getuid` and `geteuid` are compared to 0. This example is from an actual [vulnerability](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) ([VU\#837857](http://www.kb.cert.org/vuls/id/837857)) discovered in some versions of the X Window System server. The vulnerability exists because the programmer neglected to provide the open and close parentheses following the `geteuid()` function identifier. As a result, the `geteuid` token returns the address of the function, which is never equal to 0. Consequently, the `or` condition of this `if` statement is always true, and access is provided to the protected block for all users. Many compilers issue a warning noting such pointless expressions. Therefore, this coding error is normally detected by adherence to [MSC00-C. Compile cleanly at high warning levels](https://wiki.sei.cmu.edu/confluence/display/c/MSC00-C.+Compile+cleanly+at+high+warning+levels). + +```cpp +/* First the options that are allowed only for root */ +if (getuid() == 0 || geteuid != 0) { + /* ... */ +} + +``` + +## Compliant Solution + +The solution is to provide the open and close parentheses following the `geteuid` token so that the function is properly invoked: + +```cpp +/* First the options that are allowed only for root */ +if (getuid() == 0 || geteuid() != 0) { + /* ... */ +} + +``` + +## Compliant Solution + +A function pointer can be compared to a null function pointer of the same type: + +```cpp +/* First the options that are allowed only for root */ +if (getuid == (uid_t(*)(void))0 || geteuid != (uid_t(*)(void))0) { + /* ... */ +} + +``` +This code should not be diagnosed by an analyzer. + +## Noncompliant Code Example + +In this noncompliant code example, the function pointer `do_xyz` is implicitly compared unequal to 0: + +```cpp +int do_xyz(void); + +int f(void) { +/* ... */ + if (do_xyz) { + return -1; /* Indicate failure */ + } +/* ... */ + return 0; +} + +``` + +## Compliant Solution + +In this compliant solution, the function `do_xyz()` is invoked and the return value is compared to 0: + +```cpp +int do_xyz(void); + +int f(void) { +/* ... */ + if (do_xyz()) { + return -1; /* Indicate failure */ + } +/* ... */ + return 0; +} + +``` + +## Risk Assessment + +Errors of omission can result in unintended program flow. + +
    Recommendation Severity Likelihood Remediation Cost Priority Level
    EXP16-C Low Likely Medium P6 L2
    + + +## Automated Detection + +
    Tool Version Checker Description
    Astrée 24.04 function-name-constant-comparison Partially checked
    Coverity 2017.07 BAD_COMPARE Can detect the specific instance where the address of a function is compared against 0, such as in the case of geteuid versus getuid() in the implementation-specific details
    GCC 4.3.5 Can detect violations of this recommendation when the -Wall flag is used
    Helix QAC 2024.4 C0428, C3004, C3344
    Klocwork 2024.4 CWARN.NULLCHECK.FUNCNAMECWARN.FUNCADDR
    LDRA tool suite 9.7.1 99 S Partially implemented
    Parasoft C/C++test 2024.2 CERT_C-EXP16-a Function address should not be compared to zero
    PC-lint Plus 1.4 2440, 2441 Partially supported: reports address of function, array, or variable directly or indirectly compared to null
    PVS-Studio 7.35 V516, V1058
    RuleChecker 24.04 function-name-constant-comparison Partially checked
    + + +## Related Vulnerabilities + +Search for [vulnerabilities](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-vulnerability) resulting from the violation of this rule on the [CERT website](https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+EXP16-C). + +## Related Guidelines + +
    SEI CERT C++ Coding Standard VOID EXP16-CPP. Avoid conversions using void pointers
    ISO/IEC TR 24772:2013 Likely incorrect expressions \[KOA\]
    ISO/IEC TS 17961 Comparing function addresses to zero \[funcaddr\]
    MITRE CWE CWE-480 , Use of incorrect operator CWE-482 , Comparing instead of assigning
    + + +## Bibliography + +
    \[ Hatton 1995 \] Section 2.7.2, "Errors of Omission and Addition"
    + + +## Implementation notes + +None + +## References + +* CERT-C: [EXP16-C: Do not compare function pointers to constant values](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql new file mode 100644 index 0000000000..561374d66b --- /dev/null +++ b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql @@ -0,0 +1,101 @@ +/** + * @id c/cert/do-not-compare-function-pointers-to-constant-values + * @name EXP16-C: Do not compare function pointers to constant values + * @description Comparing function pointers to a constant value is not reliable and likely indicates + * a programmer error. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/exp16-c + * correctness + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.types.FunctionType +import semmle.code.cpp.controlflow.IRGuards + +class FunctionExpr extends Expr { + Element function; + string funcName; + + FunctionExpr() { + function = this.(FunctionAccess).getTarget() and + funcName = "Function " + function.(Function).getName() + or + this.(VariableAccess).getUnderlyingType() instanceof FunctionType and + function = this and + funcName = "Function pointer variable " + this.(VariableAccess).getTarget().getName() + or + this.getUnderlyingType() instanceof FunctionType and + not this instanceof FunctionAccess and + not this instanceof VariableAccess and + function = this and + funcName = "Expression with function pointer type" + } + + Element getFunction() { result = function } + + string getFuncName() { result = funcName } +} + +abstract class EffectivelyComparison extends Element { + abstract string getExplanation(); + + abstract FunctionExpr getFunctionExpr(); +} + +class ExplicitComparison extends EffectivelyComparison, ComparisonOperation { + Expr constantExpr; + FunctionExpr funcExpr; + + ExplicitComparison() { + funcExpr = getAnOperand() and + constantExpr = getAnOperand() and + exists(constantExpr.getValue()) and + not funcExpr = constantExpr and + not constantExpr.getExplicitlyConverted().getUnderlyingType() = + funcExpr.getExplicitlyConverted().getUnderlyingType() + } + + override string getExplanation() { result = "$@ compared to constant value." } + + override FunctionExpr getFunctionExpr() { result = funcExpr } +} + +class ImplicitComparison extends EffectivelyComparison, GuardCondition { + ImplicitComparison() { + this instanceof FunctionExpr and + not getParent() instanceof ComparisonOperation + } + + override string getExplanation() { result = "$@ undergoes implicit constant comparison." } + + override FunctionExpr getFunctionExpr() { result = this } +} + +from EffectivelyComparison comparison, FunctionExpr funcExpr, Element function, string funcName +where + not isExcluded(comparison, + Expressions2Package::doNotCompareFunctionPointersToConstantValuesQuery()) and + funcExpr = comparison.getFunctionExpr() and + function = funcExpr.getFunction() and + funcName = funcExpr.getFuncName() +select comparison, comparison.getExplanation(), function, funcName +//from +// EqualityOperation equality, FunctionExpr funcExpr, Element function, string funcName, +// Expr constantExpr +//where +// not isExcluded(equality, Expressions2Package::doNotCompareFunctionPointersToConstantValuesQuery()) and +// funcExpr = equality.getAnOperand() and +// constantExpr = equality.getAnOperand() and +// exists(constantExpr.getValue()) and +// function = funcExpr.getFunction() and +// funcName = funcExpr.getFuncName() and +// constantExpr.getFullyConverted().getUnderlyingType() = +// funcExpr.getFullyConverted().getUnderlyingType() +//select equality, +// "Pointer to function $@ compared to constant value." + +// constantExpr.getFullyConverted().getUnderlyingType().explain() + " / " + +// funcExpr.getFullyConverted().getUnderlyingType().explain(), function, funcName diff --git a/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.expected b/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.expected new file mode 100644 index 0000000000..a18f0d32f6 --- /dev/null +++ b/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.expected @@ -0,0 +1,16 @@ +| test.c:17:7:17:13 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Function f1 | +| test.c:20:7:20:12 | ... > ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Function f1 | +| test.c:29:7:29:13 | ... == ... | $@ compared to constant value. | test.c:29:7:29:8 | g1 | Function pointer variable g1 | +| test.c:32:7:32:16 | ... == ... | $@ compared to constant value. | test.c:32:7:32:8 | g2 | Function pointer variable g2 | +| test.c:35:7:35:15 | ... != ... | $@ compared to constant value. | test.c:35:7:35:8 | g1 | Function pointer variable g1 | +| test.c:38:7:38:8 | f1 | $@ undergoes implicit constant comparison. | test.c:3:5:3:6 | f1 | Function f1 | +| test.c:41:7:41:8 | g1 | $@ undergoes implicit constant comparison. | test.c:41:7:41:8 | g1 | Function pointer variable g1 | +| test.c:68:7:68:27 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Function f1 | +| test.c:71:7:71:18 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Function f1 | +| test.c:74:7:76:14 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Function f1 | +| test.c:83:3:83:9 | ... == ... | $@ compared to constant value. | test.c:83:3:83:4 | l1 | Function pointer variable l1 | +| test.c:84:3:84:12 | ... == ... | $@ compared to constant value. | test.c:84:3:84:4 | l1 | Function pointer variable l1 | +| test.c:91:3:91:4 | g1 | $@ undergoes implicit constant comparison. | test.c:91:3:91:4 | g1 | Function pointer variable g1 | +| test.c:96:7:96:18 | ... == ... | $@ compared to constant value. | test.c:96:9:96:10 | fp | Function pointer variable fp | +| test.c:102:7:102:22 | ... == ... | $@ compared to constant value. | test.c:14:11:14:21 | get_handler | Function get_handler | +| test.c:105:7:105:24 | ... == ... | $@ compared to constant value. | test.c:105:7:105:17 | call to get_handler | Expression with function pointer type | diff --git a/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.qlref b/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.qlref new file mode 100644 index 0000000000..7d99fa9879 --- /dev/null +++ b/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.qlref @@ -0,0 +1 @@ +rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql \ No newline at end of file diff --git a/c/cert/test/rules/EXP16-C/test.c b/c/cert/test/rules/EXP16-C/test.c new file mode 100644 index 0000000000..afc1b1b53e --- /dev/null +++ b/c/cert/test/rules/EXP16-C/test.c @@ -0,0 +1,113 @@ +#include + +int f1(); +void (*g1)(void); +int (*g2)(int); +void *g3 = NULL; + +struct S { + int (*fp)(void); + int x; +}; + +typedef int (*handler_t)(void); +handler_t get_handler(void); + +void f2(void) { + if (f1 == 0) // NON-COMPLIANT + return; + + if (f1 > 0) // NON-COMPLIANT + return; + + if (f1() == 0) // COMPLIANT + return; + + if (f1() > 0) // COMPLIANT + return; + + if (g1 == 0) // NON-COMPLIANT + return; + + if (g2 == NULL) // NON-COMPLIANT + return; + + if (g1 != 0x0) // NON-COMPLIANT + return; + + if (f1) // NON-COMPLIANT - implicit comparison + return; + + if (g1) // NON-COMPLIANT - implicit comparison + return; +} + +void f3(void *p1) { + if (g1 == p1) // COMPLIANT - comparing to variable + return; + + if (g2 == g3) // COMPLIANT - comparing to variable + return; +} + +void f4(void) { + int (*l1)(void) = 0; + + if (f1 == f1) // COMPLIANT - comparing to constant value of same type + return; + + if (f1 == l1) // COMPLIANT - comparing to constant value of same type + return; + + if (f1 == (int (*)(void))0) // COMPLIANT - explicit cast + return; + + if (f1 == (int (*)(void))0) // COMPLIANT - explicit cast + return; + + if (f1 == (int (*)(int))0) // NON-COMPLIANT - explicit cast to wrong type + return; + + if (f1 == (int)0) // NON-COMPLIANT - cast to non-function pointer type + return; + + if (f1 == + (int)(int (*)(void)) + NULL) // NON-COMPLIANT - compliant cast subsumed by non-compliant cast + return; +} + +typedef void (*func_t)(void); +void f5(void) { + func_t l1 = g1; + l1 == 0; // NON-COMPLIANT + l1 == NULL; // NON-COMPLIANT + l1 == (func_t)0; // COMPLIANT - cast to function pointer type +} + +void f6(void) { + g1 + 0; // COMPLIANT - not a comparison + g1 == g2; // COMPLIANT - not comparing to constant + g1 ? 1 : 0; // NON-COMPLIANT - implicit comparison +} + +void f7(void) { + struct S s; + if (s.fp == NULL) // NON-COMPLIANT + return; + + if (s.fp() == NULL) // COMPLIANT + return; + + if (get_handler == 0) // NON-COMPLIANT - missing parentheses + return; + + if (get_handler() == 0) // NON-COMPLIANT + return; + + if (get_handler() == (handler_t)0) // COMPLIANT + return; + + if (get_handler()() == 0) // COMPLIANT + return; +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Expressions2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Expressions2.qll new file mode 100644 index 0000000000..cc22a5ce02 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Expressions2.qll @@ -0,0 +1,26 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Expressions2Query = TDoNotCompareFunctionPointersToConstantValuesQuery() + +predicate isExpressions2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `doNotCompareFunctionPointersToConstantValues` query + Expressions2Package::doNotCompareFunctionPointersToConstantValuesQuery() and + queryId = + // `@id` for the `doNotCompareFunctionPointersToConstantValues` query + "c/cert/do-not-compare-function-pointers-to-constant-values" and + ruleId = "EXP16-C" and + category = "rule" +} + +module Expressions2Package { + Query doNotCompareFunctionPointersToConstantValuesQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotCompareFunctionPointersToConstantValues` query + TQueryC(TExpressions2PackageQuery(TDoNotCompareFunctionPointersToConstantValuesQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index ae035b9c5d..b574f7551c 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -38,6 +38,7 @@ import Declarations9 import EssentialTypes import EssentialTypes2 import Expressions +import Expressions2 import FloatingTypes import FloatingTypes2 import FunctionTypes @@ -127,6 +128,7 @@ newtype TCQuery = TEssentialTypesPackageQuery(EssentialTypesQuery q) or TEssentialTypes2PackageQuery(EssentialTypes2Query q) or TExpressionsPackageQuery(ExpressionsQuery q) or + TExpressions2PackageQuery(Expressions2Query q) or TFloatingTypesPackageQuery(FloatingTypesQuery q) or TFloatingTypes2PackageQuery(FloatingTypes2Query q) or TFunctionTypesPackageQuery(FunctionTypesQuery q) or @@ -216,6 +218,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isEssentialTypesQueryMetadata(query, queryId, ruleId, category) or isEssentialTypes2QueryMetadata(query, queryId, ruleId, category) or isExpressionsQueryMetadata(query, queryId, ruleId, category) or + isExpressions2QueryMetadata(query, queryId, ruleId, category) or isFloatingTypesQueryMetadata(query, queryId, ruleId, category) or isFloatingTypes2QueryMetadata(query, queryId, ruleId, category) or isFunctionTypesQueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll index d6f65126e8..56966b5772 100644 --- a/cpp/common/src/codingstandards/cpp/types/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -1,6 +1,7 @@ import cpp import codeql.util.Boolean import codingstandards.cpp.types.Graph +import codingstandards.cpp.types.FunctionType module TypeNamesMatchConfig implements TypeEquivalenceSig { predicate resolveTypedefs() { @@ -352,21 +353,3 @@ module FunctionDeclarationTypeEquivalence { ) } } - -/** - * Convenience class to reduce the awkwardness of how `RoutineType` and `FunctionPointerIshType` - * don't have a common ancestor. - */ -private class FunctionType extends Type { - FunctionType() { this instanceof RoutineType or this instanceof FunctionPointerIshType } - - Type getReturnType() { - result = this.(RoutineType).getReturnType() or - result = this.(FunctionPointerIshType).getReturnType() - } - - Type getParameterType(int i) { - result = this.(RoutineType).getParameterType(i) or - result = this.(FunctionPointerIshType).getParameterType(i) - } -} diff --git a/cpp/common/src/codingstandards/cpp/types/FunctionType.qll b/cpp/common/src/codingstandards/cpp/types/FunctionType.qll new file mode 100644 index 0000000000..e43d1067f1 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/types/FunctionType.qll @@ -0,0 +1,19 @@ +import cpp + +/** + * Convenience class to reduce the awkwardness of how `RoutineType` and `FunctionPointerIshType` + * don't have a common ancestor. + */ +class FunctionType extends Type { + FunctionType() { this instanceof RoutineType or this instanceof FunctionPointerIshType } + + Type getReturnType() { + result = this.(RoutineType).getReturnType() or + result = this.(FunctionPointerIshType).getReturnType() + } + + Type getParameterType(int i) { + result = this.(RoutineType).getParameterType(i) or + result = this.(FunctionPointerIshType).getParameterType(i) + } +} \ No newline at end of file diff --git a/rule_packages/c/Expressions2.json b/rule_packages/c/Expressions2.json new file mode 100644 index 0000000000..88b5dff988 --- /dev/null +++ b/rule_packages/c/Expressions2.json @@ -0,0 +1,23 @@ +{ + "CERT-C": { + "EXP16-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Comparing function pointers to a constant value is not reliable and likely indicates a programmer error.", + "kind": "problem", + "name": "Do not compare function pointers to constant values", + "precision": "very-high", + "severity": "error", + "short_name": "DoNotCompareFunctionPointersToConstantValues", + "tags": [ + "correctness" + ] + } + ], + "title": "Do not compare function pointers to constant values" + } + } +} \ No newline at end of file From f6d62ecf55ec81dec636c3ce3d9fa2ead440aa3e Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 31 Mar 2025 13:09:44 -0700 Subject: [PATCH 345/628] Format --- cpp/common/src/codingstandards/cpp/types/FunctionType.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/types/FunctionType.qll b/cpp/common/src/codingstandards/cpp/types/FunctionType.qll index e43d1067f1..20166322f1 100644 --- a/cpp/common/src/codingstandards/cpp/types/FunctionType.qll +++ b/cpp/common/src/codingstandards/cpp/types/FunctionType.qll @@ -16,4 +16,4 @@ class FunctionType extends Type { result = this.(RoutineType).getParameterType(i) or result = this.(FunctionPointerIshType).getParameterType(i) } -} \ No newline at end of file +} From 067e1724a04df9eaaad348c4886a72e3276c9bd1 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 9 Apr 2025 20:39:32 -0700 Subject: [PATCH 346/628] Change obligation --- .../EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql | 2 +- .../src/codingstandards/cpp/exclusions/c/Expressions2.qll | 2 +- rule_packages/c/Expressions2.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql index 561374d66b..88beae6bc0 100644 --- a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql +++ b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql @@ -8,7 +8,7 @@ * @problem.severity error * @tags external/cert/id/exp16-c * correctness - * external/cert/obligation/rule + * external/cert/obligation/recommendation */ import cpp diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Expressions2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Expressions2.qll index cc22a5ce02..e7dffc30bb 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Expressions2.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Expressions2.qll @@ -13,7 +13,7 @@ predicate isExpressions2QueryMetadata(Query query, string queryId, string ruleId // `@id` for the `doNotCompareFunctionPointersToConstantValues` query "c/cert/do-not-compare-function-pointers-to-constant-values" and ruleId = "EXP16-C" and - category = "rule" + category = "recommendation" } module Expressions2Package { diff --git a/rule_packages/c/Expressions2.json b/rule_packages/c/Expressions2.json index 88b5dff988..7eaa2ff2ec 100644 --- a/rule_packages/c/Expressions2.json +++ b/rule_packages/c/Expressions2.json @@ -2,7 +2,7 @@ "CERT-C": { "EXP16-C": { "properties": { - "obligation": "rule" + "obligation": "recommendation" }, "queries": [ { From 010b7c7d2b626dad88511d6292afc837eecd534d Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Wed, 9 Apr 2025 20:40:20 -0700 Subject: [PATCH 347/628] Remove commented out code --- ...NotCompareFunctionPointersToConstantValues.ql | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql index 88beae6bc0..d9622b03b9 100644 --- a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql +++ b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql @@ -83,19 +83,3 @@ where function = funcExpr.getFunction() and funcName = funcExpr.getFuncName() select comparison, comparison.getExplanation(), function, funcName -//from -// EqualityOperation equality, FunctionExpr funcExpr, Element function, string funcName, -// Expr constantExpr -//where -// not isExcluded(equality, Expressions2Package::doNotCompareFunctionPointersToConstantValuesQuery()) and -// funcExpr = equality.getAnOperand() and -// constantExpr = equality.getAnOperand() and -// exists(constantExpr.getValue()) and -// function = funcExpr.getFunction() and -// funcName = funcExpr.getFuncName() and -// constantExpr.getFullyConverted().getUnderlyingType() = -// funcExpr.getFullyConverted().getUnderlyingType() -//select equality, -// "Pointer to function $@ compared to constant value." + -// constantExpr.getFullyConverted().getUnderlyingType().explain() + " / " + -// funcExpr.getFullyConverted().getUnderlyingType().explain(), function, funcName From 65045370e3665cf3b15edcc044ddf5d81364bbce Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 15 Apr 2025 06:42:44 -0700 Subject: [PATCH 348/628] Implement package FloatingPoint --- ...suseOfInfiniteFloatingPointValue.expected} | 56 ++--- .../MisuseOfInfiniteFloatingPointValue.ql | 4 + .../test.c | 44 ++-- .../MisuseOfNaNFloatingPointValue.expected} | 68 +++--- .../MisuseOfNaNFloatingPointValue.ql | 4 + .../misuseofnanfloatingpointvalue/test.c | 212 ++++++++++++++++++ .../PossibleMisuseOfUndetectedInfinity.ql | 127 +---------- .../DIR-4-15/PossibleMisuseOfUndetectedNaN.ql | 189 +--------------- ...PossibleMisuseOfUndetectedInfinity.testref | 1 + .../PossibleMisuseOfUndetectedNaN.testref | 1 + ...025-04-14-update-infinity-nan-detection.md | 4 + .../src/codingstandards/cpp/FloatingPoint.qll | 3 +- .../cpp/RestrictedRangeAnalysis.qll | 3 +- .../cpp/exclusions/cpp/FloatingPoint.qll | 44 ++++ .../cpp/exclusions/cpp/RuleMetadata.qll | 3 + .../MisuseOfInfiniteFloatingPointValue.qll | 141 ++++++++++++ .../MisuseOfNaNFloatingPointValue.qll | 201 +++++++++++++++++ .../test/includes/standard-library/cmath | 19 ++ .../test/includes/standard-library/math.h | 6 + ...isuseOfInfiniteFloatingPointValue.expected | 113 ++++++++++ .../MisuseOfInfiniteFloatingPointValue.ql | 4 + .../test.cpp | 212 ++++++++++++++++++ .../MisuseOfNaNFloatingPointValue.expected | 136 +++++++++++ .../MisuseOfNaNFloatingPointValue.ql | 4 + .../misuseofnanfloatingpointvalue/test.cpp | 212 ++++++++++++++++++ ...sibleMisuseOfInfiniteFloatingPointValue.ql | 22 ++ .../PossibleMisuseOfNaNFloatingPointValue.ql | 23 ++ ...MisuseOfInfiniteFloatingPointValue.testref | 1 + ...sibleMisuseOfNaNFloatingPointValue.testref | 1 + rule_packages/c/FloatingTypes2.json | 2 + rule_packages/cpp/FloatingPoint.json | 38 ++++ 31 files changed, 1505 insertions(+), 393 deletions(-) rename c/{misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected => common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected} (99%) create mode 100644 c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql rename c/{misra/test/rules/DIR-4-15 => common/test/rules/misuseofinfinitefloatingpointvalue}/test.c (82%) rename c/{misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected => common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected} (99%) create mode 100644 c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql create mode 100644 c/common/test/rules/misuseofnanfloatingpointvalue/test.c create mode 100644 c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.testref create mode 100644 c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.testref create mode 100644 change_notes/2025-04-14-update-infinity-nan-detection.md create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/cpp/FloatingPoint.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.qll create mode 100644 cpp/common/src/codingstandards/cpp/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.qll create mode 100644 cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected create mode 100644 cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql create mode 100644 cpp/common/test/rules/misuseofinfinitefloatingpointvalue/test.cpp create mode 100644 cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected create mode 100644 cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql create mode 100644 cpp/common/test/rules/misuseofnanfloatingpointvalue/test.cpp create mode 100644 cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql create mode 100644 cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql create mode 100644 cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.testref create mode 100644 cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.testref create mode 100644 rule_packages/cpp/FloatingPoint.json diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected b/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected similarity index 99% rename from c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected rename to c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected index 8dd5ac15b8..f3b94b6095 100644 --- a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.expected +++ b/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected @@ -1,3 +1,30 @@ +problems +| test.c:12:8:12:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:12:8:12:9 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:13:8:13:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:13:8:13:9 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:18:8:18:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:18:3:18:9 | l2 | Possibly infinite float value $@ flows to cast to integer. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:19:8:19:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:19:3:19:9 | l3 | Possibly infinite float value $@ flows to cast to integer. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:27:19:27:20 | l2 | test.c:8:14:8:20 | ... / ... | test.c:27:19:27:20 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:28:19:28:20 | l3 | test.c:8:14:8:20 | ... / ... | test.c:28:19:28:20 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Possibly infinite float value $@ flows to cast to integer. | test.c:31:14:32:15 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:61:11:61:17 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:66:11:66:19 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:72:20:72:28 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:75:24:75:32 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:79:10:79:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:79:5:79:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:87:10:87:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:87:5:87:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:91:10:91:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:91:5:91:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:93:10:93:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:93:5:93:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:99:10:99:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:99:5:99:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:105:10:105:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:105:5:105:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:111:10:111:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:111:5:111:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:114:21:114:23 | l12 | test.c:77:15:77:21 | ... / ... | test.c:114:16:114:23 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:117:28:117:30 | l12 | test.c:77:15:77:21 | ... / ... | test.c:117:23:117:30 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:120:25:120:27 | l12 | test.c:77:15:77:21 | ... / ... | test.c:120:20:120:27 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:163:9:164:15 | ... / ... | test.c:163:3:164:16 | ... / ... | test.c:163:3:164:16 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:163:9:164:15 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:175:32:175:32 | p | test.c:189:51:189:59 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:189:51:189:59 | ... / ... | from division by zero | test.c:189:6:189:24 | addInfThenCastToInt | addInfThenCastToInt | +| test.c:175:32:175:32 | p | test.c:193:13:194:15 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:193:13:194:15 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:175:32:175:32 | p | test.c:204:19:204:27 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:204:19:204:27 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:185:18:185:18 | p | test.c:200:25:200:33 | ... / ... | test.c:185:13:185:18 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:200:25:200:33 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | edges | test.c:8:14:8:20 | ... / ... | test.c:8:14:8:20 | ... / ... | provenance | | | test.c:8:14:8:20 | ... / ... | test.c:9:14:9:16 | - ... | provenance | Config | @@ -83,31 +110,4 @@ nodes | test.c:206:21:206:31 | ... + ... | semmle.label | ... + ... | | test.c:208:13:208:21 | middleInf | semmle.label | middleInf | | test.c:210:23:210:31 | middleInf | semmle.label | middleInf | -subpaths -#select -| test.c:12:8:12:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:12:8:12:9 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:13:8:13:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:13:8:13:9 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:18:8:18:9 | l2 | test.c:8:14:8:20 | ... / ... | test.c:18:3:18:9 | l2 | Possibly infinite float value $@ flows to cast to integer. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:19:8:19:9 | l3 | test.c:8:14:8:20 | ... / ... | test.c:19:3:19:9 | l3 | Possibly infinite float value $@ flows to cast to integer. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:27:19:27:20 | l2 | test.c:8:14:8:20 | ... / ... | test.c:27:19:27:20 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:28:19:28:20 | l3 | test.c:8:14:8:20 | ... / ... | test.c:28:19:28:20 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.c:8:14:8:20 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Possibly infinite float value $@ flows to cast to integer. | test.c:31:14:32:15 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:61:11:61:17 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:66:11:66:19 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:72:20:72:28 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:75:24:75:32 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:79:10:79:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:79:5:79:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:87:10:87:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:87:5:87:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:91:10:91:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:91:5:91:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:93:10:93:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:93:5:93:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:99:10:99:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:99:5:99:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:105:10:105:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:105:5:105:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:111:10:111:12 | l12 | test.c:77:15:77:21 | ... / ... | test.c:111:5:111:12 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:114:21:114:23 | l12 | test.c:77:15:77:21 | ... / ... | test.c:114:16:114:23 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:117:28:117:30 | l12 | test.c:77:15:77:21 | ... / ... | test.c:117:23:117:30 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:120:25:120:27 | l12 | test.c:77:15:77:21 | ... / ... | test.c:120:20:120:27 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.c:77:15:77:21 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:163:9:164:15 | ... / ... | test.c:163:3:164:16 | ... / ... | test.c:163:3:164:16 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.c:163:9:164:15 | ... / ... | from division by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:175:32:175:32 | p | test.c:189:51:189:59 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:189:51:189:59 | ... / ... | from division by zero | test.c:189:6:189:24 | addInfThenCastToInt | addInfThenCastToInt | -| test.c:175:32:175:32 | p | test.c:193:13:194:15 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:193:13:194:15 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | -| test.c:175:32:175:32 | p | test.c:204:19:204:27 | ... / ... | test.c:175:27:175:32 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:204:19:204:27 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | -| test.c:185:18:185:18 | p | test.c:200:25:200:33 | ... / ... | test.c:185:13:185:18 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.c:200:25:200:33 | ... / ... | from division by zero | test.c:192:6:192:7 | f2 | f2 | +subpaths \ No newline at end of file diff --git a/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql b/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql new file mode 100644 index 0000000000..f0d160a650 --- /dev/null +++ b/c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.misuseofinfinitefloatingpointvalue.MisuseOfInfiniteFloatingPointValue + +class TestFileQuery extends MisuseOfInfiniteFloatingPointValueSharedQuery, TestQuery { } diff --git a/c/misra/test/rules/DIR-4-15/test.c b/c/common/test/rules/misuseofinfinitefloatingpointvalue/test.c similarity index 82% rename from c/misra/test/rules/DIR-4-15/test.c rename to c/common/test/rules/misuseofinfinitefloatingpointvalue/test.c index a827a7df97..85097d828b 100644 --- a/c/misra/test/rules/DIR-4-15/test.c +++ b/c/common/test/rules/misuseofinfinitefloatingpointvalue/test.c @@ -33,10 +33,10 @@ void f1(float p1) { float l8 = 0.0 / 0.0; (int)l4; // COMPLIANT - (int)l5; // NON_COMPLIANT: Casting NaN to int - (int)l6; // NON_COMPLIANT: Casting NaN to int - (int)l7; // NON_COMPLIANT: Casting NaN to int - (int)l8; // NON_COMPLIANT: Casting NaN to int + (int)l5; // COMPLIANT: Casting NaN to int + (int)l6; // COMPLIANT: Casting NaN to int + (int)l7; // NON_COMPLIANT: Casting Infinity to int + (int)l8; // COMPLIANT: Casting NaN to int l4 == 0; // COMPLIANT l4 != 0; // COMPLIANT @@ -58,21 +58,21 @@ void f1(float p1) { if (l9 != 0) { (int)(l9 / l9); // COMPLIANT: l9 is not zero } else { - (int)(l9 / l9); // NON_COMPLIANT: Guarded to not be NaN + (int)(l9 / l9); // NON_COMPLIANT[False positive]: Guarded to not be NaN } float l10 = 0; if (l10 == 0) { - (int)(l10 / l10); // NON_COMPLIANT: Casting NaN to integer + (int)(l10 / l10); // NON_COMPLIANT[False positive]: Casting NaN to integer } else { (int)(l10 / l10); // COMPLIANT: Guarded to not be NaN } float l11 = 0; - l11 == 0 ? (int)(l11 / l11) : 0; // NON_COMPLIANT + l11 == 0 ? (int)(l11 / l11) : 0; // NON_COMPLIANT[False positive] l11 == 0 ? 0 : (int)(l11 / l11); // COMPLIANT l11 != 0 ? (int)(l11 / l11) : 0; // COMPLIANT - l11 != 0 ? 0 : (int)(l11 / l11); // NON_COMPLIANT + l11 != 0 ? 0 : (int)(l11 / l11); // NON_COMPLIANT[False positive] float l12 = 1.0 / 0; if (isinf(l12)) { @@ -123,29 +123,29 @@ void f1(float p1) { if (isinf(l13)) { (int)l13; // COMPLIANT: Guarded not to be NaN } else { - (int)l13; // NON_COMPLIANT: Casting NaN to integer + (int)l13; // COMPLIANT: Casting NaN to integer } if (isinf(l13) == 1) { (int)l13; // COMPLIANT: Guarded not to be NaN (must be +Infinity) } else { - (int)l13; // NON_COMPLIANT: Casting NaN to integer + (int)l13; // COMPLIANT: Casting NaN to integer } if (isfinite(l13)) { (int)l13; // COMPLIANT: Guarded not to be NaN } else { - (int)l13; // NON_COMPLIANT: Casting NaN to integer + (int)l13; // COMPLIANT: Casting NaN to integer } if (isnormal(l13)) { (int)l13; // COMPLIANT: Guarded not to be NaN } else { - (int)l13; // NON_COMPLIANT: Casting NaN to integer + (int)l13; // COMPLIANT: Casting NaN to integer } if (isnan(l13)) { - (int)l13; // NON_COMPLIANT: Casting NaN to integer + (int)l13; // COMPLIANT: Casting NaN to integer } else { (int)l13; // COMPLIANT: Guarded not to be NaN } @@ -154,21 +154,21 @@ void f1(float p1) { : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use isinf(l13) ? 0 : (int)l13; // COMPLIANT: Check on wrong branch isfinite(l13) ? (int)l13 : 0; // COMPLIANT: Checked finite before use - isfinite(l13) ? 0 : (int)l13; // NON_COMPLIANT: Checked on wrong branch - isnan(l13) ? (int)l13 : 0; // NON_COMPLIANT: Check on wrong branch + isfinite(l13) ? 0 : (int)l13; // COMPLIANT: Checked on wrong branch + isnan(l13) ? (int)l13 : 0; // COMPLIANT: Check on wrong branch isnan(l13) ? 0 : (int)l13; // COMPLIANT: Checked not NaN before use - (int)pow(2, p1); // NON_COMPLIANT: likely to be Infinity + (int)pow(2, p1); // NON_COMPLIANT[False negative]: likely to be Infinity (int)pow(2, sin(p1)); // COMPLIANT: not likely to be Infinity (int)(1 / sin(p1)); // NON_COMPLIANT: possible infinity from zero in denominator (int)(1 / log(p1)); // COMPLIANT: not possibly zero in denominator - (int)pow(p1, p1); // NON_COMPLIANT: NaN if p1 is zero + (int)pow(p1, p1); // COMPLIANT: NaN if p1 is zero if (p1 != 0) { (int)pow(p1, p1); // COMPLIANT: p1 is not zero } - (int)acos(p1); // NON_COMPLIANT: NaN if p1 is not within -1..1 + (int)acos(p1); // COMPLIANT: NaN if p1 is not within -1..1 (int)acos(cos(p1)); // COMPLIANT: cos(p1) is within -1..1 } @@ -192,13 +192,13 @@ void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } void f2() { castToInt(1.0 / 0.0); // NON_COMPLIANT: Infinity flows to denominator in division - castToInt(0.0 / 0.0); // NON_COMPLIANT: NaN flows to denominator in division + castToInt(0.0 / 0.0); // COMPLIANT checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT addOneThenCastToInt(1.0 / 0.0); // NON_COMPLIANT[False negative] addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT castToIntToFloatToInt(1.0 / 0.0); // NON_COMPLIANT - castToIntToFloatToInt(0.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(0.0 / 0.0); // COMPLIANT // Check that during flow analysis, we only report the true root cause: float rootInf = 1.0 / 0.0; @@ -206,7 +206,7 @@ void f2() { float middleInf = rootInf + 1; float middleNaN = rootNaN + 1; castToInt(middleInf); // NON_COMPLIANT - castToInt(middleNaN); // NON_COMPLIANT + castToInt(middleNaN); // COMPLIANT addInfThenCastToInt(middleInf); // NON_COMPLIANT - addNaNThenCastToInt(middleNaN); // NON_COMPLIANT + addNaNThenCastToInt(middleNaN); // COMPLIANT } \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected b/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected similarity index 99% rename from c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected rename to c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected index aeec3c943f..1555fd5bd8 100644 --- a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.expected +++ b/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected @@ -1,3 +1,36 @@ +problems +| test.c:36:8:36:9 | l5 | test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | Possible NaN value $@ flows to a cast to integer. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:37:8:37:9 | l6 | test.c:28:14:28:20 | ... / ... | test.c:37:3:37:9 | l6 | Possible NaN value $@ flows to a cast to integer. | test.c:28:14:28:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Possible NaN value $@ flows to a cast to integer. | test.c:31:14:32:15 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:39:8:39:9 | l8 | test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | Possible NaN value $@ flows to a cast to integer. | test.c:33:14:33:22 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:46:3:46:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:46:3:46:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:47:3:47:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:47:3:47:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:48:3:48:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:48:3:48:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:49:3:49:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:49:3:49:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:50:3:50:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:50:3:50:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:51:3:51:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:51:3:51:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:52:3:52:4 | l6 | test.c:28:14:28:20 | ... / ... | test.c:52:3:52:4 | l6 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:28:14:28:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | +| test.c:53:3:53:4 | l7 | test.c:31:14:32:15 | ... / ... | test.c:53:3:53:4 | l7 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:31:14:32:15 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:54:3:54:4 | l8 | test.c:33:14:33:22 | ... / ... | test.c:54:3:54:4 | l8 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:33:14:33:22 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:61:11:61:17 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:66:11:66:19 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:72:20:72:28 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:75:24:75:32 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:126:10:126:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:126:5:126:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:132:10:132:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:132:5:132:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:138:10:138:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:138:5:138:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:144:10:144:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:144:5:144:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:148:10:148:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:148:5:148:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:155:25:155:27 | l13 | test.c:122:15:122:21 | ... / ... | test.c:155:20:155:27 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:157:28:157:30 | l13 | test.c:122:15:122:21 | ... / ... | test.c:157:23:157:30 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:158:21:158:23 | l13 | test.c:122:15:122:21 | ... / ... | test.c:158:16:158:23 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:166:8:166:10 | call to pow | test.c:166:3:166:18 | call to pow | test.c:166:3:166:18 | call to pow | Possible NaN value $@ flows to a cast to integer. | test.c:166:8:166:10 | call to pow | both arguments are equal to zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:171:8:171:11 | call to acos | test.c:171:3:171:15 | call to acos | test.c:171:3:171:15 | call to acos | Possible NaN value $@ flows to a cast to integer. | test.c:171:8:171:11 | call to acos | the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0) | test.c:6:6:6:7 | f1 | f1 | +| test.c:175:32:175:32 | p | test.c:190:51:190:59 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:190:51:190:59 | ... / ... | from division of zero by zero | test.c:190:6:190:24 | addNaNThenCastToInt | addNaNThenCastToInt | +| test.c:175:32:175:32 | p | test.c:195:13:195:21 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:195:13:195:21 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:175:32:175:32 | p | test.c:199:23:199:31 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:199:23:199:31 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:175:32:175:32 | p | test.c:205:19:205:27 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:205:19:205:27 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:185:18:185:18 | p | test.c:201:25:201:33 | ... / ... | test.c:185:13:185:18 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:201:25:201:33 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | edges | test.c:27:14:27:20 | ... / ... | test.c:27:14:27:20 | ... / ... | provenance | | | test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | provenance | | @@ -100,37 +133,4 @@ nodes | test.c:207:21:207:31 | ... + ... | semmle.label | ... + ... | | test.c:209:13:209:21 | middleNaN | semmle.label | middleNaN | | test.c:211:23:211:31 | middleNaN | semmle.label | middleNaN | -subpaths -#select -| test.c:36:8:36:9 | l5 | test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | Possible NaN value $@ flows to a cast to integer. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:37:8:37:9 | l6 | test.c:28:14:28:20 | ... / ... | test.c:37:3:37:9 | l6 | Possible NaN value $@ flows to a cast to integer. | test.c:28:14:28:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:38:8:38:9 | l7 | test.c:31:14:32:15 | ... / ... | test.c:38:3:38:9 | l7 | Possible NaN value $@ flows to a cast to integer. | test.c:31:14:32:15 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:39:8:39:9 | l8 | test.c:33:14:33:22 | ... / ... | test.c:39:3:39:9 | l8 | Possible NaN value $@ flows to a cast to integer. | test.c:33:14:33:22 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:46:3:46:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:46:3:46:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:47:3:47:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:47:3:47:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:48:3:48:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:48:3:48:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:49:3:49:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:49:3:49:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:50:3:50:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:50:3:50:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:51:3:51:4 | l5 | test.c:27:14:27:20 | ... / ... | test.c:51:3:51:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:27:14:27:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:52:3:52:4 | l6 | test.c:28:14:28:20 | ... / ... | test.c:52:3:52:4 | l6 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:28:14:28:20 | ... / ... | from division of infinity by infinity | test.c:6:6:6:7 | f1 | f1 | -| test.c:53:3:53:4 | l7 | test.c:31:14:32:15 | ... / ... | test.c:53:3:53:4 | l7 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:31:14:32:15 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:54:3:54:4 | l8 | test.c:33:14:33:22 | ... / ... | test.c:54:3:54:4 | l8 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.c:33:14:33:22 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:61:11:61:17 | ... / ... | test.c:61:5:61:18 | ... / ... | test.c:61:5:61:18 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:61:11:61:17 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:66:11:66:19 | ... / ... | test.c:66:5:66:20 | ... / ... | test.c:66:5:66:20 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:66:11:66:19 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:72:20:72:28 | ... / ... | test.c:72:14:72:29 | ... / ... | test.c:72:14:72:29 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:72:20:72:28 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:75:24:75:32 | ... / ... | test.c:75:18:75:33 | ... / ... | test.c:75:18:75:33 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.c:75:24:75:32 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:126:10:126:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:126:5:126:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:132:10:132:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:132:5:132:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:138:10:138:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:138:5:138:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:144:10:144:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:144:5:144:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:148:10:148:12 | l13 | test.c:122:15:122:21 | ... / ... | test.c:148:5:148:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:155:25:155:27 | l13 | test.c:122:15:122:21 | ... / ... | test.c:155:20:155:27 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:157:28:157:30 | l13 | test.c:122:15:122:21 | ... / ... | test.c:157:23:157:30 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:158:21:158:23 | l13 | test.c:122:15:122:21 | ... / ... | test.c:158:16:158:23 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:166:8:166:10 | call to pow | test.c:166:3:166:18 | call to pow | test.c:166:3:166:18 | call to pow | Possible NaN value $@ flows to a cast to integer. | test.c:166:8:166:10 | call to pow | both arguments are equal to zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:171:8:171:11 | call to acos | test.c:171:3:171:15 | call to acos | test.c:171:3:171:15 | call to acos | Possible NaN value $@ flows to a cast to integer. | test.c:171:8:171:11 | call to acos | the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0) | test.c:6:6:6:7 | f1 | f1 | -| test.c:175:32:175:32 | p | test.c:190:51:190:59 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:190:51:190:59 | ... / ... | from division of zero by zero | test.c:190:6:190:24 | addNaNThenCastToInt | addNaNThenCastToInt | -| test.c:175:32:175:32 | p | test.c:195:13:195:21 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:195:13:195:21 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | -| test.c:175:32:175:32 | p | test.c:199:23:199:31 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:199:23:199:31 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | -| test.c:175:32:175:32 | p | test.c:205:19:205:27 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:205:19:205:27 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | -| test.c:185:18:185:18 | p | test.c:201:25:201:33 | ... / ... | test.c:185:13:185:18 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:201:25:201:33 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | +subpaths \ No newline at end of file diff --git a/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql b/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql new file mode 100644 index 0000000000..a1f729ed02 --- /dev/null +++ b/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.misuseofnanfloatingpointvalue.MisuseOfNaNFloatingPointValue + +class TestFileQuery extends MisuseOfNaNFloatingPointValueSharedQuery, TestQuery { } diff --git a/c/common/test/rules/misuseofnanfloatingpointvalue/test.c b/c/common/test/rules/misuseofnanfloatingpointvalue/test.c new file mode 100644 index 0000000000..5115727115 --- /dev/null +++ b/c/common/test/rules/misuseofnanfloatingpointvalue/test.c @@ -0,0 +1,212 @@ +#include "math.h" + +float getFloat() { return 1.0; } + +// Parameter could be infinity +void f1(float p1) { + float l1 = 1; + float l2 = 1.0 / 0; + float l3 = -l2; + + 10 / l1; // COMPLIANT + 10 / l2; // COMPLIANT: Underflows to zero + 10 / l3; // COMPLIANT: Underflow to negative zero + 10 / p1; // COMPLIANT: Reduce false positives by assuming not infinity + 10 / getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + (int)l1; // COMPLIANT + (int)l2; // COMPLIANT + (int)l3; // COMPLIANT + (int)p1; // COMPLIANT: Reduce false positives by assuming not infinity + (int)getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + // Not NaN: + float l4 = l1 / l1; // COMPLIANT + + // NaN because of infinity divided by itself: + float l5 = l2 / l2; // COMPLIANT: Division by infinity not allowed. + float l6 = l3 / l3; // COMPLIANT: Division by infinity not allowed. + + // NaN because of zero divided by itself: + float l7 = getFloat() / + p1; // COMPLIANT: Reduce false positives by assuming not infinity + float l8 = 0.0 / 0.0; + + (int)l4; // COMPLIANT + (int)l5; // NON_COMPLIANT: Casting NaN to int + (int)l6; // NON_COMPLIANT: Casting NaN to int + (int)l7; // NON_COMPLIANT: Casting NaN to int + (int)l8; // NON_COMPLIANT: Casting NaN to int + + l4 == 0; // COMPLIANT + l4 != 0; // COMPLIANT + l4 <= 0; // COMPLIANT + l4 < 0; // COMPLIANT + l4 >= 0; // COMPLIANT + l5 == 0; // NON_COMPLIANT: Comparison with NaN always false + l5 != 0; // NON_COMPLIANT: Comparison with NaN always false + l5 < 0; // NON_COMPLIANT: Comparison with NaN always false + l5 <= 0; // NON_COMPLIANT: Comparison with NaN always false + l5 > 0; // NON_COMPLIANT: Comparison with NaN always false + l5 >= 0; // NON_COMPLIANT: Comparison with NaN always false + l6 == 0; // NON_COMPLIANT: Comparison with NaN always false + l7 == 0; // NON_COMPLIANT: Comparison with NaN always false + l8 == 0; // NON_COMPLIANT: Comparison with NaN always false + + // Guards + float l9 = 0; + if (l9 != 0) { + (int)(l9 / l9); // COMPLIANT: l9 is not zero + } else { + (int)(l9 / l9); // NON_COMPLIANT: Casting NaN to integer + } + + float l10 = 0; + if (l10 == 0) { + (int)(l10 / l10); // NON_COMPLIANT: Casting NaN to integer + } else { + (int)(l10 / l10); // COMPLIANT: Guarded to not be NaN + } + + float l11 = 0; + l11 == 0 ? (int)(l11 / l11) : 0; // NON_COMPLIANT + l11 == 0 ? 0 : (int)(l11 / l11); // COMPLIANT + l11 != 0 ? (int)(l11 / l11) : 0; // COMPLIANT + l11 != 0 ? 0 : (int)(l11 / l11); // NON_COMPLIANT + + float l12 = 1.0 / 0; + if (isinf(l12)) { + (int)l12; // COMPLIANT: Casting Infinity to integer + } else { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } + + if (!isinf(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (isinf(l12) == 1) { + (int)l12; // COMPLIANT: Must be +Infinity + } else { + (int)l12; // COMPLIANT: May be -Infinity + } + + if (isfinite(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (isnormal(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (isnan(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + isinf(l12) ? (int)l12 : 0; // COMPLIANT: Check on wrong branch + isinf(l12) ? 0 : (int)l12; // COMPLIANT: Checked not infinite before use + isfinite(l12) ? (int)l12 : 0; // COMPLIANT: Checked finite before use + isfinite(l12) ? 0 : (int)l12; // COMPLIANT: Checked on wrong branch + isnan(l12) ? (int)l12 + : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use + isnan(l12) ? 0 : (int)l12; // COMPLIANT: Check on wrong branch + + float l13 = 0.0 / 0; + if (isinf(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isinf(l13) == 1) { + (int)l13; // COMPLIANT: Guarded not to be NaN (must be +Infinity) + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isfinite(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isnormal(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (isnan(l13)) { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } else { + (int)l13; // COMPLIANT: Guarded not to be NaN + } + + isinf(l13) ? (int)l13 + : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use + isinf(l13) ? 0 : (int)l13; // NON_COMPLIANT: Check on wrong branch + isfinite(l13) ? (int)l13 : 0; // COMPLIANT: Checked finite before use + isfinite(l13) ? 0 : (int)l13; // NON_COMPLIANT: Checked on wrong branch + isnan(l13) ? (int)l13 : 0; // NON_COMPLIANT: Check on wrong branch + isnan(l13) ? 0 : (int)l13; // COMPLIANT: Checked not NaN before use + + (int)pow(2, p1); // COMPLIANT: likely to be Infinity + (int)pow(2, sin(p1)); // COMPLIANT: not likely to be Infinity + (int)(1 / + sin(p1)); // COMPLIANT: possible infinity from zero in denominator + (int)(1 / log(p1)); // COMPLIANT: not possibly zero in denominator + (int)pow(p1, p1); // NON_COMPLIANT: NaN if p1 is zero + if (p1 != 0) { + (int)pow(p1, p1); // COMPLIANT: p1 is not zero + } + + (int)acos(p1); // NON_COMPLIANT: NaN if p1 is not within -1..1 + (int)acos(cos(p1)); // COMPLIANT: cos(p1) is within -1..1 +} + +void castToInt(float p) { (int)p; } + +void checkBeforeCastToInt(float p) { + if (isfinite(p)) { + castToInt(p); + } +} + +void castToIntToFloatToInt(float p) { + // This should be reported as a violation, but not downstream from here. + castToInt((int)p); +} + +void addOneThenCastToInt(float p) { castToInt(p + 1); } +void addInfThenCastToInt(float p) { castToInt(p + 1.0 / 0.0); } +void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } + +void f2() { + castToInt(1.0 / + 0.0); // COMPLIANT: Infinity flows to denominator in division + castToInt(0.0 / 0.0); // COMPLIANT: NaN flows to denominator in division + checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT + addOneThenCastToInt(1.0 / 0.0); // COMPLIANT + addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(1.0 / 0.0); // COMPLIANT + castToIntToFloatToInt(0.0 / 0.0); // NON_COMPLIANT + + // Check that during flow analysis, we only report the true root cause: + float rootInf = 1.0 / 0.0; + float rootNaN = 0.0 / 0.0; + float middleInf = rootInf + 1; + float middleNaN = rootNaN + 1; + castToInt(middleInf); // COMPLIANT + castToInt(middleNaN); // NON_COMPLIANT + addInfThenCastToInt(middleInf); // NON_COMPLIANT + addNaNThenCastToInt(middleNaN); // NON_COMPLIANT +} \ No newline at end of file diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql index 812e9fe1e2..0294fc6919 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql @@ -13,130 +13,11 @@ */ import cpp -import codeql.util.Boolean import codingstandards.c.misra -import codingstandards.cpp.RestrictedRangeAnalysis -import codingstandards.cpp.FloatingPoint -import codingstandards.cpp.AlertReporting -import semmle.code.cpp.controlflow.Guards -import semmle.code.cpp.dataflow.new.DataFlow -import semmle.code.cpp.dataflow.new.TaintTracking -import semmle.code.cpp.controlflow.Dominance +import codingstandards.cpp.rules.misuseofinfinitefloatingpointvalue.MisuseOfInfiniteFloatingPointValue -module InvalidInfinityUsage implements DataFlow::ConfigSig { - /** - * An operation which does not have Infinity as an input, but may produce Infinity, according - * to the `RestrictedRangeAnalysis` module. - */ - predicate isSource(DataFlow::Node node) { - potentialSource(node) and - not exists(DataFlow::Node prior | - isAdditionalFlowStep(prior, node) and - potentialSource(prior) - ) - } - - /** - * An operation which may produce Infinity acconding to the `RestrictedRangeAnalysis` module. - */ - additional predicate potentialSource(DataFlow::Node node) { - node.asExpr() instanceof Operation and - exprMayEqualInfinity(node.asExpr(), _) - } - - predicate isBarrierOut(DataFlow::Node node) { - guardedNotFPClass(node.asExpr(), TInfinite()) - or - exists(Expr e | - e.getType() instanceof IntegralType and - e = node.asConvertedExpr() - ) - } - - /** - * An additional flow step to handle operations which propagate Infinity. - * - * This double checks that an Infinity may propagate by checking the `RestrictedRangeAnalysis` - * value estimate. This is conservative, since `RestrictedRangeAnalysis` is performed locally - * in scope with unanalyzable values in a finite range. However, this conservative approach - * leverages analysis of guards and other local conditions to avoid false positives. - */ - predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) { - exists(Operation o | - o.getAnOperand() = source.asExpr() and - o = sink.asExpr() and - potentialSource(sink) - ) - } - - predicate isSink(DataFlow::Node node) { - node instanceof InvalidInfinityUsage and - ( - // Require that range analysis finds this value potentially infinite, to avoid false positives - // in the presence of guards. This may induce false negatives. - exprMayEqualInfinity(node.asExpr(), _) - or - // Unanalyzable expressions are not checked against range analysis, which assumes a finite - // range. - not RestrictedRangeAnalysis::canBoundExpr(node.asExpr()) - or - node.asExpr().(VariableAccess).getTarget() instanceof Parameter - ) +class PossibleMisuseOfUndetectedInfinityQuery extends MisuseOfInfiniteFloatingPointValueSharedQuery { + PossibleMisuseOfUndetectedInfinityQuery() { + this = FloatingTypes2Package::possibleMisuseOfUndetectedInfinityQuery() } } - -class InvalidInfinityUsage extends DataFlow::Node { - string description; - - InvalidInfinityUsage() { - // Case 2: NaNs and infinities shall not be cast to integers - exists(Conversion c | - asExpr() = c.getUnconverted() and - c.getExpr().getType() instanceof FloatingPointType and - c.getType() instanceof IntegralType and - description = "cast to integer." - ) - or - // Case 3: Infinities shall not underflow or otherwise produce finite values - exists(BinaryOperation op | - asExpr() = op.getRightOperand() and - op.getOperator() = "/" and - description = "divisor, which would silently underflow and produce zero." - ) - } - - string getDescription() { result = description } -} - -module InvalidInfinityFlow = DataFlow::Global; - -import InvalidInfinityFlow::PathGraph - -from - Element elem, InvalidInfinityFlow::PathNode source, InvalidInfinityFlow::PathNode sink, - InvalidInfinityUsage usage, Expr sourceExpr, string sourceString, Function function, - string computedInFunction -where - elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and - not InvalidInfinityFlow::PathGraph::edges(_, source, _, _) and - not InvalidInfinityFlow::PathGraph::edges(sink, _, _, _) and - not isExcluded(elem, FloatingTypes2Package::possibleMisuseOfUndetectedInfinityQuery()) and - not sourceExpr.isFromTemplateInstantiation(_) and - not usage.asExpr().isFromTemplateInstantiation(_) and - usage = sink.getNode() and - sourceExpr = source.getNode().asExpr() and - function = sourceExpr.getEnclosingFunction() and - InvalidInfinityFlow::flow(source.getNode(), usage) and - ( - if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() - then computedInFunction = "computed in function $@ " - else computedInFunction = "" - ) and - ( - if sourceExpr instanceof DivExpr - then sourceString = "from division by zero" - else sourceString = sourceExpr.toString() - ) -select elem, source, sink, - "Possibly infinite float value $@ " + computedInFunction + "flows to " + usage.getDescription(), - sourceExpr, sourceString, function, function.getName() diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql index e1b6762ada..10bfcafeba 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql @@ -13,190 +13,11 @@ */ import cpp -import codeql.util.Boolean import codingstandards.c.misra -import codingstandards.cpp.RestrictedRangeAnalysis -import codingstandards.cpp.FloatingPoint -import codingstandards.cpp.AlertReporting -import semmle.code.cpp.controlflow.Guards -import semmle.code.cpp.dataflow.new.DataFlow -import semmle.code.cpp.dataflow.new.TaintTracking -import semmle.code.cpp.controlflow.Dominance +import codingstandards.cpp.rules.misuseofnanfloatingpointvalue.MisuseOfNaNFloatingPointValue -abstract class PotentiallyNaNExpr extends Expr { - abstract string getReason(); -} - -class DomainErrorFunctionCall extends FunctionCall, PotentiallyNaNExpr { - string reason; - - DomainErrorFunctionCall() { RestrictedDomainError::hasDomainError(this, reason) } - - override string getReason() { result = reason } -} - -// IEEE 754-1985 Section 7.1 invalid operations -class InvalidOperationExpr extends BinaryOperation, PotentiallyNaNExpr { - string reason; - - InvalidOperationExpr() { - // Usual arithmetic conversions in both languages mean that if either operand is a floating - // type, the other one is converted to a floating type as well. - getAnOperand().getFullyConverted().getType() instanceof FloatingPointType and - ( - // 7.1.1 propagates signaling NaNs, we rely on flow analysis and/or assume quiet NaNs, so we - // intentionally do not cover this case. - // 7.1.2: magnitude subtraction of infinities, such as +Inf + -Inf - getOperator() = "+" and - exists(Boolean sign | - exprMayEqualInfinity(getLeftOperand(), sign) and - exprMayEqualInfinity(getRightOperand(), sign.booleanNot()) - ) and - reason = "from addition of infinity and negative infinity" - or - // 7.1.2 continued - getOperator() = "-" and - exists(Boolean sign | - exprMayEqualInfinity(getLeftOperand(), sign) and - exprMayEqualInfinity(getRightOperand(), sign) - ) and - reason = "from subtraction of an infinity from itself" - or - // 7.1.3: multiplication of zero by infinity - getOperator() = "*" and - exists(Expr zeroOp, Expr infinityOp | - zeroOp = getAnOperand() and - infinityOp = getAnOperand() and - not zeroOp = infinityOp and - exprMayEqualZero(zeroOp) and - exprMayEqualInfinity(infinityOp, _) - ) and - reason = "from multiplication of zero by infinity" - or - // 7.1.4: Division of zero by zero, or infinity by infinity - getOperator() = "/" and - exprMayEqualZero(getLeftOperand()) and - exprMayEqualZero(getRightOperand()) and - reason = "from division of zero by zero" - or - // 7.1.4 continued - getOperator() = "/" and - exprMayEqualInfinity(getLeftOperand(), _) and - exprMayEqualInfinity(getRightOperand(), _) and - reason = "from division of infinity by infinity" - or - // 7.1.5: x % y where y is zero or x is infinite - getOperator() = "%" and - exprMayEqualInfinity(getLeftOperand(), _) and - reason = "from modulus of infinity" - or - // 7.1.5 continued - getOperator() = "%" and - exprMayEqualZero(getRightOperand()) and - reason = "from modulus by zero" - // 7.1.6 handles the sqrt function, not covered here. - // 7.1.7 declares exceptions during invalid conversions, which we catch as sinks in our flow - // analysis. - // 7.1.8 declares exceptions for unordered comparisons, which we catch as sinks in our flow - // analysis. - ) - } - - override string getReason() { result = reason } -} - -module InvalidNaNUsage implements DataFlow::ConfigSig { - /** - * An expression which has non-NaN inputs and may produce a NaN output. - */ - predicate isSource(DataFlow::Node node) { - potentialSource(node) and - not exists(DataFlow::Node prior | - isAdditionalFlowStep(prior, node) and - potentialSource(prior) - ) - } - - /** - * An expression which may produce a NaN output. - */ - additional predicate potentialSource(DataFlow::Node node) { - node.asExpr() instanceof PotentiallyNaNExpr - } - - predicate isBarrierOut(DataFlow::Node node) { - guardedNotFPClass(node.asExpr(), TNaN()) - or - exists(Expr e | - e.getType() instanceof IntegralType and - e = node.asConvertedExpr() - ) +class PossibleMisuseOfUndetectedNaNQuery extends MisuseOfNaNFloatingPointValueSharedQuery { + PossibleMisuseOfUndetectedNaNQuery() { + this = FloatingTypes2Package::possibleMisuseOfUndetectedNaNQuery() } - - /** - * Add an additional flow step to handle NaN propagation through floating point operations. - */ - predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) { - exists(Operation o | - o.getAnOperand() = source.asExpr() and - o = sink.asExpr() and - o.getType() instanceof FloatingPointType - ) - } - - predicate isSink(DataFlow::Node node) { - not guardedNotFPClass(node.asExpr(), TNaN()) and - node instanceof InvalidNaNUsage - } -} - -class InvalidNaNUsage extends DataFlow::Node { - string description; - - InvalidNaNUsage() { - // Case 1: NaNs shall not be compared, except to themselves - exists(ComparisonOperation cmp | - this.asExpr() = cmp.getAnOperand() and - not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand()) and - description = "comparison, which would always evaluate to false." - ) - or - // Case 2: NaNs and infinities shall not be cast to integers - exists(Conversion c | - this.asExpr() = c.getUnconverted() and - c.getExpr().getType() instanceof FloatingPointType and - c.getType() instanceof IntegralType and - description = "a cast to integer." - ) - } - - string getDescription() { result = description } -} - -module InvalidNaNFlow = DataFlow::Global; - -import InvalidNaNFlow::PathGraph - -from - Element elem, InvalidNaNFlow::PathNode source, InvalidNaNFlow::PathNode sink, - InvalidNaNUsage usage, Expr sourceExpr, string sourceString, Function function, - string computedInFunction -where - not InvalidNaNFlow::PathGraph::edges(_, source, _, _) and - not InvalidNaNFlow::PathGraph::edges(sink, _, _, _) and - not sourceExpr.isFromTemplateInstantiation(_) and - not usage.asExpr().isFromTemplateInstantiation(_) and - elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and - usage = sink.getNode() and - sourceExpr = source.getNode().asExpr() and - sourceString = source.getNode().asExpr().(PotentiallyNaNExpr).getReason() and - function = sourceExpr.getEnclosingFunction() and - InvalidNaNFlow::flow(source.getNode(), usage) and - ( - if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() - then computedInFunction = "computed in function $@ " - else computedInFunction = "" - ) -select elem, source, sink, - "Possible NaN value $@ " + computedInFunction + "flows to " + usage.getDescription(), sourceExpr, - sourceString, function, function.getName() +} \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.testref b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.testref new file mode 100644 index 0000000000..176855a83d --- /dev/null +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.testref @@ -0,0 +1 @@ +c/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.testref b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.testref new file mode 100644 index 0000000000..7cd2a4d431 --- /dev/null +++ b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.testref @@ -0,0 +1 @@ +c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql \ No newline at end of file diff --git a/change_notes/2025-04-14-update-infinity-nan-detection.md b/change_notes/2025-04-14-update-infinity-nan-detection.md new file mode 100644 index 0000000000..fe484a37fe --- /dev/null +++ b/change_notes/2025-04-14-update-infinity-nan-detection.md @@ -0,0 +1,4 @@ + - `DIR-4-15` - `PossibleMisuseOfUndetectedInfinity.ql`, `PossibleMisuseOfUndetectedNaN.ql`: + - Add logic to suppress NaNs from the CodeQL extractor in the new restricted range analysis, which can have unexpected downstream effects. + - Alter the behavior of floating point class guards (such as `isinf`, `isfinite`, `isnan`) to more correctly reflect the branches that have been guarded. + - Query files have been moved/refactored to share logic across MISRA-C and MISRA-C++; no observable change in behavior from this is expected. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/FloatingPoint.qll b/cpp/common/src/codingstandards/cpp/FloatingPoint.qll index f5ff2fefca..cebb9dd29f 100644 --- a/cpp/common/src/codingstandards/cpp/FloatingPoint.qll +++ b/cpp/common/src/codingstandards/cpp/FloatingPoint.qll @@ -325,7 +325,8 @@ predicate guardedNotFPClass(Expr e, FPClassification cls) { hashCons(checked) = hashCons(e) and guard.controls(e, cmpEq) and guard.constrainsFPClass(checked, constraint, cmpEq) and - constraint.mustNotBe(cls) + constraint.mustNotBe(cls) and + not e = checked ) } diff --git a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll index 05290b3aaf..5d955cc117 100644 --- a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll +++ b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll @@ -1093,7 +1093,8 @@ module RestrictedRangeAnalysis { ( // If the expression evaluates to a constant, then there is no // need to call getUpperBoundsImpl. - if exists(getValue(expr).toFloat()) + if exists(getValue(expr).toFloat()) and + not getValue(expr) = "NaN" then result = getValue(expr).toFloat() else ( // Some of the bounds computed by `getUpperBoundsImpl` diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/FloatingPoint.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/FloatingPoint.qll new file mode 100644 index 0000000000..0ff7a07214 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/FloatingPoint.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype FloatingPointQuery = + TPossibleMisuseOfInfiniteFloatingPointValueQuery() or + TPossibleMisuseOfNaNFloatingPointValueQuery() + +predicate isFloatingPointQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `possibleMisuseOfInfiniteFloatingPointValue` query + FloatingPointPackage::possibleMisuseOfInfiniteFloatingPointValueQuery() and + queryId = + // `@id` for the `possibleMisuseOfInfiniteFloatingPointValue` query + "cpp/misra/possible-misuse-of-infinite-floating-point-value" and + ruleId = "DIR-0-3-1" and + category = "advisory" + or + query = + // `Query` instance for the `possibleMisuseOfNaNFloatingPointValue` query + FloatingPointPackage::possibleMisuseOfNaNFloatingPointValueQuery() and + queryId = + // `@id` for the `possibleMisuseOfNaNFloatingPointValue` query + "cpp/misra/possible-misuse-of-nan-floating-point-value" and + ruleId = "DIR-0-3-1" and + category = "advisory" +} + +module FloatingPointPackage { + Query possibleMisuseOfInfiniteFloatingPointValueQuery() { + //autogenerate `Query` type + result = + // `Query` type for `possibleMisuseOfInfiniteFloatingPointValue` query + TQueryCPP(TFloatingPointPackageQuery(TPossibleMisuseOfInfiniteFloatingPointValueQuery())) + } + + Query possibleMisuseOfNaNFloatingPointValueQuery() { + //autogenerate `Query` type + result = + // `Query` type for `possibleMisuseOfNaNFloatingPointValue` query + TQueryCPP(TFloatingPointPackageQuery(TPossibleMisuseOfNaNFloatingPointValueQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index 4a6cbe936b..abd6aeff96 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -18,6 +18,7 @@ import ExceptionSafety import Exceptions1 import Exceptions2 import Expressions +import FloatingPoint import Freed import Functions import IO @@ -72,6 +73,7 @@ newtype TCPPQuery = TExceptions1PackageQuery(Exceptions1Query q) or TExceptions2PackageQuery(Exceptions2Query q) or TExpressionsPackageQuery(ExpressionsQuery q) or + TFloatingPointPackageQuery(FloatingPointQuery q) or TFreedPackageQuery(FreedQuery q) or TFunctionsPackageQuery(FunctionsQuery q) or TIOPackageQuery(IOQuery q) or @@ -126,6 +128,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isExceptions1QueryMetadata(query, queryId, ruleId, category) or isExceptions2QueryMetadata(query, queryId, ruleId, category) or isExpressionsQueryMetadata(query, queryId, ruleId, category) or + isFloatingPointQueryMetadata(query, queryId, ruleId, category) or isFreedQueryMetadata(query, queryId, ruleId, category) or isFunctionsQueryMetadata(query, queryId, ruleId, category) or isIOQueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.qll b/cpp/common/src/codingstandards/cpp/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.qll new file mode 100644 index 0000000000..eecd349ad7 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.qll @@ -0,0 +1,141 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Possible misuse of a generate infinite floating point value. + */ + +import cpp +import codeql.util.Boolean +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.RestrictedRangeAnalysis +import codingstandards.cpp.FloatingPoint +import codingstandards.cpp.AlertReporting +import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.dataflow.new.TaintTracking +import semmle.code.cpp.controlflow.Dominance + +module InvalidInfinityUsage implements DataFlow::ConfigSig { + /** + * An operation which does not have Infinity as an input, but may produce Infinity, according + * to the `RestrictedRangeAnalysis` module. + */ + predicate isSource(DataFlow::Node node) { + potentialSource(node) and + not exists(DataFlow::Node prior | + isAdditionalFlowStep(prior, node) and + potentialSource(prior) + ) + } + + /** + * An operation which may produce Infinity acconding to the `RestrictedRangeAnalysis` module. + */ + additional predicate potentialSource(DataFlow::Node node) { + node.asExpr() instanceof Operation and + exprMayEqualInfinity(node.asExpr(), _) + } + + predicate isBarrierOut(DataFlow::Node node) { + guardedNotFPClass(node.asExpr(), TInfinite()) + or + exists(Expr e | + e.getType() instanceof IntegralType and + e = node.asConvertedExpr() + ) + } + + /** + * An additional flow step to handle operations which propagate Infinity. + * + * This double checks that an Infinity may propagate by checking the `RestrictedRangeAnalysis` + * value estimate. This is conservative, since `RestrictedRangeAnalysis` is performed locally + * in scope with unanalyzable values in a finite range. However, this conservative approach + * leverages analysis of guards and other local conditions to avoid false positives. + */ + predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) { + exists(Operation o | + o.getAnOperand() = source.asExpr() and + o = sink.asExpr() and + potentialSource(sink) + ) + } + + predicate isSink(DataFlow::Node node) { + node instanceof InvalidInfinityUsage and + ( + // Require that range analysis finds this value potentially infinite, to avoid false positives + // in the presence of guards. This may induce false negatives. + exprMayEqualInfinity(node.asExpr(), _) + or + // Unanalyzable expressions are not checked against range analysis, which assumes a finite + // range. + not RestrictedRangeAnalysis::canBoundExpr(node.asExpr()) + or + node.asExpr().(VariableAccess).getTarget() instanceof Parameter + ) + } +} + +class InvalidInfinityUsage extends DataFlow::Node { + string description; + + InvalidInfinityUsage() { + // Case 2: NaNs and infinities shall not be cast to integers + exists(Conversion c | + asExpr() = c.getUnconverted() and + c.getExpr().getType() instanceof FloatingPointType and + c.getType() instanceof IntegralType and + description = "cast to integer." + ) + or + // Case 3: Infinities shall not underflow or otherwise produce finite values + exists(BinaryOperation op | + asExpr() = op.getRightOperand() and + op.getOperator() = "/" and + description = "divisor, which would silently underflow and produce zero." + ) + } + + string getDescription() { result = description } +} + +module InvalidInfinityFlow = DataFlow::Global; + +import InvalidInfinityFlow::PathGraph + +abstract class MisuseOfInfiniteFloatingPointValueSharedQuery extends Query { } + +Query getQuery() { result instanceof MisuseOfInfiniteFloatingPointValueSharedQuery } + +query predicate problems( + Element elem, InvalidInfinityFlow::PathNode source, InvalidInfinityFlow::PathNode sink, + string message, Expr sourceExpr, string sourceString, Function function, string functionName +) { + not isExcluded(elem, getQuery()) and + exists(InvalidInfinityUsage usage, string computedInFunction | + elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and + not InvalidInfinityFlow::PathGraph::edges(_, source, _, _) and + not InvalidInfinityFlow::PathGraph::edges(sink, _, _, _) and + not sourceExpr.isFromTemplateInstantiation(_) and + not usage.asExpr().isFromTemplateInstantiation(_) and + usage = sink.getNode() and + sourceExpr = source.getNode().asExpr() and + function = sourceExpr.getEnclosingFunction() and + InvalidInfinityFlow::flow(source.getNode(), usage) and + ( + if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() + then computedInFunction = "computed in function $@ " + else computedInFunction = "" + ) and + ( + if sourceExpr instanceof DivExpr + then sourceString = "from division by zero" + else sourceString = sourceExpr.toString() + ) and + message = + "Possibly infinite float value $@ " + computedInFunction + "flows to " + + usage.getDescription() and + functionName = function.getName() + ) +} diff --git a/cpp/common/src/codingstandards/cpp/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.qll b/cpp/common/src/codingstandards/cpp/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.qll new file mode 100644 index 0000000000..19ec4e1986 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.qll @@ -0,0 +1,201 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * Possible mishandling of an undetected NaN value produced by a floating point + * operation. + */ + +import cpp +import codeql.util.Boolean +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.RestrictedRangeAnalysis +import codingstandards.cpp.FloatingPoint +import codingstandards.cpp.AlertReporting +import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.dataflow.new.DataFlow +import semmle.code.cpp.dataflow.new.TaintTracking +import semmle.code.cpp.controlflow.Dominance + +abstract class PotentiallyNaNExpr extends Expr { + abstract string getReason(); +} + +class DomainErrorFunctionCall extends FunctionCall, PotentiallyNaNExpr { + string reason; + + DomainErrorFunctionCall() { RestrictedDomainError::hasDomainError(this, reason) } + + override string getReason() { result = reason } +} + +// IEEE 754-1985 Section 7.1 invalid operations +class InvalidOperationExpr extends BinaryOperation, PotentiallyNaNExpr { + string reason; + + InvalidOperationExpr() { + // Usual arithmetic conversions in both languages mean that if either operand is a floating + // type, the other one is converted to a floating type as well. + getAnOperand().getFullyConverted().getType() instanceof FloatingPointType and + ( + // 7.1.1 propagates signaling NaNs, we rely on flow analysis and/or assume quiet NaNs, so we + // intentionally do not cover this case. + // 7.1.2: magnitude subtraction of infinities, such as +Inf + -Inf + getOperator() = "+" and + exists(Boolean sign | + exprMayEqualInfinity(getLeftOperand(), sign) and + exprMayEqualInfinity(getRightOperand(), sign.booleanNot()) + ) and + reason = "from addition of infinity and negative infinity" + or + // 7.1.2 continued + getOperator() = "-" and + exists(Boolean sign | + exprMayEqualInfinity(getLeftOperand(), sign) and + exprMayEqualInfinity(getRightOperand(), sign) + ) and + reason = "from subtraction of an infinity from itself" + or + // 7.1.3: multiplication of zero by infinity + getOperator() = "*" and + exists(Expr zeroOp, Expr infinityOp | + zeroOp = getAnOperand() and + infinityOp = getAnOperand() and + not zeroOp = infinityOp and + exprMayEqualZero(zeroOp) and + exprMayEqualInfinity(infinityOp, _) + ) and + reason = "from multiplication of zero by infinity" + or + // 7.1.4: Division of zero by zero, or infinity by infinity + getOperator() = "/" and + exprMayEqualZero(getLeftOperand()) and + exprMayEqualZero(getRightOperand()) and + reason = "from division of zero by zero" + or + // 7.1.4 continued + getOperator() = "/" and + exprMayEqualInfinity(getLeftOperand(), _) and + exprMayEqualInfinity(getRightOperand(), _) and + reason = "from division of infinity by infinity" + or + // 7.1.5: x % y where y is zero or x is infinite + getOperator() = "%" and + exprMayEqualInfinity(getLeftOperand(), _) and + reason = "from modulus of infinity" + or + // 7.1.5 continued + getOperator() = "%" and + exprMayEqualZero(getRightOperand()) and + reason = "from modulus by zero" + // 7.1.6 handles the sqrt function, not covered here. + // 7.1.7 declares exceptions during invalid conversions, which we catch as sinks in our flow + // analysis. + // 7.1.8 declares exceptions for unordered comparisons, which we catch as sinks in our flow + // analysis. + ) + } + + override string getReason() { result = reason } +} + +module InvalidNaNUsage implements DataFlow::ConfigSig { + /** + * An expression which has non-NaN inputs and may produce a NaN output. + */ + predicate isSource(DataFlow::Node node) { + potentialSource(node) and + not exists(DataFlow::Node prior | + isAdditionalFlowStep(prior, node) and + potentialSource(prior) + ) + } + + /** + * An expression which may produce a NaN output. + */ + additional predicate potentialSource(DataFlow::Node node) { + node.asExpr() instanceof PotentiallyNaNExpr + } + + predicate isBarrierOut(DataFlow::Node node) { + guardedNotFPClass(node.asExpr(), TNaN()) + or + exists(Expr e | + e.getType() instanceof IntegralType and + e = node.asConvertedExpr() + ) + } + + /** + * Add an additional flow step to handle NaN propagation through floating point operations. + */ + predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node sink) { + exists(Operation o | + o.getAnOperand() = source.asExpr() and + o = sink.asExpr() and + o.getType() instanceof FloatingPointType + ) + } + + predicate isSink(DataFlow::Node node) { + not guardedNotFPClass(node.asExpr(), TNaN()) and + node instanceof InvalidNaNUsage + } +} + +class InvalidNaNUsage extends DataFlow::Node { + string description; + + InvalidNaNUsage() { + // Case 1: NaNs shall not be compared, except to themselves + exists(ComparisonOperation cmp | + this.asExpr() = cmp.getAnOperand() and + not hashCons(cmp.getLeftOperand()) = hashCons(cmp.getRightOperand()) and + description = "comparison, which would always evaluate to false." + ) + or + // Case 2: NaNs and infinities shall not be cast to integers + exists(Conversion c | + this.asExpr() = c.getUnconverted() and + c.getExpr().getType() instanceof FloatingPointType and + c.getType() instanceof IntegralType and + description = "a cast to integer." + ) + } + + string getDescription() { result = description } +} + +module InvalidNaNFlow = DataFlow::Global; + +import InvalidNaNFlow::PathGraph + +abstract class MisuseOfNaNFloatingPointValueSharedQuery extends Query { } + +Query getQuery() { result instanceof MisuseOfNaNFloatingPointValueSharedQuery } + +query predicate problems( + Element elem, InvalidNaNFlow::PathNode source, InvalidNaNFlow::PathNode sink, string message, + Expr sourceExpr, string sourceString, Function function, string functionName +) { + not isExcluded(elem, getQuery()) and + exists(InvalidNaNUsage usage, string computedInFunction | + not InvalidNaNFlow::PathGraph::edges(_, source, _, _) and + not InvalidNaNFlow::PathGraph::edges(sink, _, _, _) and + not sourceExpr.isFromTemplateInstantiation(_) and + not usage.asExpr().isFromTemplateInstantiation(_) and + elem = MacroUnwrapper::unwrapElement(sink.getNode().asExpr()) and + usage = sink.getNode() and + sourceExpr = source.getNode().asExpr() and + sourceString = source.getNode().asExpr().(PotentiallyNaNExpr).getReason() and + function = sourceExpr.getEnclosingFunction() and + InvalidNaNFlow::flow(source.getNode(), usage) and + ( + if not sourceExpr.getEnclosingFunction() = usage.asExpr().getEnclosingFunction() + then computedInFunction = "computed in function $@ " + else computedInFunction = "" + ) and + message = "Possible NaN value $@ " + computedInFunction + "flows to " + usage.getDescription() and + functionName = function.getName() + ) +} diff --git a/cpp/common/test/includes/standard-library/cmath b/cpp/common/test/includes/standard-library/cmath index e69de29bb2..9f3fffda8d 100644 --- a/cpp/common/test/includes/standard-library/cmath +++ b/cpp/common/test/includes/standard-library/cmath @@ -0,0 +1,19 @@ +namespace std { +#include + +int isinf(float x); +int isinf(double x); +int isinf(long double x); +bool isfinite(float x); +bool isfinite(double x); +bool isfinite(long double x); +bool isnan(float x); +bool isnan(double x); +bool isnan(long double x); +bool isnormal(float x); +bool isnormal(double x); +bool isnormal(long double x); +int fpclassify(float x); +int fpclassify(double x); +int fpclassify(long double x); +} \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/math.h b/cpp/common/test/includes/standard-library/math.h index 460c0a9c2f..7ff0ef8357 100644 --- a/cpp/common/test/includes/standard-library/math.h +++ b/cpp/common/test/includes/standard-library/math.h @@ -17,6 +17,9 @@ long double acoshl(long double x); double atanh(double x); float atanhf(float x); long double atanhl(long double x); +float cos(float x); +double cos(double x); +long double cos(long double x); double fmod(double x, double y); float fmodf(float x, float y); long double fmodl(long double x, long double y); @@ -47,6 +50,9 @@ long double logbl(long double x); double pow(double x, double y); float powf(float x, float y); long double powl(long double x, long double y); +float sin(float x); +double sin(double x); +long double sin(long double x); double sqrt(double x); float sqrtf(float x); long double sqrtl(long double x); diff --git a/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected new file mode 100644 index 0000000000..6624187d42 --- /dev/null +++ b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected @@ -0,0 +1,113 @@ +problems +| test.cpp:12:8:12:9 | l2 | test.cpp:8:14:8:20 | ... / ... | test.cpp:12:8:12:9 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:13:8:13:9 | l3 | test.cpp:8:14:8:20 | ... / ... | test.cpp:13:8:13:9 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:18:20:18:21 | l2 | test.cpp:8:14:8:20 | ... / ... | test.cpp:18:3:18:22 | l2 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:19:20:19:21 | l3 | test.cpp:8:14:8:20 | ... / ... | test.cpp:19:3:19:22 | l3 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:27:19:27:20 | l2 | test.cpp:8:14:8:20 | ... / ... | test.cpp:27:19:27:20 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:28:19:28:20 | l3 | test.cpp:8:14:8:20 | ... / ... | test.cpp:28:19:28:20 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:38:20:38:21 | l7 | test.cpp:31:14:32:15 | ... / ... | test.cpp:38:3:38:22 | l7 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:31:14:32:15 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:61:22:61:28 | ... / ... | test.cpp:61:5:61:29 | ... / ... | test.cpp:61:5:61:29 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:61:22:61:28 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:66:22:66:30 | ... / ... | test.cpp:66:5:66:31 | ... / ... | test.cpp:66:5:66:31 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:66:22:66:30 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:72:31:72:39 | ... / ... | test.cpp:72:14:72:40 | ... / ... | test.cpp:72:14:72:40 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:72:31:72:39 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:75:35:75:43 | ... / ... | test.cpp:75:18:75:44 | ... / ... | test.cpp:75:18:75:44 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:75:35:75:43 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:79:22:79:24 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:79:5:79:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:87:22:87:24 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:87:5:87:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:91:22:91:24 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:91:5:91:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:93:22:93:24 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:93:5:93:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:99:22:99:24 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:99:5:99:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:105:22:105:24 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:105:5:105:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:111:22:111:24 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:111:5:111:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:114:38:114:40 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:114:21:114:41 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:117:45:117:47 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:117:28:117:48 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:120:42:120:44 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:120:25:120:45 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:163:20:164:20 | ... / ... | test.cpp:163:3:164:21 | ... / ... | test.cpp:163:3:164:21 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:163:20:164:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:175:44:175:44 | p | test.cpp:189:51:189:59 | ... / ... | test.cpp:175:27:175:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:189:51:189:59 | ... / ... | from division by zero | test.cpp:189:6:189:24 | addInfThenCastToInt | addInfThenCastToInt | +| test.cpp:175:44:175:44 | p | test.cpp:193:13:194:15 | ... / ... | test.cpp:175:27:175:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:193:13:194:15 | ... / ... | from division by zero | test.cpp:192:6:192:7 | f2 | f2 | +| test.cpp:175:44:175:44 | p | test.cpp:204:19:204:27 | ... / ... | test.cpp:175:27:175:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:204:19:204:27 | ... / ... | from division by zero | test.cpp:192:6:192:7 | f2 | f2 | +| test.cpp:185:30:185:30 | p | test.cpp:200:25:200:33 | ... / ... | test.cpp:185:13:185:31 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:200:25:200:33 | ... / ... | from division by zero | test.cpp:192:6:192:7 | f2 | f2 | +edges +| test.cpp:8:14:8:20 | ... / ... | test.cpp:8:14:8:20 | ... / ... | provenance | | +| test.cpp:8:14:8:20 | ... / ... | test.cpp:9:14:9:16 | - ... | provenance | Config | +| test.cpp:8:14:8:20 | ... / ... | test.cpp:12:8:12:9 | l2 | provenance | | +| test.cpp:8:14:8:20 | ... / ... | test.cpp:18:3:18:22 | l2 | provenance | | +| test.cpp:8:14:8:20 | ... / ... | test.cpp:27:19:27:20 | l2 | provenance | | +| test.cpp:9:14:9:16 | - ... | test.cpp:9:14:9:16 | - ... | provenance | | +| test.cpp:9:14:9:16 | - ... | test.cpp:13:8:13:9 | l3 | provenance | | +| test.cpp:9:14:9:16 | - ... | test.cpp:19:3:19:22 | l3 | provenance | | +| test.cpp:9:14:9:16 | - ... | test.cpp:28:19:28:20 | l3 | provenance | | +| test.cpp:31:14:32:15 | ... / ... | test.cpp:31:14:32:15 | ... / ... | provenance | | +| test.cpp:31:14:32:15 | ... / ... | test.cpp:38:3:38:22 | l7 | provenance | | +| test.cpp:77:15:77:21 | ... / ... | test.cpp:77:15:77:21 | ... / ... | provenance | | +| test.cpp:77:15:77:21 | ... / ... | test.cpp:79:5:79:25 | l12 | provenance | | +| test.cpp:77:15:77:21 | ... / ... | test.cpp:87:5:87:25 | l12 | provenance | | +| test.cpp:77:15:77:21 | ... / ... | test.cpp:91:5:91:25 | l12 | provenance | | +| test.cpp:77:15:77:21 | ... / ... | test.cpp:93:5:93:25 | l12 | provenance | | +| test.cpp:77:15:77:21 | ... / ... | test.cpp:99:5:99:25 | l12 | provenance | | +| test.cpp:77:15:77:21 | ... / ... | test.cpp:105:5:105:25 | l12 | provenance | | +| test.cpp:77:15:77:21 | ... / ... | test.cpp:111:5:111:25 | l12 | provenance | | +| test.cpp:77:15:77:21 | ... / ... | test.cpp:114:21:114:41 | l12 | provenance | | +| test.cpp:77:15:77:21 | ... / ... | test.cpp:117:28:117:48 | l12 | provenance | | +| test.cpp:77:15:77:21 | ... / ... | test.cpp:120:25:120:45 | l12 | provenance | | +| test.cpp:175:22:175:22 | p | test.cpp:175:27:175:45 | p | provenance | | +| test.cpp:183:34:183:34 | p | test.cpp:185:13:185:31 | p | provenance | | +| test.cpp:189:32:189:32 | p | test.cpp:189:47:189:59 | ... + ... | provenance | Config | +| test.cpp:189:47:189:59 | ... + ... | test.cpp:175:22:175:22 | p | provenance | | +| test.cpp:189:47:189:59 | ... + ... | test.cpp:175:22:175:22 | p | provenance | | +| test.cpp:189:51:189:59 | ... / ... | test.cpp:189:47:189:59 | ... + ... | provenance | Config | +| test.cpp:193:13:194:15 | ... / ... | test.cpp:175:22:175:22 | p | provenance | | +| test.cpp:200:25:200:33 | ... / ... | test.cpp:183:34:183:34 | p | provenance | | +| test.cpp:204:19:204:27 | ... / ... | test.cpp:204:19:204:27 | ... / ... | provenance | | +| test.cpp:204:19:204:27 | ... / ... | test.cpp:206:21:206:31 | ... + ... | provenance | Config | +| test.cpp:206:21:206:31 | ... + ... | test.cpp:206:21:206:31 | ... + ... | provenance | | +| test.cpp:206:21:206:31 | ... + ... | test.cpp:208:13:208:21 | middleInf | provenance | | +| test.cpp:206:21:206:31 | ... + ... | test.cpp:210:23:210:31 | middleInf | provenance | | +| test.cpp:208:13:208:21 | middleInf | test.cpp:175:22:175:22 | p | provenance | | +| test.cpp:210:23:210:31 | middleInf | test.cpp:189:32:189:32 | p | provenance | | +nodes +| test.cpp:8:14:8:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:8:14:8:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:9:14:9:16 | - ... | semmle.label | - ... | +| test.cpp:9:14:9:16 | - ... | semmle.label | - ... | +| test.cpp:12:8:12:9 | l2 | semmle.label | l2 | +| test.cpp:13:8:13:9 | l3 | semmle.label | l3 | +| test.cpp:18:3:18:22 | l2 | semmle.label | l2 | +| test.cpp:19:3:19:22 | l3 | semmle.label | l3 | +| test.cpp:27:19:27:20 | l2 | semmle.label | l2 | +| test.cpp:28:19:28:20 | l3 | semmle.label | l3 | +| test.cpp:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:38:3:38:22 | l7 | semmle.label | l7 | +| test.cpp:61:5:61:29 | ... / ... | semmle.label | ... / ... | +| test.cpp:66:5:66:31 | ... / ... | semmle.label | ... / ... | +| test.cpp:72:14:72:40 | ... / ... | semmle.label | ... / ... | +| test.cpp:75:18:75:44 | ... / ... | semmle.label | ... / ... | +| test.cpp:77:15:77:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:77:15:77:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:79:5:79:25 | l12 | semmle.label | l12 | +| test.cpp:87:5:87:25 | l12 | semmle.label | l12 | +| test.cpp:91:5:91:25 | l12 | semmle.label | l12 | +| test.cpp:93:5:93:25 | l12 | semmle.label | l12 | +| test.cpp:99:5:99:25 | l12 | semmle.label | l12 | +| test.cpp:105:5:105:25 | l12 | semmle.label | l12 | +| test.cpp:111:5:111:25 | l12 | semmle.label | l12 | +| test.cpp:114:21:114:41 | l12 | semmle.label | l12 | +| test.cpp:117:28:117:48 | l12 | semmle.label | l12 | +| test.cpp:120:25:120:45 | l12 | semmle.label | l12 | +| test.cpp:163:3:164:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:175:22:175:22 | p | semmle.label | p | +| test.cpp:175:27:175:45 | p | semmle.label | p | +| test.cpp:183:34:183:34 | p | semmle.label | p | +| test.cpp:185:13:185:31 | p | semmle.label | p | +| test.cpp:189:32:189:32 | p | semmle.label | p | +| test.cpp:189:47:189:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:189:47:189:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:189:51:189:59 | ... / ... | semmle.label | ... / ... | +| test.cpp:193:13:194:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:200:25:200:33 | ... / ... | semmle.label | ... / ... | +| test.cpp:204:19:204:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:204:19:204:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:206:21:206:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:206:21:206:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:208:13:208:21 | middleInf | semmle.label | middleInf | +| test.cpp:210:23:210:31 | middleInf | semmle.label | middleInf | +subpaths diff --git a/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql new file mode 100644 index 0000000000..f0d160a650 --- /dev/null +++ b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.misuseofinfinitefloatingpointvalue.MisuseOfInfiniteFloatingPointValue + +class TestFileQuery extends MisuseOfInfiniteFloatingPointValueSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/test.cpp b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/test.cpp new file mode 100644 index 0000000000..e9067d8ce7 --- /dev/null +++ b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/test.cpp @@ -0,0 +1,212 @@ +#include + +float getFloat() { return 1.0; } + +// Parameter could be infinity +void f1(float p1) { + float l1 = 1; + float l2 = 1.0 / 0; + float l3 = -l2; + + 10 / l1; // COMPLIANT + 10 / l2; // NON_COMPLIANT: Underflows to zero + 10 / l3; // NON_COMPLIANT: Underflow to negative zero + 10 / p1; // COMPLIANT: Reduce false positives by assuming not infinity + 10 / getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + static_cast(l1); // COMPLIANT + static_cast(l2); // NON_COMPLIANT + static_cast(l3); // NON_COMPLIANT + static_cast(p1); // COMPLIANT: Reduce false positives by assuming not infinity + static_cast(getFloat()); // COMPLIANT: Reduce false positives by assuming not infinity + + // Not NaN: + float l4 = l1 / l1; // COMPLIANT + + // NaN because of infinity divided by itself: + float l5 = l2 / l2; // NON_COMPLIANT: Division by infinity not allowed. + float l6 = l3 / l3; // NON_COMPLIANT: Division by infinity not allowed. + + // NaN because of zero divided by itself: + float l7 = getFloat() / + p1; // COMPLIANT: Reduce false positives by assuming not infinity + float l8 = 0.0 / 0.0; + + static_cast(l4); // COMPLIANT + static_cast(l5); // COMPLIANT: Casting NaN to int + static_cast(l6); // COMPLIANT: Casting NaN to int + static_cast(l7); // NON_COMPLIANT: Casting Infinity to int + static_cast(l8); // COMPLIANT: Casting NaN to int + + l4 == 0; // COMPLIANT + l4 != 0; // COMPLIANT + l4 <= 0; // COMPLIANT + l4 < 0; // COMPLIANT + l4 >= 0; // COMPLIANT + l5 == 0; // NON_COMPLIANT: Comparison with NaN always false + l5 != 0; // NON_COMPLIANT: Comparison with NaN always false + l5 < 0; // NON_COMPLIANT: Comparison with NaN always false + l5 <= 0; // NON_COMPLIANT: Comparison with NaN always false + l5 > 0; // NON_COMPLIANT: Comparison with NaN always false + l5 >= 0; // NON_COMPLIANT: Comparison with NaN always false + l6 == 0; // NON_COMPLIANT: Comparison with NaN always false + l7 == 0; // NON_COMPLIANT: Comparison with NaN always false + l8 == 0; // NON_COMPLIANT: Comparison with NaN always false + + // Guards + float l9 = 0; + if (l9 != 0) { + static_cast(l9 / l9); // COMPLIANT: l9 is not zero + } else { + static_cast(l9 / l9); // NON_COMPLIANT[False positive]: Guarded to not be NaN + } + + float l10 = 0; + if (l10 == 0) { + static_cast(l10 / l10); // NON_COMPLIANT[False positive]: Casting NaN to integer + } else { + static_cast(l10 / l10); // COMPLIANT: Guarded to not be NaN + } + + float l11 = 0; + l11 == 0 ? static_cast(l11 / l11) : 0; // NON_COMPLIANT[False positive] + l11 == 0 ? 0 : static_cast(l11 / l11); // COMPLIANT + l11 != 0 ? static_cast(l11 / l11) : 0; // COMPLIANT + l11 != 0 ? 0 : static_cast(l11 / l11); // NON_COMPLIANT[False positive] + + float l12 = 1.0 / 0; + if (std::isinf(l12)) { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } else { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } + + if (!std::isinf(l12)) { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } else { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } + + if (std::isinf(l12) == 1) { + static_cast(l12); // NON_COMPLIANT: Must be +Infinity + } else { + static_cast(l12); // NON_COMPLIANT: May be -Infinity + } + + if (std::isfinite(l12)) { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } else { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } + + if (std::isnormal(l12)) { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } else { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } + + if (std::isnan(l12)) { + static_cast(l12); // COMPLIANT: Guarded not to be Infinity + } else { + static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer + } + + std::isinf(l12) ? static_cast(l12) : 0; // NON_COMPLIANT: Check on wrong branch + std::isinf(l12) ? 0 : static_cast(l12); // COMPLIANT: Checked not infinite before use + std::isfinite(l12) ? static_cast(l12) : 0; // COMPLIANT: Checked finite before use + std::isfinite(l12) ? 0 : static_cast(l12); // NON_COMPLIANT: Checked on wrong branch + std::isnan(l12) ? static_cast(l12) + : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use + std::isnan(l12) ? 0 : static_cast(l12); // NON_COMPLIANT: Check on wrong branch + + float l13 = 0.0 / 0; + if (std::isinf(l13)) { + static_cast(l13); // COMPLIANT: Guarded not to be NaN + } else { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } + + if (std::isinf(l13) == 1) { + static_cast(l13); // COMPLIANT: Guarded not to be NaN (must be +Infinity) + } else { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } + + if (std::isfinite(l13)) { + static_cast(l13); // COMPLIANT: Guarded not to be NaN + } else { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } + + if (std::isnormal(l13)) { + static_cast(l13); // COMPLIANT: Guarded not to be NaN + } else { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } + + if (std::isnan(l13)) { + static_cast(l13); // COMPLIANT: Casting NaN to integer + } else { + static_cast(l13); // COMPLIANT: Guarded not to be NaN + } + + std::isinf(l13) ? static_cast(l13) + : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use + std::isinf(l13) ? 0 : static_cast(l13); // COMPLIANT: Check on wrong branch + std::isfinite(l13) ? static_cast(l13) : 0; // COMPLIANT: Checked finite before use + std::isfinite(l13) ? 0 : static_cast(l13); // COMPLIANT: Checked on wrong branch + std::isnan(l13) ? static_cast(l13) : 0; // COMPLIANT: Check on wrong branch + std::isnan(l13) ? 0 : static_cast(l13); // COMPLIANT: Checked not NaN before use + + static_cast(std::pow(2, p1)); // NON_COMPLIANT[False negative]: likely to be Infinity + static_cast(std::pow(2, std::sin(p1))); // COMPLIANT: not likely to be Infinity + static_cast(1 / + std::sin(p1)); // NON_COMPLIANT: possible infinity from zero in denominator + static_cast(1 / std::log(p1)); // COMPLIANT: not possibly zero in denominator + static_cast(std::pow(p1, p1)); // COMPLIANT: NaN if p1 is zero + if (p1 != 0) { + static_cast(std::pow(p1, p1)); // COMPLIANT: p1 is not zero + } + + static_cast(std::acos(p1)); // COMPLIANT: NaN if p1 is not within -1..1 + static_cast(std::acos(std::cos(p1))); // COMPLIANT: cos(p1) is within -1..1 +} + +void castToInt(float p) { static_cast(p); } + +void checkBeforeCastToInt(float p) { + if (std::isfinite(p)) { + castToInt(p); + } +} + +void castToIntToFloatToInt(float p) { + // This should be reported as a violation, but not downstream from here. + castToInt(static_cast(p)); +} + +void addOneThenCastToInt(float p) { castToInt(p + 1); } +void addInfThenCastToInt(float p) { castToInt(p + 1.0 / 0.0); } +void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } + +void f2() { + castToInt(1.0 / + 0.0); // NON_COMPLIANT: Infinity flows to denominator in division + castToInt(0.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT + addOneThenCastToInt(1.0 / 0.0); // NON_COMPLIANT[False negative] + addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(1.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(0.0 / 0.0); // COMPLIANT + + // Check that during flow analysis, we only report the true root cause: + float rootInf = 1.0 / 0.0; + float rootNaN = 0.0 / 0.0; + float middleInf = rootInf + 1; + float middleNaN = rootNaN + 1; + castToInt(middleInf); // NON_COMPLIANT + castToInt(middleNaN); // COMPLIANT + addInfThenCastToInt(middleInf); // NON_COMPLIANT + addNaNThenCastToInt(middleNaN); // COMPLIANT +} \ No newline at end of file diff --git a/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected b/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected new file mode 100644 index 0000000000..576327fb21 --- /dev/null +++ b/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected @@ -0,0 +1,136 @@ +problems +| test.cpp:36:8:36:9 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:36:3:36:9 | l5 | Possible NaN value $@ flows to a cast to integer. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:37:8:37:9 | l6 | test.cpp:28:14:28:20 | ... / ... | test.cpp:37:3:37:9 | l6 | Possible NaN value $@ flows to a cast to integer. | test.cpp:28:14:28:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:38:8:38:9 | l7 | test.cpp:31:14:32:15 | ... / ... | test.cpp:38:3:38:9 | l7 | Possible NaN value $@ flows to a cast to integer. | test.cpp:31:14:32:15 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:39:8:39:9 | l8 | test.cpp:33:14:33:22 | ... / ... | test.cpp:39:3:39:9 | l8 | Possible NaN value $@ flows to a cast to integer. | test.cpp:33:14:33:22 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:46:3:46:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:46:3:46:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:47:3:47:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:47:3:47:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:48:3:48:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:48:3:48:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:49:3:49:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:49:3:49:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:50:3:50:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:50:3:50:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:51:3:51:4 | l5 | test.cpp:27:14:27:20 | ... / ... | test.cpp:51:3:51:4 | l5 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:27:14:27:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:52:3:52:4 | l6 | test.cpp:28:14:28:20 | ... / ... | test.cpp:52:3:52:4 | l6 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:28:14:28:20 | ... / ... | from division of infinity by infinity | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:53:3:53:4 | l7 | test.cpp:31:14:32:15 | ... / ... | test.cpp:53:3:53:4 | l7 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:31:14:32:15 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:54:3:54:4 | l8 | test.cpp:33:14:33:22 | ... / ... | test.cpp:54:3:54:4 | l8 | Possible NaN value $@ flows to comparison, which would always evaluate to false. | test.cpp:33:14:33:22 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:61:11:61:17 | ... / ... | test.cpp:61:5:61:18 | ... / ... | test.cpp:61:5:61:18 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:61:11:61:17 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:66:11:66:19 | ... / ... | test.cpp:66:5:66:20 | ... / ... | test.cpp:66:5:66:20 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:66:11:66:19 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:72:20:72:28 | ... / ... | test.cpp:72:14:72:29 | ... / ... | test.cpp:72:14:72:29 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:72:20:72:28 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:75:24:75:32 | ... / ... | test.cpp:75:18:75:33 | ... / ... | test.cpp:75:18:75:33 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:75:24:75:32 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:126:10:126:12 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:126:5:126:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:132:10:132:12 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:132:5:132:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:138:10:138:12 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:138:5:138:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:144:10:144:12 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:144:5:144:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:148:10:148:12 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:148:5:148:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:155:30:155:32 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:155:25:155:32 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:157:33:157:35 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:157:28:157:35 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:158:26:158:28 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:158:21:158:28 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:166:8:166:15 | call to pow | test.cpp:166:3:166:23 | call to pow | test.cpp:166:3:166:23 | call to pow | Possible NaN value $@ flows to a cast to integer. | test.cpp:166:8:166:15 | call to pow | both arguments are equal to zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:171:8:171:16 | call to acos | test.cpp:171:3:171:20 | call to acos | test.cpp:171:3:171:20 | call to acos | Possible NaN value $@ flows to a cast to integer. | test.cpp:171:8:171:16 | call to acos | the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0) | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:175:32:175:32 | p | test.cpp:190:51:190:59 | ... / ... | test.cpp:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:190:51:190:59 | ... / ... | from division of zero by zero | test.cpp:190:6:190:24 | addNaNThenCastToInt | addNaNThenCastToInt | +| test.cpp:175:32:175:32 | p | test.cpp:195:13:195:21 | ... / ... | test.cpp:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:195:13:195:21 | ... / ... | from division of zero by zero | test.cpp:192:6:192:7 | f2 | f2 | +| test.cpp:175:32:175:32 | p | test.cpp:199:23:199:31 | ... / ... | test.cpp:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:199:23:199:31 | ... / ... | from division of zero by zero | test.cpp:192:6:192:7 | f2 | f2 | +| test.cpp:175:32:175:32 | p | test.cpp:205:19:205:27 | ... / ... | test.cpp:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:205:19:205:27 | ... / ... | from division of zero by zero | test.cpp:192:6:192:7 | f2 | f2 | +| test.cpp:185:18:185:18 | p | test.cpp:201:25:201:33 | ... / ... | test.cpp:185:13:185:18 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:201:25:201:33 | ... / ... | from division of zero by zero | test.cpp:192:6:192:7 | f2 | f2 | +edges +| test.cpp:27:14:27:20 | ... / ... | test.cpp:27:14:27:20 | ... / ... | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:36:3:36:9 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:46:3:46:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:47:3:47:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:48:3:48:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:49:3:49:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:50:3:50:4 | l5 | provenance | | +| test.cpp:27:14:27:20 | ... / ... | test.cpp:51:3:51:4 | l5 | provenance | | +| test.cpp:28:14:28:20 | ... / ... | test.cpp:28:14:28:20 | ... / ... | provenance | | +| test.cpp:28:14:28:20 | ... / ... | test.cpp:37:3:37:9 | l6 | provenance | | +| test.cpp:28:14:28:20 | ... / ... | test.cpp:52:3:52:4 | l6 | provenance | | +| test.cpp:31:14:32:15 | ... / ... | test.cpp:31:14:32:15 | ... / ... | provenance | | +| test.cpp:31:14:32:15 | ... / ... | test.cpp:38:3:38:9 | l7 | provenance | | +| test.cpp:31:14:32:15 | ... / ... | test.cpp:53:3:53:4 | l7 | provenance | | +| test.cpp:33:14:33:22 | ... / ... | test.cpp:33:14:33:22 | ... / ... | provenance | | +| test.cpp:33:14:33:22 | ... / ... | test.cpp:39:3:39:9 | l8 | provenance | | +| test.cpp:33:14:33:22 | ... / ... | test.cpp:54:3:54:4 | l8 | provenance | | +| test.cpp:122:15:122:21 | ... / ... | test.cpp:122:15:122:21 | ... / ... | provenance | | +| test.cpp:122:15:122:21 | ... / ... | test.cpp:126:5:126:12 | l13 | provenance | | +| test.cpp:122:15:122:21 | ... / ... | test.cpp:132:5:132:12 | l13 | provenance | | +| test.cpp:122:15:122:21 | ... / ... | test.cpp:138:5:138:12 | l13 | provenance | | +| test.cpp:122:15:122:21 | ... / ... | test.cpp:144:5:144:12 | l13 | provenance | | +| test.cpp:122:15:122:21 | ... / ... | test.cpp:148:5:148:12 | l13 | provenance | | +| test.cpp:122:15:122:21 | ... / ... | test.cpp:155:25:155:32 | l13 | provenance | | +| test.cpp:122:15:122:21 | ... / ... | test.cpp:157:28:157:35 | l13 | provenance | | +| test.cpp:122:15:122:21 | ... / ... | test.cpp:158:21:158:28 | l13 | provenance | | +| test.cpp:175:22:175:22 | p | test.cpp:175:27:175:32 | p | provenance | | +| test.cpp:183:34:183:34 | p | test.cpp:185:13:185:18 | p | provenance | | +| test.cpp:188:32:188:32 | p | test.cpp:188:47:188:51 | ... + ... | provenance | Config | +| test.cpp:188:47:188:51 | ... + ... | test.cpp:175:22:175:22 | p | provenance | | +| test.cpp:190:32:190:32 | p | test.cpp:190:47:190:59 | ... + ... | provenance | Config | +| test.cpp:190:47:190:59 | ... + ... | test.cpp:175:22:175:22 | p | provenance | | +| test.cpp:190:47:190:59 | ... + ... | test.cpp:175:22:175:22 | p | provenance | | +| test.cpp:190:51:190:59 | ... / ... | test.cpp:190:47:190:59 | ... + ... | provenance | Config | +| test.cpp:195:13:195:21 | ... / ... | test.cpp:175:22:175:22 | p | provenance | | +| test.cpp:199:23:199:31 | ... / ... | test.cpp:188:32:188:32 | p | provenance | | +| test.cpp:201:25:201:33 | ... / ... | test.cpp:183:34:183:34 | p | provenance | | +| test.cpp:205:19:205:27 | ... / ... | test.cpp:205:19:205:27 | ... / ... | provenance | | +| test.cpp:205:19:205:27 | ... / ... | test.cpp:207:21:207:31 | ... + ... | provenance | Config | +| test.cpp:207:21:207:31 | ... + ... | test.cpp:207:21:207:31 | ... + ... | provenance | | +| test.cpp:207:21:207:31 | ... + ... | test.cpp:209:13:209:21 | middleNaN | provenance | | +| test.cpp:207:21:207:31 | ... + ... | test.cpp:211:23:211:31 | middleNaN | provenance | | +| test.cpp:209:13:209:21 | middleNaN | test.cpp:175:22:175:22 | p | provenance | | +| test.cpp:211:23:211:31 | middleNaN | test.cpp:190:32:190:32 | p | provenance | | +nodes +| test.cpp:27:14:27:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:27:14:27:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:28:14:28:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:28:14:28:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:31:14:32:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:33:14:33:22 | ... / ... | semmle.label | ... / ... | +| test.cpp:33:14:33:22 | ... / ... | semmle.label | ... / ... | +| test.cpp:36:3:36:9 | l5 | semmle.label | l5 | +| test.cpp:37:3:37:9 | l6 | semmle.label | l6 | +| test.cpp:38:3:38:9 | l7 | semmle.label | l7 | +| test.cpp:39:3:39:9 | l8 | semmle.label | l8 | +| test.cpp:46:3:46:4 | l5 | semmle.label | l5 | +| test.cpp:47:3:47:4 | l5 | semmle.label | l5 | +| test.cpp:48:3:48:4 | l5 | semmle.label | l5 | +| test.cpp:49:3:49:4 | l5 | semmle.label | l5 | +| test.cpp:50:3:50:4 | l5 | semmle.label | l5 | +| test.cpp:51:3:51:4 | l5 | semmle.label | l5 | +| test.cpp:52:3:52:4 | l6 | semmle.label | l6 | +| test.cpp:53:3:53:4 | l7 | semmle.label | l7 | +| test.cpp:54:3:54:4 | l8 | semmle.label | l8 | +| test.cpp:61:5:61:18 | ... / ... | semmle.label | ... / ... | +| test.cpp:66:5:66:20 | ... / ... | semmle.label | ... / ... | +| test.cpp:72:14:72:29 | ... / ... | semmle.label | ... / ... | +| test.cpp:75:18:75:33 | ... / ... | semmle.label | ... / ... | +| test.cpp:122:15:122:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:122:15:122:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:126:5:126:12 | l13 | semmle.label | l13 | +| test.cpp:132:5:132:12 | l13 | semmle.label | l13 | +| test.cpp:138:5:138:12 | l13 | semmle.label | l13 | +| test.cpp:144:5:144:12 | l13 | semmle.label | l13 | +| test.cpp:148:5:148:12 | l13 | semmle.label | l13 | +| test.cpp:155:25:155:32 | l13 | semmle.label | l13 | +| test.cpp:157:28:157:35 | l13 | semmle.label | l13 | +| test.cpp:158:21:158:28 | l13 | semmle.label | l13 | +| test.cpp:166:3:166:23 | call to pow | semmle.label | call to pow | +| test.cpp:171:3:171:20 | call to acos | semmle.label | call to acos | +| test.cpp:175:22:175:22 | p | semmle.label | p | +| test.cpp:175:27:175:32 | p | semmle.label | p | +| test.cpp:183:34:183:34 | p | semmle.label | p | +| test.cpp:185:13:185:18 | p | semmle.label | p | +| test.cpp:188:32:188:32 | p | semmle.label | p | +| test.cpp:188:47:188:51 | ... + ... | semmle.label | ... + ... | +| test.cpp:190:32:190:32 | p | semmle.label | p | +| test.cpp:190:47:190:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:190:47:190:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:190:51:190:59 | ... / ... | semmle.label | ... / ... | +| test.cpp:195:13:195:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:199:23:199:31 | ... / ... | semmle.label | ... / ... | +| test.cpp:201:25:201:33 | ... / ... | semmle.label | ... / ... | +| test.cpp:205:19:205:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:205:19:205:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:207:21:207:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:207:21:207:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:209:13:209:21 | middleNaN | semmle.label | middleNaN | +| test.cpp:211:23:211:31 | middleNaN | semmle.label | middleNaN | +subpaths diff --git a/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql b/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql new file mode 100644 index 0000000000..a1f729ed02 --- /dev/null +++ b/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.misuseofnanfloatingpointvalue.MisuseOfNaNFloatingPointValue + +class TestFileQuery extends MisuseOfNaNFloatingPointValueSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/misuseofnanfloatingpointvalue/test.cpp b/cpp/common/test/rules/misuseofnanfloatingpointvalue/test.cpp new file mode 100644 index 0000000000..51540bc3a1 --- /dev/null +++ b/cpp/common/test/rules/misuseofnanfloatingpointvalue/test.cpp @@ -0,0 +1,212 @@ +#include + +float getFloat() { return 1.0; } + +// Parameter could be infinity +void f1(float p1) { + float l1 = 1; + float l2 = 1.0 / 0; + float l3 = -l2; + + 10 / l1; // COMPLIANT + 10 / l2; // COMPLIANT: Underflows to zero + 10 / l3; // COMPLIANT: Underflow to negative zero + 10 / p1; // COMPLIANT: Reduce false positives by assuming not infinity + 10 / getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + (int)l1; // COMPLIANT + (int)l2; // COMPLIANT + (int)l3; // COMPLIANT + (int)p1; // COMPLIANT: Reduce false positives by assuming not infinity + (int)getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity + + // Not NaN: + float l4 = l1 / l1; // COMPLIANT + + // NaN because of infinity divided by itself: + float l5 = l2 / l2; // COMPLIANT: Division by infinity not allowed. + float l6 = l3 / l3; // COMPLIANT: Division by infinity not allowed. + + // NaN because of zero divided by itself: + float l7 = getFloat() / + p1; // COMPLIANT: Reduce false positives by assuming not infinity + float l8 = 0.0 / 0.0; + + (int)l4; // COMPLIANT + (int)l5; // NON_COMPLIANT: Casting NaN to int + (int)l6; // NON_COMPLIANT: Casting NaN to int + (int)l7; // NON_COMPLIANT: Casting NaN to int + (int)l8; // NON_COMPLIANT: Casting NaN to int + + l4 == 0; // COMPLIANT + l4 != 0; // COMPLIANT + l4 <= 0; // COMPLIANT + l4 < 0; // COMPLIANT + l4 >= 0; // COMPLIANT + l5 == 0; // NON_COMPLIANT: Comparison with NaN always false + l5 != 0; // NON_COMPLIANT: Comparison with NaN always false + l5 < 0; // NON_COMPLIANT: Comparison with NaN always false + l5 <= 0; // NON_COMPLIANT: Comparison with NaN always false + l5 > 0; // NON_COMPLIANT: Comparison with NaN always false + l5 >= 0; // NON_COMPLIANT: Comparison with NaN always false + l6 == 0; // NON_COMPLIANT: Comparison with NaN always false + l7 == 0; // NON_COMPLIANT: Comparison with NaN always false + l8 == 0; // NON_COMPLIANT: Comparison with NaN always false + + // Guards + float l9 = 0; + if (l9 != 0) { + (int)(l9 / l9); // COMPLIANT: l9 is not zero + } else { + (int)(l9 / l9); // NON_COMPLIANT: Casting NaN to integer + } + + float l10 = 0; + if (l10 == 0) { + (int)(l10 / l10); // NON_COMPLIANT: Casting NaN to integer + } else { + (int)(l10 / l10); // COMPLIANT: Guarded to not be NaN + } + + float l11 = 0; + l11 == 0 ? (int)(l11 / l11) : 0; // NON_COMPLIANT + l11 == 0 ? 0 : (int)(l11 / l11); // COMPLIANT + l11 != 0 ? (int)(l11 / l11) : 0; // COMPLIANT + l11 != 0 ? 0 : (int)(l11 / l11); // NON_COMPLIANT + + float l12 = 1.0 / 0; + if (std::isinf(l12)) { + (int)l12; // COMPLIANT: Casting Infinity to integer + } else { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } + + if (!std::isinf(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (std::isinf(l12) == 1) { + (int)l12; // COMPLIANT: Must be +Infinity + } else { + (int)l12; // COMPLIANT: May be -Infinity + } + + if (std::isfinite(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (std::isnormal(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + if (std::isnan(l12)) { + (int)l12; // COMPLIANT: Guarded not to be Infinity + } else { + (int)l12; // COMPLIANT: Casting Infinity to integer + } + + std::isinf(l12) ? (int)l12 : 0; // COMPLIANT: Check on wrong branch + std::isinf(l12) ? 0 : (int)l12; // COMPLIANT: Checked not infinite before use + std::isfinite(l12) ? (int)l12 : 0; // COMPLIANT: Checked finite before use + std::isfinite(l12) ? 0 : (int)l12; // COMPLIANT: Checked on wrong branch + std::isnan(l12) ? (int)l12 + : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use + std::isnan(l12) ? 0 : (int)l12; // COMPLIANT: Check on wrong branch + + float l13 = 0.0 / 0; + if (std::isinf(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (std::isinf(l13) == 1) { + (int)l13; // COMPLIANT: Guarded not to be NaN (must be +Infinity) + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (std::isfinite(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (std::isnormal(l13)) { + (int)l13; // COMPLIANT: Guarded not to be NaN + } else { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } + + if (std::isnan(l13)) { + (int)l13; // NON_COMPLIANT: Casting NaN to integer + } else { + (int)l13; // COMPLIANT: Guarded not to be NaN + } + + std::isinf(l13) ? (int)l13 + : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use + std::isinf(l13) ? 0 : (int)l13; // NON_COMPLIANT: Check on wrong branch + std::isfinite(l13) ? (int)l13 : 0; // COMPLIANT: Checked finite before use + std::isfinite(l13) ? 0 : (int)l13; // NON_COMPLIANT: Checked on wrong branch + std::isnan(l13) ? (int)l13 : 0; // NON_COMPLIANT: Check on wrong branch + std::isnan(l13) ? 0 : (int)l13; // COMPLIANT: Checked not NaN before use + + (int)std::pow(2, p1); // COMPLIANT: likely to be Infinity + (int)std::pow(2, std::sin(p1)); // COMPLIANT: not likely to be Infinity + (int)(1 / + std::sin(p1)); // COMPLIANT: possible infinity from zero in denominator + (int)(1 / std::log(p1)); // COMPLIANT: not possibly zero in denominator + (int)std::pow(p1, p1); // NON_COMPLIANT: NaN if p1 is zero + if (p1 != 0) { + (int)std::pow(p1, p1); // COMPLIANT: p1 is not zero + } + + (int)std::acos(p1); // NON_COMPLIANT: NaN if p1 is not within -1..1 + (int)std::acos(std::cos(p1)); // COMPLIANT: cos(p1) is within -1..1 +} + +void castToInt(float p) { (int)p; } + +void checkBeforeCastToInt(float p) { + if (std::isfinite(p)) { + castToInt(p); + } +} + +void castToIntToFloatToInt(float p) { + // This should be reported as a violation, but not downstream from here. + castToInt((int)p); +} + +void addOneThenCastToInt(float p) { castToInt(p + 1); } +void addInfThenCastToInt(float p) { castToInt(p + 1.0 / 0.0); } +void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } + +void f2() { + castToInt(1.0 / + 0.0); // COMPLIANT: Infinity flows to denominator in division + castToInt(0.0 / 0.0); // COMPLIANT: NaN flows to denominator in division + checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT + checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT + addOneThenCastToInt(1.0 / 0.0); // COMPLIANT + addOneThenCastToInt(0.0 / 0.0); // NON_COMPLIANT + castToIntToFloatToInt(1.0 / 0.0); // COMPLIANT + castToIntToFloatToInt(0.0 / 0.0); // NON_COMPLIANT + + // Check that during flow analysis, we only report the true root cause: + float rootInf = 1.0 / 0.0; + float rootNaN = 0.0 / 0.0; + float middleInf = rootInf + 1; + float middleNaN = rootNaN + 1; + castToInt(middleInf); // COMPLIANT + castToInt(middleNaN); // NON_COMPLIANT + addInfThenCastToInt(middleInf); // COMPLIANT + addNaNThenCastToInt(middleNaN); // NON_COMPLIANT +} \ No newline at end of file diff --git a/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql new file mode 100644 index 0000000000..d9810c1135 --- /dev/null +++ b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql @@ -0,0 +1,22 @@ +/** + * @id cpp/misra/possible-misuse-of-infinite-floating-point-value + * @name DIR-0-3-1: Possible misuse of a generate infinite floating point value + * @description Possible misuse of a generate infinite floating point value. + * @kind path-problem + * @precision medium + * @problem.severity warning + * @tags external/misra/id/dir-0-3-1 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.misuseofinfinitefloatingpointvalue.MisuseOfInfiniteFloatingPointValue + +class PossibleMisuseOfInfiniteFloatingPointValueQuery extends MisuseOfInfiniteFloatingPointValueSharedQuery { + PossibleMisuseOfInfiniteFloatingPointValueQuery() { + this = FloatingPointPackage::possibleMisuseOfInfiniteFloatingPointValueQuery() + } +} diff --git a/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql new file mode 100644 index 0000000000..934ee6d998 --- /dev/null +++ b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/possible-misuse-of-nan-floating-point-value + * @name DIR-0-3-1: Possible mishandling of an undetected NaN value produced by a floating point operation + * @description Possible mishandling of an undetected NaN value produced by a floating point + * operation. + * @kind path-problem + * @precision low + * @problem.severity warning + * @tags external/misra/id/dir-0-3-1 + * correctness + * external/misra/c/2012/amendment3 + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.misuseofnanfloatingpointvalue.MisuseOfNaNFloatingPointValue + +class PossibleMisuseOfNaNFloatingPointValueQuery extends MisuseOfNaNFloatingPointValueSharedQuery { + PossibleMisuseOfNaNFloatingPointValueQuery() { + this = FloatingPointPackage::possibleMisuseOfNaNFloatingPointValueQuery() + } +} diff --git a/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.testref b/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.testref new file mode 100644 index 0000000000..952d461d00 --- /dev/null +++ b/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.testref @@ -0,0 +1 @@ +cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.testref b/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.testref new file mode 100644 index 0000000000..2cd2de067d --- /dev/null +++ b/cpp/misra/test/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.testref @@ -0,0 +1 @@ +cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.ql \ No newline at end of file diff --git a/rule_packages/c/FloatingTypes2.json b/rule_packages/c/FloatingTypes2.json index 3f4771dcc6..a1c02daaf5 100644 --- a/rule_packages/c/FloatingTypes2.json +++ b/rule_packages/c/FloatingTypes2.json @@ -12,6 +12,7 @@ "precision": "medium", "severity": "warning", "short_name": "PossibleMisuseOfUndetectedInfinity", + "shared_implementation_short_name": "MisuseOfInfiniteFloatingPointValue", "tags": [ "correctness", "external/misra/c/2012/amendment3" @@ -24,6 +25,7 @@ "precision": "low", "severity": "warning", "short_name": "PossibleMisuseOfUndetectedNaN", + "shared_implementation_short_name": "MisuseOfNaNFloatingPointValue", "tags": [ "correctness", "external/misra/c/2012/amendment3" diff --git a/rule_packages/cpp/FloatingPoint.json b/rule_packages/cpp/FloatingPoint.json new file mode 100644 index 0000000000..b085e5b289 --- /dev/null +++ b/rule_packages/cpp/FloatingPoint.json @@ -0,0 +1,38 @@ +{ + "MISRA-C++-2023": { + "DIR-0-3-1": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Possible misuse of a generate infinite floating point value.", + "kind": "path-problem", + "name": "Possible misuse of a generate infinite floating point value", + "precision": "medium", + "severity": "warning", + "short_name": "PossibleMisuseOfInfiniteFloatingPointValue", + "shared_implementation_short_name": "MisuseOfInfiniteFloatingPointValue", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + }, + { + "description": "Possible mishandling of an undetected NaN value produced by a floating point operation.", + "kind": "path-problem", + "name": "Possible mishandling of an undetected NaN value produced by a floating point operation", + "precision": "low", + "severity": "warning", + "short_name": "PossibleMisuseOfNaNFloatingPointValue", + "shared_implementation_short_name": "MisuseOfNaNFloatingPointValue", + "tags": [ + "correctness", + "external/misra/c/2012/amendment3" + ] + } + ], + "title": "Floating-point arithmetic should be used appropriately" + } + } +} \ No newline at end of file From 5fa421b286c997a3b792b5c2996f5deeb8bebee6 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 15 Apr 2025 07:40:56 -0700 Subject: [PATCH 349/628] Format --- .../misuseofinfinitefloatingpointvalue/test.c | 2 +- .../MisuseOfNaNFloatingPointValue.expected | 94 ++++----- .../misuseofnanfloatingpointvalue/test.c | 10 +- .../cpp/RestrictedRangeAnalysis.qll | 5 +- ...isuseOfInfiniteFloatingPointValue.expected | 178 +++++++++--------- .../test.cpp | 89 ++++++--- .../MisuseOfNaNFloatingPointValue.expected | 144 +++++++------- .../misuseofnanfloatingpointvalue/test.cpp | 21 ++- ...sibleMisuseOfInfiniteFloatingPointValue.ql | 3 +- rule_packages/cpp/FloatingPoint.json | 6 +- 10 files changed, 289 insertions(+), 263 deletions(-) diff --git a/c/common/test/rules/misuseofinfinitefloatingpointvalue/test.c b/c/common/test/rules/misuseofinfinitefloatingpointvalue/test.c index 85097d828b..6a4ebd94b9 100644 --- a/c/common/test/rules/misuseofinfinitefloatingpointvalue/test.c +++ b/c/common/test/rules/misuseofinfinitefloatingpointvalue/test.c @@ -192,7 +192,7 @@ void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } void f2() { castToInt(1.0 / 0.0); // NON_COMPLIANT: Infinity flows to denominator in division - castToInt(0.0 / 0.0); // COMPLIANT + castToInt(0.0 / 0.0); // COMPLIANT checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT addOneThenCastToInt(1.0 / 0.0); // NON_COMPLIANT[False negative] diff --git a/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected b/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected index 1555fd5bd8..b567e06bc2 100644 --- a/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected +++ b/c/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected @@ -24,13 +24,13 @@ problems | test.c:155:25:155:27 | l13 | test.c:122:15:122:21 | ... / ... | test.c:155:20:155:27 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | | test.c:157:28:157:30 | l13 | test.c:122:15:122:21 | ... / ... | test.c:157:23:157:30 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | | test.c:158:21:158:23 | l13 | test.c:122:15:122:21 | ... / ... | test.c:158:16:158:23 | l13 | Possible NaN value $@ flows to a cast to integer. | test.c:122:15:122:21 | ... / ... | from division of zero by zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:166:8:166:10 | call to pow | test.c:166:3:166:18 | call to pow | test.c:166:3:166:18 | call to pow | Possible NaN value $@ flows to a cast to integer. | test.c:166:8:166:10 | call to pow | both arguments are equal to zero | test.c:6:6:6:7 | f1 | f1 | -| test.c:171:8:171:11 | call to acos | test.c:171:3:171:15 | call to acos | test.c:171:3:171:15 | call to acos | Possible NaN value $@ flows to a cast to integer. | test.c:171:8:171:11 | call to acos | the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0) | test.c:6:6:6:7 | f1 | f1 | -| test.c:175:32:175:32 | p | test.c:190:51:190:59 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:190:51:190:59 | ... / ... | from division of zero by zero | test.c:190:6:190:24 | addNaNThenCastToInt | addNaNThenCastToInt | -| test.c:175:32:175:32 | p | test.c:195:13:195:21 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:195:13:195:21 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | -| test.c:175:32:175:32 | p | test.c:199:23:199:31 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:199:23:199:31 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | -| test.c:175:32:175:32 | p | test.c:205:19:205:27 | ... / ... | test.c:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:205:19:205:27 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | -| test.c:185:18:185:18 | p | test.c:201:25:201:33 | ... / ... | test.c:185:13:185:18 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:201:25:201:33 | ... / ... | from division of zero by zero | test.c:192:6:192:7 | f2 | f2 | +| test.c:165:8:165:10 | call to pow | test.c:165:3:165:18 | call to pow | test.c:165:3:165:18 | call to pow | Possible NaN value $@ flows to a cast to integer. | test.c:165:8:165:10 | call to pow | both arguments are equal to zero | test.c:6:6:6:7 | f1 | f1 | +| test.c:170:8:170:11 | call to acos | test.c:170:3:170:15 | call to acos | test.c:170:3:170:15 | call to acos | Possible NaN value $@ flows to a cast to integer. | test.c:170:8:170:11 | call to acos | the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0) | test.c:6:6:6:7 | f1 | f1 | +| test.c:174:32:174:32 | p | test.c:189:51:189:59 | ... / ... | test.c:174:27:174:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:189:51:189:59 | ... / ... | from division of zero by zero | test.c:189:6:189:24 | addNaNThenCastToInt | addNaNThenCastToInt | +| test.c:174:32:174:32 | p | test.c:193:13:193:21 | ... / ... | test.c:174:27:174:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:193:13:193:21 | ... / ... | from division of zero by zero | test.c:191:6:191:7 | f2 | f2 | +| test.c:174:32:174:32 | p | test.c:197:23:197:31 | ... / ... | test.c:174:27:174:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:197:23:197:31 | ... / ... | from division of zero by zero | test.c:191:6:191:7 | f2 | f2 | +| test.c:174:32:174:32 | p | test.c:203:19:203:27 | ... / ... | test.c:174:27:174:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:203:19:203:27 | ... / ... | from division of zero by zero | test.c:191:6:191:7 | f2 | f2 | +| test.c:184:18:184:18 | p | test.c:199:25:199:33 | ... / ... | test.c:184:13:184:18 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.c:199:25:199:33 | ... / ... | from division of zero by zero | test.c:191:6:191:7 | f2 | f2 | edges | test.c:27:14:27:20 | ... / ... | test.c:27:14:27:20 | ... / ... | provenance | | | test.c:27:14:27:20 | ... / ... | test.c:36:3:36:9 | l5 | provenance | | @@ -58,24 +58,24 @@ edges | test.c:122:15:122:21 | ... / ... | test.c:155:20:155:27 | l13 | provenance | | | test.c:122:15:122:21 | ... / ... | test.c:157:23:157:30 | l13 | provenance | | | test.c:122:15:122:21 | ... / ... | test.c:158:16:158:23 | l13 | provenance | | -| test.c:175:22:175:22 | p | test.c:175:27:175:32 | p | provenance | | -| test.c:183:34:183:34 | p | test.c:185:13:185:18 | p | provenance | | -| test.c:188:32:188:32 | p | test.c:188:47:188:51 | ... + ... | provenance | Config | -| test.c:188:47:188:51 | ... + ... | test.c:175:22:175:22 | p | provenance | | -| test.c:190:32:190:32 | p | test.c:190:47:190:59 | ... + ... | provenance | Config | -| test.c:190:47:190:59 | ... + ... | test.c:175:22:175:22 | p | provenance | | -| test.c:190:47:190:59 | ... + ... | test.c:175:22:175:22 | p | provenance | | -| test.c:190:51:190:59 | ... / ... | test.c:190:47:190:59 | ... + ... | provenance | Config | -| test.c:195:13:195:21 | ... / ... | test.c:175:22:175:22 | p | provenance | | -| test.c:199:23:199:31 | ... / ... | test.c:188:32:188:32 | p | provenance | | -| test.c:201:25:201:33 | ... / ... | test.c:183:34:183:34 | p | provenance | | -| test.c:205:19:205:27 | ... / ... | test.c:205:19:205:27 | ... / ... | provenance | | -| test.c:205:19:205:27 | ... / ... | test.c:207:21:207:31 | ... + ... | provenance | Config | -| test.c:207:21:207:31 | ... + ... | test.c:207:21:207:31 | ... + ... | provenance | | -| test.c:207:21:207:31 | ... + ... | test.c:209:13:209:21 | middleNaN | provenance | | -| test.c:207:21:207:31 | ... + ... | test.c:211:23:211:31 | middleNaN | provenance | | -| test.c:209:13:209:21 | middleNaN | test.c:175:22:175:22 | p | provenance | | -| test.c:211:23:211:31 | middleNaN | test.c:190:32:190:32 | p | provenance | | +| test.c:174:22:174:22 | p | test.c:174:27:174:32 | p | provenance | | +| test.c:182:34:182:34 | p | test.c:184:13:184:18 | p | provenance | | +| test.c:187:32:187:32 | p | test.c:187:47:187:51 | ... + ... | provenance | Config | +| test.c:187:47:187:51 | ... + ... | test.c:174:22:174:22 | p | provenance | | +| test.c:189:32:189:32 | p | test.c:189:47:189:59 | ... + ... | provenance | Config | +| test.c:189:47:189:59 | ... + ... | test.c:174:22:174:22 | p | provenance | | +| test.c:189:47:189:59 | ... + ... | test.c:174:22:174:22 | p | provenance | | +| test.c:189:51:189:59 | ... / ... | test.c:189:47:189:59 | ... + ... | provenance | Config | +| test.c:193:13:193:21 | ... / ... | test.c:174:22:174:22 | p | provenance | | +| test.c:197:23:197:31 | ... / ... | test.c:187:32:187:32 | p | provenance | | +| test.c:199:25:199:33 | ... / ... | test.c:182:34:182:34 | p | provenance | | +| test.c:203:19:203:27 | ... / ... | test.c:203:19:203:27 | ... / ... | provenance | | +| test.c:203:19:203:27 | ... / ... | test.c:205:21:205:31 | ... + ... | provenance | Config | +| test.c:205:21:205:31 | ... + ... | test.c:205:21:205:31 | ... + ... | provenance | | +| test.c:205:21:205:31 | ... + ... | test.c:207:13:207:21 | middleNaN | provenance | | +| test.c:205:21:205:31 | ... + ... | test.c:209:23:209:31 | middleNaN | provenance | | +| test.c:207:13:207:21 | middleNaN | test.c:174:22:174:22 | p | provenance | | +| test.c:209:23:209:31 | middleNaN | test.c:189:32:189:32 | p | provenance | | nodes | test.c:27:14:27:20 | ... / ... | semmle.label | ... / ... | | test.c:27:14:27:20 | ... / ... | semmle.label | ... / ... | @@ -112,25 +112,25 @@ nodes | test.c:155:20:155:27 | l13 | semmle.label | l13 | | test.c:157:23:157:30 | l13 | semmle.label | l13 | | test.c:158:16:158:23 | l13 | semmle.label | l13 | -| test.c:166:3:166:18 | call to pow | semmle.label | call to pow | -| test.c:171:3:171:15 | call to acos | semmle.label | call to acos | -| test.c:175:22:175:22 | p | semmle.label | p | -| test.c:175:27:175:32 | p | semmle.label | p | -| test.c:183:34:183:34 | p | semmle.label | p | -| test.c:185:13:185:18 | p | semmle.label | p | -| test.c:188:32:188:32 | p | semmle.label | p | -| test.c:188:47:188:51 | ... + ... | semmle.label | ... + ... | -| test.c:190:32:190:32 | p | semmle.label | p | -| test.c:190:47:190:59 | ... + ... | semmle.label | ... + ... | -| test.c:190:47:190:59 | ... + ... | semmle.label | ... + ... | -| test.c:190:51:190:59 | ... / ... | semmle.label | ... / ... | -| test.c:195:13:195:21 | ... / ... | semmle.label | ... / ... | -| test.c:199:23:199:31 | ... / ... | semmle.label | ... / ... | -| test.c:201:25:201:33 | ... / ... | semmle.label | ... / ... | -| test.c:205:19:205:27 | ... / ... | semmle.label | ... / ... | -| test.c:205:19:205:27 | ... / ... | semmle.label | ... / ... | -| test.c:207:21:207:31 | ... + ... | semmle.label | ... + ... | -| test.c:207:21:207:31 | ... + ... | semmle.label | ... + ... | -| test.c:209:13:209:21 | middleNaN | semmle.label | middleNaN | -| test.c:211:23:211:31 | middleNaN | semmle.label | middleNaN | -subpaths \ No newline at end of file +| test.c:165:3:165:18 | call to pow | semmle.label | call to pow | +| test.c:170:3:170:15 | call to acos | semmle.label | call to acos | +| test.c:174:22:174:22 | p | semmle.label | p | +| test.c:174:27:174:32 | p | semmle.label | p | +| test.c:182:34:182:34 | p | semmle.label | p | +| test.c:184:13:184:18 | p | semmle.label | p | +| test.c:187:32:187:32 | p | semmle.label | p | +| test.c:187:47:187:51 | ... + ... | semmle.label | ... + ... | +| test.c:189:32:189:32 | p | semmle.label | p | +| test.c:189:47:189:59 | ... + ... | semmle.label | ... + ... | +| test.c:189:47:189:59 | ... + ... | semmle.label | ... + ... | +| test.c:189:51:189:59 | ... / ... | semmle.label | ... / ... | +| test.c:193:13:193:21 | ... / ... | semmle.label | ... / ... | +| test.c:197:23:197:31 | ... / ... | semmle.label | ... / ... | +| test.c:199:25:199:33 | ... / ... | semmle.label | ... / ... | +| test.c:203:19:203:27 | ... / ... | semmle.label | ... / ... | +| test.c:203:19:203:27 | ... / ... | semmle.label | ... / ... | +| test.c:205:21:205:31 | ... + ... | semmle.label | ... + ... | +| test.c:205:21:205:31 | ... + ... | semmle.label | ... + ... | +| test.c:207:13:207:21 | middleNaN | semmle.label | middleNaN | +| test.c:209:23:209:31 | middleNaN | semmle.label | middleNaN | +subpaths diff --git a/c/common/test/rules/misuseofnanfloatingpointvalue/test.c b/c/common/test/rules/misuseofnanfloatingpointvalue/test.c index 5115727115..bd997282f0 100644 --- a/c/common/test/rules/misuseofnanfloatingpointvalue/test.c +++ b/c/common/test/rules/misuseofnanfloatingpointvalue/test.c @@ -160,10 +160,9 @@ void f1(float p1) { (int)pow(2, p1); // COMPLIANT: likely to be Infinity (int)pow(2, sin(p1)); // COMPLIANT: not likely to be Infinity - (int)(1 / - sin(p1)); // COMPLIANT: possible infinity from zero in denominator - (int)(1 / log(p1)); // COMPLIANT: not possibly zero in denominator - (int)pow(p1, p1); // NON_COMPLIANT: NaN if p1 is zero + (int)(1 / sin(p1)); // COMPLIANT: possible infinity from zero in denominator + (int)(1 / log(p1)); // COMPLIANT: not possibly zero in denominator + (int)pow(p1, p1); // NON_COMPLIANT: NaN if p1 is zero if (p1 != 0) { (int)pow(p1, p1); // COMPLIANT: p1 is not zero } @@ -190,8 +189,7 @@ void addInfThenCastToInt(float p) { castToInt(p + 1.0 / 0.0); } void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } void f2() { - castToInt(1.0 / - 0.0); // COMPLIANT: Infinity flows to denominator in division + castToInt(1.0 / 0.0); // COMPLIANT: Infinity flows to denominator in division castToInt(0.0 / 0.0); // COMPLIANT: NaN flows to denominator in division checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT diff --git a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll index 5d955cc117..d92b46335d 100644 --- a/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll +++ b/cpp/common/src/codingstandards/cpp/RestrictedRangeAnalysis.qll @@ -1093,8 +1093,9 @@ module RestrictedRangeAnalysis { ( // If the expression evaluates to a constant, then there is no // need to call getUpperBoundsImpl. - if exists(getValue(expr).toFloat()) and - not getValue(expr) = "NaN" + if + exists(getValue(expr).toFloat()) and + not getValue(expr) = "NaN" then result = getValue(expr).toFloat() else ( // Some of the bounds computed by `getUpperBoundsImpl` diff --git a/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected index 6624187d42..45bc2466b6 100644 --- a/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected +++ b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/MisuseOfInfiniteFloatingPointValue.expected @@ -3,66 +3,66 @@ problems | test.cpp:13:8:13:9 | l3 | test.cpp:8:14:8:20 | ... / ... | test.cpp:13:8:13:9 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | | test.cpp:18:20:18:21 | l2 | test.cpp:8:14:8:20 | ... / ... | test.cpp:18:3:18:22 | l2 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | | test.cpp:19:20:19:21 | l3 | test.cpp:8:14:8:20 | ... / ... | test.cpp:19:3:19:22 | l3 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:27:19:27:20 | l2 | test.cpp:8:14:8:20 | ... / ... | test.cpp:27:19:27:20 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:28:19:28:20 | l3 | test.cpp:8:14:8:20 | ... / ... | test.cpp:28:19:28:20 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:38:20:38:21 | l7 | test.cpp:31:14:32:15 | ... / ... | test.cpp:38:3:38:22 | l7 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:31:14:32:15 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:61:22:61:28 | ... / ... | test.cpp:61:5:61:29 | ... / ... | test.cpp:61:5:61:29 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:61:22:61:28 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:66:22:66:30 | ... / ... | test.cpp:66:5:66:31 | ... / ... | test.cpp:66:5:66:31 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:66:22:66:30 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:72:31:72:39 | ... / ... | test.cpp:72:14:72:40 | ... / ... | test.cpp:72:14:72:40 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:72:31:72:39 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:75:35:75:43 | ... / ... | test.cpp:75:18:75:44 | ... / ... | test.cpp:75:18:75:44 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:75:35:75:43 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:79:22:79:24 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:79:5:79:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:87:22:87:24 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:87:5:87:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:91:22:91:24 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:91:5:91:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:93:22:93:24 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:93:5:93:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:99:22:99:24 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:99:5:99:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:105:22:105:24 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:105:5:105:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:111:22:111:24 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:111:5:111:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:114:38:114:40 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:114:21:114:41 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:117:45:117:47 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:117:28:117:48 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:120:42:120:44 | l12 | test.cpp:77:15:77:21 | ... / ... | test.cpp:120:25:120:45 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:77:15:77:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:163:20:164:20 | ... / ... | test.cpp:163:3:164:21 | ... / ... | test.cpp:163:3:164:21 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:163:20:164:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:175:44:175:44 | p | test.cpp:189:51:189:59 | ... / ... | test.cpp:175:27:175:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:189:51:189:59 | ... / ... | from division by zero | test.cpp:189:6:189:24 | addInfThenCastToInt | addInfThenCastToInt | -| test.cpp:175:44:175:44 | p | test.cpp:193:13:194:15 | ... / ... | test.cpp:175:27:175:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:193:13:194:15 | ... / ... | from division by zero | test.cpp:192:6:192:7 | f2 | f2 | -| test.cpp:175:44:175:44 | p | test.cpp:204:19:204:27 | ... / ... | test.cpp:175:27:175:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:204:19:204:27 | ... / ... | from division by zero | test.cpp:192:6:192:7 | f2 | f2 | -| test.cpp:185:30:185:30 | p | test.cpp:200:25:200:33 | ... / ... | test.cpp:185:13:185:31 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:200:25:200:33 | ... / ... | from division by zero | test.cpp:192:6:192:7 | f2 | f2 | +| test.cpp:29:19:29:20 | l2 | test.cpp:8:14:8:20 | ... / ... | test.cpp:29:19:29:20 | l2 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:30:19:30:20 | l3 | test.cpp:8:14:8:20 | ... / ... | test.cpp:30:19:30:20 | l3 | Possibly infinite float value $@ flows to divisor, which would silently underflow and produce zero. | test.cpp:8:14:8:20 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:40:20:40:21 | l7 | test.cpp:33:14:34:15 | ... / ... | test.cpp:40:3:40:22 | l7 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:33:14:34:15 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:64:9:64:15 | ... / ... | test.cpp:63:5:64:16 | ... / ... | test.cpp:63:5:64:16 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:64:9:64:15 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:70:9:70:17 | ... / ... | test.cpp:69:5:70:18 | ... / ... | test.cpp:69:5:70:18 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:70:9:70:17 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:76:31:76:39 | ... / ... | test.cpp:76:14:76:40 | ... / ... | test.cpp:76:14:76:40 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:76:31:76:39 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:79:35:79:43 | ... / ... | test.cpp:79:18:79:44 | ... / ... | test.cpp:79:18:79:44 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:79:35:79:43 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:83:22:83:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:83:5:83:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:91:22:91:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:91:5:91:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:95:22:95:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:95:5:95:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:97:22:97:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:97:5:97:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:103:22:103:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:103:5:103:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:109:22:109:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:109:5:109:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:115:22:115:24 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:115:5:115:25 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:118:38:118:40 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:118:21:118:41 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:127:26:127:28 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:127:9:127:29 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:133:26:133:28 | l12 | test.cpp:81:15:81:21 | ... / ... | test.cpp:133:9:133:29 | l12 | Possibly infinite float value $@ flows to cast to integer. | test.cpp:81:15:81:21 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:188:7:189:17 | ... / ... | test.cpp:187:3:189:18 | ... / ... | test.cpp:187:3:189:18 | ... / ... | Possibly infinite float value $@ flows to cast to integer. | test.cpp:188:7:189:17 | ... / ... | from division by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:202:44:202:44 | p | test.cpp:216:51:216:59 | ... / ... | test.cpp:202:27:202:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:216:51:216:59 | ... / ... | from division by zero | test.cpp:216:6:216:24 | addInfThenCastToInt | addInfThenCastToInt | +| test.cpp:202:44:202:44 | p | test.cpp:220:13:221:15 | ... / ... | test.cpp:202:27:202:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:220:13:221:15 | ... / ... | from division by zero | test.cpp:219:6:219:7 | f2 | f2 | +| test.cpp:202:44:202:44 | p | test.cpp:231:19:231:27 | ... / ... | test.cpp:202:27:202:45 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:231:19:231:27 | ... / ... | from division by zero | test.cpp:219:6:219:7 | f2 | f2 | +| test.cpp:212:30:212:30 | p | test.cpp:227:25:227:33 | ... / ... | test.cpp:212:13:212:31 | p | Possibly infinite float value $@ computed in function $@ flows to cast to integer. | test.cpp:227:25:227:33 | ... / ... | from division by zero | test.cpp:219:6:219:7 | f2 | f2 | edges | test.cpp:8:14:8:20 | ... / ... | test.cpp:8:14:8:20 | ... / ... | provenance | | | test.cpp:8:14:8:20 | ... / ... | test.cpp:9:14:9:16 | - ... | provenance | Config | | test.cpp:8:14:8:20 | ... / ... | test.cpp:12:8:12:9 | l2 | provenance | | | test.cpp:8:14:8:20 | ... / ... | test.cpp:18:3:18:22 | l2 | provenance | | -| test.cpp:8:14:8:20 | ... / ... | test.cpp:27:19:27:20 | l2 | provenance | | +| test.cpp:8:14:8:20 | ... / ... | test.cpp:29:19:29:20 | l2 | provenance | | | test.cpp:9:14:9:16 | - ... | test.cpp:9:14:9:16 | - ... | provenance | | | test.cpp:9:14:9:16 | - ... | test.cpp:13:8:13:9 | l3 | provenance | | | test.cpp:9:14:9:16 | - ... | test.cpp:19:3:19:22 | l3 | provenance | | -| test.cpp:9:14:9:16 | - ... | test.cpp:28:19:28:20 | l3 | provenance | | -| test.cpp:31:14:32:15 | ... / ... | test.cpp:31:14:32:15 | ... / ... | provenance | | -| test.cpp:31:14:32:15 | ... / ... | test.cpp:38:3:38:22 | l7 | provenance | | -| test.cpp:77:15:77:21 | ... / ... | test.cpp:77:15:77:21 | ... / ... | provenance | | -| test.cpp:77:15:77:21 | ... / ... | test.cpp:79:5:79:25 | l12 | provenance | | -| test.cpp:77:15:77:21 | ... / ... | test.cpp:87:5:87:25 | l12 | provenance | | -| test.cpp:77:15:77:21 | ... / ... | test.cpp:91:5:91:25 | l12 | provenance | | -| test.cpp:77:15:77:21 | ... / ... | test.cpp:93:5:93:25 | l12 | provenance | | -| test.cpp:77:15:77:21 | ... / ... | test.cpp:99:5:99:25 | l12 | provenance | | -| test.cpp:77:15:77:21 | ... / ... | test.cpp:105:5:105:25 | l12 | provenance | | -| test.cpp:77:15:77:21 | ... / ... | test.cpp:111:5:111:25 | l12 | provenance | | -| test.cpp:77:15:77:21 | ... / ... | test.cpp:114:21:114:41 | l12 | provenance | | -| test.cpp:77:15:77:21 | ... / ... | test.cpp:117:28:117:48 | l12 | provenance | | -| test.cpp:77:15:77:21 | ... / ... | test.cpp:120:25:120:45 | l12 | provenance | | -| test.cpp:175:22:175:22 | p | test.cpp:175:27:175:45 | p | provenance | | -| test.cpp:183:34:183:34 | p | test.cpp:185:13:185:31 | p | provenance | | -| test.cpp:189:32:189:32 | p | test.cpp:189:47:189:59 | ... + ... | provenance | Config | -| test.cpp:189:47:189:59 | ... + ... | test.cpp:175:22:175:22 | p | provenance | | -| test.cpp:189:47:189:59 | ... + ... | test.cpp:175:22:175:22 | p | provenance | | -| test.cpp:189:51:189:59 | ... / ... | test.cpp:189:47:189:59 | ... + ... | provenance | Config | -| test.cpp:193:13:194:15 | ... / ... | test.cpp:175:22:175:22 | p | provenance | | -| test.cpp:200:25:200:33 | ... / ... | test.cpp:183:34:183:34 | p | provenance | | -| test.cpp:204:19:204:27 | ... / ... | test.cpp:204:19:204:27 | ... / ... | provenance | | -| test.cpp:204:19:204:27 | ... / ... | test.cpp:206:21:206:31 | ... + ... | provenance | Config | -| test.cpp:206:21:206:31 | ... + ... | test.cpp:206:21:206:31 | ... + ... | provenance | | -| test.cpp:206:21:206:31 | ... + ... | test.cpp:208:13:208:21 | middleInf | provenance | | -| test.cpp:206:21:206:31 | ... + ... | test.cpp:210:23:210:31 | middleInf | provenance | | -| test.cpp:208:13:208:21 | middleInf | test.cpp:175:22:175:22 | p | provenance | | -| test.cpp:210:23:210:31 | middleInf | test.cpp:189:32:189:32 | p | provenance | | +| test.cpp:9:14:9:16 | - ... | test.cpp:30:19:30:20 | l3 | provenance | | +| test.cpp:33:14:34:15 | ... / ... | test.cpp:33:14:34:15 | ... / ... | provenance | | +| test.cpp:33:14:34:15 | ... / ... | test.cpp:40:3:40:22 | l7 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:81:15:81:21 | ... / ... | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:83:5:83:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:91:5:91:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:95:5:95:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:97:5:97:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:103:5:103:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:109:5:109:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:115:5:115:25 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:118:21:118:41 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:127:9:127:29 | l12 | provenance | | +| test.cpp:81:15:81:21 | ... / ... | test.cpp:133:9:133:29 | l12 | provenance | | +| test.cpp:202:22:202:22 | p | test.cpp:202:27:202:45 | p | provenance | | +| test.cpp:210:34:210:34 | p | test.cpp:212:13:212:31 | p | provenance | | +| test.cpp:216:32:216:32 | p | test.cpp:216:47:216:59 | ... + ... | provenance | Config | +| test.cpp:216:47:216:59 | ... + ... | test.cpp:202:22:202:22 | p | provenance | | +| test.cpp:216:47:216:59 | ... + ... | test.cpp:202:22:202:22 | p | provenance | | +| test.cpp:216:51:216:59 | ... / ... | test.cpp:216:47:216:59 | ... + ... | provenance | Config | +| test.cpp:220:13:221:15 | ... / ... | test.cpp:202:22:202:22 | p | provenance | | +| test.cpp:227:25:227:33 | ... / ... | test.cpp:210:34:210:34 | p | provenance | | +| test.cpp:231:19:231:27 | ... / ... | test.cpp:231:19:231:27 | ... / ... | provenance | | +| test.cpp:231:19:231:27 | ... / ... | test.cpp:233:21:233:31 | ... + ... | provenance | Config | +| test.cpp:233:21:233:31 | ... + ... | test.cpp:233:21:233:31 | ... + ... | provenance | | +| test.cpp:233:21:233:31 | ... + ... | test.cpp:235:13:235:21 | middleInf | provenance | | +| test.cpp:233:21:233:31 | ... + ... | test.cpp:237:23:237:31 | middleInf | provenance | | +| test.cpp:235:13:235:21 | middleInf | test.cpp:202:22:202:22 | p | provenance | | +| test.cpp:237:23:237:31 | middleInf | test.cpp:216:32:216:32 | p | provenance | | nodes | test.cpp:8:14:8:20 | ... / ... | semmle.label | ... / ... | | test.cpp:8:14:8:20 | ... / ... | semmle.label | ... / ... | @@ -72,42 +72,42 @@ nodes | test.cpp:13:8:13:9 | l3 | semmle.label | l3 | | test.cpp:18:3:18:22 | l2 | semmle.label | l2 | | test.cpp:19:3:19:22 | l3 | semmle.label | l3 | -| test.cpp:27:19:27:20 | l2 | semmle.label | l2 | -| test.cpp:28:19:28:20 | l3 | semmle.label | l3 | -| test.cpp:31:14:32:15 | ... / ... | semmle.label | ... / ... | -| test.cpp:31:14:32:15 | ... / ... | semmle.label | ... / ... | -| test.cpp:38:3:38:22 | l7 | semmle.label | l7 | -| test.cpp:61:5:61:29 | ... / ... | semmle.label | ... / ... | -| test.cpp:66:5:66:31 | ... / ... | semmle.label | ... / ... | -| test.cpp:72:14:72:40 | ... / ... | semmle.label | ... / ... | -| test.cpp:75:18:75:44 | ... / ... | semmle.label | ... / ... | -| test.cpp:77:15:77:21 | ... / ... | semmle.label | ... / ... | -| test.cpp:77:15:77:21 | ... / ... | semmle.label | ... / ... | -| test.cpp:79:5:79:25 | l12 | semmle.label | l12 | -| test.cpp:87:5:87:25 | l12 | semmle.label | l12 | +| test.cpp:29:19:29:20 | l2 | semmle.label | l2 | +| test.cpp:30:19:30:20 | l3 | semmle.label | l3 | +| test.cpp:33:14:34:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:33:14:34:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:40:3:40:22 | l7 | semmle.label | l7 | +| test.cpp:63:5:64:16 | ... / ... | semmle.label | ... / ... | +| test.cpp:69:5:70:18 | ... / ... | semmle.label | ... / ... | +| test.cpp:76:14:76:40 | ... / ... | semmle.label | ... / ... | +| test.cpp:79:18:79:44 | ... / ... | semmle.label | ... / ... | +| test.cpp:81:15:81:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:81:15:81:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:83:5:83:25 | l12 | semmle.label | l12 | | test.cpp:91:5:91:25 | l12 | semmle.label | l12 | -| test.cpp:93:5:93:25 | l12 | semmle.label | l12 | -| test.cpp:99:5:99:25 | l12 | semmle.label | l12 | -| test.cpp:105:5:105:25 | l12 | semmle.label | l12 | -| test.cpp:111:5:111:25 | l12 | semmle.label | l12 | -| test.cpp:114:21:114:41 | l12 | semmle.label | l12 | -| test.cpp:117:28:117:48 | l12 | semmle.label | l12 | -| test.cpp:120:25:120:45 | l12 | semmle.label | l12 | -| test.cpp:163:3:164:21 | ... / ... | semmle.label | ... / ... | -| test.cpp:175:22:175:22 | p | semmle.label | p | -| test.cpp:175:27:175:45 | p | semmle.label | p | -| test.cpp:183:34:183:34 | p | semmle.label | p | -| test.cpp:185:13:185:31 | p | semmle.label | p | -| test.cpp:189:32:189:32 | p | semmle.label | p | -| test.cpp:189:47:189:59 | ... + ... | semmle.label | ... + ... | -| test.cpp:189:47:189:59 | ... + ... | semmle.label | ... + ... | -| test.cpp:189:51:189:59 | ... / ... | semmle.label | ... / ... | -| test.cpp:193:13:194:15 | ... / ... | semmle.label | ... / ... | -| test.cpp:200:25:200:33 | ... / ... | semmle.label | ... / ... | -| test.cpp:204:19:204:27 | ... / ... | semmle.label | ... / ... | -| test.cpp:204:19:204:27 | ... / ... | semmle.label | ... / ... | -| test.cpp:206:21:206:31 | ... + ... | semmle.label | ... + ... | -| test.cpp:206:21:206:31 | ... + ... | semmle.label | ... + ... | -| test.cpp:208:13:208:21 | middleInf | semmle.label | middleInf | -| test.cpp:210:23:210:31 | middleInf | semmle.label | middleInf | +| test.cpp:95:5:95:25 | l12 | semmle.label | l12 | +| test.cpp:97:5:97:25 | l12 | semmle.label | l12 | +| test.cpp:103:5:103:25 | l12 | semmle.label | l12 | +| test.cpp:109:5:109:25 | l12 | semmle.label | l12 | +| test.cpp:115:5:115:25 | l12 | semmle.label | l12 | +| test.cpp:118:21:118:41 | l12 | semmle.label | l12 | +| test.cpp:127:9:127:29 | l12 | semmle.label | l12 | +| test.cpp:133:9:133:29 | l12 | semmle.label | l12 | +| test.cpp:187:3:189:18 | ... / ... | semmle.label | ... / ... | +| test.cpp:202:22:202:22 | p | semmle.label | p | +| test.cpp:202:27:202:45 | p | semmle.label | p | +| test.cpp:210:34:210:34 | p | semmle.label | p | +| test.cpp:212:13:212:31 | p | semmle.label | p | +| test.cpp:216:32:216:32 | p | semmle.label | p | +| test.cpp:216:47:216:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:216:47:216:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:216:51:216:59 | ... / ... | semmle.label | ... / ... | +| test.cpp:220:13:221:15 | ... / ... | semmle.label | ... / ... | +| test.cpp:227:25:227:33 | ... / ... | semmle.label | ... / ... | +| test.cpp:231:19:231:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:231:19:231:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:233:21:233:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:233:21:233:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:235:13:235:21 | middleInf | semmle.label | middleInf | +| test.cpp:237:23:237:31 | middleInf | semmle.label | middleInf | subpaths diff --git a/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/test.cpp b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/test.cpp index e9067d8ce7..a0624ccbf3 100644 --- a/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/test.cpp +++ b/cpp/common/test/rules/misuseofinfinitefloatingpointvalue/test.cpp @@ -14,11 +14,13 @@ void f1(float p1) { 10 / p1; // COMPLIANT: Reduce false positives by assuming not infinity 10 / getFloat(); // COMPLIANT: Reduce false positives by assuming not infinity - static_cast(l1); // COMPLIANT - static_cast(l2); // NON_COMPLIANT - static_cast(l3); // NON_COMPLIANT - static_cast(p1); // COMPLIANT: Reduce false positives by assuming not infinity - static_cast(getFloat()); // COMPLIANT: Reduce false positives by assuming not infinity + static_cast(l1); // COMPLIANT + static_cast(l2); // NON_COMPLIANT + static_cast(l3); // NON_COMPLIANT + static_cast( + p1); // COMPLIANT: Reduce false positives by assuming not infinity + static_cast( + getFloat()); // COMPLIANT: Reduce false positives by assuming not infinity // Not NaN: float l4 = l1 / l1; // COMPLIANT @@ -58,12 +60,14 @@ void f1(float p1) { if (l9 != 0) { static_cast(l9 / l9); // COMPLIANT: l9 is not zero } else { - static_cast(l9 / l9); // NON_COMPLIANT[False positive]: Guarded to not be NaN + static_cast( + l9 / l9); // NON_COMPLIANT[False positive]: Guarded to not be NaN } float l10 = 0; if (l10 == 0) { - static_cast(l10 / l10); // NON_COMPLIANT[False positive]: Casting NaN to integer + static_cast( + l10 / l10); // NON_COMPLIANT[False positive]: Casting NaN to integer } else { static_cast(l10 / l10); // COMPLIANT: Guarded to not be NaN } @@ -111,13 +115,22 @@ void f1(float p1) { static_cast(l12); // NON_COMPLIANT: Casting Infinity to integer } - std::isinf(l12) ? static_cast(l12) : 0; // NON_COMPLIANT: Check on wrong branch - std::isinf(l12) ? 0 : static_cast(l12); // COMPLIANT: Checked not infinite before use - std::isfinite(l12) ? static_cast(l12) : 0; // COMPLIANT: Checked finite before use - std::isfinite(l12) ? 0 : static_cast(l12); // NON_COMPLIANT: Checked on wrong branch - std::isnan(l12) ? static_cast(l12) - : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use - std::isnan(l12) ? 0 : static_cast(l12); // NON_COMPLIANT: Check on wrong branch + std::isinf(l12) ? static_cast(l12) + : 0; // NON_COMPLIANT: Check on wrong branch + std::isinf(l12) + ? 0 + : static_cast(l12); // COMPLIANT: Checked not infinite before use + std::isfinite(l12) ? static_cast(l12) + : 0; // COMPLIANT: Checked finite before use + std::isfinite(l12) + ? 0 + : static_cast(l12); // NON_COMPLIANT: Checked on wrong branch + std::isnan(l12) + ? static_cast(l12) + : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use + std::isnan(l12) + ? 0 + : static_cast(l12); // NON_COMPLIANT: Check on wrong branch float l13 = 0.0 / 0; if (std::isinf(l13)) { @@ -127,7 +140,8 @@ void f1(float p1) { } if (std::isinf(l13) == 1) { - static_cast(l13); // COMPLIANT: Guarded not to be NaN (must be +Infinity) + static_cast( + l13); // COMPLIANT: Guarded not to be NaN (must be +Infinity) } else { static_cast(l13); // COMPLIANT: Casting NaN to integer } @@ -150,26 +164,39 @@ void f1(float p1) { static_cast(l13); // COMPLIANT: Guarded not to be NaN } - std::isinf(l13) ? static_cast(l13) - : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use - std::isinf(l13) ? 0 : static_cast(l13); // COMPLIANT: Check on wrong branch - std::isfinite(l13) ? static_cast(l13) : 0; // COMPLIANT: Checked finite before use - std::isfinite(l13) ? 0 : static_cast(l13); // COMPLIANT: Checked on wrong branch - std::isnan(l13) ? static_cast(l13) : 0; // COMPLIANT: Check on wrong branch - std::isnan(l13) ? 0 : static_cast(l13); // COMPLIANT: Checked not NaN before use - - static_cast(std::pow(2, p1)); // NON_COMPLIANT[False negative]: likely to be Infinity - static_cast(std::pow(2, std::sin(p1))); // COMPLIANT: not likely to be Infinity + std::isinf(l13) + ? static_cast(l13) + : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use + std::isinf(l13) ? 0 + : static_cast(l13); // COMPLIANT: Check on wrong branch + std::isfinite(l13) ? static_cast(l13) + : 0; // COMPLIANT: Checked finite before use + std::isfinite(l13) + ? 0 + : static_cast(l13); // COMPLIANT: Checked on wrong branch + std::isnan(l13) ? static_cast(l13) + : 0; // COMPLIANT: Check on wrong branch + std::isnan(l13) + ? 0 + : static_cast(l13); // COMPLIANT: Checked not NaN before use + + static_cast( + std::pow(2, p1)); // NON_COMPLIANT[False negative]: likely to be Infinity + static_cast( + std::pow(2, std::sin(p1))); // COMPLIANT: not likely to be Infinity + static_cast( + 1 / std::sin( + p1)); // NON_COMPLIANT: possible infinity from zero in denominator static_cast(1 / - std::sin(p1)); // NON_COMPLIANT: possible infinity from zero in denominator - static_cast(1 / std::log(p1)); // COMPLIANT: not possibly zero in denominator - static_cast(std::pow(p1, p1)); // COMPLIANT: NaN if p1 is zero + std::log(p1)); // COMPLIANT: not possibly zero in denominator + static_cast(std::pow(p1, p1)); // COMPLIANT: NaN if p1 is zero if (p1 != 0) { static_cast(std::pow(p1, p1)); // COMPLIANT: p1 is not zero } - static_cast(std::acos(p1)); // COMPLIANT: NaN if p1 is not within -1..1 - static_cast(std::acos(std::cos(p1))); // COMPLIANT: cos(p1) is within -1..1 + static_cast(std::acos(p1)); // COMPLIANT: NaN if p1 is not within -1..1 + static_cast( + std::acos(std::cos(p1))); // COMPLIANT: cos(p1) is within -1..1 } void castToInt(float p) { static_cast(p); } @@ -192,7 +219,7 @@ void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } void f2() { castToInt(1.0 / 0.0); // NON_COMPLIANT: Infinity flows to denominator in division - castToInt(0.0 / 0.0); // COMPLIANT + castToInt(0.0 / 0.0); // COMPLIANT checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT addOneThenCastToInt(1.0 / 0.0); // NON_COMPLIANT[False negative] diff --git a/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected b/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected index 576327fb21..5e4d3cacd7 100644 --- a/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected +++ b/cpp/common/test/rules/misuseofnanfloatingpointvalue/MisuseOfNaNFloatingPointValue.expected @@ -16,21 +16,21 @@ problems | test.cpp:66:11:66:19 | ... / ... | test.cpp:66:5:66:20 | ... / ... | test.cpp:66:5:66:20 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:66:11:66:19 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | | test.cpp:72:20:72:28 | ... / ... | test.cpp:72:14:72:29 | ... / ... | test.cpp:72:14:72:29 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:72:20:72:28 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | | test.cpp:75:24:75:32 | ... / ... | test.cpp:75:18:75:33 | ... / ... | test.cpp:75:18:75:33 | ... / ... | Possible NaN value $@ flows to a cast to integer. | test.cpp:75:24:75:32 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:126:10:126:12 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:126:5:126:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:132:10:132:12 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:132:5:132:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:138:10:138:12 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:138:5:138:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:144:10:144:12 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:144:5:144:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:148:10:148:12 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:148:5:148:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:155:30:155:32 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:155:25:155:32 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:157:33:157:35 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:157:28:157:35 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:158:26:158:28 | l13 | test.cpp:122:15:122:21 | ... / ... | test.cpp:158:21:158:28 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:122:15:122:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:166:8:166:15 | call to pow | test.cpp:166:3:166:23 | call to pow | test.cpp:166:3:166:23 | call to pow | Possible NaN value $@ flows to a cast to integer. | test.cpp:166:8:166:15 | call to pow | both arguments are equal to zero | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:171:8:171:16 | call to acos | test.cpp:171:3:171:20 | call to acos | test.cpp:171:3:171:20 | call to acos | Possible NaN value $@ flows to a cast to integer. | test.cpp:171:8:171:16 | call to acos | the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0) | test.cpp:6:6:6:7 | f1 | f1 | -| test.cpp:175:32:175:32 | p | test.cpp:190:51:190:59 | ... / ... | test.cpp:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:190:51:190:59 | ... / ... | from division of zero by zero | test.cpp:190:6:190:24 | addNaNThenCastToInt | addNaNThenCastToInt | -| test.cpp:175:32:175:32 | p | test.cpp:195:13:195:21 | ... / ... | test.cpp:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:195:13:195:21 | ... / ... | from division of zero by zero | test.cpp:192:6:192:7 | f2 | f2 | -| test.cpp:175:32:175:32 | p | test.cpp:199:23:199:31 | ... / ... | test.cpp:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:199:23:199:31 | ... / ... | from division of zero by zero | test.cpp:192:6:192:7 | f2 | f2 | -| test.cpp:175:32:175:32 | p | test.cpp:205:19:205:27 | ... / ... | test.cpp:175:27:175:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:205:19:205:27 | ... / ... | from division of zero by zero | test.cpp:192:6:192:7 | f2 | f2 | -| test.cpp:185:18:185:18 | p | test.cpp:201:25:201:33 | ... / ... | test.cpp:185:13:185:18 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:201:25:201:33 | ... / ... | from division of zero by zero | test.cpp:192:6:192:7 | f2 | f2 | +| test.cpp:127:10:127:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:127:5:127:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:133:10:133:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:133:5:133:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:139:10:139:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:139:5:139:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:145:10:145:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:145:5:145:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:149:10:149:12 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:149:5:149:12 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:157:30:157:32 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:157:25:157:32 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:159:33:159:35 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:159:28:159:35 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:160:26:160:28 | l13 | test.cpp:123:15:123:21 | ... / ... | test.cpp:160:21:160:28 | l13 | Possible NaN value $@ flows to a cast to integer. | test.cpp:123:15:123:21 | ... / ... | from division of zero by zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:168:8:168:15 | call to pow | test.cpp:168:3:168:23 | call to pow | test.cpp:168:3:168:23 | call to pow | Possible NaN value $@ flows to a cast to integer. | test.cpp:168:8:168:15 | call to pow | both arguments are equal to zero | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:173:8:173:16 | call to acos | test.cpp:173:3:173:20 | call to acos | test.cpp:173:3:173:20 | call to acos | Possible NaN value $@ flows to a cast to integer. | test.cpp:173:8:173:16 | call to acos | the argument has a range -1000000000000000...1000000000000000 which is outside the domain of this function (-1.0...1.0) | test.cpp:6:6:6:7 | f1 | f1 | +| test.cpp:177:32:177:32 | p | test.cpp:192:51:192:59 | ... / ... | test.cpp:177:27:177:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:192:51:192:59 | ... / ... | from division of zero by zero | test.cpp:192:6:192:24 | addNaNThenCastToInt | addNaNThenCastToInt | +| test.cpp:177:32:177:32 | p | test.cpp:196:13:196:21 | ... / ... | test.cpp:177:27:177:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:196:13:196:21 | ... / ... | from division of zero by zero | test.cpp:194:6:194:7 | f2 | f2 | +| test.cpp:177:32:177:32 | p | test.cpp:200:23:200:31 | ... / ... | test.cpp:177:27:177:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:200:23:200:31 | ... / ... | from division of zero by zero | test.cpp:194:6:194:7 | f2 | f2 | +| test.cpp:177:32:177:32 | p | test.cpp:206:19:206:27 | ... / ... | test.cpp:177:27:177:32 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:206:19:206:27 | ... / ... | from division of zero by zero | test.cpp:194:6:194:7 | f2 | f2 | +| test.cpp:187:18:187:18 | p | test.cpp:202:25:202:33 | ... / ... | test.cpp:187:13:187:18 | p | Possible NaN value $@ computed in function $@ flows to a cast to integer. | test.cpp:202:25:202:33 | ... / ... | from division of zero by zero | test.cpp:194:6:194:7 | f2 | f2 | edges | test.cpp:27:14:27:20 | ... / ... | test.cpp:27:14:27:20 | ... / ... | provenance | | | test.cpp:27:14:27:20 | ... / ... | test.cpp:36:3:36:9 | l5 | provenance | | @@ -49,33 +49,33 @@ edges | test.cpp:33:14:33:22 | ... / ... | test.cpp:33:14:33:22 | ... / ... | provenance | | | test.cpp:33:14:33:22 | ... / ... | test.cpp:39:3:39:9 | l8 | provenance | | | test.cpp:33:14:33:22 | ... / ... | test.cpp:54:3:54:4 | l8 | provenance | | -| test.cpp:122:15:122:21 | ... / ... | test.cpp:122:15:122:21 | ... / ... | provenance | | -| test.cpp:122:15:122:21 | ... / ... | test.cpp:126:5:126:12 | l13 | provenance | | -| test.cpp:122:15:122:21 | ... / ... | test.cpp:132:5:132:12 | l13 | provenance | | -| test.cpp:122:15:122:21 | ... / ... | test.cpp:138:5:138:12 | l13 | provenance | | -| test.cpp:122:15:122:21 | ... / ... | test.cpp:144:5:144:12 | l13 | provenance | | -| test.cpp:122:15:122:21 | ... / ... | test.cpp:148:5:148:12 | l13 | provenance | | -| test.cpp:122:15:122:21 | ... / ... | test.cpp:155:25:155:32 | l13 | provenance | | -| test.cpp:122:15:122:21 | ... / ... | test.cpp:157:28:157:35 | l13 | provenance | | -| test.cpp:122:15:122:21 | ... / ... | test.cpp:158:21:158:28 | l13 | provenance | | -| test.cpp:175:22:175:22 | p | test.cpp:175:27:175:32 | p | provenance | | -| test.cpp:183:34:183:34 | p | test.cpp:185:13:185:18 | p | provenance | | -| test.cpp:188:32:188:32 | p | test.cpp:188:47:188:51 | ... + ... | provenance | Config | -| test.cpp:188:47:188:51 | ... + ... | test.cpp:175:22:175:22 | p | provenance | | -| test.cpp:190:32:190:32 | p | test.cpp:190:47:190:59 | ... + ... | provenance | Config | -| test.cpp:190:47:190:59 | ... + ... | test.cpp:175:22:175:22 | p | provenance | | -| test.cpp:190:47:190:59 | ... + ... | test.cpp:175:22:175:22 | p | provenance | | -| test.cpp:190:51:190:59 | ... / ... | test.cpp:190:47:190:59 | ... + ... | provenance | Config | -| test.cpp:195:13:195:21 | ... / ... | test.cpp:175:22:175:22 | p | provenance | | -| test.cpp:199:23:199:31 | ... / ... | test.cpp:188:32:188:32 | p | provenance | | -| test.cpp:201:25:201:33 | ... / ... | test.cpp:183:34:183:34 | p | provenance | | -| test.cpp:205:19:205:27 | ... / ... | test.cpp:205:19:205:27 | ... / ... | provenance | | -| test.cpp:205:19:205:27 | ... / ... | test.cpp:207:21:207:31 | ... + ... | provenance | Config | -| test.cpp:207:21:207:31 | ... + ... | test.cpp:207:21:207:31 | ... + ... | provenance | | -| test.cpp:207:21:207:31 | ... + ... | test.cpp:209:13:209:21 | middleNaN | provenance | | -| test.cpp:207:21:207:31 | ... + ... | test.cpp:211:23:211:31 | middleNaN | provenance | | -| test.cpp:209:13:209:21 | middleNaN | test.cpp:175:22:175:22 | p | provenance | | -| test.cpp:211:23:211:31 | middleNaN | test.cpp:190:32:190:32 | p | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:123:15:123:21 | ... / ... | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:127:5:127:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:133:5:133:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:139:5:139:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:145:5:145:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:149:5:149:12 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:157:25:157:32 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:159:28:159:35 | l13 | provenance | | +| test.cpp:123:15:123:21 | ... / ... | test.cpp:160:21:160:28 | l13 | provenance | | +| test.cpp:177:22:177:22 | p | test.cpp:177:27:177:32 | p | provenance | | +| test.cpp:185:34:185:34 | p | test.cpp:187:13:187:18 | p | provenance | | +| test.cpp:190:32:190:32 | p | test.cpp:190:47:190:51 | ... + ... | provenance | Config | +| test.cpp:190:47:190:51 | ... + ... | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:192:32:192:32 | p | test.cpp:192:47:192:59 | ... + ... | provenance | Config | +| test.cpp:192:47:192:59 | ... + ... | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:192:47:192:59 | ... + ... | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:192:51:192:59 | ... / ... | test.cpp:192:47:192:59 | ... + ... | provenance | Config | +| test.cpp:196:13:196:21 | ... / ... | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:200:23:200:31 | ... / ... | test.cpp:190:32:190:32 | p | provenance | | +| test.cpp:202:25:202:33 | ... / ... | test.cpp:185:34:185:34 | p | provenance | | +| test.cpp:206:19:206:27 | ... / ... | test.cpp:206:19:206:27 | ... / ... | provenance | | +| test.cpp:206:19:206:27 | ... / ... | test.cpp:208:21:208:31 | ... + ... | provenance | Config | +| test.cpp:208:21:208:31 | ... + ... | test.cpp:208:21:208:31 | ... + ... | provenance | | +| test.cpp:208:21:208:31 | ... + ... | test.cpp:210:13:210:21 | middleNaN | provenance | | +| test.cpp:208:21:208:31 | ... + ... | test.cpp:212:23:212:31 | middleNaN | provenance | | +| test.cpp:210:13:210:21 | middleNaN | test.cpp:177:22:177:22 | p | provenance | | +| test.cpp:212:23:212:31 | middleNaN | test.cpp:192:32:192:32 | p | provenance | | nodes | test.cpp:27:14:27:20 | ... / ... | semmle.label | ... / ... | | test.cpp:27:14:27:20 | ... / ... | semmle.label | ... / ... | @@ -102,35 +102,35 @@ nodes | test.cpp:66:5:66:20 | ... / ... | semmle.label | ... / ... | | test.cpp:72:14:72:29 | ... / ... | semmle.label | ... / ... | | test.cpp:75:18:75:33 | ... / ... | semmle.label | ... / ... | -| test.cpp:122:15:122:21 | ... / ... | semmle.label | ... / ... | -| test.cpp:122:15:122:21 | ... / ... | semmle.label | ... / ... | -| test.cpp:126:5:126:12 | l13 | semmle.label | l13 | -| test.cpp:132:5:132:12 | l13 | semmle.label | l13 | -| test.cpp:138:5:138:12 | l13 | semmle.label | l13 | -| test.cpp:144:5:144:12 | l13 | semmle.label | l13 | -| test.cpp:148:5:148:12 | l13 | semmle.label | l13 | -| test.cpp:155:25:155:32 | l13 | semmle.label | l13 | -| test.cpp:157:28:157:35 | l13 | semmle.label | l13 | -| test.cpp:158:21:158:28 | l13 | semmle.label | l13 | -| test.cpp:166:3:166:23 | call to pow | semmle.label | call to pow | -| test.cpp:171:3:171:20 | call to acos | semmle.label | call to acos | -| test.cpp:175:22:175:22 | p | semmle.label | p | -| test.cpp:175:27:175:32 | p | semmle.label | p | -| test.cpp:183:34:183:34 | p | semmle.label | p | -| test.cpp:185:13:185:18 | p | semmle.label | p | -| test.cpp:188:32:188:32 | p | semmle.label | p | -| test.cpp:188:47:188:51 | ... + ... | semmle.label | ... + ... | +| test.cpp:123:15:123:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:123:15:123:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:127:5:127:12 | l13 | semmle.label | l13 | +| test.cpp:133:5:133:12 | l13 | semmle.label | l13 | +| test.cpp:139:5:139:12 | l13 | semmle.label | l13 | +| test.cpp:145:5:145:12 | l13 | semmle.label | l13 | +| test.cpp:149:5:149:12 | l13 | semmle.label | l13 | +| test.cpp:157:25:157:32 | l13 | semmle.label | l13 | +| test.cpp:159:28:159:35 | l13 | semmle.label | l13 | +| test.cpp:160:21:160:28 | l13 | semmle.label | l13 | +| test.cpp:168:3:168:23 | call to pow | semmle.label | call to pow | +| test.cpp:173:3:173:20 | call to acos | semmle.label | call to acos | +| test.cpp:177:22:177:22 | p | semmle.label | p | +| test.cpp:177:27:177:32 | p | semmle.label | p | +| test.cpp:185:34:185:34 | p | semmle.label | p | +| test.cpp:187:13:187:18 | p | semmle.label | p | | test.cpp:190:32:190:32 | p | semmle.label | p | -| test.cpp:190:47:190:59 | ... + ... | semmle.label | ... + ... | -| test.cpp:190:47:190:59 | ... + ... | semmle.label | ... + ... | -| test.cpp:190:51:190:59 | ... / ... | semmle.label | ... / ... | -| test.cpp:195:13:195:21 | ... / ... | semmle.label | ... / ... | -| test.cpp:199:23:199:31 | ... / ... | semmle.label | ... / ... | -| test.cpp:201:25:201:33 | ... / ... | semmle.label | ... / ... | -| test.cpp:205:19:205:27 | ... / ... | semmle.label | ... / ... | -| test.cpp:205:19:205:27 | ... / ... | semmle.label | ... / ... | -| test.cpp:207:21:207:31 | ... + ... | semmle.label | ... + ... | -| test.cpp:207:21:207:31 | ... + ... | semmle.label | ... + ... | -| test.cpp:209:13:209:21 | middleNaN | semmle.label | middleNaN | -| test.cpp:211:23:211:31 | middleNaN | semmle.label | middleNaN | +| test.cpp:190:47:190:51 | ... + ... | semmle.label | ... + ... | +| test.cpp:192:32:192:32 | p | semmle.label | p | +| test.cpp:192:47:192:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:192:47:192:59 | ... + ... | semmle.label | ... + ... | +| test.cpp:192:51:192:59 | ... / ... | semmle.label | ... / ... | +| test.cpp:196:13:196:21 | ... / ... | semmle.label | ... / ... | +| test.cpp:200:23:200:31 | ... / ... | semmle.label | ... / ... | +| test.cpp:202:25:202:33 | ... / ... | semmle.label | ... / ... | +| test.cpp:206:19:206:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:206:19:206:27 | ... / ... | semmle.label | ... / ... | +| test.cpp:208:21:208:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:208:21:208:31 | ... + ... | semmle.label | ... + ... | +| test.cpp:210:13:210:21 | middleNaN | semmle.label | middleNaN | +| test.cpp:212:23:212:31 | middleNaN | semmle.label | middleNaN | subpaths diff --git a/cpp/common/test/rules/misuseofnanfloatingpointvalue/test.cpp b/cpp/common/test/rules/misuseofnanfloatingpointvalue/test.cpp index 51540bc3a1..a68a47daf7 100644 --- a/cpp/common/test/rules/misuseofnanfloatingpointvalue/test.cpp +++ b/cpp/common/test/rules/misuseofnanfloatingpointvalue/test.cpp @@ -111,12 +111,13 @@ void f1(float p1) { (int)l12; // COMPLIANT: Casting Infinity to integer } - std::isinf(l12) ? (int)l12 : 0; // COMPLIANT: Check on wrong branch - std::isinf(l12) ? 0 : (int)l12; // COMPLIANT: Checked not infinite before use + std::isinf(l12) ? (int)l12 : 0; // COMPLIANT: Check on wrong branch + std::isinf(l12) ? 0 : (int)l12; // COMPLIANT: Checked not infinite before use std::isfinite(l12) ? (int)l12 : 0; // COMPLIANT: Checked finite before use std::isfinite(l12) ? 0 : (int)l12; // COMPLIANT: Checked on wrong branch - std::isnan(l12) ? (int)l12 - : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use + std::isnan(l12) + ? (int)l12 + : 0; // COMPLIANT: Checked NaN, therefore not infinite, before use std::isnan(l12) ? 0 : (int)l12; // COMPLIANT: Check on wrong branch float l13 = 0.0 / 0; @@ -150,15 +151,16 @@ void f1(float p1) { (int)l13; // COMPLIANT: Guarded not to be NaN } - std::isinf(l13) ? (int)l13 - : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use + std::isinf(l13) + ? (int)l13 + : 0; // COMPLIANT: Checked infinite, therefore not NaN, before use std::isinf(l13) ? 0 : (int)l13; // NON_COMPLIANT: Check on wrong branch std::isfinite(l13) ? (int)l13 : 0; // COMPLIANT: Checked finite before use std::isfinite(l13) ? 0 : (int)l13; // NON_COMPLIANT: Checked on wrong branch std::isnan(l13) ? (int)l13 : 0; // NON_COMPLIANT: Check on wrong branch std::isnan(l13) ? 0 : (int)l13; // COMPLIANT: Checked not NaN before use - (int)std::pow(2, p1); // COMPLIANT: likely to be Infinity + (int)std::pow(2, p1); // COMPLIANT: likely to be Infinity (int)std::pow(2, std::sin(p1)); // COMPLIANT: not likely to be Infinity (int)(1 / std::sin(p1)); // COMPLIANT: possible infinity from zero in denominator @@ -168,7 +170,7 @@ void f1(float p1) { (int)std::pow(p1, p1); // COMPLIANT: p1 is not zero } - (int)std::acos(p1); // NON_COMPLIANT: NaN if p1 is not within -1..1 + (int)std::acos(p1); // NON_COMPLIANT: NaN if p1 is not within -1..1 (int)std::acos(std::cos(p1)); // COMPLIANT: cos(p1) is within -1..1 } @@ -190,8 +192,7 @@ void addInfThenCastToInt(float p) { castToInt(p + 1.0 / 0.0); } void addNaNThenCastToInt(float p) { castToInt(p + 0.0 / 0.0); } void f2() { - castToInt(1.0 / - 0.0); // COMPLIANT: Infinity flows to denominator in division + castToInt(1.0 / 0.0); // COMPLIANT: Infinity flows to denominator in division castToInt(0.0 / 0.0); // COMPLIANT: NaN flows to denominator in division checkBeforeCastToInt(1.0 / 0.0); // COMPLIANT checkBeforeCastToInt(0.0 / 0.0); // COMPLIANT diff --git a/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql index d9810c1135..ee7139543d 100644 --- a/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql +++ b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql @@ -15,7 +15,8 @@ import cpp import codingstandards.cpp.misra import codingstandards.cpp.rules.misuseofinfinitefloatingpointvalue.MisuseOfInfiniteFloatingPointValue -class PossibleMisuseOfInfiniteFloatingPointValueQuery extends MisuseOfInfiniteFloatingPointValueSharedQuery { +class PossibleMisuseOfInfiniteFloatingPointValueQuery extends MisuseOfInfiniteFloatingPointValueSharedQuery +{ PossibleMisuseOfInfiniteFloatingPointValueQuery() { this = FloatingPointPackage::possibleMisuseOfInfiniteFloatingPointValueQuery() } diff --git a/rule_packages/cpp/FloatingPoint.json b/rule_packages/cpp/FloatingPoint.json index b085e5b289..672e57acff 100644 --- a/rule_packages/cpp/FloatingPoint.json +++ b/rule_packages/cpp/FloatingPoint.json @@ -14,8 +14,7 @@ "short_name": "PossibleMisuseOfInfiniteFloatingPointValue", "shared_implementation_short_name": "MisuseOfInfiniteFloatingPointValue", "tags": [ - "correctness", - "external/misra/c/2012/amendment3" + "correctness" ] }, { @@ -27,8 +26,7 @@ "short_name": "PossibleMisuseOfNaNFloatingPointValue", "shared_implementation_short_name": "MisuseOfNaNFloatingPointValue", "tags": [ - "correctness", - "external/misra/c/2012/amendment3" + "correctness" ] } ], From 551c2343036c4a7eafa3397d134a91bc4158dff9 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 15 Apr 2025 08:03:15 -0700 Subject: [PATCH 350/628] Missing format, regenerate query metadata --- c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql | 2 +- .../DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql | 1 - .../rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql index 10bfcafeba..9315a4ed4c 100644 --- a/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql +++ b/c/misra/src/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql @@ -20,4 +20,4 @@ class PossibleMisuseOfUndetectedNaNQuery extends MisuseOfNaNFloatingPointValueSh PossibleMisuseOfUndetectedNaNQuery() { this = FloatingTypes2Package::possibleMisuseOfUndetectedNaNQuery() } -} \ No newline at end of file +} diff --git a/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql index ee7139543d..0e3363137e 100644 --- a/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql +++ b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfInfiniteFloatingPointValue.ql @@ -7,7 +7,6 @@ * @problem.severity warning * @tags external/misra/id/dir-0-3-1 * correctness - * external/misra/c/2012/amendment3 * external/misra/obligation/advisory */ diff --git a/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql index 934ee6d998..035edd85b8 100644 --- a/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql +++ b/cpp/misra/src/rules/DIR-0-3-1/PossibleMisuseOfNaNFloatingPointValue.ql @@ -8,7 +8,6 @@ * @problem.severity warning * @tags external/misra/id/dir-0-3-1 * correctness - * external/misra/c/2012/amendment3 * external/misra/obligation/advisory */ From 160db8381893017f0a31290b8501d53d4bcdb1cd Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 15 Apr 2025 10:18:43 -0700 Subject: [PATCH 351/628] Remove deleted test qlrefs --- .../test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.qlref | 1 - c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.qlref | 1 - 2 files changed, 2 deletions(-) delete mode 100644 c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.qlref delete mode 100644 c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.qlref diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.qlref b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.qlref deleted file mode 100644 index dccac37c5f..0000000000 --- a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/DIR-4-15/PossibleMisuseOfUndetectedInfinity.ql \ No newline at end of file diff --git a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.qlref b/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.qlref deleted file mode 100644 index d88c172bd5..0000000000 --- a/c/misra/test/rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/DIR-4-15/PossibleMisuseOfUndetectedNaN.ql \ No newline at end of file From d8ac07f96918e85310d5baa0dcbe34f25b57e163 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 21 Apr 2025 23:07:01 +0100 Subject: [PATCH 352/628] Add missing results --- .../deviations_report_deviated/UnusedReturnValue.expected | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.expected b/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.expected index 7b8860d5a3..ab75d81f6f 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.expected +++ b/cpp/common/test/deviations/deviations_report_deviated/UnusedReturnValue.expected @@ -1,3 +1,8 @@ | main.cpp:10:3:10:6 | call to getX | Return value from call to $@ is unused. | main.cpp:6:5:6:8 | getX | getX | +| main.cpp:23:3:23:6 | call to getX | Return value from call to $@ is unused. | main.cpp:6:5:6:8 | getX | getX | +| main.cpp:25:3:25:6 | call to getX | Return value from call to $@ is unused. | main.cpp:6:5:6:8 | getX | getX | +| main.cpp:31:3:31:6 | call to getX | Return value from call to $@ is unused. | main.cpp:6:5:6:8 | getX | getX | +| main.cpp:33:3:33:6 | call to getX | Return value from call to $@ is unused. | main.cpp:6:5:6:8 | getX | getX | +| main.cpp:37:3:37:6 | call to getX | Return value from call to $@ is unused. | main.cpp:6:5:6:8 | getX | getX | | nested/nested2/test2.h:5:3:5:6 | call to getZ | Return value from call to $@ is unused. | nested/nested2/test2.h:1:5:1:8 | getZ | getZ | | nested/test.h:5:3:5:6 | call to getY | Return value from call to $@ is unused. | nested/test.h:1:5:1:8 | getY | getY | From 52e64673fee3cf653027a2924b5d3095bf81b457 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 21 Apr 2025 23:17:15 +0100 Subject: [PATCH 353/628] Add comment --- .../cpp/deviations/CodeIdentifierDeviation.qll | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll index 4b2f03cf98..b7a144f429 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -341,6 +341,11 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { ) } + /** + * Holds for the region matched by this code identifier deviation. + * + * Note: this is not the location of the marker itself. + */ predicate hasLocationInfo( string filepath, int suppressedLine, int suppressedColumn, int endline, int endcolumn ) { From 184e5d3ed5bde1cd8ae5895cff70254a0ae36104 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 21 Apr 2025 23:22:27 +0100 Subject: [PATCH 354/628] Extract common library for location handling --- .../src/codingstandards/cpp/Locations.qll | 24 ++++++++++++++ .../cpp/deviations/DeviationsSuppression.ql | 31 +++---------------- 2 files changed, 28 insertions(+), 27 deletions(-) create mode 100644 cpp/common/src/codingstandards/cpp/Locations.qll diff --git a/cpp/common/src/codingstandards/cpp/Locations.qll b/cpp/common/src/codingstandards/cpp/Locations.qll new file mode 100644 index 0000000000..83dd0448af --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Locations.qll @@ -0,0 +1,24 @@ +import cpp + +/** Holds if `lineNumber` is an indexed line number in file `f`. */ +predicate isLineNumber(File f, int lineNumber) { + exists(Location l | l.getFile() = f | + l.getStartLine() = lineNumber + or + l.getEndLine() = lineNumber + ) +} + +/** Gets the last line number in `f`. */ +int getLastLineNumber(File f) { result = max(int lineNumber | isLineNumber(f, lineNumber)) } + +/** Gets the last column number on the last line of `f`. */ +int getLastColumnNumber(File f) { + result = + max(Location l | + l.getFile() = f and + l.getEndLine() = getLastLineNumber(f) + | + l.getEndColumn() + ) +} diff --git a/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql index f29c068983..94f45c74b3 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql +++ b/cpp/common/src/codingstandards/cpp/deviations/DeviationsSuppression.ql @@ -7,29 +7,7 @@ import cpp import Deviations - -/** Holds if `lineNumber` is an indexed line number in file `f`. */ -private predicate isLineNumber(File f, int lineNumber) { - exists(Location l | l.getFile() = f | - l.getStartLine() = lineNumber - or - l.getEndLine() = lineNumber - ) -} - -/** Gets the last line number in `f`. */ -private int getLastLineNumber(File f) { result = max(int lineNumber | isLineNumber(f, lineNumber)) } - -/** Gets the last column number on the last line of `f`. */ -int getLastColumnNumber(File f) { - result = - max(Location l | - l.getFile() = f and - l.getEndLine() = getLastLineNumber(f) - | - l.getEndColumn() - ) -} +import codingstandards.cpp.Locations newtype TDeviationScope = TDeviationRecordFileScope(DeviationRecord dr, File file) { @@ -71,10 +49,9 @@ class DeviationRecordFileScope extends DeviationScope, TDeviationRecordFileScope string filepath, int startline, int startcolumn, int endline, int endcolumn ) { // In an ideal world, we would produce a URL here that informed the AlertSuppression code that - // the whole file was suppressed. However, experimentation suggestions the alert suppression - // code only works with locations with lines and columns, so we generate a location that covers - // the whole "indexed" file, by finding the location indexed in the database with the latest - // line and column number. + // the whole file was suppressed. However, the alert suppression code only works with locations + // with lines and columns, so we generate a location that covers the whole "indexed" file, by + // finding the location indexed in the database with the latest line and column number. exists(File f | f = getFile() | f.getLocation().hasLocationInfo(filepath, _, _, _, _) and startline = 1 and From 126ed553e5026853250e3c62e59768eb3abd540b Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 21 Apr 2025 23:30:54 +0100 Subject: [PATCH 355/628] Add getLastColumnNumber to shared library --- cpp/common/src/codingstandards/cpp/Locations.qll | 6 ++++++ .../cpp/deviations/CodeIdentifierDeviation.qll | 9 ++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Locations.qll b/cpp/common/src/codingstandards/cpp/Locations.qll index 83dd0448af..800f44d18a 100644 --- a/cpp/common/src/codingstandards/cpp/Locations.qll +++ b/cpp/common/src/codingstandards/cpp/Locations.qll @@ -22,3 +22,9 @@ int getLastColumnNumber(File f) { l.getEndColumn() ) } + +/** Gets the last column number on the given line of `filepath`. */ +bindingset[filepath, lineNumber] +int getLastColumnNumber(string filepath, int lineNumber) { + result = max(Location l | l.hasLocationInfo(filepath, _, _, lineNumber, _) | l.getEndColumn()) +} diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll index b7a144f429..137a2a72d7 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -32,6 +32,7 @@ import cpp import Deviations +import codingstandards.cpp.Locations string supportedStandard() { result = ["misra", "autosar", "cert"] } @@ -358,13 +359,7 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { then endcolumn = commentMarker.(DeviationEndOfLineMarker).getLocation().getEndColumn() else // Find the last column for a location on the next line - endcolumn = - max(Location l | - l.hasLocationInfo(filepath, _, _, _, _) and - l.getEndLine() = suppressedLine - | - l.getEndColumn() - ) + endcolumn = getLastColumnNumber(filepath, suppressedLine) ) or this = TMultiLineDeviation(_, _, _, filepath, suppressedLine, endline) and From 5ad61ee4e441007828e966df4c61d3ad658a62e8 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 21 Apr 2025 23:42:01 +0100 Subject: [PATCH 356/628] Deviations: Include the final line in ranges The deviated locations now include the line with the _end marker, for any element before the marker. --- .../deviations/CodeIdentifierDeviation.qll | 38 ++++++++++++------- .../DeviationsSuppression.expected | 4 +- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll index 137a2a72d7..e177b84046 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -295,11 +295,11 @@ newtype TCodeIndentifierDeviation = } or TMultiLineDeviation( DeviationRecord record, DeviationBegin beginComment, DeviationEnd endComment, string filepath, - int suppressedStartLine, int suppressedEndLine + int suppressedStartLine, int suppressedEndLine, int suppressedEndColumn ) { isDeviationRangePaired(record, beginComment, endComment) and beginComment.getLocation().hasLocationInfo(filepath, suppressedStartLine, _, _, _) and - endComment.getLocation().hasLocationInfo(filepath, suppressedEndLine, _, _, _) + endComment.getLocation().hasLocationInfo(filepath, _, _, suppressedEndLine, suppressedEndColumn) } or TCodeIdentifierDeviation(DeviationRecord record, DeviationAttribute attribute) { attribute.getADeviationRecord() = record @@ -310,7 +310,7 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { DeviationRecord getADeviationRecord() { this = TSingleLineDeviation(result, _, _, _) or - this = TMultiLineDeviation(result, _, _, _, _, _) + this = TMultiLineDeviation(result, _, _, _, _, _, _) or this = TCodeIdentifierDeviation(result, _) } @@ -321,18 +321,27 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { bindingset[e] pragma[inline_late] predicate isElementMatching(Element e) { - exists(string filepath, int elementLocationStart | - e.getLocation().hasLocationInfo(filepath, elementLocationStart, _, _, _) + exists(string filepath, int elementLocationStart, int elementLocationColumnStart | + e.getLocation() + .hasLocationInfo(filepath, elementLocationStart, elementLocationColumnStart, _, _) | exists(int suppressedLine | this = TSingleLineDeviation(_, _, filepath, suppressedLine) and suppressedLine = elementLocationStart ) or - exists(int suppressedStartLine, int suppressedEndLine | - this = TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedEndLine) and - suppressedStartLine < elementLocationStart and + exists(int suppressedStartLine, int suppressedEndLine, int suppressedEndColumn | + this = + TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedEndLine, + suppressedEndColumn) and + suppressedStartLine < elementLocationStart + | + // Element starts before the end line of the suppression suppressedEndLine > elementLocationStart + or + // Element exists on the same line as the suppression, and occurs before it + suppressedEndLine = elementLocationStart and + elementLocationColumnStart < suppressedEndColumn ) ) or @@ -362,9 +371,8 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { endcolumn = getLastColumnNumber(filepath, suppressedLine) ) or - this = TMultiLineDeviation(_, _, _, filepath, suppressedLine, endline) and - suppressedColumn = 1 and - endcolumn = 1 + this = TMultiLineDeviation(_, _, _, filepath, suppressedLine, endline, endcolumn) and + suppressedColumn = 1 or exists(DeviationAttribute attribute | this = TCodeIdentifierDeviation(_, attribute) and @@ -384,11 +392,13 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { suppressedLine ) or - exists(int suppressedStartLine, int suppressedEndLine | - this = TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedEndLine) and + exists(int suppressedStartLine, int suppressedEndLine, int suppressedEndColumn | + this = + TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedEndLine, + suppressedEndColumn) and result = "Deviation of " + getADeviationRecord().getQuery() + " applied to " + filepath + " Line " + - suppressedStartLine + ":" + suppressedEndLine + suppressedStartLine + ":" + suppressedEndLine + " (Column " + suppressedEndColumn + ")" ) ) or diff --git a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected index 73f564c13c..2192b36279 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected +++ b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected @@ -1,8 +1,8 @@ | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:12:1:12:58 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 12 | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:14:1:14:65 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 14 | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:18:1:18:40 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 18 | -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:21:1:27:1 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 21:27 | -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:29:1:35:1 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 29:35 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:21:1:27:53 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 21:27 (Column 53) | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:29:1:35:53 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 29:35 (Column 53) | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/unused-return-value] | lgtm[cpp/autosar/unused-return-value] | nested/nested2/test2.h:1:1:6:1 | Deviation of cpp/autosar/unused-return-value for nested/nested2/test2.h. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | coding-standards.xml:1:1:17:19 | Deviation of cpp/autosar/useless-assignment for coding-standards.xml. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | main.cpp:1:1:39:1 | Deviation of cpp/autosar/useless-assignment for main.cpp. | From 6a5f0950ec571b46088b0f96e57fa0dbff346cac Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 21 Apr 2025 23:56:29 +0100 Subject: [PATCH 357/628] Deviations: Store start columns for comment ranges --- .../deviations/CodeIdentifierDeviation.qll | 58 ++++++++++++------- .../DeviationsSuppression.expected | 7 ++- .../deviations_report_deviated/main.cpp | 5 ++ 3 files changed, 47 insertions(+), 23 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll index e177b84046..00e02d5712 100644 --- a/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll +++ b/cpp/common/src/codingstandards/cpp/deviations/CodeIdentifierDeviation.qll @@ -295,10 +295,13 @@ newtype TCodeIndentifierDeviation = } or TMultiLineDeviation( DeviationRecord record, DeviationBegin beginComment, DeviationEnd endComment, string filepath, - int suppressedStartLine, int suppressedEndLine, int suppressedEndColumn + int suppressedStartLine, int suppressedStartColumn, int suppressedEndLine, + int suppressedEndColumn ) { isDeviationRangePaired(record, beginComment, endComment) and - beginComment.getLocation().hasLocationInfo(filepath, suppressedStartLine, _, _, _) and + beginComment + .getLocation() + .hasLocationInfo(filepath, suppressedStartLine, suppressedStartColumn, _, _) and endComment.getLocation().hasLocationInfo(filepath, _, _, suppressedEndLine, suppressedEndColumn) } or TCodeIdentifierDeviation(DeviationRecord record, DeviationAttribute attribute) { @@ -310,7 +313,7 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { DeviationRecord getADeviationRecord() { this = TSingleLineDeviation(result, _, _, _) or - this = TMultiLineDeviation(result, _, _, _, _, _, _) + this = TMultiLineDeviation(result, _, _, _, _, _, _, _) or this = TCodeIdentifierDeviation(result, _) } @@ -330,18 +333,29 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { suppressedLine = elementLocationStart ) or - exists(int suppressedStartLine, int suppressedEndLine, int suppressedEndColumn | - this = - TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedEndLine, - suppressedEndColumn) and - suppressedStartLine < elementLocationStart + exists( + int suppressedStartLine, int suppressedStartColumn, int suppressedEndLine, + int suppressedEndColumn | - // Element starts before the end line of the suppression - suppressedEndLine > elementLocationStart - or - // Element exists on the same line as the suppression, and occurs before it - suppressedEndLine = elementLocationStart and - elementLocationColumnStart < suppressedEndColumn + this = + TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedStartColumn, + suppressedEndLine, suppressedEndColumn) and + ( + // Element starts on a line after the begin marker of the suppression + suppressedStartLine < elementLocationStart + or + // Element exists on the same line as the begin marker, and occurs after it + suppressedStartLine = elementLocationStart and + suppressedStartColumn < elementLocationColumnStart + ) and + ( + // Element starts on a line before the end marker of the suppression + suppressedEndLine > elementLocationStart + or + // Element exists on the same line as the end marker of the suppression, and occurs before it + suppressedEndLine = elementLocationStart and + elementLocationColumnStart < suppressedEndColumn + ) ) ) or @@ -371,8 +385,8 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { endcolumn = getLastColumnNumber(filepath, suppressedLine) ) or - this = TMultiLineDeviation(_, _, _, filepath, suppressedLine, endline, endcolumn) and - suppressedColumn = 1 + this = + TMultiLineDeviation(_, _, _, filepath, suppressedLine, suppressedColumn, endline, endcolumn) or exists(DeviationAttribute attribute | this = TCodeIdentifierDeviation(_, attribute) and @@ -392,13 +406,17 @@ class CodeIdentifierDeviation extends TCodeIndentifierDeviation { suppressedLine ) or - exists(int suppressedStartLine, int suppressedEndLine, int suppressedEndColumn | + exists( + int suppressedStartLine, int suppressedStartColumn, int suppressedEndLine, + int suppressedEndColumn + | this = - TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedEndLine, - suppressedEndColumn) and + TMultiLineDeviation(_, _, _, filepath, suppressedStartLine, suppressedStartColumn, + suppressedEndLine, suppressedEndColumn) and result = "Deviation of " + getADeviationRecord().getQuery() + " applied to " + filepath + " Line " + - suppressedStartLine + ":" + suppressedEndLine + " (Column " + suppressedEndColumn + ")" + suppressedStartLine + ":" + suppressedStartColumn + ":" + suppressedEndLine + ":" + + suppressedEndColumn ) ) or diff --git a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected index 2192b36279..35fca84928 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected +++ b/cpp/common/test/deviations/deviations_report_deviated/DeviationsSuppression.expected @@ -1,11 +1,12 @@ | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:12:1:12:58 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 12 | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:14:1:14:65 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 14 | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:18:1:18:40 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 18 | -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:21:1:27:53 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 21:27 (Column 53) | -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:29:1:35:53 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 29:35 (Column 53) | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:21:3:27:53 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 21:3:27:53 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:29:3:35:53 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 29:3:35:53 | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/type-long-double-used] | lgtm[cpp/autosar/type-long-double-used] | main.cpp:40:39:41:99 | Deviation of cpp/autosar/type-long-double-used applied to main.cpp Line 40:39:41:99 | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/unused-return-value] | lgtm[cpp/autosar/unused-return-value] | nested/nested2/test2.h:1:1:6:1 | Deviation of cpp/autosar/unused-return-value for nested/nested2/test2.h. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | coding-standards.xml:1:1:17:19 | Deviation of cpp/autosar/useless-assignment for coding-standards.xml. | -| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | main.cpp:1:1:39:1 | Deviation of cpp/autosar/useless-assignment for main.cpp. | +| file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | main.cpp:1:1:44:1 | Deviation of cpp/autosar/useless-assignment for main.cpp. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/coding-standards.xml:1:1:13:19 | Deviation of cpp/autosar/useless-assignment for nested/coding-standards.xml. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/nested2/test2.h:1:1:6:1 | Deviation of cpp/autosar/useless-assignment for nested/nested2/test2.h. | | file://:0:0:0:0 | (no string representation) | // lgtm[cpp/autosar/useless-assignment] | lgtm[cpp/autosar/useless-assignment] | nested/test.h:1:1:6:1 | Deviation of cpp/autosar/useless-assignment for nested/test.h. | diff --git a/cpp/common/test/deviations/deviations_report_deviated/main.cpp b/cpp/common/test/deviations/deviations_report_deviated/main.cpp index 7891faea18..d2f58d9db1 100644 --- a/cpp/common/test/deviations/deviations_report_deviated/main.cpp +++ b/cpp/common/test/deviations/deviations_report_deviated/main.cpp @@ -35,5 +35,10 @@ int main(int argc, char **argv) { // codeql::autosar_deviation_end(a-0-4-2-deviation) long double d14; // NON_COMPLIANT (A0-4-2) getX(); // NON_COMPLIANT (A0-1-2) + + // clang-format off + long double d15; /* NON_COMPLIANT*/ /* codeql::autosar_deviation_begin(a-0-4-2-deviation) */ long double d16; // COMPLIANT[DEVIATED] + long double d17; /* COMPLIANT[DEVIATED] */ /* codeql::autosar_deviation_end(a-0-4-2-deviation) */ long double d18; // NON_COMPLIANT + // clang-format on return 0; } \ No newline at end of file From 8c2da1cd439f6f5df31f1756842b64832da6feae Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 22 Apr 2025 00:01:48 +0100 Subject: [PATCH 358/628] Deviations: Expand testing for ranges Ensure begin/end column code works as expected --- .../TypeLongDoubleUsed.expected | 2 + .../deviations/deviations_basic_test/main.cpp | 5 +++ .../TypeLongDoubleUsed.expected | 18 +++++++++ .../TypeLongDoubleUsed.ql | 38 +++++++++++++++++++ 4 files changed, 63 insertions(+) create mode 100644 cpp/common/test/deviations/deviations_report_deviated/TypeLongDoubleUsed.expected create mode 100644 cpp/common/test/deviations/deviations_report_deviated/TypeLongDoubleUsed.ql diff --git a/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected b/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected index f2cfd03dc6..afc613642a 100644 --- a/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected +++ b/cpp/common/test/deviations/deviations_basic_test/TypeLongDoubleUsed.expected @@ -10,3 +10,5 @@ | main.cpp:21:15:21:16 | d6 | Use of long double type. | | main.cpp:30:15:30:17 | d10 | Use of long double type. | | main.cpp:38:15:38:17 | d14 | Use of long double type. | +| main.cpp:42:15:42:17 | d15 | Use of long double type. | +| main.cpp:43:113:43:115 | d18 | Use of long double type. | diff --git a/cpp/common/test/deviations/deviations_basic_test/main.cpp b/cpp/common/test/deviations/deviations_basic_test/main.cpp index aa389ed0ad..17126364f4 100644 --- a/cpp/common/test/deviations/deviations_basic_test/main.cpp +++ b/cpp/common/test/deviations/deviations_basic_test/main.cpp @@ -37,5 +37,10 @@ int main(int argc, char **argv) { // codeql::autosar_deviation_end(a-0-4-2-deviation) long double d14; // NON_COMPLIANT (A0-4-2) getX(); // NON_COMPLIANT (A0-1-2) + + // clang-format off + long double d15; /* NON_COMPLIANT*/ /* codeql::autosar_deviation_begin(a-0-4-2-deviation) */ long double d16; // COMPLIANT[DEVIATED] + long double d17; /* COMPLIANT[DEVIATED] */ /* codeql::autosar_deviation_end(a-0-4-2-deviation) */ long double d18; // NON_COMPLIANT + // clang-format on return 0; } \ No newline at end of file diff --git a/cpp/common/test/deviations/deviations_report_deviated/TypeLongDoubleUsed.expected b/cpp/common/test/deviations/deviations_report_deviated/TypeLongDoubleUsed.expected new file mode 100644 index 0000000000..e9099fa64a --- /dev/null +++ b/cpp/common/test/deviations/deviations_report_deviated/TypeLongDoubleUsed.expected @@ -0,0 +1,18 @@ +| main.cpp:11:15:11:16 | d1 | Use of long double type. | +| main.cpp:12:15:12:16 | d2 | Use of long double type. | +| main.cpp:14:15:14:16 | d3 | Use of long double type. | +| main.cpp:16:15:16:16 | d4 | Use of long double type. | +| main.cpp:18:15:18:16 | d5 | Use of long double type. | +| main.cpp:19:15:19:16 | d6 | Use of long double type. | +| main.cpp:22:15:22:16 | d7 | Use of long double type. | +| main.cpp:24:15:24:16 | d8 | Use of long double type. | +| main.cpp:26:15:26:16 | d9 | Use of long double type. | +| main.cpp:28:15:28:17 | d10 | Use of long double type. | +| main.cpp:30:15:30:17 | d11 | Use of long double type. | +| main.cpp:32:15:32:17 | d12 | Use of long double type. | +| main.cpp:34:15:34:17 | d13 | Use of long double type. | +| main.cpp:36:15:36:17 | d14 | Use of long double type. | +| main.cpp:40:15:40:17 | d15 | Use of long double type. | +| main.cpp:40:108:40:110 | d16 | Use of long double type. | +| main.cpp:41:15:41:17 | d17 | Use of long double type. | +| main.cpp:41:113:41:115 | d18 | Use of long double type. | diff --git a/cpp/common/test/deviations/deviations_report_deviated/TypeLongDoubleUsed.ql b/cpp/common/test/deviations/deviations_report_deviated/TypeLongDoubleUsed.ql new file mode 100644 index 0000000000..0ff7b93251 --- /dev/null +++ b/cpp/common/test/deviations/deviations_report_deviated/TypeLongDoubleUsed.ql @@ -0,0 +1,38 @@ +/** + * @id cpp/autosar/type-long-double-used + * @name A0-4-2: Type long double shall not be used + * @description The type long double has an implementation-defined width and therefore shall not be + * used. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/autosar/id/a0-4-2 + * correctness + * readability + * external/autosar/allocated-target/implementation + * external/autosar/enforcement/automated + * external/autosar/obligation/required + */ + +import cpp +import codingstandards.cpp.CodingStandards +import codingstandards.cpp.exclusions.cpp.RuleMetadata + +predicate isUsingLongDouble(ClassTemplateInstantiation c) { + c.getATemplateArgument() instanceof LongDoubleType or + isUsingLongDouble(c.getATemplateArgument()) +} + +from Variable v +where + not isExcluded(v, BannedTypesPackage::typeLongDoubleUsedQuery()) and + ( + v.getUnderlyingType() instanceof LongDoubleType and + not v.isFromTemplateInstantiation(_) + or + exists(ClassTemplateInstantiation c | + c = v.getType() and + isUsingLongDouble(c) + ) + ) +select v, "Use of long double type." From ed088be3717f0722f83e37f52e68c69300b5e2a9 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 25 Apr 2025 08:12:40 -0700 Subject: [PATCH 359/628] Fix performance regression from Compatible.qll --- cpp/common/src/codingstandards/cpp/types/Compatible.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll index d6f65126e8..7ea58d766d 100644 --- a/cpp/common/src/codingstandards/cpp/types/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -69,6 +69,7 @@ module TypesCompatibleConfig implements TypeEquivalenceSig { /** * Utilize QlBuiltins::InternSets to efficiently compare the sets of specifiers on two types. */ +bindingset[t1, t2] private predicate specifiersMatchExactly(Type t1, Type t2) { t1 = t2 or From 472c93a89b47f0b7c8492c6ea12edd7fe70e616a Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 25 Apr 2025 16:29:32 -0700 Subject: [PATCH 360/628] Add changes to join order and prevent cartesian product through rewrite --- .../codingstandards/cpp/types/Compatible.qll | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll index 7ea58d766d..33b2830827 100644 --- a/cpp/common/src/codingstandards/cpp/types/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -53,8 +53,11 @@ module TypesCompatibleConfig implements TypeEquivalenceSig { or // Enum types are compatible with one of char, int, or signed int, but the implementation // decides. - [t1, t2] instanceof Enum and - ([t1, t2] instanceof CharType or [t1, t2] instanceof IntType) + t1 instanceof Enum and + (t2 instanceof CharType or t2 instanceof IntType) + or + t2 instanceof Enum and + (t1 instanceof CharType or t1 instanceof IntType) } bindingset[t1, t2] @@ -348,8 +351,15 @@ module FunctionDeclarationTypeEquivalence { predicate equalParameterTypes(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { f1.getDeclaration() = f2.getDeclaration() and forall(int i | exists([f1, f2].getParameterDeclarationEntry(i)) | - TypeEquivalence::equalTypes(f1.getParameterDeclarationEntry(i) - .getType(), f2.getParameterDeclarationEntry(i).getType()) + equalParameterTypesAt(f1, f2, pragma[only_bind_into](i)) + ) + } + + predicate equalParameterTypesAt(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, int i) { + pragma[only_bind_out](f1.getDeclaration()) = pragma[only_bind_out](f2.getDeclaration()) and + TypeEquivalence::equalTypes( + f1.getParameterDeclarationEntry(i).getType(), + f2.getParameterDeclarationEntry(i).getType() ) } } From 7f6b32d4c14035cc9eaf1bbb18fd12a3ff3c816c Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 27 Apr 2025 00:44:21 -0700 Subject: [PATCH 361/628] Try new approach to reduce search set in type equivalence, some new join orders. More pragmas added to encourage the join ordering pipeline to make function comparisons more efficient. New approach in type equivalence assumes that all types are trivially equivalent to themselves. Therefore, only type comparisons between non-identical types need to be considered as interesting roots. The types that are reachable in the type graph from these roots are the ones considered by the recursive type equivalence predicate. --- ...rousDefaultSelectionForPointerInGeneric.ql | 20 ++- .../DeclarationsOfAFunctionSameNameAndType.ql | 10 +- .../DeclarationsOfAnObjectSameNameAndType.ql | 19 ++- .../CompatibleDeclarationFunctionDefined.ql | 16 ++- .../CompatibleDeclarationObjectDefined.ql | 16 +-- ...-25-improve-type-comparison-performance.md | 6 + .../codingstandards/cpp/types/Compatible.qll | 127 ++++++++++++++---- .../cpp/types/SimpleAssignment.qll | 65 ++++++--- 8 files changed, 199 insertions(+), 80 deletions(-) create mode 100644 change_notes/2025-04-25-improve-type-comparison-performance.md diff --git a/c/misra/src/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.ql b/c/misra/src/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.ql index a009ba1b2a..f2961e2638 100644 --- a/c/misra/src/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.ql +++ b/c/misra/src/rules/RULE-23-5/DangerousDefaultSelectionForPointerInGeneric.ql @@ -20,18 +20,14 @@ import codingstandards.cpp.types.LvalueConversion import codingstandards.cpp.types.SimpleAssignment predicate typesCompatible(Type t1, Type t2) { - TypeEquivalence::equalTypes(t1, t2) + TypeEquivalence::equalTypes(t1, t2) } -class TypeFromGeneric extends Type { - TypeFromGeneric() { - exists(C11GenericExpr g | - ( - this = g.getAssociationType(_) or - this = g.getControllingExpr().getFullyConverted().getType() - ) - ) - } +predicate relevantTypes(Type a, Type b) { + exists(C11GenericExpr g | + a = g.getAnAssociationType() and + b = getLvalueConverted(g.getControllingExpr().getFullyConverted().getType()) + ) } predicate missesOnPointerConversion(Type provided, Type expected) { @@ -40,11 +36,11 @@ predicate missesOnPointerConversion(Type provided, Type expected) { // But 6.5.16.1 simple assignment constraints would have been satisfied: ( // Check as if the controlling expr is assigned to the expected type: - SimpleAssignment::satisfiesSimplePointerAssignment(expected, provided) + SimpleAssignment::satisfiesSimplePointerAssignment(expected, provided) or // Since developers typically rely on the compiler to catch const/non-const assignment // errors, don't assume a const-to-non-const generic selection miss was intentional. - SimpleAssignment::satisfiesSimplePointerAssignment(provided, expected) + SimpleAssignment::satisfiesSimplePointerAssignment(provided, expected) ) } diff --git a/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql b/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql index 2de2e4fd0a..0be6347840 100644 --- a/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql +++ b/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql @@ -16,6 +16,12 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.types.Compatible +predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + f1.getDeclaration() = f2.getDeclaration() and + not f1 = f2 and + f1.getDeclaration() = f2.getDeclaration() +} + from FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, string case, string pluralDo where not isExcluded(f1, Declarations4Package::declarationsOfAFunctionSameNameAndTypeQuery()) and @@ -24,12 +30,12 @@ where f1.getDeclaration() = f2.getDeclaration() and //return type check ( - not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, f2) and + not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, f2) and case = "return type" and pluralDo = "does" or //parameter type check - not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, f2) and + not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, f2) and case = "parameter types" and pluralDo = "do" or diff --git a/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql b/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql index 12ff583b6b..36a84b3b9c 100644 --- a/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql +++ b/c/misra/src/rules/RULE-8-3/DeclarationsOfAnObjectSameNameAndType.ql @@ -16,15 +16,6 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.types.Compatible -class RelevantType extends Type { - RelevantType() { - exists(VariableDeclarationEntry decl | - (relevantPair(decl, _) or relevantPair(_, decl)) and - decl.getType() = this - ) - } -} - predicate relevantPair(VariableDeclarationEntry decl1, VariableDeclarationEntry decl2) { not decl1 = decl2 and not decl1.getVariable().getDeclaringType().isAnonymous() and @@ -43,12 +34,20 @@ predicate relevantPair(VariableDeclarationEntry decl1, VariableDeclarationEntry ) } +predicate relevantTypes(Type a, Type b) { + exists(VariableDeclarationEntry varA, VariableDeclarationEntry varB | + a = varA.getType() and + b = varB.getType() and + relevantPair(varA, varB) + ) +} + from VariableDeclarationEntry decl1, VariableDeclarationEntry decl2 where not isExcluded(decl1, Declarations4Package::declarationsOfAnObjectSameNameAndTypeQuery()) and not isExcluded(decl2, Declarations4Package::declarationsOfAnObjectSameNameAndTypeQuery()) and relevantPair(decl1, decl2) and - not TypeEquivalence::equalTypes(decl1.getType(), + not TypeEquivalence::equalTypes(decl1.getType(), decl2.getType()) select decl1, "The object $@ of type " + decl1.getType().toString() + diff --git a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql index 98876ad1bd..2f17dd5086 100644 --- a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql +++ b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql @@ -19,6 +19,16 @@ import codingstandards.c.misra import codingstandards.cpp.Identifiers import codingstandards.cpp.types.Compatible +predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + f1.getDeclaration() instanceof ExternalIdentifiers and + f1.isDefinition() and + f1.getName() = f2.getName() and + f1.getDeclaration() = f2.getDeclaration() and + not f2.isDefinition() and + not f1.isFromTemplateInstantiation(_) and + not f2.isFromTemplateInstantiation(_) +} + from FunctionDeclarationEntry f1 where not isExcluded(f1, Declarations4Package::compatibleDeclarationFunctionDefinedQuery()) and @@ -38,10 +48,12 @@ where f2.getDeclaration() = f1.getDeclaration() and ( //return types differ - not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, f2) + not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, + f2) or //parameter types differ - not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, f2) + not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, + f2) or //parameter names differ parameterNamesUnmatched(f1, f2) diff --git a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationObjectDefined.ql b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationObjectDefined.ql index 613ce56806..bed30d673c 100644 --- a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationObjectDefined.ql +++ b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationObjectDefined.ql @@ -19,13 +19,13 @@ import codingstandards.c.misra import codingstandards.cpp.Identifiers import codingstandards.cpp.types.Compatible -class RelevantType extends Type { - RelevantType() { - exists(VariableDeclarationEntry decl | - count(VariableDeclarationEntry others | others.getDeclaration() = decl.getDeclaration()) > 1 and - decl.getType() = this - ) - } +predicate relevantTypes(Type a, Type b) { + exists(VariableDeclarationEntry varA, VariableDeclarationEntry varB | + not varA = varB and + varA.getDeclaration() = varB.getDeclaration() and + a = varA.getType() and + b = varB.getType() + ) } from VariableDeclarationEntry decl1 @@ -37,7 +37,7 @@ where not exists(VariableDeclarationEntry decl2 | not decl2.isDefinition() and decl1.getDeclaration() = decl2.getDeclaration() and - TypeEquivalence::equalTypes(decl1.getType(), + TypeEquivalence::equalTypes(decl1.getType(), decl2.getType()) ) select decl1, "No separate compatible declaration found for this definition." diff --git a/change_notes/2025-04-25-improve-type-comparison-performance.md b/change_notes/2025-04-25-improve-type-comparison-performance.md new file mode 100644 index 0000000000..91a019bdf2 --- /dev/null +++ b/change_notes/2025-04-25-improve-type-comparison-performance.md @@ -0,0 +1,6 @@ + - `RULE-8-3`, `RULE-8-4`, `DCL40-C`, `RULE-23-5`: `DeclarationsOfAFunctionSameNameAndType.ql`, `DeclarationsOfAnObjectSameNameAndType.ql`, `CompatibleDeclarationOfFunctionDefined.ql`, `CompatibleDeclarationObjectDefined.ql`, `IncompatibleFunctionDeclarations.ql`, `DangerousDefaultSelectionForPointerInGeneric.ql`: + - Added pragmas to alter join order on function parameter equivalence (names and types). + - Refactored expression which the optimizer was confused by, and compiled into a cartesian product. + - Altered the module `Compatible.qll` to only perform expensive equality checks on types that are compared to a non identical other type, and those reachable from those types in the type graph. Types that are identical will trivially be considered equivalent. + - `RULE-23-5`: `DangerousDefaultSelectionForPointerInGeneric.ql`: + - Altered the module `SimpleAssignment.qll` in accordance with the changes to `Compatible.qll`. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll index 33b2830827..db77765b5a 100644 --- a/cpp/common/src/codingstandards/cpp/types/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -25,7 +25,7 @@ class VariableType extends Type { } predicate parameterNamesUnmatched(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { - f1.getDeclaration() = f2.getDeclaration() and + pragma[only_bind_into](f1).getDeclaration() = pragma[only_bind_into](f2).getDeclaration() and exists(string p1Name, string p2Name, int i | p1Name = f1.getParameterDeclarationEntry(i).getName() and p2Name = f2.getParameterDeclarationEntry(i).getName() @@ -208,34 +208,64 @@ signature module TypeEquivalenceSig { module DefaultEquivalence implements TypeEquivalenceSig { } /** - * A signature class used to restrict the set of types considered by `TypeEquivalence`, for + * A signature predicate used to restrict the set of types considered by `TypeEquivalence`, for * performance reasons. */ -signature class TypeSubset extends Type; +signature predicate interestedInEquality(Type a, Type b); /** * A module to check the equivalence of two types, as defined by the provided `TypeEquivalenceSig`. * - * For performance reasons, this module is designed to be used with a `TypeSubset` that restricts - * the set of considered types. All types reachable (in the type graph) from a type in the subset - * will be considered. (See `RelevantType`.) + * For performance reasons, this module is designed to be used with a predicate + * `interestedInEquality` that restricts the set of considered types. * * To use this module, define a `TypeEquivalenceSig` module and implement a subset of `Type` that * selects the relevant root types to be considered. Then use the predicate `equalTypes(a, b)`. + * Note that `equalTypes(a, b)` only holds if `interestedIn(a, b)` holds. A type is always + * considered to be equal to itself, and this module does not support configurations that declare + * otherwise. + * + * Further, `interestedInEquality(a, a)` is treated differently from `interestedInEquality(a, b)`, + * assuming that `a` and `b` are not identical. This is so that we can construct a set of types + * that are not identical, but still may be equivalent by the specified configuration. We also must + * consider all types that are reachable from these types, as the equivalence relation is + * recursive. Therefore, this module is more performant when most comparisons are identical, and + * only a few are not. */ -module TypeEquivalence { +module TypeEquivalence { /** * Check whether two types are equivalent, as defined by the `TypeEquivalenceSig` module. + * + * This only holds if the specified predicate `interestedIn` holds for the types, and always + * holds if `t1` and `t2` are identical. */ - predicate equalTypes(RelevantType t1, RelevantType t2) { + predicate equalTypes(Type t1, Type t2) { + interestedInUnordered(t1, t2) and + ( + // If the types are identical, they are trivially equal. + t1 = t2 + or + not t1 = t2 and + equalTypesImpl(t1, t2) + ) + } + + /** + * This implementation handles only the slow and complex cases of type equivalence, where the + * types are not identical. + * + * Assuming that types a, b must be compared where `a` and `b` are not identical, we wish to + * search only the smallest set of possible relevant types. See `RelevantType` for more. + */ + private predicate equalTypesImpl(RelevantType t1, RelevantType t2) { if Config::overrideTypeComparison(t1, t2, _) then Config::overrideTypeComparison(t1, t2, true) else if t1 instanceof TypedefType and Config::resolveTypedefs() - then equalTypes(t1.(TypedefType).getBaseType(), t2) + then equalTypesImpl(t1.(TypedefType).getBaseType(), t2) else if t2 instanceof TypedefType and Config::resolveTypedefs() - then equalTypes(t1, t2.(TypedefType).getBaseType()) + then equalTypesImpl(t1, t2.(TypedefType).getBaseType()) else ( not t1 instanceof DerivedType and not t2 instanceof DerivedType and @@ -251,13 +281,36 @@ module TypeEquivalence { ) } + /** Whether two types will be compared, regardless of order (a, b) or (b, a). */ + private predicate interestedInUnordered(Type t1, Type t2) { + interestedIn(t1, t2) or + interestedIn(t2, t1) } + + final private class FinalType = Type; + /** - * A type that is either part of the type subset, or that is reachable from a type in the subset. + * A type that is compared to another type that is not identical. This is the set of types that + * form the roots of our more expensive type equivalence analysis. */ - private class RelevantType instanceof Type { - RelevantType() { exists(T t | typeGraph*(t, this)) } + private class InterestingType extends FinalType { + InterestingType() { + exists(Type inexactCompare | + interestedInUnordered(this, _) and + not inexactCompare = this + ) + } + } - string toString() { result = this.(Type).toString() } + /** + * A type that is reachable from an `InterestingType` (a type that is compared to a non-identical + * type). + * + * Since type equivalence is recursive, CodeQL will consider the equality of these types in a + * bottom-up evaluation, with leaf nodes first. Therefore, this set must be as small as possible + * in order to be efficient. + */ + private class RelevantType extends FinalType { + RelevantType() { exists(InterestingType t | typeGraph*(t, this)) } } private class RelevantDerivedType extends RelevantType instanceof DerivedType { @@ -296,7 +349,7 @@ module TypeEquivalence { bindingset[t1, t2] private predicate equalDerivedTypes(RelevantDerivedType t1, RelevantDerivedType t2) { exists(Boolean baseTypesEqual | - (baseTypesEqual = true implies equalTypes(t1.getBaseType(), t2.getBaseType())) and + (baseTypesEqual = true implies equalTypesImpl(t1.getBaseType(), t2.getBaseType())) and ( Config::equalPointerTypes(t1, t2, baseTypesEqual) or @@ -310,7 +363,7 @@ module TypeEquivalence { // Note that this case is different from the above, in that we don't merely get the base // type (as that could be a TypedefType that points to another SpecifiedType). We need to // unspecify the type to see if the base types are equal. - (unspecifiedTypesEqual = true implies equalTypes(unspecify(t1), unspecify(t2))) and + (unspecifiedTypesEqual = true implies equalTypesImpl(unspecify(t1), unspecify(t2))) and Config::equalSpecifiedTypes(t1, t2, unspecifiedTypesEqual) ) } @@ -318,12 +371,12 @@ module TypeEquivalence { bindingset[t1, t2] private predicate equalFunctionTypes(RelevantFunctionType t1, RelevantFunctionType t2) { exists(Boolean returnTypeEqual, Boolean parameterTypesEqual | - (returnTypeEqual = true implies equalTypes(t1.getReturnType(), t2.getReturnType())) and + (returnTypeEqual = true implies equalTypesImpl(t1.getReturnType(), t2.getReturnType())) and ( parameterTypesEqual = true implies forall(int i | exists([t1, t2].getParameterType(i)) | - equalTypes(t1.getParameterType(i), t2.getParameterType(i)) + equalTypesImpl(t1.getParameterType(i), t2.getParameterType(i)) ) ) and ( @@ -337,18 +390,41 @@ module TypeEquivalence { bindingset[t1, t2] private predicate equalTypedefTypes(RelevantTypedefType t1, RelevantTypedefType t2) { exists(Boolean baseTypesEqual | - (baseTypesEqual = true implies equalTypes(t1.getBaseType(), t2.getBaseType())) and + (baseTypesEqual = true implies equalTypesImpl(t1.getBaseType(), t2.getBaseType())) and Config::equalTypedefTypes(t1, t2, baseTypesEqual) ) } } -module FunctionDeclarationTypeEquivalence { +signature predicate interestedInFunctionDeclarations( + FunctionDeclarationEntry f1, FunctionDeclarationEntry f2 +); + +module FunctionDeclarationTypeEquivalence< + TypeEquivalenceSig Config, interestedInFunctionDeclarations/2 interestedInFunctions> +{ + private predicate interestedInReturnTypes(Type a, Type b) { + exists(FunctionDeclarationEntry aFun, FunctionDeclarationEntry bFun | + interestedInFunctions(aFun, bFun) and + a = aFun.getType() and + b = bFun.getType() + ) + } + + private predicate interestedInParameterTypes(Type a, Type b) { + exists(FunctionDeclarationEntry aFun, FunctionDeclarationEntry bFun, int i | + interestedInFunctions(pragma[only_bind_into](aFun), pragma[only_bind_into](bFun)) and + a = aFun.getParameterDeclarationEntry(i).getType() and + b = bFun.getParameterDeclarationEntry(i).getType() + ) + } + predicate equalReturnTypes(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { - TypeEquivalence::equalTypes(f1.getType(), f2.getType()) + TypeEquivalence::equalTypes(f1.getType(), f2.getType()) } predicate equalParameterTypes(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + interestedInFunctions(f1, f2) and f1.getDeclaration() = f2.getDeclaration() and forall(int i | exists([f1, f2].getParameterDeclarationEntry(i)) | equalParameterTypesAt(f1, f2, pragma[only_bind_into](i)) @@ -356,11 +432,10 @@ module FunctionDeclarationTypeEquivalence { } predicate equalParameterTypesAt(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, int i) { - pragma[only_bind_out](f1.getDeclaration()) = pragma[only_bind_out](f2.getDeclaration()) and - TypeEquivalence::equalTypes( - f1.getParameterDeclarationEntry(i).getType(), - f2.getParameterDeclarationEntry(i).getType() - ) + interestedInFunctions(f1, f2) and + f1.getDeclaration() = f2.getDeclaration() and + TypeEquivalence::equalTypes(f1.getParameterDeclarationEntry(pragma[only_bind_into](i)) + .getType(), f2.getParameterDeclarationEntry(pragma[only_bind_into](i)).getType()) } } diff --git a/cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll b/cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll index 4f7a85c80a..a31400a340 100644 --- a/cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll +++ b/cpp/common/src/codingstandards/cpp/types/SimpleAssignment.qll @@ -8,42 +8,67 @@ import codingstandards.cpp.types.LvalueConversion import codingstandards.cpp.types.Compatible -module SimpleAssignment { - final private class FinalType = Type; - - private class RelevantType extends FinalType { - RelevantType() { exists(T t | typeGraph*(t, this) or typeGraph(getLvalueConverted(t), this)) } - - string toString() { result = "relevant type" } - } - +module SimpleAssignment { /** * Whether a pair of qualified or unqualified pointer types satisfy the simple assignment * constraints from 6.5.16.1. * * There are additional constraints not implemented here involving one or more arithmetic types. */ - predicate satisfiesSimplePointerAssignment(RelevantType left, RelevantType right) { + predicate satisfiesSimplePointerAssignment(Type left, Type right) { + checksAssignment(left, right) and simplePointerAssignmentImpl(getLvalueConverted(left), right) } + private predicate satisfiedWhenTypesCompatible(Type left, Type right, Type checkA, Type checkB) { + interestedInTypes(left, right) and + exists(Type leftBase, Type rightBase | + // The left operand has atomic, qualified, or unqualified pointer type: + leftBase = left.stripTopLevelSpecifiers().(PointerType).getBaseType() and + rightBase = right.stripTopLevelSpecifiers().(PointerType).getBaseType() and + ( + // and both operands are pointers to qualified or unqualified versions of compatible types: + checkA = leftBase.stripTopLevelSpecifiers() and + checkB = rightBase.stripTopLevelSpecifiers() + ) and + // and the type pointed to by the left has all the qualifiers of the type pointed to by the + // right: + forall(Specifier s | s = rightBase.getASpecifier() | s = leftBase.getASpecifier()) + ) + } + + predicate interestedInTypes(Type left, Type right) { + exists(Type unconverted | + left = getLvalueConverted(unconverted) and + checksAssignment(unconverted, right) + ) + } + + predicate checksCompatibility(Type left, Type right) { + // Check if the types are compatible + exists(Type assignA, Type assignB | + checksAssignment(assignA, assignB) and + satisfiedWhenTypesCompatible(assignA, assignB, left, right) + ) + } + /** * Implementation of 6.5.16.1 for a pair of pointer types, that assumes lvalue conversion has been * performed on the left operand. */ - private predicate simplePointerAssignmentImpl(RelevantType left, RelevantType right) { - exists(RelevantType leftBase, RelevantType rightBase | + bindingset[left, right] + private predicate simplePointerAssignmentImpl(Type left, Type right) { + exists(Type checkA, Type checkB | + satisfiedWhenTypesCompatible(left, right, checkA, checkB) and + TypeEquivalence::equalTypes(checkA, checkB) + ) + or + exists(Type leftBase, Type rightBase | // The left operand has atomic, qualified, or unqualified pointer type: leftBase = left.stripTopLevelSpecifiers().(PointerType).getBaseType() and rightBase = right.stripTopLevelSpecifiers().(PointerType).getBaseType() and - ( - // and both operands are pointers to qualified or unqualified versions of compatible types: - TypeEquivalence::equalTypes(leftBase - .stripTopLevelSpecifiers(), rightBase.stripTopLevelSpecifiers()) - or - // or one operand is a pointer to a qualified or unqualified version of void - [leftBase, rightBase].stripTopLevelSpecifiers() instanceof VoidType - ) and + // or one operand is a pointer to a qualified or unqualified version of void + [leftBase, rightBase].stripTopLevelSpecifiers() instanceof VoidType and // and the type pointed to by the left has all the qualifiers of the type pointed to by the // right: forall(Specifier s | s = rightBase.getASpecifier() | s = leftBase.getASpecifier()) From 48257745c8e553c125aa876e9755f959888bfc4a Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 27 Apr 2025 01:49:42 -0700 Subject: [PATCH 362/628] Add missing file changed --- .../DCL40-C/IncompatibleFunctionDeclarations.ql | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql index 95ef0fd682..8cab442e54 100644 --- a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql +++ b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql @@ -19,6 +19,12 @@ import codingstandards.c.cert import codingstandards.cpp.types.Compatible import ExternalIdentifiers +predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + not f1 = f2 and + f1.getDeclaration() = f2.getDeclaration() and + f1.getName() = f2.getName() +} + from ExternalIdentifiers d, FunctionDeclarationEntry f1, FunctionDeclarationEntry f2 where not isExcluded(f1, Declarations2Package::incompatibleFunctionDeclarationsQuery()) and @@ -29,10 +35,12 @@ where f1.getName() = f2.getName() and ( //return type check - not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, f2) + not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, + f2) or //parameter type check - not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, f2) + not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, + f2) ) and // Apply ordering on start line, trying to avoid the optimiser applying this join too early // in the pipeline From 06351f52f176b55a5e3396dd8f5aa3a445d70a01 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 27 Apr 2025 01:48:55 -0700 Subject: [PATCH 363/628] Try forcing top-down pairwise comparison --- .../codingstandards/cpp/types/Compatible.qll | 138 ++++++++---------- 1 file changed, 63 insertions(+), 75 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll index db77765b5a..53b0076c7c 100644 --- a/cpp/common/src/codingstandards/cpp/types/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -224,7 +224,7 @@ signature predicate interestedInEquality(Type a, Type b); * Note that `equalTypes(a, b)` only holds if `interestedIn(a, b)` holds. A type is always * considered to be equal to itself, and this module does not support configurations that declare * otherwise. - * + * * Further, `interestedInEquality(a, a)` is treated differently from `interestedInEquality(a, b)`, * assuming that `a` and `b` are not identical. This is so that we can construct a set of types * that are not identical, but still may be equivalent by the specified configuration. We also must @@ -233,45 +233,75 @@ signature predicate interestedInEquality(Type a, Type b); * only a few are not. */ module TypeEquivalence { + /** - * Check whether two types are equivalent, as defined by the `TypeEquivalenceSig` module. - * - * This only holds if the specified predicate `interestedIn` holds for the types, and always - * holds if `t1` and `t2` are identical. + * Performance related predicate to force top down rather than bottom up evaluation of type + * equivalence. */ - predicate equalTypes(Type t1, Type t2) { - interestedInUnordered(t1, t2) and - ( - // If the types are identical, they are trivially equal. - t1 = t2 + predicate compares(Type t1, Type t2) { + interestedIn(t1, t2) + or + exists(DerivedType t1Derived, DerivedType t2Derived | + not t1Derived instanceof SpecifiedType and + not t2Derived instanceof SpecifiedType and + compares(pragma[only_bind_into](t1Derived), pragma[only_bind_into](t2Derived)) and + t1 = t1Derived.getBaseType() and + t2 = t2Derived.getBaseType() + ) + or + exists(SpecifiedType t1Spec, SpecifiedType t2Spec | + compares(pragma[only_bind_into](t1Spec), pragma[only_bind_into](t2Spec)) and + ( + t1 = unspecify(t1Spec) and + t2 = unspecify(t2Spec) + ) + ) + or + exists(FunctionType t1Func, FunctionType t2Func | + compares(pragma[only_bind_into](t1Func), pragma[only_bind_into](t2Func)) and + ( + t1 = t1Func.getReturnType() and + t2 = t2Func.getReturnType() + or + exists(int i | + t1 = t1Func.getParameterType(pragma[only_bind_out](i)) and + t2 = t2Func.getParameterType(i) + ) + ) + ) + or + Config::resolveTypedefs() and + exists(TypedefType tdtype | + tdtype.getBaseType() = t1 and + compares(pragma[only_bind_into](tdtype), t2) or - not t1 = t2 and - equalTypesImpl(t1, t2) + tdtype.getBaseType() = t2 and + compares(t1, pragma[only_bind_into](tdtype)) ) } /** - * This implementation handles only the slow and complex cases of type equivalence, where the - * types are not identical. + * Check whether two types are equivalent, as defined by the `TypeEquivalenceSig` module. * - * Assuming that types a, b must be compared where `a` and `b` are not identical, we wish to - * search only the smallest set of possible relevant types. See `RelevantType` for more. + * This only holds if the specified predicate `interestedIn` holds for the types, and always + * holds if `t1` and `t2` are identical. */ - private predicate equalTypesImpl(RelevantType t1, RelevantType t2) { + private predicate equalTypes(Type t1, Type t2) { + compares(pragma[only_bind_into](t1), pragma[only_bind_into](t2)) and if Config::overrideTypeComparison(t1, t2, _) then Config::overrideTypeComparison(t1, t2, true) else if t1 instanceof TypedefType and Config::resolveTypedefs() - then equalTypesImpl(t1.(TypedefType).getBaseType(), t2) + then equalTypes(t1.(TypedefType).getBaseType(), t2) else if t2 instanceof TypedefType and Config::resolveTypedefs() - then equalTypesImpl(t1, t2.(TypedefType).getBaseType()) + then equalTypes(t1, t2.(TypedefType).getBaseType()) else ( not t1 instanceof DerivedType and not t2 instanceof DerivedType and not t1 instanceof TypedefType and not t2 instanceof TypedefType and - LeafEquiv::getEquivalenceClass(t1) = LeafEquiv::getEquivalenceClass(t2) + equalLeafRelation(t1, t2) or equalDerivedTypes(t1, t2) or @@ -284,56 +314,14 @@ module TypeEquivalence; - - private predicate equalLeafRelation(RelevantType t1, RelevantType t2) { - Config::equalLeafTypes(t1, t2) - } + bindingset[t1, t2] + private predicate equalLeafRelation(Type t1, Type t2) { Config::equalLeafTypes(t1, t2) } - private RelevantType unspecify(SpecifiedType t) { + bindingset[t] + private Type unspecify(SpecifiedType t) { // This subtly and importantly handles the complicated cases of typedefs. Under most scenarios, // if we see a typedef in `equalTypes()` we can simply get the base type and continue. However, // there is an exception if we have a specified type that points to a typedef that points to @@ -347,9 +335,9 @@ module TypeEquivalence Date: Sun, 27 Apr 2025 12:22:21 -0700 Subject: [PATCH 364/628] Fix private predicate --- cpp/common/src/codingstandards/cpp/types/Compatible.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll index 53b0076c7c..da2b175a0d 100644 --- a/cpp/common/src/codingstandards/cpp/types/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -286,7 +286,7 @@ module TypeEquivalence Date: Mon, 28 Apr 2025 10:51:11 -0700 Subject: [PATCH 365/628] Address feedback, separate `compares` from `recurses`, format. --- .../DeclarationsOfAFunctionSameNameAndType.ql | 6 +- ...-25-improve-type-comparison-performance.md | 2 +- .../codingstandards/cpp/types/Compatible.qll | 155 ++++++++++++++---- 3 files changed, 125 insertions(+), 38 deletions(-) diff --git a/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql b/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql index 0be6347840..9ae62a7be0 100644 --- a/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql +++ b/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql @@ -30,12 +30,14 @@ where f1.getDeclaration() = f2.getDeclaration() and //return type check ( - not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, f2) and + not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, + f2) and case = "return type" and pluralDo = "does" or //parameter type check - not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, f2) and + not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, + f2) and case = "parameter types" and pluralDo = "do" or diff --git a/change_notes/2025-04-25-improve-type-comparison-performance.md b/change_notes/2025-04-25-improve-type-comparison-performance.md index 91a019bdf2..39c462fbf2 100644 --- a/change_notes/2025-04-25-improve-type-comparison-performance.md +++ b/change_notes/2025-04-25-improve-type-comparison-performance.md @@ -1,6 +1,6 @@ - `RULE-8-3`, `RULE-8-4`, `DCL40-C`, `RULE-23-5`: `DeclarationsOfAFunctionSameNameAndType.ql`, `DeclarationsOfAnObjectSameNameAndType.ql`, `CompatibleDeclarationOfFunctionDefined.ql`, `CompatibleDeclarationObjectDefined.ql`, `IncompatibleFunctionDeclarations.ql`, `DangerousDefaultSelectionForPointerInGeneric.ql`: - Added pragmas to alter join order on function parameter equivalence (names and types). - Refactored expression which the optimizer was confused by, and compiled into a cartesian product. - - Altered the module `Compatible.qll` to only perform expensive equality checks on types that are compared to a non identical other type, and those reachable from those types in the type graph. Types that are identical will trivially be considered equivalent. + - Altered the module `Compatible.qll` to compute equality in two stages. Firstly, all pairs of possible type comparisons (including recursive comparisons) are found, then those pairwise comparisons are evaluated in a second stage. This greatly reduces the number of comparisons and greatly improves performance. - `RULE-23-5`: `DangerousDefaultSelectionForPointerInGeneric.ql`: - Altered the module `SimpleAssignment.qll` in accordance with the changes to `Compatible.qll`. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll index da2b175a0d..c222cd77ba 100644 --- a/cpp/common/src/codingstandards/cpp/types/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -217,48 +217,61 @@ signature predicate interestedInEquality(Type a, Type b); * A module to check the equivalence of two types, as defined by the provided `TypeEquivalenceSig`. * * For performance reasons, this module is designed to be used with a predicate - * `interestedInEquality` that restricts the set of considered types. + * `interestedInEquality` that restricts the set of considered pairwise comparisons. * * To use this module, define a `TypeEquivalenceSig` module and implement a subset of `Type` that * selects the relevant root types to be considered. Then use the predicate `equalTypes(a, b)`. * Note that `equalTypes(a, b)` only holds if `interestedIn(a, b)` holds. A type is always * considered to be equal to itself, and this module does not support configurations that declare - * otherwise. + * otherwise. Additionally, `interestedIn(a, b)` implies `interestedIn(b, a)`. * - * Further, `interestedInEquality(a, a)` is treated differently from `interestedInEquality(a, b)`, - * assuming that `a` and `b` are not identical. This is so that we can construct a set of types - * that are not identical, but still may be equivalent by the specified configuration. We also must - * consider all types that are reachable from these types, as the equivalence relation is - * recursive. Therefore, this module is more performant when most comparisons are identical, and - * only a few are not. + * This module will recursively select pairs of types to be compared. For instance, if + * `interestedInEquality(a, b)` holds, then types `a` and `b` will be compared. If + * `Config::equalPointerTypes(a, b, true)` holds, then the pointed-to types of `a` and `b` will be + * compared. However, if `Config::equalPointerTypes(a, b, false)` holds, then `a` and `b` will be + * compared, but their pointed-to types will not. Similarly, inner types will not be compared if + * `Config::overrideTypeComparison(a, b, _)` holds. For detail, see the module predicates + * `recurses` and `compares`. */ module TypeEquivalence { - /** * Performance related predicate to force top down rather than bottom up evaluation of type * equivalence. + * + * This interoperates with the predicate `recurses` to find types that will be compared, along + * with the inner types of those types that will be compared. See `recurses` for cases where this + * algorithm will or will not recurse. We still need to know which types are compared, even if + * we do not recurse on them, in order to properly constrain `equalTypes(x, y)` to hold for types + * such as leaf types, where we do not recurse during comparison. + * + * At each stage of recursion, we specify `pragma[only_bind_into]` to ensure that the + * prior `recurses` results are considered first in the pipeline. */ predicate compares(Type t1, Type t2) { - interestedIn(t1, t2) + // Base case: config specifies that these root types will be compared. + interestedInUnordered(t1, t2) or + // If derived types are compared, their base types must be compared. exists(DerivedType t1Derived, DerivedType t2Derived | not t1Derived instanceof SpecifiedType and not t2Derived instanceof SpecifiedType and - compares(pragma[only_bind_into](t1Derived), pragma[only_bind_into](t2Derived)) and + recurses(pragma[only_bind_into](t1Derived), pragma[only_bind_into](t2Derived)) and t1 = t1Derived.getBaseType() and t2 = t2Derived.getBaseType() ) or + // If specified types are compared, their unspecified types must be compared. exists(SpecifiedType t1Spec, SpecifiedType t2Spec | - compares(pragma[only_bind_into](t1Spec), pragma[only_bind_into](t2Spec)) and + recurses(pragma[only_bind_into](t1Spec), pragma[only_bind_into](t2Spec)) and ( t1 = unspecify(t1Spec) and t2 = unspecify(t2Spec) ) ) or + // If function types are compared, their return types and parameter types must be compared. exists(FunctionType t1Func, FunctionType t2Func | - compares(pragma[only_bind_into](t1Func), pragma[only_bind_into](t2Func)) and + recurses(pragma[only_bind_into](t1Func), pragma[only_bind_into](t2Func)) and ( t1 = t1Func.getReturnType() and t2 = t2Func.getReturnType() @@ -270,13 +283,79 @@ module TypeEquivalence::equalTypes(f1.getType(), f2.getType()) } From 6c14eebefbe9c9b3a23f6d234417c82adbe7a7e5 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 28 Apr 2025 10:53:10 -0700 Subject: [PATCH 366/628] Remove redundant condition --- .../src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql | 1 - 1 file changed, 1 deletion(-) diff --git a/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql b/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql index 9ae62a7be0..fe0ae81ab1 100644 --- a/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql +++ b/c/misra/src/rules/RULE-8-3/DeclarationsOfAFunctionSameNameAndType.ql @@ -17,7 +17,6 @@ import codingstandards.c.misra import codingstandards.cpp.types.Compatible predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { - f1.getDeclaration() = f2.getDeclaration() and not f1 = f2 and f1.getDeclaration() = f2.getDeclaration() } From 4b8cdd339caa9329eac90143f8534406f1935a20 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Mon, 28 Apr 2025 18:47:07 -0700 Subject: [PATCH 367/628] Address next round of feedback --- .../CompatibleDeclarationFunctionDefined.ql | 5 +- .../codingstandards/cpp/types/Compatible.qll | 109 ++++++++++-------- 2 files changed, 67 insertions(+), 47 deletions(-) diff --git a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql index 2f17dd5086..9631b02839 100644 --- a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql +++ b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql @@ -22,8 +22,9 @@ import codingstandards.cpp.types.Compatible predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { f1.getDeclaration() instanceof ExternalIdentifiers and f1.isDefinition() and - f1.getName() = f2.getName() and f1.getDeclaration() = f2.getDeclaration() and + // This condition should always hold, but removing it affects join order performance. + f1.getName() = f2.getName() and not f2.isDefinition() and not f1.isFromTemplateInstantiation(_) and not f2.isFromTemplateInstantiation(_) @@ -51,10 +52,12 @@ where not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, f2) or + //not compatibleReturns(f1, f2) //parameter types differ not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, f2) or + //not compatibleParams(f1, f2) //parameter names differ parameterNamesUnmatched(f1, f2) ) diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll index c222cd77ba..ded3794658 100644 --- a/cpp/common/src/codingstandards/cpp/types/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -231,23 +231,31 @@ signature predicate interestedInEquality(Type a, Type b); * compared. However, if `Config::equalPointerTypes(a, b, false)` holds, then `a` and `b` will be * compared, but their pointed-to types will not. Similarly, inner types will not be compared if * `Config::overrideTypeComparison(a, b, _)` holds. For detail, see the module predicates - * `recurses` and `compares`. + * `shouldRecurseOn` and `interestedInNestedTypes`. */ module TypeEquivalence { /** - * Performance related predicate to force top down rather than bottom up evaluation of type - * equivalence. + * Performance-related predicate that holds for a pair of types `(a, b)` such that + * `interestedIn(a, b)` holds, or there exists a pair of types `(c, d)` such that + * `interestedIn(c, d)` holds, and computing `equalTypes(a, b)` requires computing + * `equalTypes(c, d)`. + * + * The goal of this predicate is to force top down rather than bottom up evaluation of type + * equivalence. That is to say, if we compare array types `int[]` and `int[]`, we to compare that + * both types are arrays first, and then compare that their base types are equal. Naively, CodeQL + * is liable to compute this kind of recursive equality in a bottom up fashion, where the cross + * product of all types is considered in computing `equalTypes(a, b)`. * - * This interoperates with the predicate `recurses` to find types that will be compared, along - * with the inner types of those types that will be compared. See `recurses` for cases where this - * algorithm will or will not recurse. We still need to know which types are compared, even if - * we do not recurse on them, in order to properly constrain `equalTypes(x, y)` to hold for types - * such as leaf types, where we do not recurse during comparison. + * This interoperates with the predicate `shouldRecurseOn` to find types that will be compared, + * along with the inner types of those types that will be compared. See `shouldRecurseOn` for + * cases where this algorithm will or will not recurse. We still need to know which types are + * compared, even if we do not recurse on them, in order to properly constrain `equalTypes(x, y)` + * to hold for types such as leaf types, where we do not recurse during comparison. * * At each stage of recursion, we specify `pragma[only_bind_into]` to ensure that the - * prior `recurses` results are considered first in the pipeline. + * prior `shouldRecurseOn` results are considered first in the pipeline. */ - predicate compares(Type t1, Type t2) { + private predicate interestedInNestedTypes(Type t1, Type t2) { // Base case: config specifies that these root types will be compared. interestedInUnordered(t1, t2) or @@ -255,14 +263,14 @@ module TypeEquivalence Date: Tue, 29 Apr 2025 09:09:58 -0700 Subject: [PATCH 368/628] Ensure Config::resolvesTypedefs() enforced, remove comments --- .../rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql | 2 -- cpp/common/src/codingstandards/cpp/types/Compatible.qll | 5 +++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql index 9631b02839..73abc1e048 100644 --- a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql +++ b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql @@ -52,12 +52,10 @@ where not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, f2) or - //not compatibleReturns(f1, f2) //parameter types differ not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, f2) or - //not compatibleParams(f1, f2) //parameter names differ parameterNamesUnmatched(f1, f2) ) diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll index ded3794658..c4ee9a22e3 100644 --- a/cpp/common/src/codingstandards/cpp/types/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -390,8 +390,6 @@ module TypeEquivalence Date: Wed, 30 Apr 2025 15:05:55 +0000 Subject: [PATCH 369/628] Bump version to 2.45.0-dev --- c/cert/src/qlpack.yml | 2 +- c/cert/test/qlpack.yml | 2 +- c/common/src/qlpack.yml | 2 +- c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- c/misra/test/qlpack.yml | 2 +- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/qlpack.yml | 2 +- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- docs/user_manual.md | 12 ++++++------ 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 631639301e..b79fbf3cbb 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.44.0-dev +version: 2.45.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index 6eaaba1e91..f7fe527dab 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.44.0-dev +version: 2.45.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 4c21dc9b18..ad3f825a4b 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.44.0-dev +version: 2.45.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index 1dbb59b4fd..cbadd7f238 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.44.0-dev +version: 2.45.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 54cda2c1cc..b5d16e9974 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.44.0-dev +version: 2.45.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index 9148e26b59..e6932cc894 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.44.0-dev +version: 2.45.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index 6d31398b2c..b9cd9b72a8 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.44.0-dev +version: 2.45.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index ff7621c9d1..0b92541fdf 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.44.0-dev +version: 2.45.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index f44646cdbe..a3b60a7e07 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.44.0-dev +version: 2.45.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index c6d57b0d33..1baf2b3fc3 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.44.0-dev +version: 2.45.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index 302955fc78..47a116582c 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards -version: 2.44.0-dev +version: 2.45.0-dev license: MIT dependencies: codeql/cpp-all: 2.1.1 diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index 1f0b830de8..a636b824dc 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.44.0-dev +version: 2.45.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 27e0893ed6..a98ccfa757 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.44.0-dev +version: 2.45.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index cdf6cbcdea..aad59493fe 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.44.0-dev +version: 2.45.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index 83188c2748..731d68dd29 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.44.0-dev +version: 2.45.0-dev license: MIT dependencies: codeql/cpp-all: 2.1.1 diff --git a/docs/user_manual.md b/docs/user_manual.md index 1e14744f80..2920e024a6 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -35,14 +35,14 @@ ## Release information -This user manual documents release `2.44.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.45.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: - `coding-standards-codeql-packs-2.37.0-dev.zip`: CodeQL packs that can be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `code-scanning-cpp-query-pack-2.44.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.44.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.44.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.44.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.45.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.45.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.45.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.45.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -667,7 +667,7 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.44.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.45.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | From a1f45ff00ee89988bd1ad0121a2ad7ceed2ece1f Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 1 May 2025 23:39:39 +0100 Subject: [PATCH 370/628] Add a script to lift CERT risk assessment tags from help files --- scripts/add_risk_assessment_tags.py | 160 ++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 scripts/add_risk_assessment_tags.py diff --git a/scripts/add_risk_assessment_tags.py b/scripts/add_risk_assessment_tags.py new file mode 100644 index 0000000000..f2ed9a5a73 --- /dev/null +++ b/scripts/add_risk_assessment_tags.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python3 +""" +Add risk assessment tags to rule package JSON files. + +This script: +1. Iterates through each JSON file in rule_packages directory +2. Looks for CERT-C or CERT-CPP sections +3. For each rule, finds the corresponding markdown file +4. Extracts risk assessment data from the markdown file +5. Adds risk assessment data as tags to each query in the JSON file +""" + +import os +import json +import re +import glob +from bs4 import BeautifulSoup +import logging + +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logger = logging.getLogger(__name__) + +def find_rule_packages(): + """Find all JSON rule package files in the rule_packages directory.""" + repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + rule_packages_dir = os.path.join(repo_root, "rule_packages") + return glob.glob(os.path.join(rule_packages_dir, "**", "*.json"), recursive=True) + +def extract_risk_assessment_from_md(md_file_path): + """Extract risk assessment data from the markdown file.""" + risk_data = {} + + try: + with open(md_file_path, 'r', encoding='utf-8') as f: + content = f.read() + + # Find the Risk Assessment section + risk_section_match = re.search(r'## Risk Assessment(.*?)##', content, re.DOTALL) + if not risk_section_match: + # Try to find it as the last section + risk_section_match = re.search(r'## Risk Assessment(.*?)$', content, re.DOTALL) + if not risk_section_match: + logger.warning(f"No Risk Assessment section found in {md_file_path}") + return risk_data + + risk_section = risk_section_match.group(1) + + # Look for the table with risk assessment data + table_match = re.search(r'(.*?)
    ', risk_section, re.DOTALL) + if not table_match: + logger.warning(f"No risk assessment table found in {md_file_path}") + return risk_data + + table_html = table_match.group(0) + soup = BeautifulSoup(table_html, 'html.parser') + + # Find all rows in the table + rows = soup.find_all('tr') + if len(rows) < 2: # Need at least header and data row + logger.warning(f"Incomplete risk assessment table in {md_file_path}") + return risk_data + + # Extract headers and values + headers = [th.get_text().strip() for th in rows[0].find_all('th')] + values = [td.get_text().strip() for td in rows[1].find_all('td')] + + # Create a dictionary of headers and values + if len(headers) == len(values): + for i, header in enumerate(headers): + risk_data[header] = values[i] + else: + logger.warning(f"Header and value count mismatch in {md_file_path}") + + except Exception as e: + logger.error(f"Error extracting risk assessment from {md_file_path}: {e}") + + return risk_data + +def find_md_file(rule_id, short_name, language): + """Find the markdown file for the given rule ID and short name.""" + repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + md_path = os.path.join(repo_root, language, "cert", "src", "rules", rule_id, f"{short_name}.md") + + if os.path.exists(md_path): + return md_path + else: + # Try without short name (sometimes the file is named after the rule ID) + md_path = os.path.join(repo_root, language, "cert", "src", "rules", rule_id, f"{rule_id}.md") + if os.path.exists(md_path): + return md_path + else: + logger.warning(f"Could not find markdown file for {language} rule {rule_id} ({short_name})") + return None + +def process_rule_package(rule_package_file): + """Process a single rule package JSON file.""" + try: + with open(rule_package_file, 'r', encoding='utf-8') as f: + data = json.load(f) + + modified = False + + # Look for CERT-C and CERT-CPP sections + for cert_key in ["CERT-C", "CERT-C++"]: + if cert_key in data: + language = "c" if cert_key == "CERT-C" else "cpp" + + # Process each rule in the CERT section + for rule_id, rule_data in data[cert_key].items(): + if "queries" in rule_data: + for query in rule_data["queries"]: + if "short_name" in query: + md_file = find_md_file(rule_id, query["short_name"], language) + + if md_file: + risk_data = extract_risk_assessment_from_md(md_file) + + if risk_data: + # Add risk assessment data as tags + if "tags" not in query: + query["tags"] = [] + + # Add each risk assessment property as a tag + for key, value in risk_data.items(): + key_sanitized = key.lower().replace(" ", "-") + if key_sanitized == "rule": + # skip rule, as that is already in the rule ID + continue + tag = f"external/cert/{key_sanitized}/{value.lower()}" + if tag not in query["tags"]: + query["tags"].append(tag) + modified = True + logger.info(f"Added tag {tag} to {rule_id} ({query['short_name']})") + + # Save the modified data back to the file if any changes were made + if modified: + with open(rule_package_file, 'w', encoding='utf-8') as f: + json.dump(data, f, indent=2) + logger.info(f"Updated {rule_package_file}") + else: + logger.info(f"No changes made to {rule_package_file}") + + except Exception as e: + logger.error(f"Error processing {rule_package_file}: {e}") + +def main(): + """Main function to process all rule packages.""" + logger.info("Starting risk assessment tag addition process") + + rule_packages = find_rule_packages() + logger.info(f"Found {len(rule_packages)} rule package files") + + for rule_package in rule_packages: + logger.info(f"Processing {rule_package}") + process_rule_package(rule_package) + + logger.info("Completed risk assessment tag addition process") + +if __name__ == "__main__": + main() \ No newline at end of file From 242744c7e2f68f5af63feab8af20a6a2d1d14140 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 1 May 2025 23:41:37 +0100 Subject: [PATCH 371/628] Add additional CERT risk assessment tags --- rule_packages/c/Banned.json | 7 ++- rule_packages/c/Concurrency1.json | 21 ++++++- rule_packages/c/Concurrency2.json | 14 ++++- rule_packages/c/Concurrency3.json | 28 +++++++-- rule_packages/c/Concurrency4.json | 23 ++++++- rule_packages/c/Concurrency5.json | 14 ++++- rule_packages/c/Contracts.json | 7 ++- rule_packages/c/Contracts1.json | 14 ++++- rule_packages/c/Contracts2.json | 21 ++++++- rule_packages/c/Contracts4.json | 28 +++++++-- rule_packages/c/Contracts5.json | 14 ++++- rule_packages/c/Contracts6.json | 7 ++- rule_packages/c/Contracts7.json | 14 ++++- rule_packages/c/Declarations1.json | 14 ++++- rule_packages/c/Declarations2.json | 35 +++++++++-- rule_packages/c/Declarations7.json | 7 ++- rule_packages/c/Declarations8.json | 14 ++++- rule_packages/c/Expressions.json | 28 +++++++-- rule_packages/c/FloatingTypes.json | 28 +++++++-- rule_packages/c/IO1.json | 42 +++++++++++-- rule_packages/c/IO2.json | 28 +++++++-- rule_packages/c/IO3.json | 14 ++++- rule_packages/c/IO4.json | 28 +++++++-- rule_packages/c/IntegerOverflow.json | 35 +++++++++-- rule_packages/c/InvalidMemory1.json | 21 ++++++- rule_packages/c/InvalidMemory2.json | 21 ++++++- rule_packages/c/Memory2.json | 57 ++++++++++++++--- rule_packages/c/Memory3.json | 7 ++- rule_packages/c/Misc.json | 21 ++++++- rule_packages/c/OutOfBounds.json | 14 ++++- rule_packages/c/Pointers2.json | 7 ++- rule_packages/c/Pointers3.json | 36 +++++++++-- rule_packages/c/Preprocessor5.json | 14 ++++- rule_packages/c/SideEffects1.json | 29 +++++++-- rule_packages/c/SideEffects4.json | 7 ++- rule_packages/c/SignalHandlers.json | 28 +++++++-- rule_packages/c/Statements4.json | 7 ++- rule_packages/c/Strings1.json | 21 ++++++- rule_packages/c/Strings2.json | 7 ++- rule_packages/c/Strings3.json | 14 ++++- rule_packages/c/Types1.json | 16 ++++- rule_packages/cpp/Allocations.json | 77 +++++++++++++++++++---- rule_packages/cpp/BannedFunctions.json | 21 ++++++- rule_packages/cpp/BannedSyntax.json | 7 ++- rule_packages/cpp/Classes.json | 7 ++- rule_packages/cpp/Concurrency.json | 63 ++++++++++++++++--- rule_packages/cpp/Const.json | 7 ++- rule_packages/cpp/ExceptionSafety.json | 14 ++++- rule_packages/cpp/Exceptions1.json | 77 +++++++++++++++++++---- rule_packages/cpp/Exceptions2.json | 14 ++++- rule_packages/cpp/Expressions.json | 23 +++++-- rule_packages/cpp/Freed.json | 28 +++++++-- rule_packages/cpp/Functions.json | 21 ++++++- rule_packages/cpp/IO.json | 14 ++++- rule_packages/cpp/Inheritance.json | 24 ++++++- rule_packages/cpp/Initialization.json | 21 ++++++- rule_packages/cpp/Invariants.json | 28 +++++++-- rule_packages/cpp/Iterators.json | 35 +++++++++-- rule_packages/cpp/Lambdas.json | 14 ++++- rule_packages/cpp/MoveForward.json | 7 ++- rule_packages/cpp/Naming.json | 56 ++++++++++++++--- rule_packages/cpp/Null.json | 7 ++- rule_packages/cpp/OperatorInvariants.json | 14 ++++- rule_packages/cpp/OutOfBounds.json | 21 ++++++- rule_packages/cpp/Pointers.json | 42 +++++++++++-- rule_packages/cpp/Representation.json | 21 ++++++- rule_packages/cpp/Scope.json | 42 +++++++++++-- rule_packages/cpp/SideEffects1.json | 49 ++++++++++++--- rule_packages/cpp/SideEffects2.json | 7 ++- rule_packages/cpp/SmartPointers2.json | 15 ++++- rule_packages/cpp/Strings.json | 16 ++++- rule_packages/cpp/TrustBoundaries.json | 14 ++++- rule_packages/cpp/TypeRanges.json | 14 ++++- rule_packages/cpp/Uninitialized.json | 14 ++++- 74 files changed, 1411 insertions(+), 235 deletions(-) diff --git a/rule_packages/c/Banned.json b/rule_packages/c/Banned.json index 4decbae6f2..265a41de51 100644 --- a/rule_packages/c/Banned.json +++ b/rule_packages/c/Banned.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "DoNotCallSystem", "tags": [ - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ] } ], diff --git a/rule_packages/c/Concurrency1.json b/rule_packages/c/Concurrency1.json index 15e38e941d..9daa2a83be 100644 --- a/rule_packages/c/Concurrency1.json +++ b/rule_packages/c/Concurrency1.json @@ -15,7 +15,12 @@ "shared_implementation_short_name": "GuardAccessToBitFields", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -35,7 +40,12 @@ "short_name": "RaceConditionsWhenUsingLibraryFunctions", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -55,7 +65,12 @@ "short_name": "DoNotCallSignalInMultithreadedProgram", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/low", + "external/cert/priority/p6", + "external/cert/level/l2" ], "implementation_scope": { "description": "This implementation does not consider threads created function pointers." diff --git a/rule_packages/c/Concurrency2.json b/rule_packages/c/Concurrency2.json index d9102a07df..d9e364d046 100644 --- a/rule_packages/c/Concurrency2.json +++ b/rule_packages/c/Concurrency2.json @@ -15,7 +15,12 @@ "shared_implementation_short_name": "PreventDeadlockByLockingInPredefinedOrder", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -36,7 +41,12 @@ "shared_implementation_short_name": "WrapSpuriousFunctionInLoop", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/Concurrency3.json b/rule_packages/c/Concurrency3.json index a57b73f034..6328f6b43c 100644 --- a/rule_packages/c/Concurrency3.json +++ b/rule_packages/c/Concurrency3.json @@ -15,7 +15,12 @@ "shared_implementation_short_name": "DoNotAllowAMutexToGoOutOfScopeWhileLocked", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "This implementation does not allow for thread synchronization to be performed in subroutines. All synchronization must be performed within the context of the other thread management functions." @@ -31,7 +36,12 @@ "shared_implementation_short_name": "DoNotDestroyAMutexWhileItIsLocked", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -52,7 +62,12 @@ "shared_implementation_short_name": "PreserveSafetyWhenUsingConditionVariables", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ], "implementation_scope": { "description": "This implementation does not attempt to identify unique condition variables and instead advocates for the usage of `cnd_broadcast`." @@ -75,7 +90,12 @@ "short_name": "WrapFunctionsThatCanFailSpuriouslyInLoop", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ], "implementation_scope": { "description": "This implementation does not attempt to identify a relationship between the condition variable and the atomic operation." diff --git a/rule_packages/c/Concurrency4.json b/rule_packages/c/Concurrency4.json index d537ee713e..45f4b495fc 100644 --- a/rule_packages/c/Concurrency4.json +++ b/rule_packages/c/Concurrency4.json @@ -14,7 +14,12 @@ "short_name": "CleanUpThreadSpecificStorage", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "This query does not attempt to ensure that the deallocation function in fact deallocates memory and instead assumes the contract is valid. Additionally, this query requires that all `tss_create` calls are bookended by calls to `tss_delete`, even if a thread is not created." @@ -37,7 +42,13 @@ "short_name": "AppropriateThreadObjectStorageDurations", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/recommendation/con34-c", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "This query does not consider Windows implementations or OpenMP implementations. This query is primarily about excluding cases wherein the storage duration of a variable is appropriate. As such, this query is not concerned if the appropriate synchronization mechanisms are used, such as sequencing calls to `thrd_join` and `free`. An audit query is supplied to handle some of those cases." @@ -53,7 +64,13 @@ "tags": [ "external/cert/audit", "correctness", - "concurrency" + "concurrency", + "external/cert/recommendation/con34-c", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/Concurrency5.json b/rule_packages/c/Concurrency5.json index 0cef2d8b3a..d1a685dd34 100644 --- a/rule_packages/c/Concurrency5.json +++ b/rule_packages/c/Concurrency5.json @@ -15,7 +15,12 @@ "shared_implementation_short_name": "JoinOrDetachThreadOnlyOnce", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ], "implementation_scope": { "description": "This query considers problematic usages of join and detach irrespective of the execution of the program and other synchronization and interprocess communication mechanisms that may be used." @@ -38,7 +43,12 @@ "short_name": "AtomicVariableTwiceInExpression", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/c/Contracts.json b/rule_packages/c/Contracts.json index e7db6fff86..0d2e0a97bd 100644 --- a/rule_packages/c/Contracts.json +++ b/rule_packages/c/Contracts.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "DoNotViolateInLineLinkageConstraints", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ], "implementation_scope": { "description": "This query only considers the constraints related to inline extern functions." diff --git a/rule_packages/c/Contracts1.json b/rule_packages/c/Contracts1.json index 21641922af..65ffdc5e71 100644 --- a/rule_packages/c/Contracts1.json +++ b/rule_packages/c/Contracts1.json @@ -14,7 +14,12 @@ "short_name": "DoNotModifyTheReturnValueOfCertainFunctions", "shared_implementation_short_name": "ConstLikeReturnValue", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -33,7 +38,12 @@ "severity": "error", "short_name": "EnvPointerIsInvalidAfterCertainOperations", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." diff --git a/rule_packages/c/Contracts2.json b/rule_packages/c/Contracts2.json index b07f8f0503..6c1bf77de2 100644 --- a/rule_packages/c/Contracts2.json +++ b/rule_packages/c/Contracts2.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "ExitHandlersMustReturnNormally", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ] } ], @@ -33,7 +38,12 @@ "short_name": "DoNotStorePointersReturnedByEnvFunctions", "shared_implementation_short_name": "InvalidatedEnvStringPointers", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -45,7 +55,12 @@ "short_name": "DoNotStorePointersReturnedByEnvironmentFunWarn", "shared_implementation_short_name": "InvalidatedEnvStringPointersWarn", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/Contracts4.json b/rule_packages/c/Contracts4.json index 8ba25ab32b..a62e9d1762 100644 --- a/rule_packages/c/Contracts4.json +++ b/rule_packages/c/Contracts4.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "SetlocaleMightSetErrno", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] }, { @@ -24,7 +29,12 @@ "severity": "error", "short_name": "ErrnoReadBeforeReturn", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] }, { @@ -35,7 +45,12 @@ "severity": "error", "short_name": "FunctionCallBeforeErrnoCheck", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] }, { @@ -46,7 +61,12 @@ "severity": "error", "short_name": "ErrnoNotSetToZero", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/c/Contracts5.json b/rule_packages/c/Contracts5.json index 9f62ce9255..d4b38b5756 100644 --- a/rule_packages/c/Contracts5.json +++ b/rule_packages/c/Contracts5.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "DoNotRelyOnIndeterminateValuesOfErrno", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." @@ -35,7 +40,12 @@ "severity": "error", "short_name": "DetectAndHandleStandardLibraryErrors", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." diff --git a/rule_packages/c/Contracts6.json b/rule_packages/c/Contracts6.json index c46ef2f710..d89617d6dc 100644 --- a/rule_packages/c/Contracts6.json +++ b/rule_packages/c/Contracts6.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "DoNotModifyConstantObjects", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ], "implementation_scope": { "description": "The implementation does not consider pointer aliasing via multiple indirection." diff --git a/rule_packages/c/Contracts7.json b/rule_packages/c/Contracts7.json index f76b737db1..95df01ca32 100644 --- a/rule_packages/c/Contracts7.json +++ b/rule_packages/c/Contracts7.json @@ -14,7 +14,12 @@ "short_name": "DoNotPassInvalidDataToTheAsctimeFunction", "tags": [ "security", - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p27", + "external/cert/level/l1" ] } ], @@ -33,7 +38,12 @@ "severity": "error", "short_name": "DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/Declarations1.json b/rule_packages/c/Declarations1.json index 90202a5b52..dba6a07eeb 100644 --- a/rule_packages/c/Declarations1.json +++ b/rule_packages/c/Declarations1.json @@ -15,7 +15,12 @@ "shared_implementation_short_name": "TypeOmitted", "tags": [ "correctness", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ], "implementation_scope": { "description": "This query does not check for implicitly typed parameters, typedefs or member declarations as this is partially compiler checked.", @@ -41,7 +46,12 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ], "implementation_scope": { "description": "This query does not consider identifiers described in the future library directions section of the standard. This query also checks for any reserved identifier as declared regardless of whether its header file is included or not.", diff --git a/rule_packages/c/Declarations2.json b/rule_packages/c/Declarations2.json index 9acb117d1e..c5b827e682 100644 --- a/rule_packages/c/Declarations2.json +++ b/rule_packages/c/Declarations2.json @@ -15,7 +15,12 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], @@ -37,7 +42,12 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ], "implementation_scope": { "description": "This query considers the first 31 characters of identifiers as significant, as per C99 and reports the case when names are longer than 31 characters and differ in those characters past the 31 first only. This query does not consider universal or extended source characters.", @@ -54,7 +64,12 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] }, { @@ -67,7 +82,12 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -88,7 +108,12 @@ "tags": [ "correctness", "maintainability", - "readability" + "readability", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/Declarations7.json b/rule_packages/c/Declarations7.json index cdb74123b1..86818cdcb5 100644 --- a/rule_packages/c/Declarations7.json +++ b/rule_packages/c/Declarations7.json @@ -14,7 +14,12 @@ "short_name": "InformationLeakageAcrossTrustBoundariesC", "shared_implementation_short_name": "InformationLeakageAcrossBoundaries", "tags": [ - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/high", + "external/cert/priority/p1", + "external/cert/level/l3" ], "implementation_scope": { "description": "The rule does not detect cases where fields may have uninitialized padding but are initialized via an initializer." diff --git a/rule_packages/c/Declarations8.json b/rule_packages/c/Declarations8.json index a70523b72f..6275e32595 100644 --- a/rule_packages/c/Declarations8.json +++ b/rule_packages/c/Declarations8.json @@ -14,7 +14,12 @@ "short_name": "AppropriateStorageDurationsStackAdressEscape", "shared_implementation_short_name": "DoNotCopyAddressOfAutoStorageObjectToOtherObject", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ], "implementation_scope": { "description": "The rule checks specifically for pointers to objects with automatic storage duration that are assigned to static storage duration variables." @@ -28,7 +33,12 @@ "severity": "error", "short_name": "AppropriateStorageDurationsFunctionReturn", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ], "implementation_scope": { "description": "The rule checks specifically for pointers to objects with automatic storage duration that are returned by functions or assigned to function output parameters." diff --git a/rule_packages/c/Expressions.json b/rule_packages/c/Expressions.json index 9d1f8b16a7..9be722b761 100644 --- a/rule_packages/c/Expressions.json +++ b/rule_packages/c/Expressions.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "DoNotCallFunctionPointerWithIncompatibleType", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "This query raises a result for a function assigned to a function pointer of an incompatible type even if the function pointer is never eventually called." @@ -27,7 +32,12 @@ "severity": "error", "short_name": "DoNotCallFunctionsWithIncompatibleArguments", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -39,7 +49,12 @@ "short_name": "CallPOSIXOpenWithCorrectArgumentCount", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "The analysis of invalid parameter count passed to POSIX open calls only applies when the value of the flags argument is computed locally." @@ -62,7 +77,12 @@ "short_name": "DoNotUseABitwiseOperatorWithABooleanLikeOperand", "tags": [ "maintainability", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/c/FloatingTypes.json b/rule_packages/c/FloatingTypes.json index 7df2298ad1..17690574e5 100644 --- a/rule_packages/c/FloatingTypes.json +++ b/rule_packages/c/FloatingTypes.json @@ -14,7 +14,12 @@ "short_name": "UncheckedRangeDomainPoleErrors", "shared_implementation_short_name": "UncheckedRangeDomainPoleErrors", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ], "implementation_scope": { "description": "This query identifies possible domain, pole and range errors on a selection of C standard library fuctions from math.h." @@ -36,7 +41,12 @@ "severity": "error", "short_name": "UncheckedFloatingPointConversion", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], @@ -55,7 +65,12 @@ "severity": "error", "short_name": "IntToFloatPreservePrecision", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -74,7 +89,12 @@ "severity": "error", "short_name": "MemcmpUsedToCompareFloats", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/IO1.json b/rule_packages/c/IO1.json index f5b9ec8b0e..8a42c4e52a 100644 --- a/rule_packages/c/IO1.json +++ b/rule_packages/c/IO1.json @@ -15,7 +15,12 @@ "shared_implementation_short_name": "NonConstantFormat", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -35,7 +40,12 @@ "short_name": "DistinguishBetweenCharReadFromAFileAndEofOrWeof", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function. The query does not validate if the FILE status is handled correctly after being read." @@ -50,7 +60,12 @@ "short_name": "EndOfFileCheckPortability", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function. The query does not validate if the FILE status is handled correctly after being read." @@ -73,7 +88,12 @@ "short_name": "DoNotAlternatelyIOFromAStreamWithoutPositioning", "shared_implementation_short_name": "IOFstreamMissingPositioning", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." @@ -97,7 +117,12 @@ "shared_implementation_short_name": "CloseFileHandleWhenNoLongerNeededShared", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." @@ -120,7 +145,12 @@ "short_name": "UndefinedBehaviorAccessingAClosedFile", "shared_implementation_short_name": "DoNotAccessAClosedFile", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." diff --git a/rule_packages/c/IO2.json b/rule_packages/c/IO2.json index 41c14a0d0e..69c12d7723 100644 --- a/rule_packages/c/IO2.json +++ b/rule_packages/c/IO2.json @@ -14,7 +14,12 @@ "short_name": "DoNotCopyAFileObject", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -34,7 +39,12 @@ "short_name": "ResetStringsOnFgetsOrFgetwsFailure", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -53,7 +63,12 @@ "severity": "error", "short_name": "DoNotCallGetcAndPutcWithSideEffects", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -72,7 +87,12 @@ "severity": "error", "short_name": "OnlyUseValuesForFsetposThatAreReturnedFromFgetpos", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/IO3.json b/rule_packages/c/IO3.json index 52276eb05c..af6e9da732 100644 --- a/rule_packages/c/IO3.json +++ b/rule_packages/c/IO3.json @@ -14,7 +14,12 @@ "short_name": "DoNotPerformFileOperationsOnDevices", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "The rule checks that filenames are not tainted. It does not verify that appropriate OS-specific checks are in place to exclude that the opened file is a device." @@ -36,7 +41,12 @@ "severity": "error", "short_name": "SuccessfulFgetsOrFgetwsMayReturnAnEmptyString", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ], "implementation_scope": { "description": "The rule checks that access to a string returned by fgets() or fgetws() if protected by a guard condition. The rule is enforced in the context of a single function." diff --git a/rule_packages/c/IO4.json b/rule_packages/c/IO4.json index 1303f9b50f..8d9c150335 100644 --- a/rule_packages/c/IO4.json +++ b/rule_packages/c/IO4.json @@ -14,7 +14,12 @@ "short_name": "ToctouRaceConditionsWhileAccessingFiles", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ], "implementation_scope": { "description": "The query is limited to the specific class of TOCTOU race conditions that derives from the incorrectuse of `fopen` to check the existence of a file." @@ -37,7 +42,12 @@ "short_name": "UseValidSpecifiers", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -49,7 +59,12 @@ "short_name": "WrongNumberOfFormatArguments", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -61,7 +76,12 @@ "short_name": "WrongTypeFormatArguments", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/c/IntegerOverflow.json b/rule_packages/c/IntegerOverflow.json index a7897fad9e..f528d3d542 100644 --- a/rule_packages/c/IntegerOverflow.json +++ b/rule_packages/c/IntegerOverflow.json @@ -15,7 +15,12 @@ "shared_implementation_short_name": "UnsignedOperationWithConstantOperandsWraps", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -34,7 +39,12 @@ "severity": "error", "short_name": "IntegerConversionCausesDataLoss", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -54,7 +64,12 @@ "short_name": "SignedIntegerOverflow", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -73,7 +88,12 @@ "severity": "error", "short_name": "DivOrRemByZero", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -92,7 +112,12 @@ "severity": "error", "short_name": "UseCorrectIntegerPrecisions", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/InvalidMemory1.json b/rule_packages/c/InvalidMemory1.json index 227ec37558..3b0a6bb40c 100644 --- a/rule_packages/c/InvalidMemory1.json +++ b/rule_packages/c/InvalidMemory1.json @@ -15,7 +15,12 @@ "short_name": "DoNotReadUninitializedMemory", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ] } ], @@ -35,7 +40,12 @@ "shared_implementation_short_name": "DereferenceOfNullPointer", "short_name": "DoNotDereferenceNullPointers", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -55,7 +65,12 @@ "short_name": "DoNotAccessFreedMemory", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], diff --git a/rule_packages/c/InvalidMemory2.json b/rule_packages/c/InvalidMemory2.json index cb7d380159..025a5d246c 100644 --- a/rule_packages/c/InvalidMemory2.json +++ b/rule_packages/c/InvalidMemory2.json @@ -14,7 +14,12 @@ "short_name": "VariableLengthArraySizeNotInValidRange", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -33,7 +38,12 @@ "severity": "error", "short_name": "DoNotUsePointerArithmeticOnNonArrayObjectPointers", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -52,7 +62,12 @@ "severity": "error", "short_name": "DoNotModifyObjectsWithTemporaryLifetime", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ], "implementation_scope": { "description": "This implementation also always reports non-modifying accesses of objects with temporary lifetime, which are only compliant in C11." diff --git a/rule_packages/c/Memory2.json b/rule_packages/c/Memory2.json index 358d482194..9f475e4df8 100644 --- a/rule_packages/c/Memory2.json +++ b/rule_packages/c/Memory2.json @@ -14,7 +14,12 @@ "short_name": "DoNotSubtractPointersThatDoNotReferToTheSameArray", "shared_implementation_short_name": "DoNotSubtractPointersAddressingDifferentArrays", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] }, { @@ -26,7 +31,12 @@ "short_name": "DoNotRelatePointersThatDoNotReferToTheSameArray", "shared_implementation_short_name": "DoNotUseRelationalOperatorsWithDifferingArrays", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -46,7 +56,12 @@ "short_name": "DoNotComparePaddingData", "shared_implementation_short_name": "MemcmpUsedToComparePaddingData", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -67,7 +82,12 @@ "shared_implementation_short_name": "FreeMemoryWhenNoLongerNeededShared", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ], "implementation_scope": { "description": "The rule is enforced in the context of a single function." @@ -89,7 +109,12 @@ "severity": "error", "short_name": "AllocStructsWithAFlexibleArrayMemberDynamically", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -100,7 +125,12 @@ "severity": "error", "short_name": "CopyStructsWithAFlexibleArrayMemberDynamically", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], @@ -121,7 +151,12 @@ "shared_implementation_short_name": "OnlyFreeMemoryAllocatedDynamicallyShared", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -141,7 +176,13 @@ "short_name": "DoNotModifyAlignmentOfMemoryWithRealloc", "tags": [ "correctness", - "security" + "security", + "external/cert/recommendation/mem36-c", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/Memory3.json b/rule_packages/c/Memory3.json index 6eafcc6509..e1ed7382e0 100644 --- a/rule_packages/c/Memory3.json +++ b/rule_packages/c/Memory3.json @@ -14,7 +14,12 @@ "short_name": "InsufficientMemoryAllocatedForObject", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/c/Misc.json b/rule_packages/c/Misc.json index bba96db85c..183c05988b 100644 --- a/rule_packages/c/Misc.json +++ b/rule_packages/c/Misc.json @@ -14,7 +14,12 @@ "short_name": "RandUsedForGeneratingPseudorandomNumbers", "shared_implementation_short_name": "DoNotUseRandForGeneratingPseudorandomNumbers", "tags": [ - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -33,7 +38,12 @@ "severity": "error", "short_name": "ProperlySeedPseudorandomNumberGenerators", "tags": [ - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p18", + "external/cert/level/l1" ], "implementation_scope": { "description": "This rule will be checked by looking for calls to random that are no preceded by a call to srandom(). We perform a simple check for the argument to srandom() and verify it is not a literal (or a value easily deduced to be a literal)." @@ -56,7 +66,12 @@ "short_name": "ControlFlowReachesTheEndOfANonVoidFunction", "shared_implementation_short_name": "NonVoidFunctionDoesNotReturn", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/c/OutOfBounds.json b/rule_packages/c/OutOfBounds.json index 759b68e294..3354348230 100644 --- a/rule_packages/c/OutOfBounds.json +++ b/rule_packages/c/OutOfBounds.json @@ -14,7 +14,12 @@ "short_name": "DoNotFormOutOfBoundsPointersOrArraySubscripts", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -34,7 +39,12 @@ "short_name": "LibraryFunctionArgumentOutOfBounds", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], diff --git a/rule_packages/c/Pointers2.json b/rule_packages/c/Pointers2.json index 9abf4c98ce..fcfd9356e6 100644 --- a/rule_packages/c/Pointers2.json +++ b/rule_packages/c/Pointers2.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "DoNotAddOrSubtractAScaledIntegerToAPointer", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/c/Pointers3.json b/rule_packages/c/Pointers3.json index f35f5b7bd1..f00018b1ad 100644 --- a/rule_packages/c/Pointers3.json +++ b/rule_packages/c/Pointers3.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "DoNotAccessVolatileObjectWithNonVolatileReference", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ], "implementation_scope": { "description": "In limited cases, this query can raise false-positives for assignment of volatile objects and subsequent accesses of those objects via non-volatile pointers." @@ -35,7 +40,12 @@ "severity": "error", "short_name": "DoNotCastPointerToMoreStrictlyAlignedPointerType", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -54,7 +64,13 @@ "severity": "error", "short_name": "DoNotAccessVariableViaPointerOfIncompatibleType", "tags": [ - "correctness" + "correctness", + "external/cert/recommendation/exp39-c", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -74,7 +90,12 @@ "short_name": "DoNotPassAliasedPointerToRestrictQualifiedParam", "shared_implementation_short_name": "DoNotPassAliasedPointerToRestrictQualifiedParamShared", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -85,7 +106,12 @@ "severity": "error", "short_name": "RestrictPointerReferencesOverlappingObject", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/Preprocessor5.json b/rule_packages/c/Preprocessor5.json index ef17b83c00..60a1752e73 100644 --- a/rule_packages/c/Preprocessor5.json +++ b/rule_packages/c/Preprocessor5.json @@ -14,7 +14,12 @@ "short_name": "DoNotTreatAPredefinedIdentifierAsObject", "tags": [ "correctness", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ], "implementation_scope": { "description": "This query reports locations corresponding to both redefinitions of those standard library macros as well as locations where the identifiers used for accesses.", @@ -38,7 +43,12 @@ "short_name": "MacroOrFunctionArgsContainHashToken", "tags": [ "correctness", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ], "implementation_scope": { "description": "This query defines end of function call as the next node in the control flow graph.", diff --git a/rule_packages/c/SideEffects1.json b/rule_packages/c/SideEffects1.json index 9d91fce671..7e0ab9c90b 100644 --- a/rule_packages/c/SideEffects1.json +++ b/rule_packages/c/SideEffects1.json @@ -13,7 +13,12 @@ "severity": "warning", "short_name": "DependenceOnOrderOfScalarEvaluationForSideEffects", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] }, { @@ -24,7 +29,12 @@ "severity": "warning", "short_name": "DependenceOnOrderOfFunctionArgumentsForSideEffects", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -43,7 +53,12 @@ "severity": "error", "short_name": "UnevaluatedOperandWithSideEffect", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], @@ -62,7 +77,13 @@ "severity": "error", "short_name": "AssignmentsInSelectionStatements", "tags": [ - "correctness" + "correctness", + "external/cert/recommendation/exp45-c", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/c/SideEffects4.json b/rule_packages/c/SideEffects4.json index 77121019de..5b0c6da3f5 100644 --- a/rule_packages/c/SideEffects4.json +++ b/rule_packages/c/SideEffects4.json @@ -13,7 +13,12 @@ "severity": "error", "short_name": "SideEffectsInArgumentsToUnsafeMacros", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ], "implementation_scope": { "description": "This implementation only considers ++ and function call side effects. Due to the textual nature of macro expansion it is not always possible to determine accurately whether a side-effect was produced by a particular argument, and this may cause both false positives and false negatives. The query does not consider the case where a macro argument including a side-effect is never evaluated." diff --git a/rule_packages/c/SignalHandlers.json b/rule_packages/c/SignalHandlers.json index 0ceaa5914d..ae9045a64d 100644 --- a/rule_packages/c/SignalHandlers.json +++ b/rule_packages/c/SignalHandlers.json @@ -14,7 +14,12 @@ "short_name": "CallOnlyAsyncSafeFunctionsWithinSignalHandlers", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -34,7 +39,12 @@ "short_name": "DoNotAccessSharedObjectsInSignalHandlers", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p9", + "external/cert/level/l2" ], "implementation_scope": { "description": "The implementation does not verify the correct usage of `atomic_is_lock_free`." @@ -57,7 +67,12 @@ "short_name": "DoNotCallSignalFromInterruptibleSignalHandlers", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], @@ -77,7 +92,12 @@ "short_name": "DoNotReturnFromAComputationalExceptionHandler", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/high", + "external/cert/priority/p1", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/Statements4.json b/rule_packages/c/Statements4.json index 5b0cc9be26..e770fe032a 100644 --- a/rule_packages/c/Statements4.json +++ b/rule_packages/c/Statements4.json @@ -15,7 +15,12 @@ "tags": [ "maintainability", "readability", - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/low", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/c/Strings1.json b/rule_packages/c/Strings1.json index 39529df3cc..c4565fc898 100644 --- a/rule_packages/c/Strings1.json +++ b/rule_packages/c/Strings1.json @@ -14,7 +14,12 @@ "short_name": "DoNotAttemptToModifyStringLiterals", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -34,7 +39,12 @@ "short_name": "StringsHasSufficientSpaceForTheNullTerminator", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ], "implementation_scope": { "description": "The enforcement of this rule does not try to approximate the effects of loops and as such may not find cases where a loop operation on a string fails to null terminate a string (or causes an overflow)." @@ -57,7 +67,12 @@ "short_name": "NonNullTerminatedToFunctionThatExpectsAString", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ], "implementation_scope": { "description": "Wide character types are not handled correctly on the `aarch64le` architecture. This can lead to false negative alerts." diff --git a/rule_packages/c/Strings2.json b/rule_packages/c/Strings2.json index 99f5e240d7..a32b1b4c28 100644 --- a/rule_packages/c/Strings2.json +++ b/rule_packages/c/Strings2.json @@ -14,7 +14,12 @@ "short_name": "ToCharacterHandlingFunctionsRepresentableAsUChar", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/c/Strings3.json b/rule_packages/c/Strings3.json index 1cecf390ec..c9003f2ff8 100644 --- a/rule_packages/c/Strings3.json +++ b/rule_packages/c/Strings3.json @@ -15,7 +15,12 @@ "shared_implementation_short_name": "CastCharBeforeConvertingToLargerSizes", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -35,7 +40,12 @@ "short_name": "DoNotConfuseNarrowAndWideFunctions", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p27", + "external/cert/level/l1" ], "implementation_scope": { "description": "Wide character types are not handled correctly on the `aarch64le` architecture. This can lead to false negative alerts." diff --git a/rule_packages/c/Types1.json b/rule_packages/c/Types1.json index cbf7f0b632..bb451eba70 100644 --- a/rule_packages/c/Types1.json +++ b/rule_packages/c/Types1.json @@ -12,7 +12,13 @@ "precision": "very-high", "severity": "error", "short_name": "ExprShiftedbyNegativeOrGreaterPrecisionOperand", - "tags": [] + "tags": [ + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" + ] } ], "title": "Do not shift an expression by a negative number of bits or by greater than or equal to the number of bits that exist in the operand" @@ -29,7 +35,13 @@ "precision": "very-high", "severity": "error", "short_name": "ConvertingAPointerToIntegerOrIntegerToPointer", - "tags": [] + "tags": [ + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" + ] } ], "title": "Converting a pointer to integer or integer to pointer" diff --git a/rule_packages/cpp/Allocations.json b/rule_packages/cpp/Allocations.json index 6b40523e16..416cd3b567 100644 --- a/rule_packages/cpp/Allocations.json +++ b/rule_packages/cpp/Allocations.json @@ -197,7 +197,12 @@ "short_name": "ProperlyDeallocateDynamicallyAllocatedResources", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -216,7 +221,12 @@ "severity": "error", "short_name": "DetectAndHandleMemoryAllocationErrors", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -235,7 +245,12 @@ "severity": "error", "short_name": "MissingConstructorCallForManuallyManagedObject", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] }, { @@ -246,7 +261,12 @@ "severity": "error", "short_name": "MissingDestructorCallForManuallyManagedObject", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -267,7 +287,12 @@ "shared_implementation_short_name": "PlacementNewNotProperlyAligned", "tags": [ "security", - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] }, { @@ -280,7 +305,12 @@ "shared_implementation_short_name": "PlacementNewInsufficientStorage", "tags": [ "security", - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -300,7 +330,12 @@ "short_name": "ThrowingOperatorNewReturnsNullCert", "shared_implementation_short_name": "ThrowingOperatorNewReturnsNull", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] }, { @@ -312,7 +347,12 @@ "short_name": "ThrowingOperatorNewThrowsInvalidExceptionCert", "shared_implementation_short_name": "ThrowingOperatorNewThrowsInvalidException", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] }, { @@ -324,7 +364,12 @@ "short_name": "ThrowingNoThrowOperatorNewDeleteCert", "shared_implementation_short_name": "ThrowingNoThrowOperatorNewDelete", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] }, { @@ -336,7 +381,12 @@ "short_name": "OperatorDeleteMissingPartnerCert", "shared_implementation_short_name": "OperatorDeleteMissingPartner", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -356,7 +406,12 @@ "short_name": "UsingDefaultOperatorNewForOverAlignedTypes", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/BannedFunctions.json b/rule_packages/cpp/BannedFunctions.json index 8ef93db1a0..6cdb019ace 100644 --- a/rule_packages/cpp/BannedFunctions.json +++ b/rule_packages/cpp/BannedFunctions.json @@ -215,7 +215,12 @@ "shared_implementation_short_name": "DoNotUseSetjmpOrLongjmpShared", "tags": [ "correctness", - "scope/single-translation-unit" + "scope/single-translation-unit", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -236,7 +241,12 @@ "shared_implementation_short_name": "DoNotUseRandForGeneratingPseudorandomNumbers", "tags": [ "security", - "scope/single-translation-unit" + "scope/single-translation-unit", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -256,7 +266,12 @@ "short_name": "PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions", "tags": [ "correctness", - "scope/single-translation-unit" + "scope/single-translation-unit", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/BannedSyntax.json b/rule_packages/cpp/BannedSyntax.json index 8e307c02db..8f739145f7 100644 --- a/rule_packages/cpp/BannedSyntax.json +++ b/rule_packages/cpp/BannedSyntax.json @@ -417,7 +417,12 @@ "tags": [ "correctness", "security", - "scope/single-translation-unit" + "scope/single-translation-unit", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ] } ], diff --git a/rule_packages/cpp/Classes.json b/rule_packages/cpp/Classes.json index 59eb9a0418..e7c8a10d92 100644 --- a/rule_packages/cpp/Classes.json +++ b/rule_packages/cpp/Classes.json @@ -315,7 +315,12 @@ "severity": "recommendation", "short_name": "OffsetUsedOnInvalidTypeOrMember", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Concurrency.json b/rule_packages/cpp/Concurrency.json index 6e5898ecd8..3bba2f409f 100644 --- a/rule_packages/cpp/Concurrency.json +++ b/rule_packages/cpp/Concurrency.json @@ -15,7 +15,12 @@ "shared_implementation_short_name": "DoNotAllowAMutexToGoOutOfScopeWhileLocked", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -28,7 +33,12 @@ "shared_implementation_short_name": "DoNotDestroyAMutexWhileItIsLocked", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -48,7 +58,12 @@ "short_name": "EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/low", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -69,7 +84,12 @@ "shared_implementation_short_name": "GuardAccessToBitFields", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -90,7 +110,12 @@ "shared_implementation_short_name": "PreventDeadlockByLockingInPredefinedOrder", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -111,7 +136,12 @@ "shared_implementation_short_name": "WrapSpuriousFunctionInLoop", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -132,7 +162,12 @@ "shared_implementation_short_name": "PreserveSafetyWhenUsingConditionVariables", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -152,7 +187,12 @@ "short_name": "DoNotSpeculativelyLockALockedNonRecursiveMutex", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/high", + "external/cert/priority/p1", + "external/cert/level/l3" ] }, { @@ -164,7 +204,12 @@ "short_name": "LockedALockedNonRecursiveMutexAudit", "tags": [ "correctness", - "concurrency" + "concurrency", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/high", + "external/cert/priority/p1", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Const.json b/rule_packages/cpp/Const.json index 55c5ed6f90..6f76b7f5b8 100644 --- a/rule_packages/cpp/Const.json +++ b/rule_packages/cpp/Const.json @@ -251,7 +251,12 @@ "shared_implementation_short_name": "RemoveConstOrVolatileQualification", "short_name": "RemoveConstOrVolatileQualificationCert", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/ExceptionSafety.json b/rule_packages/cpp/ExceptionSafety.json index 07e97ae328..73b84edde4 100644 --- a/rule_packages/cpp/ExceptionSafety.json +++ b/rule_packages/cpp/ExceptionSafety.json @@ -90,7 +90,12 @@ "short_name": "GuaranteeExceptionSafety", "shared_implementation_short_name": "ExceptionSafetyGuarantees", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -111,7 +116,12 @@ "shared_implementation_short_name": "ExceptionSafetyValidState", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Exceptions1.json b/rule_packages/cpp/Exceptions1.json index 23b37778db..7c3a2a708a 100644 --- a/rule_packages/cpp/Exceptions1.json +++ b/rule_packages/cpp/Exceptions1.json @@ -502,7 +502,12 @@ "shared_implementation_short_name": "ConditionVariablePostConditionFailed", "tags": [ "correctness", - "external/cert/audit" + "external/cert/audit", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -513,7 +518,12 @@ "short_name": "JoinableThreadCopiedOrDestroyedCert", "shared_implementation_short_name": "JoinableThreadCopiedOrDestroyed", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -525,7 +535,12 @@ "short_name": "RethrowNestedWithoutCaptureCert", "shared_implementation_short_name": "RethrowNestedWithoutCapture", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -537,7 +552,12 @@ "short_name": "ExplicitAbruptTerminationCert", "shared_implementation_short_name": "ExplicitAbruptTermination", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -549,7 +569,12 @@ "short_name": "ExitHandlerThrowsExceptionCert", "shared_implementation_short_name": "ExitHandlerThrowsException", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -568,7 +593,12 @@ "kind": "path-problem", "short_name": "HandleAllExceptions", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -587,7 +617,12 @@ "shared_implementation_short_name": "DestroyedValueReferencedInDestructorCatchBlock", "short_name": "DestroyedValueReferencedInConstructorDestructorCatchBlock", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -606,7 +641,12 @@ "kind": "path-problem", "short_name": "HonorExceptionSpecifications", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -626,7 +666,12 @@ "shared_implementation_short_name": "HandleAllExceptionsDuringStartup", "short_name": "HandleAllExceptionsThrownBeforeMainBeginsExecuting", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -644,7 +689,12 @@ "severity": "error", "short_name": "ExceptionObjectsMustBeNothrowCopyConstructible", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -663,7 +713,12 @@ "shared_implementation_short_name": "CatchExceptionsByLvalueReference", "short_name": "CatchExceptionsByLvalueReference", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Exceptions2.json b/rule_packages/cpp/Exceptions2.json index ece305a04a..2e2f2dfba6 100644 --- a/rule_packages/cpp/Exceptions2.json +++ b/rule_packages/cpp/Exceptions2.json @@ -295,7 +295,12 @@ "severity": "error", "short_name": "DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -315,7 +320,12 @@ "shared_implementation_short_name": "CatchBlockShadowing", "short_name": "CatchBlockShadowingCert", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], diff --git a/rule_packages/cpp/Expressions.json b/rule_packages/cpp/Expressions.json index 935c3fa6f1..10f85237de 100644 --- a/rule_packages/cpp/Expressions.json +++ b/rule_packages/cpp/Expressions.json @@ -130,7 +130,7 @@ }, "queries": [ { - "description": "Expressions with type (plain) char and wchar_t shall not be used as operands to built-in operators other than the assignment operator =, the equality operators == and ! =, and the unary & operator. Manipulation of character data may generate results that are contrary to developer expectations. For example, ISO/IEC 14882:2003 [1] §2.2(3) only requires that the digits \"0\" to \"9\" have consecutive numerical values.", + "description": "Expressions with type (plain) char and wchar_t shall not be used as operands to built-in operators other than the assignment operator =, the equality operators == and ! =, and the unary & operator. Manipulation of character data may generate results that are contrary to developer expectations. For example, ISO/IEC 14882:2003 [1] \u00a72.2(3) only requires that the digits \"0\" to \"9\" have consecutive numerical values.", "kind": "problem", "name": "Expressions with type (plain) char and wchar_t shall only be used as operands to =, ==, !=, &", "precision": "very-high", @@ -323,7 +323,12 @@ "severity": "error", "short_name": "PassPromotablePrimitiveTypeToVaStart", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -334,7 +339,12 @@ "severity": "error", "short_name": "PassReferenceTypeToVaStart", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -345,7 +355,12 @@ "severity": "warning", "short_name": "PassNonTrivialObjectToVaStart", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Freed.json b/rule_packages/cpp/Freed.json index 36b9b31c3d..30ab6982b2 100644 --- a/rule_packages/cpp/Freed.json +++ b/rule_packages/cpp/Freed.json @@ -111,7 +111,12 @@ "severity": "error", "short_name": "DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -132,7 +137,12 @@ "short_name": "ObjectAccessedBeforeLifetimeCert", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -145,7 +155,12 @@ "short_name": "ObjectAccessedAfterLifetimeCert", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -166,7 +181,12 @@ "short_name": "UseAfterFree", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], diff --git a/rule_packages/cpp/Functions.json b/rule_packages/cpp/Functions.json index 367ab67437..b650b0937c 100644 --- a/rule_packages/cpp/Functions.json +++ b/rule_packages/cpp/Functions.json @@ -281,7 +281,12 @@ "severity": "error", "short_name": "FunctionWithMismatchedLanguageLinkage", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -301,7 +306,12 @@ "short_name": "NonVoidFunctionDoesNotReturnCert", "shared_implementation_short_name": "NonVoidFunctionDoesNotReturn", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -321,7 +331,12 @@ "short_name": "FunctionNoReturnAttributeConditionCert", "shared_implementation_short_name": "FunctionNoReturnAttributeCondition", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/IO.json b/rule_packages/cpp/IO.json index 9ad0650e62..3d1012232c 100644 --- a/rule_packages/cpp/IO.json +++ b/rule_packages/cpp/IO.json @@ -43,7 +43,12 @@ "short_name": "InterleavedInputOutputWithoutPosition", "shared_implementation_short_name": "IOFstreamMissingPositioning", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -63,7 +68,12 @@ "short_name": "CloseFilesWhenTheyAreNoLongerNeeded", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Inheritance.json b/rule_packages/cpp/Inheritance.json index efc241a8e6..fc4805fc21 100644 --- a/rule_packages/cpp/Inheritance.json +++ b/rule_packages/cpp/Inheritance.json @@ -229,7 +229,13 @@ "precision": "very-high", "severity": "error", "short_name": "DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors", - "tags": [] + "tags": [ + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" + ] } ], "title": "Do not invoke virtual functions from constructors or destructors" @@ -246,7 +252,13 @@ "precision": "very-high", "severity": "error", "short_name": "DoNotSliceDerivedObjects", - "tags": [] + "tags": [ + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" + ] } ], "title": "Do not slice derived objects" @@ -263,7 +275,13 @@ "precision": "very-high", "severity": "warning", "short_name": "DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor", - "tags": [] + "tags": [ + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p9", + "external/cert/level/l2" + ] } ], "title": "Do not delete a polymorphic object without a virtual destructor" diff --git a/rule_packages/cpp/Initialization.json b/rule_packages/cpp/Initialization.json index 3ca901a865..e81160a273 100644 --- a/rule_packages/cpp/Initialization.json +++ b/rule_packages/cpp/Initialization.json @@ -417,7 +417,12 @@ "short_name": "CyclesDuringStaticObjectInit", "tags": [ "correctness", - "maintainability" + "maintainability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -437,7 +442,12 @@ "short_name": "BadlySeededRandomNumberGenerator", "tags": [ "security", - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -460,7 +470,12 @@ "correctness", "security", "maintainability", - "readability" + "readability", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Invariants.json b/rule_packages/cpp/Invariants.json index b473fb499d..215e4edff4 100644 --- a/rule_packages/cpp/Invariants.json +++ b/rule_packages/cpp/Invariants.json @@ -63,7 +63,12 @@ "shared_implementation_short_name": "OrderingPredicateMustBeStrictlyWeak", "short_name": "ProvideAValidOrderingPredicate", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -82,7 +87,12 @@ "severity": "error", "short_name": "SignalHandlerMustBeAPlainOldFunction", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -101,7 +111,12 @@ "severity": "error", "short_name": "HonorTerminationReplacementHandlerRequirements", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" ] }, { @@ -112,7 +127,12 @@ "severity": "error", "short_name": "HonorNewReplacementHandlerRequirements", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Iterators.json b/rule_packages/cpp/Iterators.json index a43740f7e7..c345adb371 100644 --- a/rule_packages/cpp/Iterators.json +++ b/rule_packages/cpp/Iterators.json @@ -61,7 +61,12 @@ "severity": "error", "short_name": "UsesValidContainerElementAccess", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -80,7 +85,12 @@ "severity": "error", "short_name": "UseValidIteratorRanges", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -99,7 +109,12 @@ "severity": "error", "short_name": "DoNotSubtractIteratorsForDifferentContainers", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -118,7 +133,12 @@ "severity": "error", "short_name": "DoNotUseAnAdditiveOperatorOnAnIterator", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -138,7 +158,12 @@ "severity": "error", "short_name": "UseValidReferencesForElementsOfString", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/Lambdas.json b/rule_packages/cpp/Lambdas.json index ea43fa0231..8f973c361f 100644 --- a/rule_packages/cpp/Lambdas.json +++ b/rule_packages/cpp/Lambdas.json @@ -205,7 +205,12 @@ "shared_implementation_short_name": "DanglingCaptureWhenReturningLambdaObject", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -218,7 +223,12 @@ "shared_implementation_short_name": "DanglingCaptureWhenMovingLambdaObject", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/MoveForward.json b/rule_packages/cpp/MoveForward.json index b7e47116f1..6f071a6f53 100644 --- a/rule_packages/cpp/MoveForward.json +++ b/rule_packages/cpp/MoveForward.json @@ -154,7 +154,12 @@ "short_name": "DoNotRelyOnTheValueOfAMovedFromObject", "shared_implementation_short_name": "MovedFromObjectsUnspecifiedState", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/Naming.json b/rule_packages/cpp/Naming.json index 441979c3c9..34a9f2c66e 100644 --- a/rule_packages/cpp/Naming.json +++ b/rule_packages/cpp/Naming.json @@ -382,7 +382,12 @@ "severity": "error", "short_name": "RedefiningOfStandardLibraryName", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -392,7 +397,12 @@ "severity": "error", "short_name": "ReuseOfReservedIdentifier", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -403,7 +413,12 @@ "short_name": "UseOfSingleUnderscoreReservedPrefix", "tags": [ "maintainability", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -414,7 +429,12 @@ "short_name": "UseOfDoubleUnderscoreReservedPrefix", "tags": [ "maintainability", - "readability" + "readability", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -426,7 +446,12 @@ "tags": [ "maintainability", "readability", - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -438,7 +463,12 @@ "tags": [ "maintainability", "readability", - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -450,7 +480,12 @@ "tags": [ "maintainability", "readability", - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -462,7 +497,12 @@ "tags": [ "maintainability", "readability", - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Null.json b/rule_packages/cpp/Null.json index a5410840ce..543552660c 100644 --- a/rule_packages/cpp/Null.json +++ b/rule_packages/cpp/Null.json @@ -63,7 +63,12 @@ "severity": "error", "short_name": "DoNotAttemptToCreateAStringFromANullPointer", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], diff --git a/rule_packages/cpp/OperatorInvariants.json b/rule_packages/cpp/OperatorInvariants.json index 8ba76cd0f7..5eaefd68c8 100644 --- a/rule_packages/cpp/OperatorInvariants.json +++ b/rule_packages/cpp/OperatorInvariants.json @@ -177,7 +177,12 @@ "severity": "error", "short_name": "GracefullyHandleSelfCopyAssignment", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -196,7 +201,12 @@ "severity": "error", "short_name": "CopyOperationsMustNotMutateTheSourceObject", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/OutOfBounds.json b/rule_packages/cpp/OutOfBounds.json index a3cb8fbf91..2a657df95c 100644 --- a/rule_packages/cpp/OutOfBounds.json +++ b/rule_packages/cpp/OutOfBounds.json @@ -42,7 +42,12 @@ "shared_implementation_short_name": "ContainerAccessWithoutRangeCheck", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -62,7 +67,12 @@ "short_name": "GuaranteeGenericCppLibraryFunctionsDoNotOverflow", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" ] } ], @@ -82,7 +92,12 @@ "short_name": "RangeCheckStringElementAccess", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/Pointers.json b/rule_packages/cpp/Pointers.json index b6a0aaef09..fb1fbe2918 100644 --- a/rule_packages/cpp/Pointers.json +++ b/rule_packages/cpp/Pointers.json @@ -396,7 +396,12 @@ "severity": "warning", "short_name": "DoNotUsePointerArithmeticOnPolymorphicObjects", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p9", + "external/cert/level/l2" ] } ], @@ -416,7 +421,12 @@ "short_name": "DeletingPointerToIncompleteClass", "shared_implementation_short_name": "DeleteOfPointerToIncompleteClass", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] }, { @@ -427,7 +437,12 @@ "severity": "error", "short_name": "CastOfPointerToIncompleteClass", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -447,7 +462,12 @@ "short_name": "UseOfPointerToMemberToAccessUndefinedMember", "shared_implementation_short_name": "AccessOfUndefinedMemberThroughNullPointer", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -459,7 +479,12 @@ "short_name": "MemberAccessWithUninitializedStaticPointerToMember", "shared_implementation_short_name": "AccessOfUndefinedMemberThroughUninitializedStaticPointer", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -471,7 +496,12 @@ "short_name": "UseOfPointerToMemberToAccessNonexistentMember", "shared_implementation_short_name": "AccessOfNonExistingMemberThroughPointerToMember", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/Representation.json b/rule_packages/cpp/Representation.json index 0284d8098f..813373afb4 100644 --- a/rule_packages/cpp/Representation.json +++ b/rule_packages/cpp/Representation.json @@ -131,7 +131,12 @@ "severity": "error", "short_name": "MemsetUsedToAccessObjectRepresentation", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -143,7 +148,12 @@ "short_name": "MemcmpUsedToAccessObjectRepresentation", "shared_implementation_short_name": "MemcmpUsedToComparePaddingData", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] }, { @@ -154,7 +164,12 @@ "severity": "error", "short_name": "MemcpyUsedToAccessObjectRepresentation", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/high", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], diff --git a/rule_packages/cpp/Scope.json b/rule_packages/cpp/Scope.json index 6677b8b81a..6fc3aa8487 100644 --- a/rule_packages/cpp/Scope.json +++ b/rule_packages/cpp/Scope.json @@ -254,7 +254,12 @@ "severity": "warning", "short_name": "LocalFunctionDeclaration", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] }, { @@ -265,7 +270,12 @@ "severity": "warning", "short_name": "LocalConstructorInitializedObjectHidesIdentifier", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p2", + "external/cert/level/l3" ] } ], @@ -284,7 +294,12 @@ "severity": "error", "short_name": "SingularOverloadOfMemoryFunction", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/low", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -304,7 +319,12 @@ "short_name": "ModificationOfTheStandardNamespaces", "shared_implementation_short_name": "NonStandardEntitiesInStandardNamespaces", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], @@ -323,7 +343,12 @@ "severity": "error", "short_name": "UnnamedNamespaceInHeaderFile", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -343,7 +368,12 @@ "short_name": "OneDefinitionRuleNotObeyed", "shared_implementation_short_name": "OneDefinitionRuleViolation", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/high", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/SideEffects1.json b/rule_packages/cpp/SideEffects1.json index adddbc3b36..587a6ceb66 100644 --- a/rule_packages/cpp/SideEffects1.json +++ b/rule_packages/cpp/SideEffects1.json @@ -84,7 +84,12 @@ "severity": "warning", "short_name": "DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] }, { @@ -95,7 +100,12 @@ "severity": "warning", "short_name": "DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p8", + "external/cert/level/l2" ] } ], @@ -114,7 +124,12 @@ "severity": "warning", "short_name": "DoNotRelyOnSideEffectsInSizeOfOperand", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -125,7 +140,12 @@ "severity": "warning", "short_name": "DoNotRelyOnSideEffectsInTypeIdOperand", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -136,7 +156,12 @@ "severity": "warning", "short_name": "DoNotRelyOnSideEffectsInNoExceptOperand", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -147,7 +172,12 @@ "severity": "warning", "short_name": "DoNotRelyOnSideEffectsInDeclTypeOperand", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] }, { @@ -158,7 +188,12 @@ "severity": "warning", "short_name": "DoNotRelyOnSideEffectsInDeclValExpression", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/low", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/SideEffects2.json b/rule_packages/cpp/SideEffects2.json index 6e5e4812fb..0338b88895 100644 --- a/rule_packages/cpp/SideEffects2.json +++ b/rule_packages/cpp/SideEffects2.json @@ -165,7 +165,12 @@ "shared_implementation_short_name": "PredicateFunctionObjectsShouldNotBeMutable", "short_name": "PredicateFunctionObjectsShouldNotBeMutable", "tags": [ - "correctness" + "correctness", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/high", + "external/cert/priority/p3", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/SmartPointers2.json b/rule_packages/cpp/SmartPointers2.json index 2f89c4868a..db641b4c7e 100644 --- a/rule_packages/cpp/SmartPointers2.json +++ b/rule_packages/cpp/SmartPointers2.json @@ -16,7 +16,10 @@ "precision": "medium", "severity": "warning", "short_name": "WeakPtrNotUsedToRepresentTemporarySharedOwnership", - "tags": ["correctness", "external/autosar/audit"] + "tags": [ + "correctness", + "external/autosar/audit" + ] } ], "title": "A std::weak_ptr shall be used to represent temporary shared ownership." @@ -36,8 +39,14 @@ "severity": "error", "short_name": "OwnedPointerValueStoredInUnrelatedSmartPointerCert", "shared_implementation_short_name": "OwnedPointerValueStoredInUnrelatedSmartPointer", - - "tags": ["correctness"] + "tags": [ + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" + ] } ], "title": "Do not store an already-owned pointer value in an unrelated smart pointer" diff --git a/rule_packages/cpp/Strings.json b/rule_packages/cpp/Strings.json index 2152684792..acccdc7753 100644 --- a/rule_packages/cpp/Strings.json +++ b/rule_packages/cpp/Strings.json @@ -133,7 +133,13 @@ "severity": "recommendation", "shared_implementation_short_name": "BasicStringMayNotBeNullTerminated", "short_name": "BasicStringMayNotBeNullTerminatedCert", - "tags": [] + "tags": [ + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" + ] }, { "description": "Certain operations may not null terminate CStyle strings which may cause unpredictable behavior.", @@ -143,7 +149,13 @@ "severity": "recommendation", "shared_implementation_short_name": "OperationMayNotNullTerminateCStyleString", "short_name": "OperationMayNotNullTerminateCStyleStringCert", - "tags": [] + "tags": [ + "external/cert/severity/high", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p18", + "external/cert/level/l1" + ] } ], "title": "Guarantee that storage for strings has sufficient space for character data and the null terminator" diff --git a/rule_packages/cpp/TrustBoundaries.json b/rule_packages/cpp/TrustBoundaries.json index 7387fffc1f..0b697cd49c 100644 --- a/rule_packages/cpp/TrustBoundaries.json +++ b/rule_packages/cpp/TrustBoundaries.json @@ -38,7 +38,12 @@ "severity": "error", "short_name": "DoNotThrowAnExceptionAcrossExecutionBoundaries", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ] } ], @@ -57,7 +62,12 @@ "severity": "error", "short_name": "DoNotPassANonstandardObjectAcrossBoundaries", "tags": [ - "correctness" + "correctness", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ] } ], diff --git a/rule_packages/cpp/TypeRanges.json b/rule_packages/cpp/TypeRanges.json index 1b27e0ed91..1e8ef914bf 100644 --- a/rule_packages/cpp/TypeRanges.json +++ b/rule_packages/cpp/TypeRanges.json @@ -184,7 +184,12 @@ "short_name": "DetectErrorsWhenConvertingAStringToANumber", "shared_implementation_short_name": "StringNumberConversionMissingErrorCheck", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], @@ -203,7 +208,12 @@ "severity": "error", "short_name": "DoNotCastToAnOutOfRangeEnumerationValue", "tags": [ - "correctness" + "correctness", + "external/cert/severity/medium", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/medium", + "external/cert/priority/p4", + "external/cert/level/l3" ] } ], diff --git a/rule_packages/cpp/Uninitialized.json b/rule_packages/cpp/Uninitialized.json index 019987eef4..1432e11603 100644 --- a/rule_packages/cpp/Uninitialized.json +++ b/rule_packages/cpp/Uninitialized.json @@ -41,7 +41,12 @@ "short_name": "InformationLeakageAcrossTrustBoundaries", "shared_implementation_short_name": "InformationLeakageAcrossBoundaries", "tags": [ - "security" + "security", + "external/cert/severity/low", + "external/cert/likelihood/unlikely", + "external/cert/remediation-cost/high", + "external/cert/priority/p1", + "external/cert/level/l3" ], "implementation_scope": { "description": "The rule does not detect cases where fields may have uninitialized padding but are initialized via an initializer." @@ -65,7 +70,12 @@ "shared_implementation_short_name": "ReadOfUninitializedMemory", "tags": [ "correctness", - "security" + "security", + "external/cert/severity/high", + "external/cert/likelihood/probable", + "external/cert/remediation-cost/medium", + "external/cert/priority/p12", + "external/cert/level/l1" ] } ], From cb66b8c842930e97a5f1fefc69c42707f9976acf Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 1 May 2025 23:42:11 +0100 Subject: [PATCH 372/628] Update script to check for CERT risk assessment tags --- scripts/verify_rule_package_consistency.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/scripts/verify_rule_package_consistency.py b/scripts/verify_rule_package_consistency.py index 034e367db2..b9eaa5b934 100644 --- a/scripts/verify_rule_package_consistency.py +++ b/scripts/verify_rule_package_consistency.py @@ -109,6 +109,24 @@ print( f' - ERROR: {standard_name} query {query["short_name"]}.ql for Rule {rule_id} in {package_name}.json has a spurious `external/misra/c/2012/...` tag.') failed = True + if standard_name == "CERT-C" or standard_name == "CERT-C++": + expected_properties = [ + "severity", + "likelihood", + "remediation-cost", + "priority", + "level" + ] + for expected_property in expected_properties: + if not any(tag for tag in query["tags"] if tag.startswith(f"external/cert/{expected_property}/")): + print( + f' - ERROR: {standard_name} query {query["short_name"]}.ql for Rule {rule_id} in {package_name}.json is missing a `external/cert/{expected_property}/...` tag.') + failed = True + if not standard_name == "CERT-C" and not standard_name == "CERT-C++": + if any(tag for tag in query["tags"] if tag.startswith("external/cert/")): + print( + f' - ERROR: {standard_name} query {query["short_name"]}.ql for Rule {rule_id} in {package_name}.json has a spurious `external/cert/...` tag.') + failed = True rules_csv_rule_ids = package_rules_from_csv[package_name] json_missing_rules = rules_csv_rule_ids.difference(package_json_rule_ids) From 0b279397def7164aa132fecf6c57701437a47c8e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 1 May 2025 23:44:27 +0100 Subject: [PATCH 373/628] Add missing header markers to markdown files --- .../rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.md | 2 +- c/cert/src/rules/INT32-C/SignedIntegerOverflow.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.md b/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.md index cdc62493a1..4dd3bcbe3c 100644 --- a/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.md +++ b/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.md @@ -249,7 +249,7 @@ In addition, this solution assumes that there are no integer padding bits in an From this situation, it can be seen that special care must be taken because no solution to the bit-field padding issue will be 100% portable. -Risk Assessment +## Risk Assessment Padding units might contain sensitive data because the C Standard allows any padding to take [unspecified values](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unspecifiedvalue). A pointer to such a structure could be passed to other functions, causing information leakage. diff --git a/c/cert/src/rules/INT32-C/SignedIntegerOverflow.md b/c/cert/src/rules/INT32-C/SignedIntegerOverflow.md index dbe36775bf..50a9d01dcd 100644 --- a/c/cert/src/rules/INT32-C/SignedIntegerOverflow.md +++ b/c/cert/src/rules/INT32-C/SignedIntegerOverflow.md @@ -398,7 +398,8 @@ void func(signed long s_a) { } ``` -Risk Assessment + +## Risk Assessment Integer overflow can lead to buffer overflows and the execution of arbitrary code by an attacker. From be2985722a7585fdf23f9dc5c4addbae555d2e63 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 1 May 2025 23:45:16 +0100 Subject: [PATCH 374/628] Add risk assessment tags to CERT queries --- .../DoNotFormOutOfBoundsPointersOrArraySubscripts.ql | 5 +++++ .../rules/ARR32-C/VariableLengthArraySizeNotInValidRange.ql | 5 +++++ .../DoNotRelatePointersThatDoNotReferToTheSameArray.ql | 5 +++++ .../DoNotSubtractPointersThatDoNotReferToTheSameArray.ql | 5 +++++ .../DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql | 5 +++++ .../src/rules/ARR38-C/LibraryFunctionArgumentOutOfBounds.ql | 5 +++++ .../ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql | 5 +++++ c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql | 5 +++++ .../CON31-C/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql | 5 +++++ .../src/rules/CON31-C/DoNotDestroyAMutexWhileItIsLocked.ql | 5 +++++ .../rules/CON32-C/PreventDataRacesWithMultipleThreads.ql | 5 +++++ .../CON33-C/RaceConditionsWhenUsingLibraryFunctions.ql | 5 +++++ .../CON34-C/AppropriateThreadObjectStorageDurations.ql | 6 ++++++ .../CON34-C/ThreadObjectStorageDurationsNotInitialized.ql | 6 ++++++ .../src/rules/CON35-C/DeadlockByLockingInPredefinedOrder.ql | 5 +++++ .../CON36-C/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql | 5 +++++ .../rules/CON37-C/DoNotCallSignalInMultithreadedProgram.ql | 5 +++++ .../CON38-C/PreserveSafetyWhenUsingConditionVariables.ql | 5 +++++ .../rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql | 5 +++++ c/cert/src/rules/CON40-C/AtomicVariableTwiceInExpression.ql | 5 +++++ .../CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.ql | 5 +++++ .../DCL30-C/AppropriateStorageDurationsFunctionReturn.ql | 5 +++++ .../DCL30-C/AppropriateStorageDurationsStackAdressEscape.ql | 5 +++++ .../src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.ql | 5 +++++ .../DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.ql | 5 +++++ c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.ql | 5 +++++ .../DCL39-C/InformationLeakageAcrossTrustBoundariesC.ql | 5 +++++ .../DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.ql | 5 +++++ .../src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql | 5 +++++ c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql | 5 +++++ c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.ql | 5 +++++ .../ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.ql | 5 +++++ .../ENV31-C/EnvPointerIsInvalidAfterCertainOperations.ql | 5 +++++ c/cert/src/rules/ENV32-C/ExitHandlersMustReturnNormally.ql | 5 +++++ c/cert/src/rules/ENV33-C/DoNotCallSystem.ql | 5 +++++ .../ENV34-C/DoNotStorePointersReturnedByEnvFunctions.ql | 5 +++++ .../DoNotStorePointersReturnedByEnvironmentFunWarn.ql | 5 +++++ c/cert/src/rules/ERR30-C/ErrnoNotSetToZero.ql | 5 +++++ c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.ql | 5 +++++ c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql | 5 +++++ c/cert/src/rules/ERR30-C/SetlocaleMightSetErrno.ql | 5 +++++ .../rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql | 5 +++++ .../rules/ERR33-C/DetectAndHandleStandardLibraryErrors.ql | 5 +++++ .../DependenceOnOrderOfFunctionArgumentsForSideEffects.ql | 5 +++++ .../DependenceOnOrderOfScalarEvaluationForSideEffects.ql | 5 +++++ .../DoNotAccessVolatileObjectWithNonVolatileReference.ql | 5 +++++ c/cert/src/rules/EXP33-C/DoNotReadUninitializedMemory.ql | 5 +++++ c/cert/src/rules/EXP34-C/DoNotDereferenceNullPointers.ql | 5 +++++ .../EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql | 5 +++++ .../DoNotCastPointerToMoreStrictlyAlignedPointerType.ql | 5 +++++ .../rules/EXP37-C/CallPOSIXOpenWithCorrectArgumentCount.ql | 5 +++++ .../EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql | 5 +++++ .../EXP37-C/DoNotCallFunctionsWithIncompatibleArguments.ql | 5 +++++ .../DoNotAccessVariableViaPointerOfIncompatibleType.ql | 6 ++++++ c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql | 5 +++++ c/cert/src/rules/EXP42-C/DoNotComparePaddingData.ql | 5 +++++ .../DoNotPassAliasedPointerToRestrictQualifiedParam.ql | 5 +++++ .../EXP43-C/RestrictPointerReferencesOverlappingObject.ql | 5 +++++ .../src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.ql | 5 +++++ .../src/rules/EXP45-C/AssignmentsInSelectionStatements.ql | 6 ++++++ .../DoNotUseABitwiseOperatorWithABooleanLikeOperand.ql | 5 +++++ .../src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.ql | 5 +++++ .../rules/FIO32-C/DoNotPerformFileOperationsOnDevices.ql | 5 +++++ .../DistinguishBetweenCharReadFromAFileAndEofOrWeof.ql | 5 +++++ c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.ql | 5 +++++ .../SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql | 5 +++++ c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.ql | 5 +++++ .../DoNotAlternatelyIOFromAStreamWithoutPositioning.ql | 5 +++++ .../src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql | 5 +++++ .../rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.ql | 5 +++++ .../rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql | 5 +++++ .../OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql | 5 +++++ .../FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql | 5 +++++ .../rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.ql | 5 +++++ c/cert/src/rules/FIO47-C/UseValidSpecifiers.ql | 5 +++++ c/cert/src/rules/FIO47-C/WrongNumberOfFormatArguments.ql | 5 +++++ c/cert/src/rules/FIO47-C/WrongTypeFormatArguments.ql | 5 +++++ c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql | 5 +++++ c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.ql | 5 +++++ .../src/rules/FLP34-C/UncheckedFloatingPointConversion.ql | 5 +++++ c/cert/src/rules/FLP36-C/IntToFloatPreservePrecision.ql | 5 +++++ c/cert/src/rules/FLP37-C/MemcmpUsedToCompareFloats.ql | 5 +++++ .../rules/INT30-C/UnsignedIntegerOperationsWrapAround.ql | 5 +++++ c/cert/src/rules/INT31-C/IntegerConversionCausesDataLoss.ql | 5 +++++ c/cert/src/rules/INT32-C/SignedIntegerOverflow.ql | 5 +++++ c/cert/src/rules/INT33-C/DivOrRemByZero.ql | 5 +++++ .../ExprShiftedbyNegativeOrGreaterPrecisionOperand.ql | 5 +++++ c/cert/src/rules/INT35-C/UseCorrectIntegerPrecisions.ql | 5 +++++ .../ConvertingAPointerToIntegerOrIntegerToPointer.ql | 5 +++++ c/cert/src/rules/MEM30-C/DoNotAccessFreedMemory.ql | 5 +++++ .../src/rules/MEM31-C/FreeMemoryWhenNoLongerNeededCert.ql | 5 +++++ .../AllocStructsWithAFlexibleArrayMemberDynamically.ql | 5 +++++ .../CopyStructsWithAFlexibleArrayMemberDynamically.ql | 5 +++++ .../rules/MEM34-C/OnlyFreeMemoryAllocatedDynamicallyCert.ql | 5 +++++ .../rules/MEM35-C/InsufficientMemoryAllocatedForObject.ql | 5 +++++ .../MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql | 6 ++++++ .../MSC30-C/RandUsedForGeneratingPseudorandomNumbers.ql | 5 +++++ .../MSC32-C/ProperlySeedPseudorandomNumberGenerators.ql | 5 +++++ .../MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql | 5 +++++ .../MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.ql | 5 +++++ .../MSC38-C/DoNotTreatAPredefinedIdentifierAsObject.ql | 5 +++++ .../DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql | 5 +++++ .../rules/MSC40-C/DoNotViolateInLineLinkageConstraints.ql | 5 +++++ .../rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql | 5 +++++ .../rules/PRE32-C/MacroOrFunctionArgsContainHashToken.ql | 5 +++++ .../CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql | 5 +++++ .../SIG31-C/DoNotAccessSharedObjectsInSignalHandlers.ql | 5 +++++ .../DoNotCallSignalFromInterruptibleSignalHandlers.ql | 5 +++++ .../DoNotReturnFromAComputationalExceptionHandler.ql | 5 +++++ .../src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql | 5 +++++ .../StringsHasSufficientSpaceForTheNullTerminator.ql | 5 +++++ .../NonNullTerminatedToFunctionThatExpectsAString.ql | 5 +++++ .../rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql | 5 +++++ .../ToCharacterHandlingFunctionsRepresentableAsUChar.ql | 5 +++++ .../src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.ql | 5 +++++ .../CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql | 5 +++++ .../rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.ql | 5 +++++ ...reActivelyHeldLocksAreReleasedOnExceptionalConditions.ql | 5 +++++ .../CON52-CPP/PreventBitFieldAccessFromMultipleThreads.ql | 5 +++++ .../rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.ql | 5 +++++ .../CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql | 5 +++++ .../CON55-CPP/PreserveSafetyWhenUsingConditionVariables.ql | 5 +++++ .../DoNotSpeculativelyLockALockedNonRecursiveMutex.ql | 5 +++++ .../rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.ql | 5 +++++ .../rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.ql | 5 +++++ .../src/rules/CTR51-CPP/UsesValidContainerElementAccess.ql | 5 +++++ .../GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql | 5 +++++ cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.ql | 5 +++++ .../DoNotSubtractIteratorsForDifferentContainers.ql | 5 +++++ .../CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.ql | 5 +++++ .../DoNotUsePointerArithmeticOnPolymorphicObjects.ql | 5 +++++ .../src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.ql | 5 +++++ .../CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.ql | 5 +++++ .../rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.ql | 5 +++++ .../src/rules/DCL51-CPP/EnumeratorReusesReservedName.ql | 5 +++++ cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.ql | 5 +++++ cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.ql | 5 +++++ .../src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.ql | 5 +++++ cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.ql | 5 +++++ .../rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.ql | 5 +++++ .../rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.ql | 5 +++++ .../rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.ql | 5 +++++ .../LocalConstructorInitializedObjectHidesIdentifier.ql | 5 +++++ cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.ql | 5 +++++ .../src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.ql | 5 +++++ .../DCL55-CPP/InformationLeakageAcrossTrustBoundaries.ql | 5 +++++ .../src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.ql | 5 +++++ ...xceptionsEscapeFromDestructorsOrDeallocationFunctions.ql | 5 +++++ .../rules/DCL58-CPP/ModificationOfTheStandardNamespaces.ql | 5 +++++ .../src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.ql | 5 +++++ cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.ql | 5 +++++ .../ERR50-CPP/ConditionVariablePostConditionFailedCert.ql | 5 +++++ .../src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.ql | 5 +++++ .../src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.ql | 5 +++++ .../rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.ql | 5 +++++ .../src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.ql | 5 +++++ cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.ql | 5 +++++ cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.ql | 5 +++++ ...royedValueReferencedInConstructorDestructorCatchBlock.ql | 5 +++++ cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.ql | 5 +++++ .../src/rules/ERR55-CPP/HonorExceptionSpecifications.ql | 5 +++++ cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.ql | 5 +++++ .../ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.ql | 5 +++++ .../HandleAllExceptionsThrownBeforeMainBeginsExecuting.ql | 5 +++++ .../DoNotThrowAnExceptionAcrossExecutionBoundaries.ql | 5 +++++ .../ExceptionObjectsMustBeNothrowCopyConstructible.ql | 5 +++++ .../src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.ql | 5 +++++ .../ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.ql | 5 +++++ ...ationForSideEffectsInFunctionCallsAsFunctionArguments.ql | 5 +++++ ...ependOnTheOrderOfScalarObjectEvaluationForSideEffects.ql | 5 +++++ .../DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql | 5 +++++ .../EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.ql | 5 +++++ .../EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.ql | 5 +++++ .../EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.ql | 5 +++++ .../EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.ql | 5 +++++ .../EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.ql | 5 +++++ .../src/rules/EXP53-CPP/DoNotReadUninitializedMemory.ql | 5 +++++ .../src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.ql | 5 +++++ .../src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.ql | 5 +++++ .../EXP55-CPP/RemoveConstOrVolatileQualificationCert.ql | 5 +++++ .../EXP56-CPP/FunctionWithMismatchedLanguageLinkage.ql | 5 +++++ .../src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.ql | 5 +++++ .../src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.ql | 5 +++++ .../src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.ql | 5 +++++ .../rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.ql | 5 +++++ cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.ql | 5 +++++ .../src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.ql | 5 +++++ .../DoNotPassANonstandardObjectAcrossBoundaries.ql | 5 +++++ .../EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.ql | 5 +++++ .../ReturningLambdaObjectWithCaptureByReference.ql | 5 +++++ .../EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.ql | 5 +++++ .../EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.ql | 5 +++++ .../EXP62-CPP/MemsetUsedToAccessObjectRepresentation.ql | 5 +++++ .../EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.ql | 5 +++++ .../FIO50-CPP/InterleavedInputOutputWithoutPosition.ql | 5 +++++ .../rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.ql | 5 +++++ .../INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.ql | 5 +++++ cpp/cert/src/rules/MEM50-CPP/UseAfterFree.ql | 5 +++++ .../ProperlyDeallocateDynamicallyAllocatedResources.ql | 5 +++++ .../MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql | 5 +++++ .../MissingConstructorCallForManuallyManagedObject.ql | 5 +++++ .../MissingDestructorCallForManuallyManagedObject.ql | 5 +++++ .../rules/MEM54-CPP/PlacementNewInsufficientStorageCert.ql | 5 +++++ .../rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.ql | 5 +++++ .../src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.ql | 5 +++++ .../rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.ql | 5 +++++ .../rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.ql | 5 +++++ .../ThrowingOperatorNewThrowsInvalidExceptionCert.ql | 5 +++++ .../OwnedPointerValueStoredInUnrelatedSmartPointerCert.ql | 5 +++++ .../MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.ql | 5 +++++ .../DoNotUseRandForGeneratingPseudorandomNumbers.ql | 5 +++++ .../src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.ql | 5 +++++ .../src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.ql | 5 +++++ .../MSC53-CPP/FunctionNoReturnAttributeConditionCert.ql | 5 +++++ .../rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.ql | 5 +++++ ...otInvokeVirtualFunctionsFromConstructorsOrDestructors.ql | 5 +++++ cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.ql | 5 +++++ ...oNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.ql | 5 +++++ .../src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.ql | 5 +++++ .../rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.ql | 5 +++++ .../MemberAccessWithUninitializedStaticPointerToMember.ql | 5 +++++ .../UseOfPointerToMemberToAccessNonexistentMember.ql | 5 +++++ .../UseOfPointerToMemberToAccessUndefinedMember.ql | 5 +++++ .../OOP56-CPP/HonorNewReplacementHandlerRequirements.ql | 5 +++++ .../HonorTerminationReplacementHandlerRequirements.ql | 5 +++++ ...ionsAndOverloadedOperatorsToCStandardLibraryFunctions.ql | 5 +++++ .../OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.ql | 5 +++++ .../STR50-CPP/BasicStringMayNotBeNullTerminatedCert.ql | 5 +++++ .../OperationMayNotNullTerminateCStyleStringCert.ql | 5 +++++ .../DoNotAttemptToCreateAStringFromANullPointer.ql | 5 +++++ .../STR52-CPP/UseValidReferencesForElementsOfString.ql | 5 +++++ .../src/rules/STR53-CPP/RangeCheckStringElementAccess.ql | 5 +++++ 232 files changed, 1165 insertions(+) diff --git a/c/cert/src/rules/ARR30-C/DoNotFormOutOfBoundsPointersOrArraySubscripts.ql b/c/cert/src/rules/ARR30-C/DoNotFormOutOfBoundsPointersOrArraySubscripts.ql index cc4c99c002..fed579bf34 100644 --- a/c/cert/src/rules/ARR30-C/DoNotFormOutOfBoundsPointersOrArraySubscripts.ql +++ b/c/cert/src/rules/ARR30-C/DoNotFormOutOfBoundsPointersOrArraySubscripts.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/arr30-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.ql b/c/cert/src/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.ql index 40a800aa69..85fc7b9022 100644 --- a/c/cert/src/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.ql +++ b/c/cert/src/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/arr32-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ARR36-C/DoNotRelatePointersThatDoNotReferToTheSameArray.ql b/c/cert/src/rules/ARR36-C/DoNotRelatePointersThatDoNotReferToTheSameArray.ql index 93244bd483..e42437042f 100644 --- a/c/cert/src/rules/ARR36-C/DoNotRelatePointersThatDoNotReferToTheSameArray.ql +++ b/c/cert/src/rules/ARR36-C/DoNotRelatePointersThatDoNotReferToTheSameArray.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/arr36-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ARR36-C/DoNotSubtractPointersThatDoNotReferToTheSameArray.ql b/c/cert/src/rules/ARR36-C/DoNotSubtractPointersThatDoNotReferToTheSameArray.ql index b3ed62d5d7..a9e53e68b7 100644 --- a/c/cert/src/rules/ARR36-C/DoNotSubtractPointersThatDoNotReferToTheSameArray.ql +++ b/c/cert/src/rules/ARR36-C/DoNotSubtractPointersThatDoNotReferToTheSameArray.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/arr36-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql b/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql index 0ddf56150c..635d9d5c03 100644 --- a/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql +++ b/c/cert/src/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/arr37-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ARR38-C/LibraryFunctionArgumentOutOfBounds.ql b/c/cert/src/rules/ARR38-C/LibraryFunctionArgumentOutOfBounds.ql index 5082743193..04e1c8a505 100644 --- a/c/cert/src/rules/ARR38-C/LibraryFunctionArgumentOutOfBounds.ql +++ b/c/cert/src/rules/ARR38-C/LibraryFunctionArgumentOutOfBounds.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/arr38-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql b/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql index 61dd77f6f4..c3ebd6ede6 100644 --- a/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql +++ b/c/cert/src/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/arr39-c * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql b/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql index 69b1b333be..1e03c089e8 100644 --- a/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql +++ b/c/cert/src/rules/CON30-C/CleanUpThreadSpecificStorage.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con30-c * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON31-C/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql b/c/cert/src/rules/CON31-C/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql index 0bde0b0de7..345623fe0d 100644 --- a/c/cert/src/rules/CON31-C/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql +++ b/c/cert/src/rules/CON31-C/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con31-c * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON31-C/DoNotDestroyAMutexWhileItIsLocked.ql b/c/cert/src/rules/CON31-C/DoNotDestroyAMutexWhileItIsLocked.ql index b37dccab3a..40c4e936dd 100644 --- a/c/cert/src/rules/CON31-C/DoNotDestroyAMutexWhileItIsLocked.ql +++ b/c/cert/src/rules/CON31-C/DoNotDestroyAMutexWhileItIsLocked.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/con31-c * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.ql b/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.ql index d4f3cbbe10..3ea9e1e1fd 100644 --- a/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.ql +++ b/c/cert/src/rules/CON32-C/PreventDataRacesWithMultipleThreads.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con32-c * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.ql b/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.ql index 4efafd8ebf..c9bcaa6bd2 100644 --- a/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.ql +++ b/c/cert/src/rules/CON33-C/RaceConditionsWhenUsingLibraryFunctions.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/con33-c * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql index 3d0cc3f481..eef196a9ec 100644 --- a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql +++ b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql @@ -9,6 +9,12 @@ * @tags external/cert/id/con34-c * correctness * concurrency + * external/cert/recommendation/con34-c + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql b/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql index fc75cb94ff..fa0587bce0 100644 --- a/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql +++ b/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql @@ -10,6 +10,12 @@ * external/cert/audit * correctness * concurrency + * external/cert/recommendation/con34-c + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON35-C/DeadlockByLockingInPredefinedOrder.ql b/c/cert/src/rules/CON35-C/DeadlockByLockingInPredefinedOrder.ql index 143e0a58be..764b0f263f 100644 --- a/c/cert/src/rules/CON35-C/DeadlockByLockingInPredefinedOrder.ql +++ b/c/cert/src/rules/CON35-C/DeadlockByLockingInPredefinedOrder.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con35-c * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON36-C/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql b/c/cert/src/rules/CON36-C/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql index 430a0e7c19..d0d948d9b2 100644 --- a/c/cert/src/rules/CON36-C/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql +++ b/c/cert/src/rules/CON36-C/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con36-c * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.ql b/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.ql index 00cf456948..17691f24dd 100644 --- a/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.ql +++ b/c/cert/src/rules/CON37-C/DoNotCallSignalInMultithreadedProgram.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con37-c * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/low + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON38-C/PreserveSafetyWhenUsingConditionVariables.ql b/c/cert/src/rules/CON38-C/PreserveSafetyWhenUsingConditionVariables.ql index 470480ae62..3b2ae558d8 100644 --- a/c/cert/src/rules/CON38-C/PreserveSafetyWhenUsingConditionVariables.ql +++ b/c/cert/src/rules/CON38-C/PreserveSafetyWhenUsingConditionVariables.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con38-c * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql b/c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql index 0604d2d483..6ef617ca72 100644 --- a/c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql +++ b/c/cert/src/rules/CON39-C/ThreadWasPreviouslyJoinedOrDetached.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con39-c * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON40-C/AtomicVariableTwiceInExpression.ql b/c/cert/src/rules/CON40-C/AtomicVariableTwiceInExpression.ql index 8a44013277..0ec195868f 100644 --- a/c/cert/src/rules/CON40-C/AtomicVariableTwiceInExpression.ql +++ b/c/cert/src/rules/CON40-C/AtomicVariableTwiceInExpression.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con40-c * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.ql b/c/cert/src/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.ql index dd8aed6a55..57be1bc488 100644 --- a/c/cert/src/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.ql +++ b/c/cert/src/rules/CON41-C/WrapFunctionsThatCanFailSpuriouslyInLoop.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con41-c * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql index e4f5341014..2e1064ee9d 100644 --- a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql +++ b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl30-c * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsStackAdressEscape.ql b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsStackAdressEscape.ql index fb9b13b39c..a5749aa8bc 100644 --- a/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsStackAdressEscape.ql +++ b/c/cert/src/rules/DCL30-C/AppropriateStorageDurationsStackAdressEscape.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl30-c * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.ql b/c/cert/src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.ql index 369baa4a63..35e6cd057a 100644 --- a/c/cert/src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.ql +++ b/c/cert/src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/dcl31-c * correctness * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.ql b/c/cert/src/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.ql index 99c5a9708b..04a3030cc1 100644 --- a/c/cert/src/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.ql +++ b/c/cert/src/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.ql @@ -9,6 +9,11 @@ * correctness * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.ql b/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.ql index e9fa3f1017..d6000852c6 100644 --- a/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.ql +++ b/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.ql @@ -10,6 +10,11 @@ * correctness * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.ql b/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.ql index 1199fbeb9b..dd2c1217cf 100644 --- a/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.ql +++ b/c/cert/src/rules/DCL39-C/InformationLeakageAcrossTrustBoundariesC.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl39-c * security + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/high + * external/cert/priority/p1 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.ql b/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.ql index ba2cc5c23f..d002326fae 100644 --- a/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.ql +++ b/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.ql @@ -9,6 +9,11 @@ * correctness * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql index 8cab442e54..8c25fe3350 100644 --- a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql +++ b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql @@ -11,6 +11,11 @@ * correctness * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql b/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql index 151d33db5c..8e220062d4 100644 --- a/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql +++ b/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql @@ -10,6 +10,11 @@ * correctness * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.ql b/c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.ql index db42f7102c..6f06174b99 100644 --- a/c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.ql +++ b/c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.ql @@ -10,6 +10,11 @@ * correctness * maintainability * readability + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.ql b/c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.ql index 42f13f6244..f69a78ba2c 100644 --- a/c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.ql +++ b/c/cert/src/rules/ENV30-C/DoNotModifyTheReturnValueOfCertainFunctions.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/env30-c * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.ql b/c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.ql index a925b80e74..b4d4a74d57 100644 --- a/c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.ql +++ b/c/cert/src/rules/ENV31-C/EnvPointerIsInvalidAfterCertainOperations.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/env31-c * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ENV32-C/ExitHandlersMustReturnNormally.ql b/c/cert/src/rules/ENV32-C/ExitHandlersMustReturnNormally.ql index 1b360ca0d8..19cf28b3e9 100644 --- a/c/cert/src/rules/ENV32-C/ExitHandlersMustReturnNormally.ql +++ b/c/cert/src/rules/ENV32-C/ExitHandlersMustReturnNormally.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/env32-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ENV33-C/DoNotCallSystem.ql b/c/cert/src/rules/ENV33-C/DoNotCallSystem.ql index 58a9c8db79..3b21cd7544 100644 --- a/c/cert/src/rules/ENV33-C/DoNotCallSystem.ql +++ b/c/cert/src/rules/ENV33-C/DoNotCallSystem.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/env33-c * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvFunctions.ql b/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvFunctions.ql index 505f26046a..af54dfa823 100644 --- a/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvFunctions.ql +++ b/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvFunctions.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/env34-c * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvironmentFunWarn.ql b/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvironmentFunWarn.ql index b5dd9f4d80..784b7898d6 100644 --- a/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvironmentFunWarn.ql +++ b/c/cert/src/rules/ENV34-C/DoNotStorePointersReturnedByEnvironmentFunWarn.ql @@ -9,6 +9,11 @@ * @problem.severity warning * @tags external/cert/id/env34-c * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ERR30-C/ErrnoNotSetToZero.ql b/c/cert/src/rules/ERR30-C/ErrnoNotSetToZero.ql index cc1dd82bbb..06ac9d1198 100644 --- a/c/cert/src/rules/ERR30-C/ErrnoNotSetToZero.ql +++ b/c/cert/src/rules/ERR30-C/ErrnoNotSetToZero.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err30-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.ql b/c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.ql index 527529cc30..13f7e40303 100644 --- a/c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.ql +++ b/c/cert/src/rules/ERR30-C/ErrnoReadBeforeReturn.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err30-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql b/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql index 17714c646f..8bf583faff 100644 --- a/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql +++ b/c/cert/src/rules/ERR30-C/FunctionCallBeforeErrnoCheck.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err30-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ERR30-C/SetlocaleMightSetErrno.ql b/c/cert/src/rules/ERR30-C/SetlocaleMightSetErrno.ql index 9c94284841..a7ccf8c041 100644 --- a/c/cert/src/rules/ERR30-C/SetlocaleMightSetErrno.ql +++ b/c/cert/src/rules/ERR30-C/SetlocaleMightSetErrno.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/err30-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql b/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql index 0e3bf26124..c7dfd58c6b 100644 --- a/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql +++ b/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/err32-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.ql b/c/cert/src/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.ql index 6641fe8a52..01e7b83d13 100644 --- a/c/cert/src/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.ql +++ b/c/cert/src/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err33-c * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql index a761ec7f48..48b9487728 100644 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp30-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.ql b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.ql index c478a3d51e..51b505ec63 100644 --- a/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.ql +++ b/c/cert/src/rules/EXP30-C/DependenceOnOrderOfScalarEvaluationForSideEffects.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp30-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.ql b/c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.ql index 47b94c5288..891b93bcda 100644 --- a/c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.ql +++ b/c/cert/src/rules/EXP32-C/DoNotAccessVolatileObjectWithNonVolatileReference.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp32-c * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP33-C/DoNotReadUninitializedMemory.ql b/c/cert/src/rules/EXP33-C/DoNotReadUninitializedMemory.ql index ef59be1c10..94deea912e 100644 --- a/c/cert/src/rules/EXP33-C/DoNotReadUninitializedMemory.ql +++ b/c/cert/src/rules/EXP33-C/DoNotReadUninitializedMemory.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/exp33-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP34-C/DoNotDereferenceNullPointers.ql b/c/cert/src/rules/EXP34-C/DoNotDereferenceNullPointers.ql index 042e55dbfd..51b93c8000 100644 --- a/c/cert/src/rules/EXP34-C/DoNotDereferenceNullPointers.ql +++ b/c/cert/src/rules/EXP34-C/DoNotDereferenceNullPointers.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/exp34-c * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql b/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql index 3689aa4397..3f7d9ae142 100644 --- a/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql +++ b/c/cert/src/rules/EXP35-C/DoNotModifyObjectsWithTemporaryLifetime.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp35-c * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql b/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql index f3b3aa364d..0d294e48b1 100644 --- a/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql +++ b/c/cert/src/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp36-c * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP37-C/CallPOSIXOpenWithCorrectArgumentCount.ql b/c/cert/src/rules/EXP37-C/CallPOSIXOpenWithCorrectArgumentCount.ql index ad8520e321..a6e633d7f6 100644 --- a/c/cert/src/rules/EXP37-C/CallPOSIXOpenWithCorrectArgumentCount.ql +++ b/c/cert/src/rules/EXP37-C/CallPOSIXOpenWithCorrectArgumentCount.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/exp37-c * correctness * security + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql b/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql index 9bbe27aa31..6d223dab72 100644 --- a/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql +++ b/c/cert/src/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp37-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP37-C/DoNotCallFunctionsWithIncompatibleArguments.ql b/c/cert/src/rules/EXP37-C/DoNotCallFunctionsWithIncompatibleArguments.ql index e76c62ee2d..4c5ba57504 100644 --- a/c/cert/src/rules/EXP37-C/DoNotCallFunctionsWithIncompatibleArguments.ql +++ b/c/cert/src/rules/EXP37-C/DoNotCallFunctionsWithIncompatibleArguments.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp37-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql b/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql index fde564665c..c5772340ef 100644 --- a/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql +++ b/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql @@ -8,6 +8,12 @@ * @problem.severity error * @tags external/cert/id/exp39-c * correctness + * external/cert/recommendation/exp39-c + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql b/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql index 20c9f1bcc8..9d8e4b16d4 100644 --- a/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql +++ b/c/cert/src/rules/EXP40-C/DoNotModifyConstantObjects.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/exp40-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP42-C/DoNotComparePaddingData.ql b/c/cert/src/rules/EXP42-C/DoNotComparePaddingData.ql index 9592ebfd30..4fb80352a3 100644 --- a/c/cert/src/rules/EXP42-C/DoNotComparePaddingData.ql +++ b/c/cert/src/rules/EXP42-C/DoNotComparePaddingData.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/exp42-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql b/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql index 08121f8c2b..4aced57136 100644 --- a/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql +++ b/c/cert/src/rules/EXP43-C/DoNotPassAliasedPointerToRestrictQualifiedParam.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/exp43-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql b/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql index 1d740ec4f3..31618785d2 100644 --- a/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql +++ b/c/cert/src/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/exp43-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.ql b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.ql index 32d30a09ad..02d71b3497 100644 --- a/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.ql +++ b/c/cert/src/rules/EXP44-C/UnevaluatedOperandWithSideEffect.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/exp44-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql index f6e29eb28c..5478bb03f7 100644 --- a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql +++ b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql @@ -8,6 +8,12 @@ * @problem.severity error * @tags external/cert/id/exp45-c * correctness + * external/cert/recommendation/exp45-c + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/EXP46-C/DoNotUseABitwiseOperatorWithABooleanLikeOperand.ql b/c/cert/src/rules/EXP46-C/DoNotUseABitwiseOperatorWithABooleanLikeOperand.ql index 040a8bb6ee..549e57236a 100644 --- a/c/cert/src/rules/EXP46-C/DoNotUseABitwiseOperatorWithABooleanLikeOperand.ql +++ b/c/cert/src/rules/EXP46-C/DoNotUseABitwiseOperatorWithABooleanLikeOperand.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/exp46-c * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.ql b/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.ql index b9df838b06..81ecf56ccf 100644 --- a/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.ql +++ b/c/cert/src/rules/FIO30-C/ExcludeUserInputFromFormatStrings.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio30-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.ql b/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.ql index 5784e820d9..78817d31e9 100644 --- a/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.ql +++ b/c/cert/src/rules/FIO32-C/DoNotPerformFileOperationsOnDevices.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio32-c * correctness * security + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.ql b/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.ql index a55c2dbf29..01c13e642b 100644 --- a/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.ql +++ b/c/cert/src/rules/FIO34-C/DistinguishBetweenCharReadFromAFileAndEofOrWeof.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio34-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.ql b/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.ql index 274514e598..3336a059cd 100644 --- a/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.ql +++ b/c/cert/src/rules/FIO34-C/EndOfFileCheckPortability.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/fio34-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql index 5945da57f4..ad3a2c8192 100644 --- a/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql +++ b/c/cert/src/rules/FIO37-C/SuccessfulFgetsOrFgetwsMayReturnAnEmptyString.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/fio37-c * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.ql b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.ql index e8e897009e..5b5a043395 100644 --- a/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.ql +++ b/c/cert/src/rules/FIO38-C/DoNotCopyAFileObject.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio38-c * correctness * security + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql index 668a7d982e..09289d1f79 100644 --- a/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql +++ b/c/cert/src/rules/FIO39-C/DoNotAlternatelyIOFromAStreamWithoutPositioning.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/fio39-c * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql index 69fb92a15c..b54436c835 100644 --- a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql +++ b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/fio40-c * correctness * security + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.ql b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.ql index 7fc1c11d26..5c7d759606 100644 --- a/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.ql +++ b/c/cert/src/rules/FIO41-C/DoNotCallGetcAndPutcWithSideEffects.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/fio41-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql index 3650fad82f..26f8aa239d 100644 --- a/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql +++ b/c/cert/src/rules/FIO42-C/CloseFilesWhenTheyAreNoLongerNeeded.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/fio42-c * correctness * security + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql index 7ed5887e42..bc0a417bd0 100644 --- a/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql +++ b/c/cert/src/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/fio44-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql b/c/cert/src/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql index b02ce2f58d..85369b502e 100644 --- a/c/cert/src/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql +++ b/c/cert/src/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio45-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.ql b/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.ql index 6bc284c2c7..dc52dca487 100644 --- a/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.ql +++ b/c/cert/src/rules/FIO46-C/UndefinedBehaviorAccessingAClosedFile.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/fio46-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO47-C/UseValidSpecifiers.ql b/c/cert/src/rules/FIO47-C/UseValidSpecifiers.ql index 2062cba2c4..8ed99d4541 100644 --- a/c/cert/src/rules/FIO47-C/UseValidSpecifiers.ql +++ b/c/cert/src/rules/FIO47-C/UseValidSpecifiers.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio47-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO47-C/WrongNumberOfFormatArguments.ql b/c/cert/src/rules/FIO47-C/WrongNumberOfFormatArguments.ql index a8b9e9fbac..7266f1fc7c 100644 --- a/c/cert/src/rules/FIO47-C/WrongNumberOfFormatArguments.ql +++ b/c/cert/src/rules/FIO47-C/WrongNumberOfFormatArguments.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio47-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FIO47-C/WrongTypeFormatArguments.ql b/c/cert/src/rules/FIO47-C/WrongTypeFormatArguments.ql index 66cbe409f6..00853abfbc 100644 --- a/c/cert/src/rules/FIO47-C/WrongTypeFormatArguments.ql +++ b/c/cert/src/rules/FIO47-C/WrongTypeFormatArguments.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio47-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql b/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql index a26736707c..a042d80ba5 100644 --- a/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql +++ b/c/cert/src/rules/FLP30-C/FloatingPointLoopCounters.ql @@ -9,6 +9,11 @@ * maintainability * readability * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/low + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.ql b/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.ql index fc054d7289..1e87aa3fae 100644 --- a/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.ql +++ b/c/cert/src/rules/FLP32-C/UncheckedRangeDomainPoleErrors.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/flp32-c * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FLP34-C/UncheckedFloatingPointConversion.ql b/c/cert/src/rules/FLP34-C/UncheckedFloatingPointConversion.ql index 4637985076..eebc16afe3 100644 --- a/c/cert/src/rules/FLP34-C/UncheckedFloatingPointConversion.ql +++ b/c/cert/src/rules/FLP34-C/UncheckedFloatingPointConversion.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/flp34-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FLP36-C/IntToFloatPreservePrecision.ql b/c/cert/src/rules/FLP36-C/IntToFloatPreservePrecision.ql index e3b98c61c5..81e5670b11 100644 --- a/c/cert/src/rules/FLP36-C/IntToFloatPreservePrecision.ql +++ b/c/cert/src/rules/FLP36-C/IntToFloatPreservePrecision.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/flp36-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/FLP37-C/MemcmpUsedToCompareFloats.ql b/c/cert/src/rules/FLP37-C/MemcmpUsedToCompareFloats.ql index 0e3031262e..8735a804fa 100644 --- a/c/cert/src/rules/FLP37-C/MemcmpUsedToCompareFloats.ql +++ b/c/cert/src/rules/FLP37-C/MemcmpUsedToCompareFloats.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/flp37-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/INT30-C/UnsignedIntegerOperationsWrapAround.ql b/c/cert/src/rules/INT30-C/UnsignedIntegerOperationsWrapAround.ql index 1c7ae3e31b..c893584a1e 100644 --- a/c/cert/src/rules/INT30-C/UnsignedIntegerOperationsWrapAround.ql +++ b/c/cert/src/rules/INT30-C/UnsignedIntegerOperationsWrapAround.ql @@ -10,6 +10,11 @@ * @tags external/cert/id/int30-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/INT31-C/IntegerConversionCausesDataLoss.ql b/c/cert/src/rules/INT31-C/IntegerConversionCausesDataLoss.ql index 51ae704461..203e60a9e3 100644 --- a/c/cert/src/rules/INT31-C/IntegerConversionCausesDataLoss.ql +++ b/c/cert/src/rules/INT31-C/IntegerConversionCausesDataLoss.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/int31-c * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/INT32-C/SignedIntegerOverflow.ql b/c/cert/src/rules/INT32-C/SignedIntegerOverflow.ql index 4c781c4e50..2edee2e5c6 100644 --- a/c/cert/src/rules/INT32-C/SignedIntegerOverflow.ql +++ b/c/cert/src/rules/INT32-C/SignedIntegerOverflow.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/int32-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/INT33-C/DivOrRemByZero.ql b/c/cert/src/rules/INT33-C/DivOrRemByZero.ql index a5e34f13c4..6090e8842a 100644 --- a/c/cert/src/rules/INT33-C/DivOrRemByZero.ql +++ b/c/cert/src/rules/INT33-C/DivOrRemByZero.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/int33-c * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/INT34-C/ExprShiftedbyNegativeOrGreaterPrecisionOperand.ql b/c/cert/src/rules/INT34-C/ExprShiftedbyNegativeOrGreaterPrecisionOperand.ql index d6445d4937..4260a5e677 100644 --- a/c/cert/src/rules/INT34-C/ExprShiftedbyNegativeOrGreaterPrecisionOperand.ql +++ b/c/cert/src/rules/INT34-C/ExprShiftedbyNegativeOrGreaterPrecisionOperand.ql @@ -7,6 +7,11 @@ * @precision very-high * @problem.severity error * @tags external/cert/id/int34-c + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/INT35-C/UseCorrectIntegerPrecisions.ql b/c/cert/src/rules/INT35-C/UseCorrectIntegerPrecisions.ql index cf510bf999..1bc372506d 100644 --- a/c/cert/src/rules/INT35-C/UseCorrectIntegerPrecisions.ql +++ b/c/cert/src/rules/INT35-C/UseCorrectIntegerPrecisions.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/int35-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/INT36-C/ConvertingAPointerToIntegerOrIntegerToPointer.ql b/c/cert/src/rules/INT36-C/ConvertingAPointerToIntegerOrIntegerToPointer.ql index 3052f0aadd..1cbdcc4e12 100644 --- a/c/cert/src/rules/INT36-C/ConvertingAPointerToIntegerOrIntegerToPointer.ql +++ b/c/cert/src/rules/INT36-C/ConvertingAPointerToIntegerOrIntegerToPointer.ql @@ -7,6 +7,11 @@ * @precision very-high * @problem.severity error * @tags external/cert/id/int36-c + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MEM30-C/DoNotAccessFreedMemory.ql b/c/cert/src/rules/MEM30-C/DoNotAccessFreedMemory.ql index 800ec103ff..59ab0df670 100644 --- a/c/cert/src/rules/MEM30-C/DoNotAccessFreedMemory.ql +++ b/c/cert/src/rules/MEM30-C/DoNotAccessFreedMemory.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/mem30-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MEM31-C/FreeMemoryWhenNoLongerNeededCert.ql b/c/cert/src/rules/MEM31-C/FreeMemoryWhenNoLongerNeededCert.ql index d4c81748a2..18e9478aee 100644 --- a/c/cert/src/rules/MEM31-C/FreeMemoryWhenNoLongerNeededCert.ql +++ b/c/cert/src/rules/MEM31-C/FreeMemoryWhenNoLongerNeededCert.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/mem31-c * correctness * security + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql b/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql index f4483bd9fe..2ed5035ff0 100644 --- a/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql +++ b/c/cert/src/rules/MEM33-C/AllocStructsWithAFlexibleArrayMemberDynamically.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/mem33-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MEM33-C/CopyStructsWithAFlexibleArrayMemberDynamically.ql b/c/cert/src/rules/MEM33-C/CopyStructsWithAFlexibleArrayMemberDynamically.ql index b4993e2cae..b4d2a9127b 100644 --- a/c/cert/src/rules/MEM33-C/CopyStructsWithAFlexibleArrayMemberDynamically.ql +++ b/c/cert/src/rules/MEM33-C/CopyStructsWithAFlexibleArrayMemberDynamically.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/mem33-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MEM34-C/OnlyFreeMemoryAllocatedDynamicallyCert.ql b/c/cert/src/rules/MEM34-C/OnlyFreeMemoryAllocatedDynamicallyCert.ql index 95da1cc86a..78081944be 100644 --- a/c/cert/src/rules/MEM34-C/OnlyFreeMemoryAllocatedDynamicallyCert.ql +++ b/c/cert/src/rules/MEM34-C/OnlyFreeMemoryAllocatedDynamicallyCert.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/mem34-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MEM35-C/InsufficientMemoryAllocatedForObject.ql b/c/cert/src/rules/MEM35-C/InsufficientMemoryAllocatedForObject.ql index 5ff1725269..06fd267560 100644 --- a/c/cert/src/rules/MEM35-C/InsufficientMemoryAllocatedForObject.ql +++ b/c/cert/src/rules/MEM35-C/InsufficientMemoryAllocatedForObject.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/mem35-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql b/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql index df0eb3b1e3..5515bfc80d 100644 --- a/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql +++ b/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql @@ -9,6 +9,12 @@ * @tags external/cert/id/mem36-c * correctness * security + * external/cert/recommendation/mem36-c + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.ql b/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.ql index ed553b9814..722e6fff80 100644 --- a/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.ql +++ b/c/cert/src/rules/MSC30-C/RandUsedForGeneratingPseudorandomNumbers.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/msc30-c * security + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.ql b/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.ql index 2c3db87ee8..85623d9390 100644 --- a/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.ql +++ b/c/cert/src/rules/MSC32-C/ProperlySeedPseudorandomNumberGenerators.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/msc32-c * security + * external/cert/severity/medium + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql b/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql index fa4a29cb3d..67fa83e852 100644 --- a/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql +++ b/c/cert/src/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/msc33-c * security * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p27 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.ql b/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.ql index c56f3e48c1..265fc0af55 100644 --- a/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.ql +++ b/c/cert/src/rules/MSC37-C/ControlFlowReachesTheEndOfANonVoidFunction.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/msc37-c * correctness + * external/cert/severity/high + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MSC38-C/DoNotTreatAPredefinedIdentifierAsObject.ql b/c/cert/src/rules/MSC38-C/DoNotTreatAPredefinedIdentifierAsObject.ql index 76e9c4539f..828f86dd95 100644 --- a/c/cert/src/rules/MSC38-C/DoNotTreatAPredefinedIdentifierAsObject.ql +++ b/c/cert/src/rules/MSC38-C/DoNotTreatAPredefinedIdentifierAsObject.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/msc38-c * correctness * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql b/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql index 1c706a8e3f..56613c1943 100644 --- a/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql +++ b/c/cert/src/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/msc39-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.ql b/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.ql index 63dec179c6..746cea2e9f 100644 --- a/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.ql +++ b/c/cert/src/rules/MSC40-C/DoNotViolateInLineLinkageConstraints.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/msc40-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql b/c/cert/src/rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql index 7974c4d601..322048f6de 100644 --- a/c/cert/src/rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql +++ b/c/cert/src/rules/PRE31-C/SideEffectsInArgumentsToUnsafeMacros.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/pre31-c * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/PRE32-C/MacroOrFunctionArgsContainHashToken.ql b/c/cert/src/rules/PRE32-C/MacroOrFunctionArgsContainHashToken.ql index 9680bea813..0a777dc25d 100644 --- a/c/cert/src/rules/PRE32-C/MacroOrFunctionArgsContainHashToken.ql +++ b/c/cert/src/rules/PRE32-C/MacroOrFunctionArgsContainHashToken.ql @@ -10,6 +10,11 @@ * @tags external/cert/id/pre32-c * correctness * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql b/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql index 0da48daa70..4cc0f9e32c 100644 --- a/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql +++ b/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/sig30-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/SIG31-C/DoNotAccessSharedObjectsInSignalHandlers.ql b/c/cert/src/rules/SIG31-C/DoNotAccessSharedObjectsInSignalHandlers.ql index 2a7a6a77f2..eaa0a446b5 100644 --- a/c/cert/src/rules/SIG31-C/DoNotAccessSharedObjectsInSignalHandlers.ql +++ b/c/cert/src/rules/SIG31-C/DoNotAccessSharedObjectsInSignalHandlers.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/sig31-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/SIG34-C/DoNotCallSignalFromInterruptibleSignalHandlers.ql b/c/cert/src/rules/SIG34-C/DoNotCallSignalFromInterruptibleSignalHandlers.ql index d1eb773acb..0586c40c36 100644 --- a/c/cert/src/rules/SIG34-C/DoNotCallSignalFromInterruptibleSignalHandlers.ql +++ b/c/cert/src/rules/SIG34-C/DoNotCallSignalFromInterruptibleSignalHandlers.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/sig34-c * correctness * security + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.ql b/c/cert/src/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.ql index fa3cc3bf14..bd65019f98 100644 --- a/c/cert/src/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.ql +++ b/c/cert/src/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/sig35-c * correctness * security + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/high + * external/cert/priority/p1 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql index 244fe6d8e5..397e1bfc9e 100644 --- a/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql +++ b/c/cert/src/rules/STR30-C/DoNotAttemptToModifyStringLiterals.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/str30-c * correctness * security + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql index 3742207720..437b13f7f9 100644 --- a/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql +++ b/c/cert/src/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.ql @@ -10,6 +10,11 @@ * @tags external/cert/id/str31-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql index 8b9b23cd4c..723c8ee0ea 100644 --- a/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql +++ b/c/cert/src/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/str32-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql index 394df49d99..d814951b37 100644 --- a/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql +++ b/c/cert/src/rules/STR34-C/CastCharBeforeConvertingToLargerSizes.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/str34-c * correctness * security + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql index 8dda9012d2..a29dbd34b9 100644 --- a/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql +++ b/c/cert/src/rules/STR37-C/ToCharacterHandlingFunctionsRepresentableAsUChar.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/str37-c * correctness * security + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.ql b/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.ql index a45f7ec7e1..58b2b1c7dd 100644 --- a/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.ql +++ b/c/cert/src/rules/STR38-C/DoNotConfuseNarrowAndWideFunctions.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/str38-c * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p27 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql b/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql index 88232118bb..53f362e275 100644 --- a/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql +++ b/cpp/cert/src/rules/CON50-CPP/DoNotAllowAMutexToGoOutOfScopeWhileLocked.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con50-cpp * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.ql b/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.ql index 2f2f5a6cdb..c15dfca5fc 100644 --- a/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.ql +++ b/cpp/cert/src/rules/CON50-CPP/DoNotDestroyAMutexWhileItIsLocked.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/con50-cpp * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.ql b/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.ql index df17ec9a27..ac09d41c42 100644 --- a/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.ql +++ b/cpp/cert/src/rules/CON51-CPP/EnsureActivelyHeldLocksAreReleasedOnExceptionalConditions.ql @@ -10,6 +10,11 @@ * @tags external/cert/id/con51-cpp * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/low + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.ql b/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.ql index 49d5309113..9ca1a89525 100644 --- a/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.ql +++ b/cpp/cert/src/rules/CON52-CPP/PreventBitFieldAccessFromMultipleThreads.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con52-cpp * correctness * concurrency + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.ql b/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.ql index bbd075b930..d83b3d520b 100644 --- a/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.ql +++ b/cpp/cert/src/rules/CON53-CPP/DeadlockByLockingInPredefinedOrder.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con53-cpp * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql b/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql index 5584b7bec2..84255dbfc7 100644 --- a/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql +++ b/cpp/cert/src/rules/CON54-CPP/WrapFunctionsThatCanSpuriouslyWakeUpInLoop.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con54-cpp * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON55-CPP/PreserveSafetyWhenUsingConditionVariables.ql b/cpp/cert/src/rules/CON55-CPP/PreserveSafetyWhenUsingConditionVariables.ql index 05d73a4d9f..d4f43c7d09 100644 --- a/cpp/cert/src/rules/CON55-CPP/PreserveSafetyWhenUsingConditionVariables.ql +++ b/cpp/cert/src/rules/CON55-CPP/PreserveSafetyWhenUsingConditionVariables.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con55-cpp * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex.ql b/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex.ql index 94d23c8664..67edf2fc22 100644 --- a/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex.ql +++ b/cpp/cert/src/rules/CON56-CPP/DoNotSpeculativelyLockALockedNonRecursiveMutex.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con56-cpp * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/high + * external/cert/priority/p1 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.ql b/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.ql index 478a37af65..09ec2fa3d5 100644 --- a/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.ql +++ b/cpp/cert/src/rules/CON56-CPP/LockedALockedNonRecursiveMutexAudit.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/con56-cpp * correctness * concurrency + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/high + * external/cert/priority/p1 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.ql b/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.ql index a64e8fca2c..e5565ccbbb 100644 --- a/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.ql +++ b/cpp/cert/src/rules/CTR50-CPP/ContainerAccessWithoutRangeCheckCert.ql @@ -10,6 +10,11 @@ * @tags external/cert/id/ctr50-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess.ql b/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess.ql index 2163412435..0652f065cb 100644 --- a/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess.ql +++ b/cpp/cert/src/rules/CTR51-CPP/UsesValidContainerElementAccess.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/ctr51-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql b/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql index 9f49b43786..b022869136 100644 --- a/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql +++ b/cpp/cert/src/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/ctr52-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.ql b/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.ql index d0afb7754c..3702cbcd6e 100644 --- a/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.ql +++ b/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/ctr53-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.ql b/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.ql index f47f9db201..2401bcbf54 100644 --- a/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.ql +++ b/cpp/cert/src/rules/CTR54-CPP/DoNotSubtractIteratorsForDifferentContainers.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/ctr54-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.ql b/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.ql index ce1fb52667..3f2de63246 100644 --- a/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.ql +++ b/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/ctr55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql b/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql index 0f5c50164c..b4ac267225 100644 --- a/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql +++ b/cpp/cert/src/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/ctr56-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.ql b/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.ql index f28409bfc9..950ecd0c46 100644 --- a/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.ql +++ b/cpp/cert/src/rules/CTR57-CPP/ProvideAValidOrderingPredicate.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/ctr57-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.ql b/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.ql index be26725105..304b532b79 100644 --- a/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.ql +++ b/cpp/cert/src/rules/CTR58-CPP/PredicateFunctionObjectsShouldNotBeMutable.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/ctr58-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.ql b/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.ql index 368f154e22..b24988823c 100644 --- a/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.ql +++ b/cpp/cert/src/rules/DCL50-CPP/DoNotDefineACStyleVariadicFunction.ql @@ -9,6 +9,11 @@ * correctness * security * scope/single-translation-unit + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName.ql b/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName.ql index 074ae6ebfc..3f8ea668dd 100644 --- a/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName.ql +++ b/cpp/cert/src/rules/DCL51-CPP/EnumeratorReusesReservedName.ql @@ -10,6 +10,11 @@ * maintainability * readability * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.ql b/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.ql index 8cae916a9a..74d683a0cb 100644 --- a/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.ql +++ b/cpp/cert/src/rules/DCL51-CPP/FunctionReusesReservedName.ql @@ -10,6 +10,11 @@ * maintainability * readability * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.ql b/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.ql index 03e1ef7264..fabf036198 100644 --- a/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.ql +++ b/cpp/cert/src/rules/DCL51-CPP/ObjectReusesReservedName.ql @@ -10,6 +10,11 @@ * maintainability * readability * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.ql b/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.ql index 974b231c26..3aaf5d37cb 100644 --- a/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.ql +++ b/cpp/cert/src/rules/DCL51-CPP/RedefiningOfStandardLibraryName.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl51-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.ql b/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.ql index b32bdf70ba..583a768d22 100644 --- a/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.ql +++ b/cpp/cert/src/rules/DCL51-CPP/ReuseOfReservedIdentifier.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl51-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.ql b/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.ql index 472f0444ad..c85a7536e9 100644 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.ql +++ b/cpp/cert/src/rules/DCL51-CPP/UseOfDoubleUnderscoreReservedPrefix.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/dcl51-cpp * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.ql b/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.ql index eb2163f667..81036f6f57 100644 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.ql +++ b/cpp/cert/src/rules/DCL51-CPP/UseOfReservedLiteralSuffixIdentifier.ql @@ -10,6 +10,11 @@ * maintainability * readability * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.ql b/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.ql index e2f7270f9c..ed57351d6a 100644 --- a/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.ql +++ b/cpp/cert/src/rules/DCL51-CPP/UseOfSingleUnderscoreReservedPrefix.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/dcl51-cpp * maintainability * readability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.ql b/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.ql index f6fe18a3db..f576144c46 100644 --- a/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.ql +++ b/cpp/cert/src/rules/DCL53-CPP/LocalConstructorInitializedObjectHidesIdentifier.ql @@ -9,6 +9,11 @@ * @problem.severity warning * @tags external/cert/id/dcl53-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.ql b/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.ql index 368c0a05e4..45aa70dc31 100644 --- a/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.ql +++ b/cpp/cert/src/rules/DCL53-CPP/LocalFunctionDeclaration.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/dcl53-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.ql b/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.ql index 7f419397ee..8f168e90c8 100644 --- a/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.ql +++ b/cpp/cert/src/rules/DCL54-CPP/SingularOverloadOfMemoryFunction.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/dcl54-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/low + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries.ql b/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries.ql index cf301dfb5f..85b72afaeb 100644 --- a/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries.ql +++ b/cpp/cert/src/rules/DCL55-CPP/InformationLeakageAcrossTrustBoundaries.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl55-cpp * security + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/high + * external/cert/priority/p1 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.ql b/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.ql index 1ad411427f..4eb94f3d1d 100644 --- a/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.ql +++ b/cpp/cert/src/rules/DCL56-CPP/CyclesDuringStaticObjectInit.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/dcl56-cpp * correctness * maintainability + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions.ql b/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions.ql index 951169abe5..6f625fd308 100644 --- a/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions.ql +++ b/cpp/cert/src/rules/DCL57-CPP/DoNotLetExceptionsEscapeFromDestructorsOrDeallocationFunctions.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl57-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces.ql b/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces.ql index a0e94d083c..81242bc0f4 100644 --- a/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces.ql +++ b/cpp/cert/src/rules/DCL58-CPP/ModificationOfTheStandardNamespaces.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/dcl58-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.ql b/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.ql index 57dae96f09..2b8b364c7d 100644 --- a/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.ql +++ b/cpp/cert/src/rules/DCL59-CPP/UnnamedNamespaceInHeaderFile.ql @@ -10,6 +10,11 @@ * @problem.severity error * @tags external/cert/id/dcl59-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.ql b/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.ql index 7908609cc6..84e63a9569 100644 --- a/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.ql +++ b/cpp/cert/src/rules/DCL60-CPP/OneDefinitionRuleNotObeyed.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/dcl60-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/high + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert.ql b/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert.ql index 6c22010ef7..40a884fc5a 100644 --- a/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert.ql +++ b/cpp/cert/src/rules/ERR50-CPP/ConditionVariablePostConditionFailedCert.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/err50-cpp * correctness * external/cert/audit + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.ql b/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.ql index 9c312672e7..548b7b4b94 100644 --- a/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.ql +++ b/cpp/cert/src/rules/ERR50-CPP/ExitHandlerThrowsExceptionCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err50-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.ql b/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.ql index ddee05aecf..4fe89c634d 100644 --- a/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.ql +++ b/cpp/cert/src/rules/ERR50-CPP/ExplicitAbruptTerminationCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err50-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.ql b/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.ql index 015a5ffede..2036ff2f46 100644 --- a/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.ql +++ b/cpp/cert/src/rules/ERR50-CPP/JoinableThreadCopiedOrDestroyedCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err50-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.ql b/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.ql index 088cfe93b0..05d04de99e 100644 --- a/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.ql +++ b/cpp/cert/src/rules/ERR50-CPP/RethrowNestedWithoutCaptureCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err50-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.ql b/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.ql index 2811815821..f8447d4af5 100644 --- a/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.ql +++ b/cpp/cert/src/rules/ERR51-CPP/HandleAllExceptions.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err51-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.ql b/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.ql index 45e29d02ff..6c9cb2e436 100644 --- a/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.ql +++ b/cpp/cert/src/rules/ERR52-CPP/DoNotUseSetjmpOrLongjmp.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/err52-cpp * correctness * scope/single-translation-unit + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock.ql b/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock.ql index c45c3785e6..8587a73c33 100644 --- a/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock.ql +++ b/cpp/cert/src/rules/ERR53-CPP/DestroyedValueReferencedInConstructorDestructorCatchBlock.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/err53-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.ql b/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.ql index 8c4c5b5f06..c3e0aeb2f5 100644 --- a/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.ql +++ b/cpp/cert/src/rules/ERR54-CPP/CatchBlockShadowingCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err54-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications.ql b/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications.ql index 7d433e2480..4f35d3cd93 100644 --- a/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications.ql +++ b/cpp/cert/src/rules/ERR55-CPP/HonorExceptionSpecifications.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/err55-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.ql b/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.ql index b027d02e3f..5831a7f404 100644 --- a/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.ql +++ b/cpp/cert/src/rules/ERR56-CPP/GuaranteeExceptionSafety.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/err56-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/high + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.ql b/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.ql index e283ca8e95..6180bf2f83 100644 --- a/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.ql +++ b/cpp/cert/src/rules/ERR57-CPP/DoNotLeakResourcesWhenHandlingExceptions.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/err57-cpp * correctness * security + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting.ql b/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting.ql index 843b1f0964..ca6b6ae83f 100644 --- a/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting.ql +++ b/cpp/cert/src/rules/ERR58-CPP/HandleAllExceptionsThrownBeforeMainBeginsExecuting.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/err58-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries.ql b/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries.ql index 902d392c5f..e1c7af4030 100644 --- a/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries.ql +++ b/cpp/cert/src/rules/ERR59-CPP/DoNotThrowAnExceptionAcrossExecutionBoundaries.ql @@ -11,6 +11,11 @@ * @problem.severity error * @tags external/cert/id/err59-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible.ql b/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible.ql index 37a5fedd14..61a145c7a1 100644 --- a/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible.ql +++ b/cpp/cert/src/rules/ERR60-CPP/ExceptionObjectsMustBeNothrowCopyConstructible.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err60-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.ql b/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.ql index 29b879b5ea..8cc9c47854 100644 --- a/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.ql +++ b/cpp/cert/src/rules/ERR61-CPP/CatchExceptionsByLvalueReference.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err61-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.ql b/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.ql index 9c6f8120c5..e5451a0fc4 100644 --- a/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.ql +++ b/cpp/cert/src/rules/ERR62-CPP/DetectErrorsWhenConvertingAStringToANumber.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/err62-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql index 7bfb298d3d..960d04449e 100644 --- a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql +++ b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp50-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.ql b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.ql index 1ddb315506..4c268e9c7e 100644 --- a/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.ql +++ b/cpp/cert/src/rules/EXP50-CPP/DoNotDependOnTheOrderOfScalarObjectEvaluationForSideEffects.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp50-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql index e900d1b259..d0935cc798 100644 --- a/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql +++ b/cpp/cert/src/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp51-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.ql b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.ql index 217be3db6a..59745c2cd0 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.ql +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclTypeOperand.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp52-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.ql b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.ql index 93bb653c11..c9ced6825c 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.ql +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInDeclValExpression.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp52-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.ql b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.ql index a32aa1eb14..d8ed036a06 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.ql +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInNoExceptOperand.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp52-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.ql b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.ql index 4cc602362e..aa0b8ff23a 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.ql +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInSizeOfOperand.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp52-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.ql b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.ql index cc43a008d9..dc65dddcd1 100644 --- a/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.ql +++ b/cpp/cert/src/rules/EXP52-CPP/DoNotRelyOnSideEffectsInTypeIdOperand.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp52-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p3 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory.ql b/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory.ql index 47ee746038..9839fae0fd 100644 --- a/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory.ql +++ b/cpp/cert/src/rules/EXP53-CPP/DoNotReadUninitializedMemory.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/exp53-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.ql b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.ql index 4f72fc725a..534bb83796 100644 --- a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.ql +++ b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedAfterLifetimeCert.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/exp54-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.ql b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.ql index d97c002dbd..ea2349194b 100644 --- a/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.ql +++ b/cpp/cert/src/rules/EXP54-CPP/ObjectAccessedBeforeLifetimeCert.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/exp54-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert.ql b/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert.ql index 3c915191d4..68216f2e43 100644 --- a/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert.ql +++ b/cpp/cert/src/rules/EXP55-CPP/RemoveConstOrVolatileQualificationCert.ql @@ -8,6 +8,11 @@ * @problem.severity warning * @tags external/cert/id/exp55-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage.ql b/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage.ql index 23efb87e0b..d8460c58fa 100644 --- a/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage.ql +++ b/cpp/cert/src/rules/EXP56-CPP/FunctionWithMismatchedLanguageLinkage.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/exp56-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.ql b/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.ql index 4358f11b34..2a8345c05d 100644 --- a/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.ql +++ b/cpp/cert/src/rules/EXP57-CPP/CastOfPointerToIncompleteClass.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp57-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.ql b/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.ql index 8534885c9e..935218f78e 100644 --- a/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.ql +++ b/cpp/cert/src/rules/EXP57-CPP/DeletingPointerToIncompleteClass.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/exp57-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.ql b/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.ql index 5c7ef31a6f..b537fa34c5 100644 --- a/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.ql +++ b/cpp/cert/src/rules/EXP58-CPP/PassNonTrivialObjectToVaStart.ql @@ -9,6 +9,11 @@ * @problem.severity warning * @tags external/cert/id/exp58-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.ql b/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.ql index dab95c8303..1d34680261 100644 --- a/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.ql +++ b/cpp/cert/src/rules/EXP58-CPP/PassPromotablePrimitiveTypeToVaStart.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/exp58-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.ql b/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.ql index 0b9e0a9f99..ce340d63c8 100644 --- a/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.ql +++ b/cpp/cert/src/rules/EXP58-CPP/PassReferenceTypeToVaStart.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/exp58-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.ql b/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.ql index 8cda1c0851..7ece8faef6 100644 --- a/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.ql +++ b/cpp/cert/src/rules/EXP59-CPP/OffsetUsedOnInvalidTypeOrMember.ql @@ -7,6 +7,11 @@ * @problem.severity recommendation * @tags external/cert/id/exp59-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries.ql b/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries.ql index 8442e5eda1..ddd6fa0efc 100644 --- a/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries.ql +++ b/cpp/cert/src/rules/EXP60-CPP/DoNotPassANonstandardObjectAcrossBoundaries.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/exp60-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p12 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.ql b/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.ql index c57de9b2d1..1268d1c82b 100644 --- a/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.ql +++ b/cpp/cert/src/rules/EXP61-CPP/EscapingLambdaObjectWithCaptureByReference.ql @@ -10,6 +10,11 @@ * @tags external/cert/id/exp61-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference.ql b/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference.ql index 8487c78039..eb76ba6187 100644 --- a/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference.ql +++ b/cpp/cert/src/rules/EXP61-CPP/ReturningLambdaObjectWithCaptureByReference.ql @@ -10,6 +10,11 @@ * @tags external/cert/id/exp61-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.ql b/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.ql index 4b8b67368f..64bfb4673b 100644 --- a/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.ql +++ b/cpp/cert/src/rules/EXP62-CPP/MemcmpUsedToAccessObjectRepresentation.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp62-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.ql b/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.ql index 87f797bf25..0e8847257c 100644 --- a/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.ql +++ b/cpp/cert/src/rules/EXP62-CPP/MemcpyUsedToAccessObjectRepresentation.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp62-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation.ql b/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation.ql index 302410def1..a4ae635289 100644 --- a/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation.ql +++ b/cpp/cert/src/rules/EXP62-CPP/MemsetUsedToAccessObjectRepresentation.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/exp62-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.ql b/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.ql index 785d4b8b2b..48e534bfbb 100644 --- a/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.ql +++ b/cpp/cert/src/rules/EXP63-CPP/DoNotRelyOnTheValueOfAMovedFromObject.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/exp63-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition.ql b/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition.ql index e30168dc23..0333955f72 100644 --- a/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition.ql +++ b/cpp/cert/src/rules/FIO50-CPP/InterleavedInputOutputWithoutPosition.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/fio50-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.ql b/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.ql index 383fb9db1f..a444692594 100644 --- a/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.ql +++ b/cpp/cert/src/rules/FIO51-CPP/CloseFilesWhenTheyAreNoLongerNeeded.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/fio51-cpp * correctness * security + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.ql b/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.ql index f90d3a42ef..c7437073e9 100644 --- a/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.ql +++ b/cpp/cert/src/rules/INT50-CPP/DoNotCastToAnOutOfRangeEnumerationValue.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/int50-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM50-CPP/UseAfterFree.ql b/cpp/cert/src/rules/MEM50-CPP/UseAfterFree.ql index 59bf3e5bc7..8c31fc104c 100644 --- a/cpp/cert/src/rules/MEM50-CPP/UseAfterFree.ql +++ b/cpp/cert/src/rules/MEM50-CPP/UseAfterFree.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/mem50-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources.ql b/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources.ql index 5854b169f2..70fd363c64 100644 --- a/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources.ql +++ b/cpp/cert/src/rules/MEM51-CPP/ProperlyDeallocateDynamicallyAllocatedResources.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/mem51-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql b/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql index 083aad1e3c..90685f1c96 100644 --- a/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql +++ b/cpp/cert/src/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/mem52-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql index 5398aa04e1..a56fa18da8 100644 --- a/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql +++ b/cpp/cert/src/rules/MEM53-CPP/MissingConstructorCallForManuallyManagedObject.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/mem53-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql b/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql index 22e2ac336f..fe6fff2d4f 100644 --- a/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql +++ b/cpp/cert/src/rules/MEM53-CPP/MissingDestructorCallForManuallyManagedObject.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/mem53-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert.ql b/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert.ql index 695d39de69..fca9190552 100644 --- a/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert.ql +++ b/cpp/cert/src/rules/MEM54-CPP/PlacementNewInsufficientStorageCert.ql @@ -10,6 +10,11 @@ * @tags external/cert/id/mem54-cpp * security * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.ql b/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.ql index 4993de85ed..d623e85a50 100644 --- a/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.ql +++ b/cpp/cert/src/rules/MEM54-CPP/PlacementNewNotProperlyAlignedCert.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/mem54-cpp * security * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.ql b/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.ql index d3366f15fc..fd8f4f3a04 100644 --- a/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.ql +++ b/cpp/cert/src/rules/MEM55-CPP/OperatorDeleteMissingPartnerCert.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/mem55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.ql b/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.ql index 564d74c333..2740498eef 100644 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.ql +++ b/cpp/cert/src/rules/MEM55-CPP/ThrowingNoThrowOperatorNewDeleteCert.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/mem55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.ql b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.ql index c07dbff76c..072c69201f 100644 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.ql +++ b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewReturnsNullCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/mem55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert.ql b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert.ql index 0b02be8b3f..da4b63200b 100644 --- a/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert.ql +++ b/cpp/cert/src/rules/MEM55-CPP/ThrowingOperatorNewThrowsInvalidExceptionCert.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/mem55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert.ql b/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert.ql index 7fa3209151..ba7a39272a 100644 --- a/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert.ql +++ b/cpp/cert/src/rules/MEM56-CPP/OwnedPointerValueStoredInUnrelatedSmartPointerCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/mem56-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.ql b/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.ql index f8a5247ff1..6c3d18c27f 100644 --- a/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.ql +++ b/cpp/cert/src/rules/MEM57-CPP/UsingDefaultOperatorNewForOverAlignedTypes.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/mem57-cpp * correctness * security + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.ql b/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.ql index 8ab68974cb..b67cec99f3 100644 --- a/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.ql +++ b/cpp/cert/src/rules/MSC50-CPP/DoNotUseRandForGeneratingPseudorandomNumbers.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/msc50-cpp * security * scope/single-translation-unit + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.ql b/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.ql index 76f8500362..5322fbbde3 100644 --- a/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.ql +++ b/cpp/cert/src/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/msc51-cpp * security * correctness + * external/cert/severity/medium + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.ql b/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.ql index 9634592715..dcf42a78f4 100644 --- a/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.ql +++ b/cpp/cert/src/rules/MSC52-CPP/NonVoidFunctionDoesNotReturnCert.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/msc52-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p8 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert.ql b/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert.ql index 511369e46c..5044b3b421 100644 --- a/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert.ql +++ b/cpp/cert/src/rules/MSC53-CPP/FunctionNoReturnAttributeConditionCert.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/msc53-cpp * correctness + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/low + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.ql b/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.ql index a537346630..885d8caa0a 100644 --- a/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.ql +++ b/cpp/cert/src/rules/MSC54-CPP/SignalHandlerMustBeAPlainOldFunction.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/msc54-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors.ql b/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors.ql index 5cbcee6be9..1c3df97cfa 100644 --- a/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors.ql +++ b/cpp/cert/src/rules/OOP50-CPP/DoNotInvokeVirtualFunctionsFromConstructorsOrDestructors.ql @@ -7,6 +7,11 @@ * @precision very-high * @problem.severity error * @tags external/cert/id/oop50-cpp + * external/cert/severity/low + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.ql b/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.ql index f0af256fb9..4cb654730b 100644 --- a/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.ql +++ b/cpp/cert/src/rules/OOP51-CPP/DoNotSliceDerivedObjects.ql @@ -7,6 +7,11 @@ * @precision very-high * @problem.severity error * @tags external/cert/id/oop51-cpp + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.ql b/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.ql index 13bfdd5c0c..190c4d720d 100644 --- a/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.ql +++ b/cpp/cert/src/rules/OOP52-CPP/DoNotDeleteAPolymorphicObjectWithoutAVirtualDestructor.ql @@ -7,6 +7,11 @@ * @precision very-high * @problem.severity warning * @tags external/cert/id/oop52-cpp + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.ql b/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.ql index 96fd7812d7..b42b54ef6c 100644 --- a/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.ql +++ b/cpp/cert/src/rules/OOP53-CPP/UseCanonicalOrderForMemberInit.ql @@ -12,6 +12,11 @@ * security * maintainability * readability + * external/cert/severity/medium + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p4 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.ql b/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.ql index 85940bf862..844d0f54bb 100644 --- a/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.ql +++ b/cpp/cert/src/rules/OOP54-CPP/GracefullyHandleSelfCopyAssignment.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/oop54-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember.ql b/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember.ql index ead970ca71..27c63c2c16 100644 --- a/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember.ql +++ b/cpp/cert/src/rules/OOP55-CPP/MemberAccessWithUninitializedStaticPointerToMember.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/oop55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember.ql b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember.ql index 614d3fbaca..72d640f29b 100644 --- a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember.ql +++ b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessNonexistentMember.ql @@ -9,6 +9,11 @@ * @problem.severity error * @tags external/cert/id/oop55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember.ql b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember.ql index e6b8f10d9c..202123c11c 100644 --- a/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember.ql +++ b/cpp/cert/src/rules/OOP55-CPP/UseOfPointerToMemberToAccessUndefinedMember.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/oop55-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements.ql b/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements.ql index 18b259ef86..981bd1ce5b 100644 --- a/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements.ql +++ b/cpp/cert/src/rules/OOP56-CPP/HonorNewReplacementHandlerRequirements.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/oop56-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements.ql b/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements.ql index ea499791ff..4d59b36b52 100644 --- a/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements.ql +++ b/cpp/cert/src/rules/OOP56-CPP/HonorTerminationReplacementHandlerRequirements.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/oop56-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p2 + * external/cert/level/l3 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions.ql b/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions.ql index 19b14730bb..9ac17e84a0 100644 --- a/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions.ql +++ b/cpp/cert/src/rules/OOP57-CPP/PreferSpecialMemberFunctionsAndOverloadedOperatorsToCStandardLibraryFunctions.ql @@ -8,6 +8,11 @@ * @tags external/cert/id/oop57-cpp * correctness * scope/single-translation-unit + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.ql b/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.ql index 97cfe0fa3c..9ad0593702 100644 --- a/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.ql +++ b/cpp/cert/src/rules/OOP58-CPP/CopyOperationsMustNotMutateTheSourceObject.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/oop58-cpp * correctness + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/low + * external/cert/priority/p9 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert.ql b/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert.ql index 9ff12eca5c..2cd08be70a 100644 --- a/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert.ql +++ b/cpp/cert/src/rules/STR50-CPP/BasicStringMayNotBeNullTerminatedCert.ql @@ -7,6 +7,11 @@ * @precision very-high * @problem.severity recommendation * @tags external/cert/id/str50-cpp + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert.ql b/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert.ql index d79297a63b..59f56207cd 100644 --- a/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert.ql +++ b/cpp/cert/src/rules/STR50-CPP/OperationMayNotNullTerminateCStyleStringCert.ql @@ -7,6 +7,11 @@ * @precision very-high * @problem.severity recommendation * @tags external/cert/id/str50-cpp + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer.ql b/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer.ql index e775dc205f..a6337e2fcf 100644 --- a/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer.ql +++ b/cpp/cert/src/rules/STR51-CPP/DoNotAttemptToCreateAStringFromANullPointer.ql @@ -7,6 +7,11 @@ * @problem.severity error * @tags external/cert/id/str51-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/likely + * external/cert/remediation-cost/medium + * external/cert/priority/p18 + * external/cert/level/l1 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString.ql b/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString.ql index 211e490b33..21c29f54ef 100644 --- a/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString.ql +++ b/cpp/cert/src/rules/STR52-CPP/UseValidReferencesForElementsOfString.ql @@ -8,6 +8,11 @@ * @problem.severity error * @tags external/cert/id/str52-cpp * correctness + * external/cert/severity/high + * external/cert/likelihood/probable + * external/cert/remediation-cost/high + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ diff --git a/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess.ql b/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess.ql index 3300b77e18..c92f2b2316 100644 --- a/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess.ql +++ b/cpp/cert/src/rules/STR53-CPP/RangeCheckStringElementAccess.ql @@ -9,6 +9,11 @@ * @tags external/cert/id/str53-cpp * correctness * security + * external/cert/severity/high + * external/cert/likelihood/unlikely + * external/cert/remediation-cost/medium + * external/cert/priority/p6 + * external/cert/level/l2 * external/cert/obligation/rule */ From 54416547ef052258c37bb7db49f26fb84e6f0802 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 2 May 2025 11:04:59 +0100 Subject: [PATCH 375/628] Add query suites for levels 1 to 3. --- c/cert/src/codeql-suites/cert-c-l1.qls | 12 ++++++++++++ c/cert/src/codeql-suites/cert-c-l2.qls | 12 ++++++++++++ c/cert/src/codeql-suites/cert-c-l3.qls | 12 ++++++++++++ cpp/cert/src/codeql-suites/cert-cpp-l1.qls | 12 ++++++++++++ cpp/cert/src/codeql-suites/cert-cpp-l2.qls | 12 ++++++++++++ cpp/cert/src/codeql-suites/cert-cpp-l3.qls | 12 ++++++++++++ 6 files changed, 72 insertions(+) create mode 100644 c/cert/src/codeql-suites/cert-c-l1.qls create mode 100644 c/cert/src/codeql-suites/cert-c-l2.qls create mode 100644 c/cert/src/codeql-suites/cert-c-l3.qls create mode 100644 cpp/cert/src/codeql-suites/cert-cpp-l1.qls create mode 100644 cpp/cert/src/codeql-suites/cert-cpp-l2.qls create mode 100644 cpp/cert/src/codeql-suites/cert-cpp-l3.qls diff --git a/c/cert/src/codeql-suites/cert-c-l1.qls b/c/cert/src/codeql-suites/cert-c-l1.qls new file mode 100644 index 0000000000..b2056fbec8 --- /dev/null +++ b/c/cert/src/codeql-suites/cert-c-l1.qls @@ -0,0 +1,12 @@ +- description: CERT C 2016 Level 1 Rules (Priority 12 - Priority 27) +- qlpack: codeql/cert-c-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/rule + tags contain: + - external/cert/level/l1 +- exclude: + tags contain: + - external/cert/default-disabled \ No newline at end of file diff --git a/c/cert/src/codeql-suites/cert-c-l2.qls b/c/cert/src/codeql-suites/cert-c-l2.qls new file mode 100644 index 0000000000..9c0a4b1ef9 --- /dev/null +++ b/c/cert/src/codeql-suites/cert-c-l2.qls @@ -0,0 +1,12 @@ +- description: CERT C 2016 Level 2 Rules (Priority 6 - Priority 9) +- qlpack: codeql/cert-c-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/rule + tags contain: + - external/cert/level/l2 +- exclude: + tags contain: + - external/cert/default-disabled \ No newline at end of file diff --git a/c/cert/src/codeql-suites/cert-c-l3.qls b/c/cert/src/codeql-suites/cert-c-l3.qls new file mode 100644 index 0000000000..462a6d816f --- /dev/null +++ b/c/cert/src/codeql-suites/cert-c-l3.qls @@ -0,0 +1,12 @@ +- description: CERT C 2016 Level 3 Rules (Priority 1 - Priority 4) +- qlpack: codeql/cert-c-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/rule + tags contain: + - external/cert/level/l3 +- exclude: + tags contain: + - external/cert/default-disabled \ No newline at end of file diff --git a/cpp/cert/src/codeql-suites/cert-cpp-l1.qls b/cpp/cert/src/codeql-suites/cert-cpp-l1.qls new file mode 100644 index 0000000000..d96def2456 --- /dev/null +++ b/cpp/cert/src/codeql-suites/cert-cpp-l1.qls @@ -0,0 +1,12 @@ +- description: CERT C++ 2016 Level 1 Rules (Priority 12 - Priority 27) +- qlpack: codeql/cert-cpp-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/rule + tags contain: + - external/cert/level/l1 +- exclude: + tags contain: + - external/cert/default-disabled \ No newline at end of file diff --git a/cpp/cert/src/codeql-suites/cert-cpp-l2.qls b/cpp/cert/src/codeql-suites/cert-cpp-l2.qls new file mode 100644 index 0000000000..b08cb07536 --- /dev/null +++ b/cpp/cert/src/codeql-suites/cert-cpp-l2.qls @@ -0,0 +1,12 @@ +- description: CERT C++ 2016 Level 2 Rules (Priority 6 - Priority 9) +- qlpack: codeql/cert-cpp-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/rule + tags contain: + - external/cert/level/l2 +- exclude: + tags contain: + - external/cert/default-disabled \ No newline at end of file diff --git a/cpp/cert/src/codeql-suites/cert-cpp-l3.qls b/cpp/cert/src/codeql-suites/cert-cpp-l3.qls new file mode 100644 index 0000000000..ca621c96ab --- /dev/null +++ b/cpp/cert/src/codeql-suites/cert-cpp-l3.qls @@ -0,0 +1,12 @@ +- description: CERT C++ 2016 Level 3 Rules (Priority 1 - Priority 4) +- qlpack: codeql/cert-cpp-coding-standards +- include: + kind: + - problem + - path-problem + - external/cert/obligation/rule + tags contain: + - external/cert/level/l3 +- exclude: + tags contain: + - external/cert/default-disabled \ No newline at end of file From df44da0bf059d33abdedd6d4997631c13f617e31 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 2 May 2025 11:32:50 +0100 Subject: [PATCH 376/628] Add change note --- change_notes/2025-05-01-cert-extra-props.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change_notes/2025-05-01-cert-extra-props.md diff --git a/change_notes/2025-05-01-cert-extra-props.md b/change_notes/2025-05-01-cert-extra-props.md new file mode 100644 index 0000000000..3244360703 --- /dev/null +++ b/change_notes/2025-05-01-cert-extra-props.md @@ -0,0 +1,2 @@ + - All CERT rules now include additional tags to represent the [Risk Assessment](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RiskAssessment) properties specified on CERT rules. + - In addition, new query suites are included which allow the selection of queries that represent CERT Rules (not Recommendations) for each of the Levels (1-3). These are called `cert--.qls` and can be used either directly in the CodeQL CLI, or via the CodeQL Action. \ No newline at end of file From 9e24b41e85cbecee58cc3e333fbc3cd695134dfc Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 5 May 2025 15:47:32 +0100 Subject: [PATCH 377/628] Remove spurious recommendation tag In some of the CERT help files they use "Recommendation" rather than "Rule" as a header in the Risk Assessment table, creating spurious query tags. --- .../rules/CON34-C/AppropriateThreadObjectStorageDurations.ql | 1 - .../CON34-C/ThreadObjectStorageDurationsNotInitialized.ql | 1 - .../DoNotAccessVariableViaPointerOfIncompatibleType.ql | 1 - c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql | 1 - .../rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql | 1 - rule_packages/c/Concurrency4.json | 2 -- rule_packages/c/Memory2.json | 1 - rule_packages/c/Pointers3.json | 1 - rule_packages/c/SideEffects1.json | 1 - scripts/add_risk_assessment_tags.py | 4 ++-- 10 files changed, 2 insertions(+), 12 deletions(-) diff --git a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql index eef196a9ec..4fb034406b 100644 --- a/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql +++ b/c/cert/src/rules/CON34-C/AppropriateThreadObjectStorageDurations.ql @@ -9,7 +9,6 @@ * @tags external/cert/id/con34-c * correctness * concurrency - * external/cert/recommendation/con34-c * external/cert/severity/medium * external/cert/likelihood/probable * external/cert/remediation-cost/high diff --git a/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql b/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql index fa0587bce0..07b114d6ca 100644 --- a/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql +++ b/c/cert/src/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.ql @@ -10,7 +10,6 @@ * external/cert/audit * correctness * concurrency - * external/cert/recommendation/con34-c * external/cert/severity/medium * external/cert/likelihood/probable * external/cert/remediation-cost/high diff --git a/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql b/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql index c5772340ef..856cad1d58 100644 --- a/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql +++ b/c/cert/src/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.ql @@ -8,7 +8,6 @@ * @problem.severity error * @tags external/cert/id/exp39-c * correctness - * external/cert/recommendation/exp39-c * external/cert/severity/medium * external/cert/likelihood/unlikely * external/cert/remediation-cost/high diff --git a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql index 5478bb03f7..c831713486 100644 --- a/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql +++ b/c/cert/src/rules/EXP45-C/AssignmentsInSelectionStatements.ql @@ -8,7 +8,6 @@ * @problem.severity error * @tags external/cert/id/exp45-c * correctness - * external/cert/recommendation/exp45-c * external/cert/severity/low * external/cert/likelihood/likely * external/cert/remediation-cost/medium diff --git a/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql b/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql index 5515bfc80d..90c34a44a2 100644 --- a/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql +++ b/c/cert/src/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.ql @@ -9,7 +9,6 @@ * @tags external/cert/id/mem36-c * correctness * security - * external/cert/recommendation/mem36-c * external/cert/severity/low * external/cert/likelihood/probable * external/cert/remediation-cost/high diff --git a/rule_packages/c/Concurrency4.json b/rule_packages/c/Concurrency4.json index 45f4b495fc..b981ebaa8b 100644 --- a/rule_packages/c/Concurrency4.json +++ b/rule_packages/c/Concurrency4.json @@ -43,7 +43,6 @@ "tags": [ "correctness", "concurrency", - "external/cert/recommendation/con34-c", "external/cert/severity/medium", "external/cert/likelihood/probable", "external/cert/remediation-cost/high", @@ -65,7 +64,6 @@ "external/cert/audit", "correctness", "concurrency", - "external/cert/recommendation/con34-c", "external/cert/severity/medium", "external/cert/likelihood/probable", "external/cert/remediation-cost/high", diff --git a/rule_packages/c/Memory2.json b/rule_packages/c/Memory2.json index 9f475e4df8..55a7dd2a35 100644 --- a/rule_packages/c/Memory2.json +++ b/rule_packages/c/Memory2.json @@ -177,7 +177,6 @@ "tags": [ "correctness", "security", - "external/cert/recommendation/mem36-c", "external/cert/severity/low", "external/cert/likelihood/probable", "external/cert/remediation-cost/high", diff --git a/rule_packages/c/Pointers3.json b/rule_packages/c/Pointers3.json index f00018b1ad..8a169b71a8 100644 --- a/rule_packages/c/Pointers3.json +++ b/rule_packages/c/Pointers3.json @@ -65,7 +65,6 @@ "short_name": "DoNotAccessVariableViaPointerOfIncompatibleType", "tags": [ "correctness", - "external/cert/recommendation/exp39-c", "external/cert/severity/medium", "external/cert/likelihood/unlikely", "external/cert/remediation-cost/high", diff --git a/rule_packages/c/SideEffects1.json b/rule_packages/c/SideEffects1.json index 7e0ab9c90b..4dec3d8bbf 100644 --- a/rule_packages/c/SideEffects1.json +++ b/rule_packages/c/SideEffects1.json @@ -78,7 +78,6 @@ "short_name": "AssignmentsInSelectionStatements", "tags": [ "correctness", - "external/cert/recommendation/exp45-c", "external/cert/severity/low", "external/cert/likelihood/likely", "external/cert/remediation-cost/medium", diff --git a/scripts/add_risk_assessment_tags.py b/scripts/add_risk_assessment_tags.py index f2ed9a5a73..6560d82a44 100644 --- a/scripts/add_risk_assessment_tags.py +++ b/scripts/add_risk_assessment_tags.py @@ -123,8 +123,8 @@ def process_rule_package(rule_package_file): # Add each risk assessment property as a tag for key, value in risk_data.items(): key_sanitized = key.lower().replace(" ", "-") - if key_sanitized == "rule": - # skip rule, as that is already in the rule ID + if key_sanitized == "rule" or key_sanitized == "recommendation": + # skip rule/recommendation as they just repeat the rule ID continue tag = f"external/cert/{key_sanitized}/{value.lower()}" if tag not in query["tags"]: From 44617e8d78b44bf7dd8ae0258751eb4fc33753db Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 5 May 2025 22:16:18 +0100 Subject: [PATCH 378/628] Update expected results for query file changes Deprecation warning lists location in query file, which has changed due to addition of new tags. --- ...bleLengthArraySizeNotInValidRange.expected | 4 +- ...rithmeticOnNonArrayObjectPointers.expected | 10 ++-- ...rSubtractAScaledIntegerToAPointer.expected | 8 ++-- .../CleanUpThreadSpecificStorage.expected | 12 ++--- ...riateThreadObjectStorageDurations.expected | 26 +++++----- ...ectStorageDurationsNotInitialized.expected | 10 ++-- ...ateStorageDurationsFunctionReturn.expected | 10 ++-- .../ERR30-C/ErrnoReadBeforeReturn.expected | 2 +- .../ERR30-C/SetlocaleMightSetErrno.expected | 2 +- ...tRelyOnIndeterminateValuesOfErrno.expected | 8 ++-- ...ectAndHandleStandardLibraryErrors.expected | 2 +- ...OfFunctionArgumentsForSideEffects.expected | 48 +++++++++---------- ...rToMoreStrictlyAlignedPointerType.expected | 20 ++++---- ...nctionPointerWithIncompatibleType.expected | 8 ++-- ...iableViaPointerOfIncompatibleType.expected | 14 +++--- .../DoNotModifyConstantObjects.expected | 8 ++-- ...ointerReferencesOverlappingObject.expected | 14 +++--- ...esetStringsOnFgetsOrFgetwsFailure.expected | 6 +-- ...FsetposThatAreReturnedFromFgetpos.expected | 10 ++-- ...RaceConditionsWhileAccessingFiles.expected | 2 +- ...ufficientMemoryAllocatedForObject.expected | 4 +- ...odifyAlignmentOfMemoryWithRealloc.expected | 10 ++-- ...ssInvalidDataToTheAsctimeFunction.expected | 8 ++-- ...VaListThatHasAnIndeterminateValue.expected | 14 +++--- ...SafeFunctionsWithinSignalHandlers.expected | 6 +-- ...romAComputationalExceptionHandler.expected | 2 +- ...oNotAttemptToModifyStringLiterals.expected | 26 +++++----- ...fficientSpaceForTheNullTerminator.expected | 12 ++--- ...natedToFunctionThatExpectsAString.expected | 20 ++++---- ...cCppLibraryFunctionsDoNotOverflow.expected | 18 +++---- .../CTR53-CPP/UseValidIteratorRanges.expected | 12 ++--- ...UseAnAdditiveOperatorOnAnIterator.expected | 18 +++---- ...terArithmeticOnPolymorphicObjects.expected | 8 ++-- ...nFunctionCallsAsFunctionArguments.expected | 48 +++++++++---------- ...ThroughAPointerOfTheIncorrectType.expected | 8 ++-- ...ctAndHandleMemoryAllocationErrors.expected | 14 +++--- .../BadlySeededRandomNumberGenerator.expected | 2 +- 37 files changed, 227 insertions(+), 227 deletions(-) diff --git a/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected b/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected index 083e7dfb87..0b400c5256 100644 --- a/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected +++ b/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected @@ -1,5 +1,5 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:104,11-19) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:87,5-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:109,11-19) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:92,5-18) | test.c:14:8:14:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | | test.c:15:8:15:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | | test.c:16:8:16:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | diff --git a/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected b/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected index ca4ef2a7a0..fb0074e0e6 100644 --- a/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected +++ b/c/cert/test/rules/ARR37-C/DoNotUsePointerArithmeticOnNonArrayObjectPointers.expected @@ -1,8 +1,8 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:23,60-68) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:24,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:36,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:44,26-34) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:65,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:28,60-68) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:29,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:41,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:49,26-34) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnNonArrayObjectPointers.ql:70,3-11) edges | test.c:14:38:14:39 | p1 | test.c:18:10:18:11 | v1 | provenance | | | test.c:14:38:14:39 | p1 | test.c:19:10:19:11 | v2 | provenance | | diff --git a/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected b/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected index d343811aaf..0a6471deac 100644 --- a/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected +++ b/c/cert/test/rules/ARR39-C/DoNotAddOrSubtractAScaledIntegerToAPointer.expected @@ -1,7 +1,7 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:72,56-64) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:73,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:75,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:84,45-53) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:77,56-64) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:78,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:80,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAddOrSubtractAScaledIntegerToAPointer.ql:89,45-53) edges | test.c:7:13:7:14 | p1 | test.c:9:9:9:10 | p1 | provenance | | | test.c:16:19:16:41 | ... - ... | test.c:18:26:18:31 | offset | provenance | | diff --git a/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected b/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected index 047ed12e8e..f3ea87136a 100644 --- a/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected +++ b/c/cert/test/rules/CON30-C/CleanUpThreadSpecificStorage.expected @@ -1,9 +1,9 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:20,46-54) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:21,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:30,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:40,35-43) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:48,36-44) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:50,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:25,46-54) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:26,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:35,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:45,35-43) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:53,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CleanUpThreadSpecificStorage.ql:55,36-44) | test.c:27:3:27:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | | test.c:49:3:49:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | | test.c:71:3:71:12 | call to tss_create | Resources used by thread specific storage may not be cleaned up. | diff --git a/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected b/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected index 503a01bdad..2cd844f81b 100644 --- a/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected +++ b/c/cert/test/rules/CON34-C/AppropriateThreadObjectStorageDurations.expected @@ -1,16 +1,16 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:30,14-22) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:32,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:34,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:37,45-53) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:47,33-41) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:47,58-66) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:48,42-50) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:51,9-17) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:51,34-42) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:52,9-17) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:52,34-42) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:37,9-22) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:47,7-20) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:35,14-22) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:37,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:39,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:42,45-53) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:52,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:52,58-66) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:53,42-50) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:56,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:56,34-42) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:57,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:57,34-42) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:42,9-22) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (AppropriateThreadObjectStorageDurations.ql:52,7-20) | test.c:23:3:23:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:23:24:23:29 | & ... | Shared object | | test.c:74:3:74:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:74:24:74:24 | p | Shared object | | test.c:85:3:85:13 | call to thrd_create | $@ not declared with appropriate storage duration | test.c:85:24:85:24 | p | Shared object | diff --git a/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected b/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected index f8e86fbb51..b2ac853fbf 100644 --- a/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected +++ b/c/cert/test/rules/CON34-C/ThreadObjectStorageDurationsNotInitialized.expected @@ -1,6 +1,6 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:27,38-46) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:30,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:30,30-38) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:31,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:31,30-38) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:32,38-46) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:35,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:35,30-38) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:36,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ThreadObjectStorageDurationsNotInitialized.ql:36,30-38) | test.c:14:7:14:13 | call to tss_get | Call to a thread specific storage function from within a threaded context on an object that may not be owned by this thread. | diff --git a/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected b/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected index f60689dbb1..a4359d7000 100644 --- a/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected +++ b/c/cert/test/rules/DCL30-C/AppropriateStorageDurationsFunctionReturn.expected @@ -1,7 +1,7 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:28,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:32,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:45,6-14) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:45,26-34) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:51,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:33,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:37,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:50,6-14) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:50,26-34) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (AppropriateStorageDurationsFunctionReturn.ql:56,3-11) | test.c:3:10:3:10 | a | $@ with automatic storage may be accessible outside of its lifetime. | test.c:3:10:3:10 | a | a | | test.c:15:4:15:8 | param [inner post update] | $@ with automatic storage may be accessible outside of its lifetime. | test.c:15:12:15:13 | a2 | a2 | diff --git a/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected b/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected index e925901b47..125f55118b 100644 --- a/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected +++ b/c/cert/test/rules/ERR30-C/ErrnoReadBeforeReturn.expected @@ -1,4 +1,4 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ErrnoReadBeforeReturn.ql:41,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ErrnoReadBeforeReturn.ql:46,7-15) | test.c:69:7:69:11 | * ... | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | | test.c:69:7:69:11 | call to __errno_location | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | | test.c:70:5:70:10 | call to perror | Do not read `errno` before checking the return value of function $@. | test.c:68:3:68:7 | call to ftell | call to ftell | diff --git a/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected b/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected index 489bfc6bb0..20a7ff60b1 100644 --- a/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected +++ b/c/cert/test/rules/ERR30-C/SetlocaleMightSetErrno.expected @@ -1,3 +1,3 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (SetlocaleMightSetErrno.ql:65,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (SetlocaleMightSetErrno.ql:70,7-15) | test.c:98:3:98:11 | call to setlocale | Do not read `errno` before checking the return value of a call to `setlocale`. | | test.c:104:7:104:15 | call to setlocale | The value of `errno` may be different than `0` when `setlocale` is called. The following `errno` check might be invalid. | diff --git a/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected b/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected index a90dd6b7f5..1f313cb90d 100644 --- a/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected +++ b/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected @@ -1,7 +1,7 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:50,7-15) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:50,27-35) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:51,9-17) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:54,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:55,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:55,27-35) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:56,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:59,9-17) | test.c:12:5:12:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:10:21:10:26 | call to signal | call to signal | | test.c:30:5:30:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:26:21:26:26 | call to signal | call to signal | | test.c:49:5:49:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:45:21:45:26 | call to signal | call to signal | diff --git a/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected b/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected index 030596976e..b13f34522c 100644 --- a/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected +++ b/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected @@ -1,4 +1,4 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleStandardLibraryErrors.ql:453,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleStandardLibraryErrors.ql:458,5-13) | test.c:18:3:18:11 | call to setlocale | Missing error detection for the call to function `setlocale`. | | test.c:24:23:24:31 | call to setlocale | Missing error detection for the call to function `setlocale`. | | test.c:29:22:29:27 | call to calloc | Missing error detection for the call to function `calloc`. | diff --git a/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected index ec791fe3e4..034f7e9366 100644 --- a/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected +++ b/c/cert/test/rules/EXP30-C/DependenceOnOrderOfFunctionArgumentsForSideEffects.expected @@ -1,25 +1,25 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:23,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:23,59-67) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:26,33-41) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:26,57-65) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:30,33-41) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:30,59-67) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:39,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:39,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:39,53-61) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:42,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:42,57-65) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:51,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:51,55-63) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:58,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:58,57-65) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:70,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:70,55-63) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:23,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:26,7-20) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:30,7-20) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:42,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:51,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:58,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:70,5-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:28,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:28,59-67) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:35,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:35,59-67) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:44,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:44,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:44,53-61) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:47,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:47,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:56,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:56,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:63,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:63,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:75,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:75,55-63) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:28,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:31,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:35,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:47,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:56,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:63,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DependenceOnOrderOfFunctionArgumentsForSideEffects.ql:75,5-18) | test.c:20:3:20:4 | call to f1 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.c:20:6:20:7 | call to f2 | call to f2 | test.c:20:12:20:13 | call to f3 | call to f3 | diff --git a/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected b/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected index eed9fb4585..eb7642ae28 100644 --- a/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected +++ b/c/cert/test/rules/EXP36-C/DoNotCastPointerToMoreStrictlyAlignedPointerType.expected @@ -1,13 +1,13 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:98,86-94) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:120,3-11) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:122,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:127,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:133,3-11) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:139,55-63) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:140,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:142,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:149,26-34) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:164,44-52) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:103,86-94) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:125,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:127,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:132,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:138,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:144,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:145,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:147,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:154,26-34) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCastPointerToMoreStrictlyAlignedPointerType.ql:169,44-52) edges | test.c:75:14:75:16 | & ... | test.c:76:11:76:12 | v1 | provenance | | | test.c:75:14:75:16 | & ... | test.c:77:12:77:13 | v1 | provenance | | diff --git a/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected b/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected index 229bd74165..8daaf8361a 100644 --- a/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected +++ b/c/cert/test/rules/EXP37-C/DoNotCallFunctionPointerWithIncompatibleType.expected @@ -1,7 +1,7 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:40,54-62) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:41,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:45,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:50,43-51) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:45,54-62) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:46,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:50,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallFunctionPointerWithIncompatibleType.ql:55,43-51) edges | test.c:48:68:48:70 | fns [f1] | test.c:49:3:49:5 | fns [f1] | provenance | | | test.c:49:3:49:5 | fns [f1] | test.c:49:8:49:9 | f1 | provenance | | diff --git a/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected b/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected index 9f0880455f..381e409d2a 100644 --- a/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected +++ b/c/cert/test/rules/EXP39-C/DoNotAccessVariableViaPointerOfIncompatibleType.expected @@ -1,10 +1,10 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:61,38-46) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:64,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:69,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:102,23-31) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:111,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:111,45-53) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:133,27-35) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:66,38-46) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:69,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:74,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:107,23-31) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:116,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:116,45-53) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAccessVariableViaPointerOfIncompatibleType.ql:138,27-35) edges | test.c:49:8:49:9 | s3 | test.c:50:8:50:9 | s1 | provenance | | | test.c:60:16:60:18 | E1A | test.c:61:16:61:17 | e1 | provenance | | diff --git a/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected b/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected index 6dd4ec261a..2ac874e770 100644 --- a/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected +++ b/c/cert/test/rules/EXP40-C/DoNotModifyConstantObjects.expected @@ -1,7 +1,7 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:35,30-38) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:36,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:42,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:47,19-27) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:40,30-38) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:41,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:47,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyConstantObjects.ql:52,19-27) edges | test.c:5:8:5:9 | & ... | test.c:6:4:6:5 | aa | provenance | | | test.c:26:15:26:15 | a | test.c:27:4:27:4 | a | provenance | | diff --git a/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected b/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected index b9765e77fb..40009edc03 100644 --- a/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected +++ b/c/cert/test/rules/EXP43-C/RestrictPointerReferencesOverlappingObject.expected @@ -1,10 +1,10 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:42,57-65) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:43,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:47,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:53,3-11) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:56,58-66) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:72,64-72) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:73,64-72) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:47,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:48,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:52,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:58,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:61,58-66) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:77,64-72) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (RestrictPointerReferencesOverlappingObject.ql:78,64-72) | test.c:18:22:18:23 | i2 | Assignment to restrict-qualified pointer $@ results in pointers aliasing $@. | test.c:18:17:18:18 | i3 | i3 | test.c:18:22:18:23 | i2 | the object pointed to by i2 | | test.c:19:8:19:9 | g2 | Assignment to restrict-qualified pointer $@ results in pointers aliasing $@. | test.c:5:15:5:16 | g1 | g1 | test.c:19:8:19:9 | g2 | the object pointed to by g2 | | test.c:20:8:20:9 | i2 | Assignment to restrict-qualified pointer $@ results in pointers aliasing $@. | test.c:16:17:16:18 | i1 | i1 | test.c:20:8:20:9 | i2 | the object pointed to by i2 | diff --git a/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected b/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected index 669dd829c8..7d3cbe355b 100644 --- a/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected +++ b/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected @@ -1,6 +1,6 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:42,11-19) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:42,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:43,13-21) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:47,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:47,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:48,13-21) | test.c:20:10:20:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:15:7:15:11 | call to fgets | call to fgets | | test.c:57:10:57:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:52:7:52:11 | call to fgets | call to fgets | | test.c:66:18:66:20 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:61:7:61:11 | call to fgets | call to fgets | diff --git a/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected b/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected index 5bff6016e4..ec05727161 100644 --- a/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected +++ b/c/cert/test/rules/FIO44-C/OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.expected @@ -1,7 +1,7 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:25,32-40) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:26,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:28,14-22) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:31,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:37,21-29) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:30,32-40) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:31,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:33,14-22) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:36,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (OnlyUseValuesForFsetposThatAreReturnedFromFgetpos.ql:42,21-29) | test.c:7:24:7:30 | & ... | The position argument of a call to `fsetpos()` should be obtained from a call to `fgetpos()`. | | test.c:33:24:33:30 | & ... | The position argument of a call to `fsetpos()` should be obtained from a call to `fgetpos()`. | diff --git a/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected b/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected index 71df14e907..a211aa4002 100644 --- a/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected +++ b/c/cert/test/rules/FIO45-C/ToctouRaceConditionsWhileAccessingFiles.expected @@ -1,3 +1,3 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ToctouRaceConditionsWhileAccessingFiles.ql:27,35-43) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ToctouRaceConditionsWhileAccessingFiles.ql:32,35-43) | test.c:4:13:4:17 | call to fopen | This call is trying to prevent an existing file from being overwritten by $@. An attacker might be able to exploit the race window between the two calls. | test.c:11:9:11:13 | call to fopen | another call | | test.c:88:13:88:17 | call to fopen | This call is trying to prevent an existing file from being overwritten by $@. An attacker might be able to exploit the race window between the two calls. | test.c:95:9:95:13 | call to fopen | another call | diff --git a/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected b/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected index 6bfbbefc14..86bdeedf5f 100644 --- a/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected +++ b/c/cert/test/rules/MEM35-C/InsufficientMemoryAllocatedForObject.expected @@ -1,5 +1,5 @@ -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (InsufficientMemoryAllocatedForObject.ql:85,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (InsufficientMemoryAllocatedForObject.ql:143,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (InsufficientMemoryAllocatedForObject.ql:90,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (InsufficientMemoryAllocatedForObject.ql:148,5-18) | test.c:12:19:12:24 | call to malloc | Allocation size (32 bytes) is not a multiple of the size of 'S1' (36 bytes). | test.c:12:26:12:32 | 32 | | | test.c:15:19:15:24 | call to malloc | Allocation size calculated from the size of a different type ($@). | test.c:15:26:15:35 | sizeof() | sizeof(S1 *) | | test.c:20:19:20:24 | call to malloc | Allocation size (128 bytes) is not a multiple of the size of 'S1' (36 bytes). | test.c:20:26:20:36 | ... * ... | | diff --git a/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected b/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected index 2f5889c4c6..587ae786d1 100644 --- a/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected +++ b/c/cert/test/rules/MEM36-C/DoNotModifyAlignmentOfMemoryWithRealloc.expected @@ -1,8 +1,8 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:26,36-44) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:40,47-55) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:41,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:45,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:50,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:31,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:45,47-55) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:46,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:50,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotModifyAlignmentOfMemoryWithRealloc.ql:55,36-44) edges | test.c:5:10:5:22 | call to aligned_alloc | test.c:15:8:15:28 | call to aligned_alloc_wrapper | provenance | | | test.c:8:29:8:31 | ptr | test.c:8:64:8:66 | ptr | provenance | | diff --git a/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected b/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected index 853d999d4e..7ebeb7a8c1 100644 --- a/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected +++ b/c/cert/test/rules/MSC33-C/DoNotPassInvalidDataToTheAsctimeFunction.expected @@ -1,5 +1,5 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:33,38-46) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:34,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:41,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:44,27-35) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:38,38-46) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:39,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:46,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotPassInvalidDataToTheAsctimeFunction.ql:49,27-35) | test.c:6:24:6:30 | time_tm | The function `asctime` and `asctime_r` should be discouraged. Unsanitized input can overflow the output buffer. | diff --git a/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected b/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected index 4eaa05b179..4e14eb2873 100644 --- a/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected +++ b/c/cert/test/rules/MSC39-C/DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.expected @@ -1,10 +1,10 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:38,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:39,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:44,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:47,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:68,10-18) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:69,29-37) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:70,29-37) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:43,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:44,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:49,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:52,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:73,10-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:74,29-37) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotCallVaArgOnAVaListThatHasAnIndeterminateValue.ql:75,29-37) | test.c:23:32:23:33 | ap | The value of ap is indeterminate after the $@. | test.c:17:7:17:19 | call to contains_zero | call to contains_zero | | test.c:26:10:26:11 | ap | The value of ap is indeterminate after the $@. | test.c:17:7:17:19 | call to contains_zero | call to contains_zero | | test.c:39:12:39:13 | ap | The value of ap is indeterminate after the $@. | test.c:35:7:35:19 | call to contains_zero | call to contains_zero | diff --git a/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected b/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected index 6190259408..4898448814 100644 --- a/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected +++ b/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected @@ -1,6 +1,6 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:105,11-19) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:105,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:106,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:110,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:110,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:111,9-17) | test.c:10:3:10:18 | call to log_local_unsafe | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:16:7:16:12 | call to signal | signal handler | | test.c:11:3:11:6 | call to free | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:16:7:16:12 | call to signal | signal handler | | test.c:46:3:46:9 | call to longjmp | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:50:7:50:12 | call to signal | signal handler | diff --git a/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected b/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected index e861e90e9e..fb78049d25 100644 --- a/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected +++ b/c/cert/test/rules/SIG35-C/DoNotReturnFromAComputationalExceptionHandler.expected @@ -1,2 +1,2 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotReturnFromAComputationalExceptionHandler.ql:39,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotReturnFromAComputationalExceptionHandler.ql:44,5-13) | test.c:10:1:10:1 | return ... | Do not return from a $@ signal handler. | test.c:13:10:13:15 | SIGFPE | computational exception | diff --git a/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected b/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected index 2a45193a17..d95b48e1c3 100644 --- a/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected +++ b/c/cert/test/rules/STR30-C/DoNotAttemptToModifyStringLiterals.expected @@ -1,18 +1,18 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:42,65-73) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:43,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:64,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:77,3-11) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:101,11-19) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:101,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:101,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:47,65-73) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:48,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:69,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:82,3-11) WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,11-19) WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,57-65) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:139,11-19) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:139,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:139,55-63) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:150,53-61) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:151,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:106,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:111,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:111,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:111,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:144,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:144,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:144,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:155,53-61) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotAttemptToModifyStringLiterals.ql:156,5-13) | test.c:7:3:7:3 | a | This operation may write to a string that may be a string literal that was $@. | test.c:6:13:6:20 | codeql | created here | | test.c:30:3:30:3 | a | This operation may write to a string that may be a string literal that was $@. | test.c:29:13:29:18 | call to strchr | created here | | test.c:36:3:36:3 | b | This operation may write to a string that may be a string literal that was $@. | test.c:35:13:35:18 | call to strchr | created here | diff --git a/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected b/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected index 9012a2d78a..9a87a6775b 100644 --- a/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected +++ b/c/cert/test/rules/STR31-C/StringsHasSufficientSpaceForTheNullTerminator.expected @@ -1,9 +1,9 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:57,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:57,55-63) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:63,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:63,54-62) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:57,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:63,5-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:62,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:62,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:68,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:68,54-62) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:62,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (StringsHasSufficientSpaceForTheNullTerminator.ql:68,5-18) | test.c:10:20:10:24 | Cod | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | | test.c:16:3:16:9 | call to strncpy | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | | test.c:26:3:26:10 | call to snprintf | Expression produces or consumes a string that may not have sufficient space for a null-terminator. | diff --git a/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected b/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected index da86e69b88..f537cc72ac 100644 --- a/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected +++ b/c/cert/test/rules/STR32-C/NonNullTerminatedToFunctionThatExpectsAString.expected @@ -1,13 +1,13 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:64,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:66,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:74,39-47) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:75,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:81,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:83,34-42) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:83,57-65) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:123,3-11) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:123,26-34) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:120,17-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:69,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:71,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:79,39-47) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:80,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:86,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:88,34-42) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:88,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:128,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:128,26-34) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (NonNullTerminatedToFunctionThatExpectsAString.ql:125,17-30) | test.c:20:3:20:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:8:20:8:24 | Cod | this expression | | test.c:21:3:21:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:8:20:8:24 | Cod | this expression | | test.c:23:3:23:8 | call to printf | String modified by $@ is passed to function expecting a null-terminated string. | test.c:14:3:14:9 | call to strncpy | this expression | diff --git a/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected b/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected index 209d81ba8b..6be9fd55cc 100644 --- a/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected +++ b/cpp/cert/test/rules/CTR52-CPP/GuaranteeGenericCppLibraryFunctionsDoNotOverflow.expected @@ -1,12 +1,12 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:88,7-15) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:88,27-35) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:89,9-17) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:93,9-17) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:93,29-37) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:94,11-19) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:104,35-43) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:105,11-19) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:104,9-22) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:93,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:93,27-35) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:94,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:98,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:98,29-37) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:99,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:109,35-43) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:110,11-19) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (GuaranteeGenericCppLibraryFunctionsDoNotOverflow.ql:109,9-22) | test.cpp:8:42:8:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:8:3:8:11 | call to copy | call to copy | | test.cpp:17:42:17:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:17:3:17:11 | call to copy | call to copy | | test.cpp:55:42:55:46 | call to begin | Output iterator for $@ is not guaranteed to be large enough for the input iterator. | test.cpp:55:3:55:11 | call to copy | call to copy | diff --git a/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected b/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected index b5c36727f5..1953314c2f 100644 --- a/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected +++ b/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected @@ -1,9 +1,9 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:23,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:23,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:24,7-15) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:30,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:30,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:31,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:28,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:28,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:29,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:35,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:35,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:36,7-15) | test.cpp:7:3:7:15 | call to for_each | The $@ of iterator range function does not point to the end of an iterator. | test.cpp:7:28:7:32 | call to begin | argument | | test.cpp:7:3:7:15 | call to for_each | The $@ of iterator range function does not point to the start of an iterator. | test.cpp:7:19:7:21 | call to end | argument | | test.cpp:8:3:8:15 | call to for_each | The $@ of iterator range function does not point to the end of an iterator. | test.cpp:8:30:8:34 | call to begin | argument | diff --git a/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected b/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected index 0ba2fad433..48da16d208 100644 --- a/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected +++ b/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected @@ -1,12 +1,12 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:38,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:38,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:38,51-59) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:39,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:39,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:39,52-60) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:74,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:74,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:75,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:43,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:43,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:43,51-59) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:44,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:44,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:44,52-60) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:79,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:79,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:80,7-15) | test.cpp:8:7:8:7 | i | Increment of iterator may overflow since its bounds are not checked. | | test.cpp:9:9:9:9 | i | Increment of iterator may overflow since its bounds are not checked. | | test.cpp:10:9:10:9 | i | Increment of iterator may overflow since its bounds are not checked. | diff --git a/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected b/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected index 59caaa22d8..51ef13412c 100644 --- a/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected +++ b/cpp/cert/test/rules/CTR56-CPP/DoNotUsePointerArithmeticOnPolymorphicObjects.expected @@ -1,7 +1,7 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:41,62-70) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:42,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:51,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:57,3-11) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:46,62-70) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:47,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:56,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUsePointerArithmeticOnPolymorphicObjects.ql:62,3-11) edges | test.cpp:15:19:15:21 | foo | test.cpp:16:24:16:26 | foo | provenance | | | test.cpp:15:19:15:21 | foo | test.cpp:16:51:16:53 | foo | provenance | | diff --git a/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected b/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected index 00f1a6ba03..08d46a7bbd 100644 --- a/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected +++ b/cpp/cert/test/rules/EXP50-CPP/DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.expected @@ -1,27 +1,27 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:24,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:24,59-67) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:27,33-41) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:27,57-65) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:31,33-41) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:31,59-67) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:40,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:40,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:40,53-61) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:43,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:43,57-65) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:52,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:52,55-63) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:59,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:59,57-65) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:71,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:71,55-63) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:24,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:27,7-20) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:31,7-20) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:43,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:52,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:59,5-18) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:71,5-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:29,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:29,59-67) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:32,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:32,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:36,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:36,59-67) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:45,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:45,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:45,53-61) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:48,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:48,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:57,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:57,55-63) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:64,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:64,57-65) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:76,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:76,55-63) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:29,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:32,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:36,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:48,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:57,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:64,5-18) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (DoNotDependOnTheOrderOfEvaluationForSideEffectsInFunctionCallsAsFunctionArguments.ql:76,5-18) | test.cpp:82:3:82:4 | call to f2 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.cpp:82:6:82:7 | call to f5 | call to f5 | test.cpp:82:12:82:13 | call to f6 | call to f6 | | test.cpp:84:3:84:4 | call to f2 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.cpp:84:6:84:7 | call to f5 | call to f5 | test.cpp:84:12:84:13 | call to f7 | call to f7 | | test.cpp:87:3:87:4 | call to f2 | Depending on the order of evaluation for the arguments $@ and $@ for side effects on shared state is unspecified and can result in unexpected behavior. | test.cpp:87:9:87:10 | call to m1 | call to m1 | test.cpp:87:18:87:19 | call to m1 | call to m1 | diff --git a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected index c271269ab8..8b7a4902cc 100644 --- a/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected +++ b/cpp/cert/test/rules/EXP51-CPP/DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.expected @@ -1,7 +1,7 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:19,44-52) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:20,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:22,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:27,33-41) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:24,44-52) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:25,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:27,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotDeleteAnArrayThroughAPointerOfTheIncorrectType.ql:32,33-41) edges | test.cpp:6:19:6:37 | new[] | test.cpp:9:12:9:13 | l1 | provenance | | | test.cpp:7:22:7:40 | new[] | test.cpp:10:12:10:13 | l2 | provenance | | diff --git a/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected b/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected index b7b4891776..41fa58045f 100644 --- a/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected +++ b/cpp/cert/test/rules/MEM52-CPP/DetectAndHandleMemoryAllocationErrors.expected @@ -1,9 +1,9 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:59,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:61,36-44) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:77,46-54) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:78,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:82,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:85,35-43) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:90,38-46) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:64,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:66,36-44) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:82,46-54) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:83,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:87,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:90,35-43) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleMemoryAllocationErrors.ql:95,38-46) | test.cpp:24:7:24:34 | new | nothrow new allocation of $@ returns here without a subsequent check to see whether the pointer is valid. | test.cpp:24:7:24:34 | new | StructA * | | test.cpp:40:17:40:38 | call to allocate_without_check | nothrow new allocation of $@ returns here without a subsequent check to see whether the pointer is valid. | test.cpp:35:17:35:44 | new | StructA * | diff --git a/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected b/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected index 3743c3d414..606ccbff2b 100644 --- a/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected +++ b/cpp/cert/test/rules/MSC51-CPP/BadlySeededRandomNumberGenerator.expected @@ -1,4 +1,4 @@ -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (BadlySeededRandomNumberGenerator.ql:37,7-20) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (BadlySeededRandomNumberGenerator.ql:42,7-20) | test.cpp:9:33:9:33 | call to linear_congruential_engine | Random number generator linear_congruential_engine is default-initialized and is therefore not properly seeded. | | test.cpp:10:30:10:31 | call to linear_congruential_engine | Random number generator linear_congruential_engine is default-initialized and is therefore not properly seeded. | | test.cpp:11:21:11:22 | call to linear_congruential_engine | Random number generator linear_congruential_engine is default-initialized and is therefore not properly seeded. | From f7c77cb9749547ee38201774d1bacb935621e72d Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 6 May 2025 06:52:46 -0400 Subject: [PATCH 379/628] Update rule package schema for new allowed tags --- schemas/rule-package.schema.json | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/schemas/rule-package.schema.json b/schemas/rule-package.schema.json index f8c3f028e3..fff79fede0 100644 --- a/schemas/rule-package.schema.json +++ b/schemas/rule-package.schema.json @@ -348,7 +348,29 @@ "external/misra/c/2012/amendment2", "external/misra/c/2012/amendment3", "external/misra/c/2012/amendment4", - "external/misra/c/strict" + "external/misra/c/strict", + "external/cert/severity/low", + "external/cert/severity/medium", + "external/cert/severity/high", + "external/cert/likelihood/unlikely", + "external/cert/likelihood/probable", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/low", + "external/cert/remediation-cost/medium", + "external/cert/remediation-cost/high", + "external/cert/priority/p1", + "external/cert/priority/p2", + "external/cert/priority/p3", + "external/cert/priority/p4", + "external/cert/priority/p6", + "external/cert/priority/p8", + "external/cert/priority/p9", + "external/cert/priority/p12", + "external/cert/priority/p18", + "external/cert/priority/p27", + "external/cert/level/l1", + "external/cert/level/l2", + "external/cert/level/l3" ] }, "minLength": 1 From 9169ec6831ed6382bd764d3a7e4fbd64607c9954 Mon Sep 17 00:00:00 2001 From: Max Base Date: Tue, 13 May 2025 18:35:12 +0000 Subject: [PATCH 380/628] fix: occured -> occurred --- cpp/report/src/Diagnostics/ExtractionErrors.qll | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/report/src/Diagnostics/ExtractionErrors.qll b/cpp/report/src/Diagnostics/ExtractionErrors.qll index 55e1c96461..58757ca544 100644 --- a/cpp/report/src/Diagnostics/ExtractionErrors.qll +++ b/cpp/report/src/Diagnostics/ExtractionErrors.qll @@ -60,10 +60,10 @@ class ExtractionError extends TExtractionError { /** Gets the error message for this error. */ string getErrorMessage() { none() } - /** Gets the file this error occured in. */ + /** Gets the file this error occurred in. */ File getFile() { none() } - /** Gets the location this error occured in. */ + /** Gets the location this error occurred in. */ Location getLocation() { none() } /** Gets the SARIF severity of this error. */ From af488d1ba039526901d6a94a1922a2535a17fcd9 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 15 May 2025 21:25:26 +0100 Subject: [PATCH 381/628] Update README.md to list MISRA C 2023 as completed, and update date for MISRA C++ 2023. --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0f24587afe..02c226f84a 100644 --- a/README.md +++ b/README.md @@ -15,14 +15,15 @@ The following coding standards are supported: - [MISRA C 2012, 3rd Edition, 1st revision](https://www.misra.org.uk/product/misra-c2012-third-edition-first-revision/) (incoporating Amendment 1 & Technical Corrigendum 1). In addition, we support the following additional amendments and technical corrigendums: - [MISRA C 2012 Amendment 2](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD2.pdf) - [MISRA C 2012 Technical Corrigendum 2](https://misra.org.uk/app/uploads/2022/04/MISRA-C-2012-TC2.pdf) + - [MISRA C 2012 Amendment 3](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD3.pdf) + - [MISRA C 2012 Amendment 4](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD4.pdf) +- [MISRA C 2023](https://misra.org.uk/product/misra-c2023/) ## :construction: Standards under development :construction: -The following standards are under active development: +The following standards are under active development for [C++17](https://www.iso.org/standard/68564.html): -- [MISRA C++ 2023](https://misra.org.uk/product/misra-cpp2023/) - under development - _scheduled for release 2025 Q1_ -- [MISRA C 2023](https://misra.org.uk/product/misra-c2023/) - under development - _scheduled for release 2025 Q1_ - - This includes the development of [MISRA C 2012 Amendment 3](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD3.pdf) and [MISRA C 2012 Amendment 4](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD4.pdf), which are incorporated into MISRA C 2023. +- [MISRA C++ 2023](https://misra.org.uk/product/misra-cpp2023/) - under development - _scheduled for release 2025 Q2/Q3_ ## How do I use the CodeQL Coding Standards Queries? From 80529f072f721fb14e782d1e4041423246dba381 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 15 May 2025 21:26:15 +0100 Subject: [PATCH 382/628] Update user manual with MISRA C 2023 coverage. --- docs/user_manual.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/docs/user_manual.md b/docs/user_manual.md index 2920e024a6..4ab3de39c0 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -31,7 +31,8 @@ | 0.23.0 | 2024-10-21 | Luke Cartey | Add assembly as a hazard. | | 0.24.0 | 2024-10-22 | Luke Cartey | Add CodeQL packs as a usable output, update release artifacts list. | | 0.25.0 | 2025-01-15 | Mike Fairhurst | Add guidance for the usage of 'strict' queries. | -| 0.26.0 | 2025-02-12 | Luke Cartey | Describe support for new deviation code identifier formats | +| 0.26.0 | 2025-02-12 | Luke Cartey | Describe support for new deviation code identifier formats | +| 0.27.0 | 2025-05-15 | Luke Cartey | Documented completed support for MISRA C 2023. | ## Release information @@ -59,16 +60,16 @@ A _coding standard_ is a set of rules or guidelines which restrict or prohibit t The _CodeQL Coding Standards_ product is a set of CodeQL queries for identifying contraventions of rules in the following coding standards: -| Standard | Version | Rules | Supportable rules | Implemented rules | Status | -| -------------------------------------------------------------------------------------------------------------------- | ------- | ----------- | ----------------------- | ----------------- | ------- | -| AUTOSAR C++ | [^1] [R22-11](https://www.autosar.org/fileadmin/standards/R22-11/AP/AUTOSAR_RS_CPP14Guidelines.pdf), R21-11, R20-11, R19-11, R19-03 | 397 | 372 | 370[^2] | Implemented | -| CERT-C++ | [2016](https://resources.sei.cmu.edu/downloads/secure-coding/assets/sei-cert-cpp-coding-standard-2016-v01.pdf) | 83 | 82 | 82 | Implemented | -| CERT C | [2016](https://resources.sei.cmu.edu/downloads/secure-coding/assets/sei-cert-c-coding-standard-2016-v01.pdf) | 99 | 97 | 97 | Implemented | -| MISRA C | [2012 Third Edition, First Revision](https://www.misra.org.uk/product/misra-c2012-third-edition-first-revision/), [Amendment 2](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD2.pdf) and TC2 | 175 | 164 | 162[^3] | Implemented | -| | [MISRA C 2012 Amendment 3](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD3.pdf) | 24 | 24 | - | Under development | -| | [MISRA C 2012 Amendment 4](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD4.pdf) | 22 | 22 | - | Under development | -| | [2023 Third Edition, Second Revision](https://misra.org.uk/product/misra-c2023/) | 221 | 210 | - | Under development | -| MISRA C++ | [2023](https://misra.org.uk/product/misra-cpp2023/) | 179 | 176[^4] | - | Under development | +| Standard | Version | Rules | Supportable rules | Implemented rules | Status | +| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | ----------------- | ----------------- | ----------------- | +| AUTOSAR C++ | [^1] [R22-11](https://www.autosar.org/fileadmin/standards/R22-11/AP/AUTOSAR_RS_CPP14Guidelines.pdf), R21-11, R20-11, R19-11, R19-03 | 397 | 372 | 370[^2] | Implemented | +| CERT-C++ | [2016](https://resources.sei.cmu.edu/downloads/secure-coding/assets/sei-cert-cpp-coding-standard-2016-v01.pdf) | 83 | 82 | 82 | Implemented | +| CERT C | [2016](https://resources.sei.cmu.edu/downloads/secure-coding/assets/sei-cert-c-coding-standard-2016-v01.pdf) | 99 | 97 | 97 | Implemented | +| MISRA C | [2012 Third Edition, First Revision](https://www.misra.org.uk/product/misra-c2012-third-edition-first-revision/), [Amendment 2](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD2.pdf) and TC2 | 175 | 164 | 162[^3] | Implemented | +| | [2012 Amendment 3](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD3.pdf) | 24 | 24 | 24 | Implemented | +| | [2012 Amendment 4](https://misra.org.uk/app/uploads/2021/06/MISRA-C-2012-AMD4.pdf) | 22 | 22 | 21[^4] | Implemented | +| | [2023 Third Edition, Second Revision](https://misra.org.uk/product/misra-c2023/) | 221 | 210 | 207[^5] | Implemented | +| MISRA C++ | [2023](https://misra.org.uk/product/misra-cpp2023/) | 179 | 176[^6] | - | Under development | Not all rules in these standards are amenable to static analysis by CodeQL - some rules require external or domain specific knowledge to validate, or refer to properties which are not present in our representation of the codebase under analysis. In addition, some rules are natively enforced by the supported compilers. As CodeQL requires that the program under analysis compiles, we are unable to implement queries for these rules, and doing so would be redundant. @@ -84,8 +85,10 @@ The datasheet _"CodeQL Coding Standards: supported rules"_, provided with each r [^1]: AUTOSAR C++ versions R22-11, R21-11, R20-11, R19-11 and R19-03 are all identical as indicated in the document change history. [^2]: The unimplemented supportable AUTOSAR rules are `A7-1-8` and `A8-2-1`. These rules require additional support in the CodeQL CLI to ensure the required information is available in the CodeQL database to identify violations of these rules. -[^3]: The unimplemented supportable MISRA C 2012 rules are `Rule 9.5`, `Rule 17.13`, and `Dir 4.14`. `Rule 9.5` and `Rule 17.13` require additional support in the CodeQL CLI to ensure the required information is available in the CodeQL database to identify violations of these rules. `Dir 4.14` is covered by the default CodeQL queries, which identify potential security vulnerabilities caused by not validating external input. -[^4]: The rules 5.13.7, 19.0.1 and 19.1.2 are not planned to be implemented by CodeQL as they are compiler checked in all supported compilers. +[^3]: The unimplemented supportable MISRA C 2012 rules are `Rule 9.5`, `Rule 17.13`. `Rule 9.5` and `Rule 17.13` require additional support in the CodeQL CLI to ensure the required information is available in the CodeQL database to identify violations of these rules. Note: `Dir 4.14` is covered by the default CodeQL queries, which identify potential security vulnerabilities caused by not validating external input. +[^4]: The unimplemented supportable MISRA C 2012 Amendment 4 rule is `Rule 9.6`. `Rule 9.6` requires additional support in the CodeQL CLI to ensure the required information is available in the CodeQL database to identify violations of this rule. +[^5]: The unimplemented supportable MISRA C 2023 rules are `Rule 9.5`, `Rule 9.6`, `Rule 17.13`. `Rule 9.5`, `Rule 9.6` and `Rule 17.13` require additional support in the CodeQL CLI to ensure the required information is available in the CodeQL database to identify violations of these rules. Note: `Dir 4.14` is covered by the default CodeQL queries, which identify potential security vulnerabilities caused by not validating external input. +[^6]: The rules `5.13.7`, `19.0.1` and `19.1.2` are not planned to be implemented by CodeQL as they are compiler checked in all supported compilers. ## Supported environment From b8b66ae31e67393246afcaf1dce260c5ba8d9c89 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 15 May 2025 21:26:49 +0100 Subject: [PATCH 383/628] Update query suites to reference MISRA C 2023. --- c/misra/src/codeql-suites/misra-c-advisory.qls | 2 +- c/misra/src/codeql-suites/misra-c-audit.qls | 2 +- c/misra/src/codeql-suites/misra-c-default.qls | 2 +- c/misra/src/codeql-suites/misra-c-mandatory.qls | 2 +- c/misra/src/codeql-suites/misra-c-required.qls | 2 +- c/misra/src/codeql-suites/misra-c-strict.qls | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/c/misra/src/codeql-suites/misra-c-advisory.qls b/c/misra/src/codeql-suites/misra-c-advisory.qls index 517f449b13..39df0d6583 100644 --- a/c/misra/src/codeql-suites/misra-c-advisory.qls +++ b/c/misra/src/codeql-suites/misra-c-advisory.qls @@ -1,4 +1,4 @@ -- description: MISRA C 2012 (Advisory) +- description: MISRA C 2023 (Advisory) - qlpack: codeql/misra-c-coding-standards - include: kind: diff --git a/c/misra/src/codeql-suites/misra-c-audit.qls b/c/misra/src/codeql-suites/misra-c-audit.qls index ce1b9fed68..cac9df04ae 100644 --- a/c/misra/src/codeql-suites/misra-c-audit.qls +++ b/c/misra/src/codeql-suites/misra-c-audit.qls @@ -1,4 +1,4 @@ -- description: MISRA C 2012 (Audit) +- description: MISRA C 2023 (Audit) - qlpack: codeql/misra-c-coding-standards - include: kind: diff --git a/c/misra/src/codeql-suites/misra-c-default.qls b/c/misra/src/codeql-suites/misra-c-default.qls index f72a63ba49..cdc6eb65ad 100644 --- a/c/misra/src/codeql-suites/misra-c-default.qls +++ b/c/misra/src/codeql-suites/misra-c-default.qls @@ -1,4 +1,4 @@ -- description: MISRA C 2012 (Default) +- description: MISRA C 2023 (Default) - qlpack: codeql/misra-c-coding-standards - include: kind: diff --git a/c/misra/src/codeql-suites/misra-c-mandatory.qls b/c/misra/src/codeql-suites/misra-c-mandatory.qls index 454b8487ab..09eccdc50c 100644 --- a/c/misra/src/codeql-suites/misra-c-mandatory.qls +++ b/c/misra/src/codeql-suites/misra-c-mandatory.qls @@ -1,4 +1,4 @@ -- description: MISRA C 2012 (Advisory) +- description: MISRA C 2023 (Advisory) - qlpack: codeql/misra-c-coding-standards - include: kind: diff --git a/c/misra/src/codeql-suites/misra-c-required.qls b/c/misra/src/codeql-suites/misra-c-required.qls index ca32b9ca97..f7c77e937a 100644 --- a/c/misra/src/codeql-suites/misra-c-required.qls +++ b/c/misra/src/codeql-suites/misra-c-required.qls @@ -1,4 +1,4 @@ -- description: MISRA C 2012 (Required) +- description: MISRA C 2023 (Required) - qlpack: codeql/misra-c-coding-standards - include: kind: diff --git a/c/misra/src/codeql-suites/misra-c-strict.qls b/c/misra/src/codeql-suites/misra-c-strict.qls index 6fb642424c..b8f4885189 100644 --- a/c/misra/src/codeql-suites/misra-c-strict.qls +++ b/c/misra/src/codeql-suites/misra-c-strict.qls @@ -1,4 +1,4 @@ -- description: MISRA C 2012 (Strict) +- description: MISRA C 2023 (Strict) - qlpack: codeql/misra-c-coding-standards - include: kind: From 837af1f46780fd6c62452c2260ccbc6757c5a183 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 15 May 2025 21:27:43 +0100 Subject: [PATCH 384/628] Add changelog for MISRA C 2023. --- change_notes/2025-05-15-misra-c-2023.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 change_notes/2025-05-15-misra-c-2023.md diff --git a/change_notes/2025-05-15-misra-c-2023.md b/change_notes/2025-05-15-misra-c-2023.md new file mode 100644 index 0000000000..defd2ff823 --- /dev/null +++ b/change_notes/2025-05-15-misra-c-2023.md @@ -0,0 +1,4 @@ + - Support for MISRA C 2023 is now completed. + - The default query suites for MISRA C now target MISRA C 2023. + - The user manual has been updated to list MISRA C 2023 as completed. + - The `misra-c-2012-third-edition-with-amendment-2.qls` query suite can be used to run the queries present in MISRA C 2012 (3rd Edition) and Amendment 2. \ No newline at end of file From e1d028cd93b671a3e775d4dd1fe111b51b1862ce Mon Sep 17 00:00:00 2001 From: knewbury01 Date: Wed, 21 May 2025 18:06:18 +0000 Subject: [PATCH 385/628] Bump version to 2.46.0-dev --- c/cert/src/qlpack.yml | 2 +- c/cert/test/qlpack.yml | 2 +- c/common/src/qlpack.yml | 2 +- c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- c/misra/test/qlpack.yml | 2 +- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/qlpack.yml | 2 +- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- docs/user_manual.md | 12 ++++++------ 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 46124fd7c4..128ac606f8 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.45.0-dev +version: 2.46.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index f7fe527dab..6920ec1771 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.45.0-dev +version: 2.46.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index ad3f825a4b..13a994e0a3 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.45.0-dev +version: 2.46.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index cbadd7f238..09640c31c9 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.45.0-dev +version: 2.46.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index b5d16e9974..d37d64c88a 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.45.0-dev +version: 2.46.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index e6932cc894..a22391774f 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.45.0-dev +version: 2.46.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index b9cd9b72a8..dd095ff354 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.45.0-dev +version: 2.46.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index 0b92541fdf..7182f771d5 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.45.0-dev +version: 2.46.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index d23ea8fc34..792575ad6e 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.45.0-dev +version: 2.46.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index 1baf2b3fc3..7463027aaf 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.45.0-dev +version: 2.46.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index 47a116582c..1813fb7fe3 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards -version: 2.45.0-dev +version: 2.46.0-dev license: MIT dependencies: codeql/cpp-all: 2.1.1 diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index a636b824dc..8912a9c683 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.45.0-dev +version: 2.46.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index a98ccfa757..5cb9d79b87 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.45.0-dev +version: 2.46.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index aad59493fe..69cd110473 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.45.0-dev +version: 2.46.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index 731d68dd29..c6f5f7052f 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.45.0-dev +version: 2.46.0-dev license: MIT dependencies: codeql/cpp-all: 2.1.1 diff --git a/docs/user_manual.md b/docs/user_manual.md index 4ab3de39c0..a758d3678c 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -36,14 +36,14 @@ ## Release information -This user manual documents release `2.45.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.46.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: - `coding-standards-codeql-packs-2.37.0-dev.zip`: CodeQL packs that can be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `code-scanning-cpp-query-pack-2.45.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.45.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.45.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.45.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.46.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.46.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.46.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.46.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -670,7 +670,7 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.45.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.46.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | From 18443397f5a4713f426384167c968c50e4f4bfde Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 2 Jun 2025 15:50:45 +0100 Subject: [PATCH 386/628] Add BannedAPIs package details --- .../cpp/exclusions/cpp/BannedAPIs.qll | 163 ++++++++++++++++ .../cpp/exclusions/cpp/RuleMetadata.qll | 3 + rule_packages/cpp/BannedAPIs.json | 184 ++++++++++++++++++ 3 files changed, 350 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll create mode 100644 rule_packages/cpp/BannedAPIs.json diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll new file mode 100644 index 0000000000..571a48a625 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll @@ -0,0 +1,163 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype BannedAPIsQuery = + TAvoidProgramTerminatingFunctionsQuery() or + TNoVariadicFunctionMacrosQuery() or + TNoCsetjmpHeaderQuery() or + TUnsafeStringHandlingFunctionsQuery() or + TBannedSystemFunctionQuery() or + TUseSmartPtrFactoryFunctionsQuery() or + TCharacterHandlingFunctionRestrictionsQuery() or + TNoMemoryFunctionsFromCStringQuery() or + TLocaleGlobalFunctionNotAllowedQuery() + +predicate isBannedAPIsQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `avoidProgramTerminatingFunctions` query + BannedAPIsPackage::avoidProgramTerminatingFunctionsQuery() and + queryId = + // `@id` for the `avoidProgramTerminatingFunctions` query + "cpp/misra/avoid-program-terminating-functions" and + ruleId = "RULE-18-5-2" and + category = "advisory" + or + query = + // `Query` instance for the `noVariadicFunctionMacros` query + BannedAPIsPackage::noVariadicFunctionMacrosQuery() and + queryId = + // `@id` for the `noVariadicFunctionMacros` query + "cpp/misra/no-variadic-function-macros" and + ruleId = "RULE-21-10-1" and + category = "required" + or + query = + // `Query` instance for the `noCsetjmpHeader` query + BannedAPIsPackage::noCsetjmpHeaderQuery() and + queryId = + // `@id` for the `noCsetjmpHeader` query + "cpp/misra/no-csetjmp-header" and + ruleId = "RULE-21-10-2" and + category = "required" + or + query = + // `Query` instance for the `unsafeStringHandlingFunctions` query + BannedAPIsPackage::unsafeStringHandlingFunctionsQuery() and + queryId = + // `@id` for the `unsafeStringHandlingFunctions` query + "cpp/misra/unsafe-string-handling-functions" and + ruleId = "RULE-21-2-2" and + category = "required" + or + query = + // `Query` instance for the `bannedSystemFunction` query + BannedAPIsPackage::bannedSystemFunctionQuery() and + queryId = + // `@id` for the `bannedSystemFunction` query + "cpp/misra/banned-system-function" and + ruleId = "RULE-21-2-3" and + category = "required" + or + query = + // `Query` instance for the `useSmartPtrFactoryFunctions` query + BannedAPIsPackage::useSmartPtrFactoryFunctionsQuery() and + queryId = + // `@id` for the `useSmartPtrFactoryFunctions` query + "cpp/misra/use-smart-ptr-factory-functions" and + ruleId = "RULE-23-11-1" and + category = "advisory" + or + query = + // `Query` instance for the `characterHandlingFunctionRestrictions` query + BannedAPIsPackage::characterHandlingFunctionRestrictionsQuery() and + queryId = + // `@id` for the `characterHandlingFunctionRestrictions` query + "cpp/misra/character-handling-function-restrictions" and + ruleId = "RULE-24-5-1" and + category = "required" + or + query = + // `Query` instance for the `noMemoryFunctionsFromCString` query + BannedAPIsPackage::noMemoryFunctionsFromCStringQuery() and + queryId = + // `@id` for the `noMemoryFunctionsFromCString` query + "cpp/misra/no-memory-functions-from-c-string" and + ruleId = "RULE-24-5-2" and + category = "required" + or + query = + // `Query` instance for the `localeGlobalFunctionNotAllowed` query + BannedAPIsPackage::localeGlobalFunctionNotAllowedQuery() and + queryId = + // `@id` for the `localeGlobalFunctionNotAllowed` query + "cpp/misra/locale-global-function-not-allowed" and + ruleId = "RULE-25-5-1" and + category = "required" +} + +module BannedAPIsPackage { + Query avoidProgramTerminatingFunctionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `avoidProgramTerminatingFunctions` query + TQueryCPP(TBannedAPIsPackageQuery(TAvoidProgramTerminatingFunctionsQuery())) + } + + Query noVariadicFunctionMacrosQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noVariadicFunctionMacros` query + TQueryCPP(TBannedAPIsPackageQuery(TNoVariadicFunctionMacrosQuery())) + } + + Query noCsetjmpHeaderQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noCsetjmpHeader` query + TQueryCPP(TBannedAPIsPackageQuery(TNoCsetjmpHeaderQuery())) + } + + Query unsafeStringHandlingFunctionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `unsafeStringHandlingFunctions` query + TQueryCPP(TBannedAPIsPackageQuery(TUnsafeStringHandlingFunctionsQuery())) + } + + Query bannedSystemFunctionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `bannedSystemFunction` query + TQueryCPP(TBannedAPIsPackageQuery(TBannedSystemFunctionQuery())) + } + + Query useSmartPtrFactoryFunctionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `useSmartPtrFactoryFunctions` query + TQueryCPP(TBannedAPIsPackageQuery(TUseSmartPtrFactoryFunctionsQuery())) + } + + Query characterHandlingFunctionRestrictionsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `characterHandlingFunctionRestrictions` query + TQueryCPP(TBannedAPIsPackageQuery(TCharacterHandlingFunctionRestrictionsQuery())) + } + + Query noMemoryFunctionsFromCStringQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noMemoryFunctionsFromCString` query + TQueryCPP(TBannedAPIsPackageQuery(TNoMemoryFunctionsFromCStringQuery())) + } + + Query localeGlobalFunctionNotAllowedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `localeGlobalFunctionNotAllowed` query + TQueryCPP(TBannedAPIsPackageQuery(TLocaleGlobalFunctionNotAllowedQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index abd6aeff96..92e1bba574 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -3,6 +3,7 @@ import cpp import codingstandards.cpp.exclusions.RuleMetadata //** Import packages for this language **/ import Allocations +import BannedAPIs import BannedFunctions import BannedLibraries import BannedSyntax @@ -58,6 +59,7 @@ import VirtualFunctions /** The TQuery type representing this language * */ newtype TCPPQuery = TAllocationsPackageQuery(AllocationsQuery q) or + TBannedAPIsPackageQuery(BannedAPIsQuery q) or TBannedFunctionsPackageQuery(BannedFunctionsQuery q) or TBannedLibrariesPackageQuery(BannedLibrariesQuery q) or TBannedSyntaxPackageQuery(BannedSyntaxQuery q) or @@ -113,6 +115,7 @@ newtype TCPPQuery = /** The metadata predicate * */ predicate isQueryMetadata(Query query, string queryId, string ruleId, string category) { isAllocationsQueryMetadata(query, queryId, ruleId, category) or + isBannedAPIsQueryMetadata(query, queryId, ruleId, category) or isBannedFunctionsQueryMetadata(query, queryId, ruleId, category) or isBannedLibrariesQueryMetadata(query, queryId, ruleId, category) or isBannedSyntaxQueryMetadata(query, queryId, ruleId, category) or diff --git a/rule_packages/cpp/BannedAPIs.json b/rule_packages/cpp/BannedAPIs.json new file mode 100644 index 0000000000..591f50b5e6 --- /dev/null +++ b/rule_packages/cpp/BannedAPIs.json @@ -0,0 +1,184 @@ +{ + "MISRA-C++-2023": { + "RULE-18-5-2": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Using program-terminating functions like abort, exit, _Exit, quick_exit or terminate causes the stack to not be unwound and object destructors to not be called, potentially leaving the environment in an undesirable state.", + "kind": "problem", + "name": "Program-terminating functions should not be used", + "precision": "very-high", + "severity": "error", + "short_name": "AvoidProgramTerminatingFunctions", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Program-terminating functions should not be used" + }, + "RULE-21-10-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using features like va_list, va_arg, va_start, va_end and va_copy bypasses compiler type checking and leads to undefined behavior when used incorrectly.", + "kind": "problem", + "name": "The features of shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "NoVariadicFunctionMacros", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The features of shall not be used" + }, + "RULE-21-10-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using facilities from the header causes undefined behavior by bypassing normal function return mechanisms and may result in non-trivial object destruction being omitted.", + "kind": "problem", + "name": "The standard header file shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "NoCsetjmpHeader", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The standard header file shall not be used" + }, + "RULE-21-2-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using string handling functions from , , and headers may result in buffer overflows or unreliable error detection through errno.", + "kind": "problem", + "name": "The string handling functions from , , and shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "UnsafeStringHandlingFunctions", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The string handling functions from , , and shall not be used" + }, + "RULE-21-2-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using the system() function from cstdlib or stdlib.h causes undefined behavior and potential security vulnerabilities.", + "kind": "problem", + "name": "The library function system from shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "BannedSystemFunction", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The library function system from shall not be used" + }, + "RULE-23-11-1": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Using raw pointer constructors of std::shared_ptr and std::unique_ptr instead of make_shared/make_unique can lead to memory leaks if exceptions occur during construction.", + "kind": "problem", + "name": "The raw pointer constructors of std::shared_ptr and std::unique_ptr should not be used", + "precision": "very-high", + "severity": "error", + "short_name": "UseSmartPtrFactoryFunctions", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The raw pointer constructors of std::shared_ptr and std::unique_ptr should not be used" + }, + "RULE-24-5-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using character classification and case mapping functions from and causes undefined behavior when arguments are not representable as unsigned char or not equal to EOF.", + "kind": "problem", + "name": "The character handling functions from and shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "CharacterHandlingFunctionRestrictions", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The character handling functions from and shall not be used" + }, + "RULE-24-5-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using memcpy, memmove or memcmp from can result in undefined behavior due to overlapping memory, non-trivially copyable objects, or unequal comparison of logically equal objects.", + "kind": "problem", + "name": "The C++ Standard Library functions memcpy, memmove and memcmp from shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "NoMemoryFunctionsFromCString", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The C++ Standard Library functions memcpy, memmove and memcmp from shall not be used" + }, + "RULE-25-5-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Calling setlocale or std::locale::global functions can introduce data races with functions that use the locale, leading to undefined behavior.", + "kind": "problem", + "name": "The setlocale and std::locale::global functions shall not be called", + "precision": "very-high", + "severity": "error", + "short_name": "LocaleGlobalFunctionNotAllowed", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The setlocale and std::locale::global functions shall not be called" + } + } +} \ No newline at end of file From 102703a3a25ee130af03de7b2c41245d3ee409c6 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 2 Jun 2025 16:08:50 +0100 Subject: [PATCH 387/628] Rule 18.5.2: AvoidProgramTerminatingFunctions.ql Add a query to identify uses of terminating program functions. [a] --- .../test/includes/standard-library/cstdlib.h | 13 ++-- .../test/includes/standard-library/stdlib.h | 8 ++- .../AvoidProgramTerminatingFunctions.ql | 53 +++++++++++++++ .../AvoidProgramTerminatingFunctions.expected | 27 ++++++++ .../AvoidProgramTerminatingFunctions.qlref | 1 + cpp/misra/test/rules/RULE-18-5-2/test.cpp | 65 +++++++++++++++++++ 6 files changed, 160 insertions(+), 7 deletions(-) create mode 100644 cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql create mode 100644 cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected create mode 100644 cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.qlref create mode 100644 cpp/misra/test/rules/RULE-18-5-2/test.cpp diff --git a/cpp/common/test/includes/standard-library/cstdlib.h b/cpp/common/test/includes/standard-library/cstdlib.h index 4a2d0cd9ee..50c17d4ec0 100644 --- a/cpp/common/test/includes/standard-library/cstdlib.h +++ b/cpp/common/test/includes/standard-library/cstdlib.h @@ -2,15 +2,18 @@ #define _GHLIBCPP_CSTDLIB #include "stdlib.h" namespace std { -[[noreturn]] void _Exit(int status) noexcept; -[[noreturn]] void abort(void) noexcept; -[[noreturn]] void quick_exit(int status) noexcept; -extern "C++" int atexit(void (*f)(void)) noexcept; -extern "C++" int at_quick_exit(void (*f)(void)) noexcept; +using ::_Exit; +using ::abort; +using ::at_quick_exit; +using ::atexit; using ::atof; using ::atoi; using ::atol; using ::atoll; +using ::exit; +using ::free; +using ::malloc; +using ::quick_exit; using ::rand; } // namespace std #endif // _GHLIBCPP_CSTDLIB \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/stdlib.h b/cpp/common/test/includes/standard-library/stdlib.h index 67f1abd694..7bfb3dc997 100644 --- a/cpp/common/test/includes/standard-library/stdlib.h +++ b/cpp/common/test/includes/standard-library/stdlib.h @@ -8,14 +8,18 @@ void free(void *ptr); void *malloc(size_t size); void *realloc(void *ptr, size_t size); -void abort(); +[[noreturn]] void _Exit(int status) noexcept; +[[noreturn]] void abort(void) noexcept; +[[noreturn]] void quick_exit(int status) noexcept; +extern "C++" int atexit(void (*f)(void)) noexcept; +extern "C++" int at_quick_exit(void (*f)(void)) noexcept; void exit(int code); int system(const char *command); char *getenv(const char *name); -int setenv (const char *, const char *, int); +int setenv(const char *, const char *, int); int atoi(const char *str); long int atol(const char *str); diff --git a/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql new file mode 100644 index 0000000000..e15c4f2b00 --- /dev/null +++ b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql @@ -0,0 +1,53 @@ +/** + * @id cpp/misra/avoid-program-terminating-functions + * @name RULE-18-5-2: Program-terminating functions should not be used + * @description Using program-terminating functions like abort, exit, _Exit, quick_exit or terminate + * causes the stack to not be unwound and object destructors to not be called, + * potentially leaving the environment in an undesirable state. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-18-5-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra + +predicate isTerminatingFunction(Function f, string functionName) { + functionName = f.getName() and + ( + functionName in ["abort", "exit", "_Exit", "quick_exit"] and + (f.hasQualifiedName("", functionName) or f.hasQualifiedName("std", functionName)) + or + // std::terminate does not occur in the global namespace. + functionName = "terminate" and f.hasQualifiedName("std", functionName) + ) +} + +predicate isAssertMacroCall(FunctionCall call) { + exists(MacroInvocation mi | + mi.getMacroName() = "assert" and + mi.getAnExpandedElement() = call + ) +} + +from Expr e, Function f, string functionName, string action +where + not isExcluded(e, BannedAPIsPackage::avoidProgramTerminatingFunctionsQuery()) and + isTerminatingFunction(f, functionName) and + ( + // Direct function calls (excluding assert macro calls) + e instanceof FunctionCall and + f = e.(FunctionCall).getTarget() and + not isAssertMacroCall(e) and + action = "Call to" + or + // Function access + e instanceof FunctionAccess and + f = e.(FunctionAccess).getTarget() and + action = "Address taken for" + ) +select e, action + " program-terminating function '" + functionName + "'." diff --git a/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected new file mode 100644 index 0000000000..e9419d5cb7 --- /dev/null +++ b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected @@ -0,0 +1,27 @@ +| test.cpp:7:3:7:7 | call to abort | Call to program-terminating function 'abort'. | +| test.cpp:8:3:8:6 | call to exit | Call to program-terminating function 'exit'. | +| test.cpp:9:3:9:7 | call to _Exit | Call to program-terminating function '_Exit'. | +| test.cpp:10:3:10:12 | call to quick_exit | Call to program-terminating function 'quick_exit'. | +| test.cpp:15:3:15:12 | call to abort | Call to program-terminating function 'abort'. | +| test.cpp:16:3:16:11 | call to exit | Call to program-terminating function 'exit'. | +| test.cpp:17:3:17:12 | call to _Exit | Call to program-terminating function '_Exit'. | +| test.cpp:18:3:18:17 | call to quick_exit | Call to program-terminating function 'quick_exit'. | +| test.cpp:19:3:19:16 | call to terminate | Call to program-terminating function 'terminate'. | +| test.cpp:24:14:24:18 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:25:14:25:17 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:26:14:26:18 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:27:14:27:23 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:28:14:28:23 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:29:14:29:22 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:30:14:30:23 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:31:14:31:28 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:32:14:32:27 | terminate | Address taken for program-terminating function 'terminate'. | +| test.cpp:37:18:37:22 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:38:21:38:24 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:39:21:39:25 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:40:21:40:30 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:41:18:41:27 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:42:21:42:29 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:43:21:43:30 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:44:21:44:35 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:45:18:45:31 | terminate | Address taken for program-terminating function 'terminate'. | diff --git a/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.qlref b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.qlref new file mode 100644 index 0000000000..afb81410c4 --- /dev/null +++ b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.qlref @@ -0,0 +1 @@ +rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-18-5-2/test.cpp b/cpp/misra/test/rules/RULE-18-5-2/test.cpp new file mode 100644 index 0000000000..ae7354adb2 --- /dev/null +++ b/cpp/misra/test/rules/RULE-18-5-2/test.cpp @@ -0,0 +1,65 @@ +#include +#include +#include + +void test_direct_calls_to_terminating_functions() { + // Direct calls to program-terminating functions + abort(); // NON_COMPLIANT + exit(0); // NON_COMPLIANT + _Exit(1); // NON_COMPLIANT + quick_exit(2); // NON_COMPLIANT +} + +void test_std_namespace_calls() { + // Calls to functions in std namespace + std::abort(); // NON_COMPLIANT + std::exit(0); // NON_COMPLIANT + std::_Exit(1); // NON_COMPLIANT + std::quick_exit(2); // NON_COMPLIANT + std::terminate(); // NON_COMPLIANT +} + +void test_taking_addresses_of_terminating_functions() { + // Taking addresses of program-terminating functions + auto l1 = &abort; // NON_COMPLIANT + auto l2 = &exit; // NON_COMPLIANT + auto l3 = &_Exit; // NON_COMPLIANT + auto l4 = &quick_exit; // NON_COMPLIANT + auto l5 = &std::abort; // NON_COMPLIANT + auto l6 = &std::exit; // NON_COMPLIANT + auto l7 = &std::_Exit; // NON_COMPLIANT + auto l8 = &std::quick_exit; // NON_COMPLIANT + auto l9 = &std::terminate; // NON_COMPLIANT +} + +void test_function_pointers_to_terminating_functions() { + // Function pointers to program-terminating functions + void (*l1)() = abort; // NON_COMPLIANT + void (*l2)(int) = exit; // NON_COMPLIANT + void (*l3)(int) = _Exit; // NON_COMPLIANT + void (*l4)(int) = quick_exit; // NON_COMPLIANT + void (*l5)() = std::abort; // NON_COMPLIANT + void (*l6)(int) = std::exit; // NON_COMPLIANT + void (*l7)(int) = std::_Exit; // NON_COMPLIANT + void (*l8)(int) = std::quick_exit; // NON_COMPLIANT + void (*l9)() = std::terminate; // NON_COMPLIANT +} + +void test_assert_macro_exception() { + // The call to abort via assert macro is compliant by exception + assert(true); // COMPLIANT + assert(1 == 1); // COMPLIANT +} + +void f1() { + // Valid alternative: normal function return + return; // COMPLIANT +} + +void test_compliant_alternatives() { + // Using normal control flow instead of terminating functions + f1(); // COMPLIANT + + // Using exceptions for error handling + throw std::runtime_error("error"); // COMPLIANT +} \ No newline at end of file From 31039e343133feea7974c1d9a66a89c9eda84f31 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 2 Jun 2025 16:42:23 +0100 Subject: [PATCH 388/628] RULE-18-5-2: Improve macro defined results Make the results easier to understand by reporting calls in macro expansions in the macros themselves, if they are defined by the developers of this project. --- .../includes/custom-library/custom_abort.h | 3 + .../AvoidProgramTerminatingFunctions.ql | 56 ++++++++++++------ .../AvoidProgramTerminatingFunctions.expected | 58 ++++++++++--------- cpp/misra/test/rules/RULE-18-5-2/test.cpp | 14 +++++ 4 files changed, 86 insertions(+), 45 deletions(-) create mode 100644 cpp/common/test/includes/custom-library/custom_abort.h diff --git a/cpp/common/test/includes/custom-library/custom_abort.h b/cpp/common/test/includes/custom-library/custom_abort.h new file mode 100644 index 0000000000..bab19a8e80 --- /dev/null +++ b/cpp/common/test/includes/custom-library/custom_abort.h @@ -0,0 +1,3 @@ +// Used for RULE-18-5-2 for library aborts +#include +#define LIBRARY_ABORT() std::abort() \ No newline at end of file diff --git a/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql index e15c4f2b00..c262030c9b 100644 --- a/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql +++ b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql @@ -15,6 +15,7 @@ import cpp import codingstandards.cpp.misra +import codingstandards.cpp.AlertReporting predicate isTerminatingFunction(Function f, string functionName) { functionName = f.getName() and @@ -27,27 +28,46 @@ predicate isTerminatingFunction(Function f, string functionName) { ) } -predicate isAssertMacroCall(FunctionCall call) { +class TerminatingFunctionUse extends Expr { + string action; + string functionName; + + TerminatingFunctionUse() { + exists(Function f | isTerminatingFunction(f, functionName) | + this.(FunctionCall).getTarget() = f and + action = "Call to" + or + this.(FunctionAccess).getTarget() = f and + action = "Address taken for" + ) + } + + string getFunctionName() { result = functionName } + + string getAction() { result = action } + + Element getPrimaryElement() { + // If this is defined in a macro in the users source location, then report the macro + // expansion, otherwise report the element itself. This ensures that we always report + // the use of the terminating function, but combine usages when the macro is defined + // by the user. + exists(Element e | e = MacroUnwrapper::unwrapElement(this) | + if exists(e.getFile().getRelativePath()) then result = e else result = this + ) + } +} + +predicate isInAssertMacroInvocation(TerminatingFunctionUse use) { exists(MacroInvocation mi | mi.getMacroName() = "assert" and - mi.getAnExpandedElement() = call + mi.getAnExpandedElement() = use ) } -from Expr e, Function f, string functionName, string action +from TerminatingFunctionUse use where - not isExcluded(e, BannedAPIsPackage::avoidProgramTerminatingFunctionsQuery()) and - isTerminatingFunction(f, functionName) and - ( - // Direct function calls (excluding assert macro calls) - e instanceof FunctionCall and - f = e.(FunctionCall).getTarget() and - not isAssertMacroCall(e) and - action = "Call to" - or - // Function access - e instanceof FunctionAccess and - f = e.(FunctionAccess).getTarget() and - action = "Address taken for" - ) -select e, action + " program-terminating function '" + functionName + "'." + not isExcluded(use, BannedAPIsPackage::avoidProgramTerminatingFunctionsQuery()) and + // Exclude the uses in the assert macro + not isInAssertMacroInvocation(use) +select use.getPrimaryElement(), + use.getAction() + " program-terminating function '" + use.getFunctionName() + "'." diff --git a/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected index e9419d5cb7..4f0a79dcb3 100644 --- a/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected +++ b/cpp/misra/test/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.expected @@ -1,27 +1,31 @@ -| test.cpp:7:3:7:7 | call to abort | Call to program-terminating function 'abort'. | -| test.cpp:8:3:8:6 | call to exit | Call to program-terminating function 'exit'. | -| test.cpp:9:3:9:7 | call to _Exit | Call to program-terminating function '_Exit'. | -| test.cpp:10:3:10:12 | call to quick_exit | Call to program-terminating function 'quick_exit'. | -| test.cpp:15:3:15:12 | call to abort | Call to program-terminating function 'abort'. | -| test.cpp:16:3:16:11 | call to exit | Call to program-terminating function 'exit'. | -| test.cpp:17:3:17:12 | call to _Exit | Call to program-terminating function '_Exit'. | -| test.cpp:18:3:18:17 | call to quick_exit | Call to program-terminating function 'quick_exit'. | -| test.cpp:19:3:19:16 | call to terminate | Call to program-terminating function 'terminate'. | -| test.cpp:24:14:24:18 | abort | Address taken for program-terminating function 'abort'. | -| test.cpp:25:14:25:17 | exit | Address taken for program-terminating function 'exit'. | -| test.cpp:26:14:26:18 | _Exit | Address taken for program-terminating function '_Exit'. | -| test.cpp:27:14:27:23 | quick_exit | Address taken for program-terminating function 'quick_exit'. | -| test.cpp:28:14:28:23 | abort | Address taken for program-terminating function 'abort'. | -| test.cpp:29:14:29:22 | exit | Address taken for program-terminating function 'exit'. | -| test.cpp:30:14:30:23 | _Exit | Address taken for program-terminating function '_Exit'. | -| test.cpp:31:14:31:28 | quick_exit | Address taken for program-terminating function 'quick_exit'. | -| test.cpp:32:14:32:27 | terminate | Address taken for program-terminating function 'terminate'. | -| test.cpp:37:18:37:22 | abort | Address taken for program-terminating function 'abort'. | -| test.cpp:38:21:38:24 | exit | Address taken for program-terminating function 'exit'. | -| test.cpp:39:21:39:25 | _Exit | Address taken for program-terminating function '_Exit'. | -| test.cpp:40:21:40:30 | quick_exit | Address taken for program-terminating function 'quick_exit'. | -| test.cpp:41:18:41:27 | abort | Address taken for program-terminating function 'abort'. | -| test.cpp:42:21:42:29 | exit | Address taken for program-terminating function 'exit'. | -| test.cpp:43:21:43:30 | _Exit | Address taken for program-terminating function '_Exit'. | -| test.cpp:44:21:44:35 | quick_exit | Address taken for program-terminating function 'quick_exit'. | -| test.cpp:45:18:45:31 | terminate | Address taken for program-terminating function 'terminate'. | +| test.cpp:8:3:8:7 | call to abort | Call to program-terminating function 'abort'. | +| test.cpp:9:3:9:6 | call to exit | Call to program-terminating function 'exit'. | +| test.cpp:10:3:10:7 | call to _Exit | Call to program-terminating function '_Exit'. | +| test.cpp:11:3:11:12 | call to quick_exit | Call to program-terminating function 'quick_exit'. | +| test.cpp:16:3:16:12 | call to abort | Call to program-terminating function 'abort'. | +| test.cpp:17:3:17:11 | call to exit | Call to program-terminating function 'exit'. | +| test.cpp:18:3:18:12 | call to _Exit | Call to program-terminating function '_Exit'. | +| test.cpp:19:3:19:17 | call to quick_exit | Call to program-terminating function 'quick_exit'. | +| test.cpp:20:3:20:16 | call to terminate | Call to program-terminating function 'terminate'. | +| test.cpp:25:14:25:18 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:26:14:26:17 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:27:14:27:18 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:28:14:28:23 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:29:14:29:23 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:30:14:30:22 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:31:14:31:23 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:32:14:32:28 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:33:14:33:27 | terminate | Address taken for program-terminating function 'terminate'. | +| test.cpp:38:18:38:22 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:39:21:39:24 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:40:21:40:25 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:41:21:41:30 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:42:18:42:27 | abort | Address taken for program-terminating function 'abort'. | +| test.cpp:43:21:43:29 | exit | Address taken for program-terminating function 'exit'. | +| test.cpp:44:21:44:30 | _Exit | Address taken for program-terminating function '_Exit'. | +| test.cpp:45:21:45:35 | quick_exit | Address taken for program-terminating function 'quick_exit'. | +| test.cpp:46:18:46:31 | terminate | Address taken for program-terminating function 'terminate'. | +| test.cpp:68:1:68:33 | #define CALL_ABORT() std::abort() | Call to program-terminating function 'abort'. | +| test.cpp:69:1:69:33 | #define CALL_EXIT(x) std::exit(x) | Call to program-terminating function 'exit'. | +| test.cpp:70:1:70:41 | #define CALL_TERMINATE() std::terminate() | Call to program-terminating function 'terminate'. | +| test.cpp:77:3:77:17 | call to abort | Call to program-terminating function 'abort'. | diff --git a/cpp/misra/test/rules/RULE-18-5-2/test.cpp b/cpp/misra/test/rules/RULE-18-5-2/test.cpp index ae7354adb2..d2e2cca386 100644 --- a/cpp/misra/test/rules/RULE-18-5-2/test.cpp +++ b/cpp/misra/test/rules/RULE-18-5-2/test.cpp @@ -1,3 +1,4 @@ +#include "custom_abort.h" #include #include #include @@ -62,4 +63,17 @@ void test_compliant_alternatives() { // Using exceptions for error handling throw std::runtime_error("error"); // COMPLIANT +} + +#define CALL_ABORT() std::abort() // NON_COMPLIANT +#define CALL_EXIT(x) std::exit(x) // NON_COMPLIANT +#define CALL_TERMINATE() std::terminate() // NON_COMPLIANT + +void test_macro_expansion_with_terminating_functions() { + // Macro expansions containing terminating functions + CALL_ABORT(); // reported at the definition site + CALL_EXIT(1); // reported at the definition site + CALL_TERMINATE(); // reported at the definition site + LIBRARY_ABORT(); // NON_COMPLIANT - macro not defined by user, so flagged at + // the call site } \ No newline at end of file From e9c0fe4bbfa8258819b7cef57dd44b248e544cd2 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 2 Jun 2025 16:49:39 +0100 Subject: [PATCH 389/628] Remove cstdlib.h This header shouldn't exist. --- .../test/includes/standard-library/cstdlib | 20 ++++++++++++++++++- .../test/includes/standard-library/cstdlib.h | 19 ------------------ 2 files changed, 19 insertions(+), 20 deletions(-) delete mode 100644 cpp/common/test/includes/standard-library/cstdlib.h diff --git a/cpp/common/test/includes/standard-library/cstdlib b/cpp/common/test/includes/standard-library/cstdlib index 23eab7eaca..50c17d4ec0 100644 --- a/cpp/common/test/includes/standard-library/cstdlib +++ b/cpp/common/test/includes/standard-library/cstdlib @@ -1 +1,19 @@ -#include "cstdlib.h" \ No newline at end of file +#ifndef _GHLIBCPP_CSTDLIB +#define _GHLIBCPP_CSTDLIB +#include "stdlib.h" +namespace std { +using ::_Exit; +using ::abort; +using ::at_quick_exit; +using ::atexit; +using ::atof; +using ::atoi; +using ::atol; +using ::atoll; +using ::exit; +using ::free; +using ::malloc; +using ::quick_exit; +using ::rand; +} // namespace std +#endif // _GHLIBCPP_CSTDLIB \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cstdlib.h b/cpp/common/test/includes/standard-library/cstdlib.h deleted file mode 100644 index 50c17d4ec0..0000000000 --- a/cpp/common/test/includes/standard-library/cstdlib.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _GHLIBCPP_CSTDLIB -#define _GHLIBCPP_CSTDLIB -#include "stdlib.h" -namespace std { -using ::_Exit; -using ::abort; -using ::at_quick_exit; -using ::atexit; -using ::atof; -using ::atoi; -using ::atol; -using ::atoll; -using ::exit; -using ::free; -using ::malloc; -using ::quick_exit; -using ::rand; -} // namespace std -#endif // _GHLIBCPP_CSTDLIB \ No newline at end of file From 58e43adbd7a84e174e029f4d61c8d1145c114e5f Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 2 Jun 2025 22:31:58 +0100 Subject: [PATCH 390/628] Improve C++ stub headers for cstdarg --- cpp/common/test/includes/standard-library/cstdarg | 10 +++++----- cpp/common/test/includes/standard-library/stdarg.h | 6 ++++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/cpp/common/test/includes/standard-library/cstdarg b/cpp/common/test/includes/standard-library/cstdarg index f2b84242a0..6dd883b683 100644 --- a/cpp/common/test/includes/standard-library/cstdarg +++ b/cpp/common/test/includes/standard-library/cstdarg @@ -1,9 +1,9 @@ #pragma once +#ifndef _GHLIBCPP_CSTDARG +#define _GHLIBCPP_CSTDARG +#include "stdarg.h" namespace std { - typedef __builtin_va_list va_list; +using ::va_list; } // namespace std - -#define va_arg(v, p) __builtin_va_arg(v, p) -#define va_end(v) __builtin_va_end(v) -#define va_start(v,l) __builtin_va_start(v,l) \ No newline at end of file +#endif // _GHLIBCPP_CSTDARG \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/stdarg.h b/cpp/common/test/includes/standard-library/stdarg.h index e69de29bb2..cab940168a 100644 --- a/cpp/common/test/includes/standard-library/stdarg.h +++ b/cpp/common/test/includes/standard-library/stdarg.h @@ -0,0 +1,6 @@ + +typedef __builtin_va_list va_list; +#define va_arg(v, p) __builtin_va_arg(v, p) +#define va_end(v) __builtin_va_end(v) +#define va_start(v, l) __builtin_va_start(v, l) +#define va_copy(d, s) __builtin_va_copy(d, s) \ No newline at end of file From ffed4673ca327f950798f57c3cd56e9e84fd2130 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 2 Jun 2025 22:37:16 +0100 Subject: [PATCH 391/628] Rule 21.10.1: NoVariadicFunctionMacros.ql A query for reporting the use of variadic functions. [a] --- .../RULE-21-10-1/NoVariadicFunctionMacros.ql | 53 ++++++++++++++++ .../NoVariadicFunctionMacros.expected | 29 +++++++++ .../NoVariadicFunctionMacros.qlref | 1 + cpp/misra/test/rules/RULE-21-10-1/test.cpp | 60 +++++++++++++++++++ 4 files changed, 143 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql create mode 100644 cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected create mode 100644 cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.qlref create mode 100644 cpp/misra/test/rules/RULE-21-10-1/test.cpp diff --git a/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql b/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql new file mode 100644 index 0000000000..7e96f70222 --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql @@ -0,0 +1,53 @@ +/** + * @id cpp/misra/no-variadic-function-macros + * @name RULE-21-10-1: The features of shall not be used + * @description Using features like va_list, va_arg, va_start, va_end and va_copy bypasses + * compiler type checking and leads to undefined behavior when used incorrectly. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-10-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +class VaListType extends Type { + VaListType() { + this.getName() = "va_list" or + this.getName() = "__va_list_tag" or + this.(SpecifiedType).getBaseType() instanceof VaListType or + this.(TypedefType).getBaseType() instanceof VaListType + } +} + +from Element element, string message +where + not isExcluded(element, BannedAPIsPackage::noVariadicFunctionMacrosQuery()) and + ( + element.(Variable).getType() instanceof VaListType and + message = "Declaration of variable '" + element.(Variable).getName() + "' of type 'va_list'." + or + element.(Parameter).getType() instanceof VaListType and + message = "Declaration of parameter '" + element.(Parameter).getName() + "' of type 'va_list'." + or + element instanceof BuiltInVarArgsStart and + message = "Call to 'va_start'." + or + element instanceof BuiltInVarArgsEnd and + message = "Call to 'va_end'." + or + element instanceof BuiltInVarArg and + message = "Call to 'va_arg'." + or + element instanceof BuiltInVarArgCopy and + message = "Call to 'va_copy'." + or + element.(TypedefType).getBaseType() instanceof VaListType and + message = + "Declaration of typedef '" + element.(TypedefType).getName() + "' aliasing 'va_list' type." + ) +select element, message \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected new file mode 100644 index 0000000000..3c47cc4aa5 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected @@ -0,0 +1,29 @@ +| test.cpp:5:11:5:12 | l1 | Declaration of variable 'l1' of type 'va_list'. | +| test.cpp:9:11:9:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:10:3:10:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:11:3:11:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:15:11:15:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:16:3:16:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:17:21:17:44 | __builtin_va_arg | Call to 'va_arg'. | +| test.cpp:18:3:18:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:22:11:22:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:23:3:23:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:24:3:24:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:28:11:28:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:28:15:28:16 | l3 | Declaration of variable 'l3' of type 'va_list'. | +| test.cpp:29:3:29:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:30:3:30:17 | __builtin_va_copy | Call to 'va_copy'. | +| test.cpp:31:3:31:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:32:3:32:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:35:37:35:38 | l1 | Declaration of parameter 'l1' of type 'va_list'. | +| test.cpp:35:37:35:38 | l1 | Declaration of variable 'l1' of type 'va_list'. | +| test.cpp:36:15:36:32 | __builtin_va_arg | Call to 'va_arg'. | +| test.cpp:40:11:40:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:41:3:41:18 | __builtin_va_start | Call to 'va_start'. | +| test.cpp:42:21:42:44 | __builtin_va_arg | Call to 'va_arg'. | +| test.cpp:43:15:43:32 | __builtin_va_arg | Call to 'va_arg'. | +| test.cpp:44:3:44:12 | __builtin_va_end | Call to 'va_end'. | +| test.cpp:55:17:55:29 | va_list_alias | Declaration of typedef 'va_list_alias' aliasing 'va_list' type. | +| test.cpp:56:17:56:25 | SOME_TYPE | Declaration of typedef 'SOME_TYPE' aliasing 'va_list' type. | +| test.cpp:58:17:58:18 | l1 | Declaration of variable 'l1' of type 'va_list'. | +| test.cpp:59:13:59:14 | l2 | Declaration of variable 'l2' of type 'va_list'. | diff --git a/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.qlref b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.qlref new file mode 100644 index 0000000000..7106c2aa2d --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.qlref @@ -0,0 +1 @@ +rules/RULE-21-10-1/NoVariadicFunctionMacros.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-10-1/test.cpp b/cpp/misra/test/rules/RULE-21-10-1/test.cpp new file mode 100644 index 0000000000..1ff0793e05 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-1/test.cpp @@ -0,0 +1,60 @@ +#include +#include + +void test_va_list_declaration() { + va_list l1; // NON_COMPLIANT +} + +void test_va_start_usage(std::int32_t l1, ...) { + va_list l2; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_va_arg_usage(std::int32_t l1, ...) { + va_list l2; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + std::int32_t l3 = va_arg(l2, std::int32_t); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_va_end_usage(std::int32_t l1, ...) { + va_list l2; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_va_copy_usage(std::int32_t l1, ...) { + va_list l2, l3; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + va_copy(l3, l2); // NON_COMPLIANT + va_end(l3); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_va_list_parameter(va_list l1) { // NON_COMPLIANT + double l2 = va_arg(l1, double); // NON_COMPLIANT +} + +void test_multiple_va_arg_calls(std::int32_t l1, ...) { + va_list l2; // NON_COMPLIANT + va_start(l2, l1); // NON_COMPLIANT + std::int32_t l3 = va_arg(l2, std::int32_t); // NON_COMPLIANT + double l4 = va_arg(l2, double); // NON_COMPLIANT + va_end(l2); // NON_COMPLIANT +} + +void test_variadic_function_declaration(std::int16_t l1, ...) { + // Function declaration with ellipsis is compliant +} + +void test_variadic_function_call() { + test_variadic_function_declaration(1, 2.0, 3.0); // COMPLIANT +} + +typedef va_list va_list_alias; // NON_COMPLIANT +typedef va_list SOME_TYPE; // NON_COMPLIANT +void test_va_list_alias() { + va_list_alias l1; // NON_COMPLIANT + SOME_TYPE l2; // NON_COMPLIANT +} \ No newline at end of file From d3ec7b09b2aaa9f0c59155c70519abf318856b72 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 10:53:09 +0100 Subject: [PATCH 392/628] Remove redundant header stub file --- .../test/includes/standard-library/cstring | 30 ++++++++++++++++++- .../test/includes/standard-library/cstring.h | 29 ------------------ 2 files changed, 29 insertions(+), 30 deletions(-) delete mode 100644 cpp/common/test/includes/standard-library/cstring.h diff --git a/cpp/common/test/includes/standard-library/cstring b/cpp/common/test/includes/standard-library/cstring index 105e3e4693..2034c3963b 100644 --- a/cpp/common/test/includes/standard-library/cstring +++ b/cpp/common/test/includes/standard-library/cstring @@ -1 +1,29 @@ -#include "cstring.h" \ No newline at end of file +#ifndef _GHLIBCPP_CSTRING +#define _GHLIBCPP_CSTRING + +#include + +namespace std { +using ::memcmp; +using ::memcpy; +using ::memmove; +using ::memset; +using ::size_t; +using ::strcat; +using ::strchr; +using ::strcmp; +using ::strcoll; +using ::strcpy; +using ::strcspn; +using ::strlen; +using ::strncat; +using ::strncmp; +using ::strncpy; +using ::strpbrk; +using ::strrchr; +using ::strspn; +using ::strstr; +using ::strtok; +using ::strxfrm; +} // namespace std +#endif // _GHLIBCPP_CSTRING \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cstring.h b/cpp/common/test/includes/standard-library/cstring.h deleted file mode 100644 index 2f3ffd393e..0000000000 --- a/cpp/common/test/includes/standard-library/cstring.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _GHLIBCPP_CSTRING -#define _GHLIBCPP_CSTRING - -#include - -namespace std { -using ::memcmp; -using ::memcpy; -using ::memmove; -using ::memset; -using ::size_t; -using ::strcat; -using ::strchr; -using ::strcmp; -using ::strcoll; -using ::strcpy; -using ::strcspn; -using ::strlen; -using ::strncat; -using ::strncmp; -using ::strncpy; -using ::strpbrk; -using ::strrchr; -using ::strspn; -using ::strstr; -using ::strtok; -using ::strxfrm; -} // namespace std -#endif // _GHLIBCPP_CSTRING From aae01d00b2b224b95bb1bfb38ddc2c128d4d3dc4 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 11:32:19 +0100 Subject: [PATCH 393/628] Add csetjmp header --- cpp/common/test/includes/standard-library/csetjmp | 12 ++++++++++++ cpp/common/test/includes/standard-library/setjmp.h | 12 +++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/cpp/common/test/includes/standard-library/csetjmp b/cpp/common/test/includes/standard-library/csetjmp index e69de29bb2..c1f7ceed39 100644 --- a/cpp/common/test/includes/standard-library/csetjmp +++ b/cpp/common/test/includes/standard-library/csetjmp @@ -0,0 +1,12 @@ +#ifndef _GHLIBCPP_CSETJMP +#define _GHLIBCPP_CSETJMP + +#include "setjmp.h" + +// C++ std namespace declarations +namespace std { +using ::jmp_buf; +using ::longjmp; +} // namespace std + +#endif // _GHLIBCPP_CSETJMP \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/setjmp.h b/cpp/common/test/includes/standard-library/setjmp.h index bb7e4fdc27..3d9ac27eb5 100644 --- a/cpp/common/test/includes/standard-library/setjmp.h +++ b/cpp/common/test/includes/standard-library/setjmp.h @@ -1,14 +1,12 @@ #ifndef _GHLIBCPP_SETJMP #define _GHLIBCPP_SETJMP - -struct __jmp_buf_tag - { - int x; - }; +struct __jmp_buf_tag { + int x; +}; typedef struct __jmp_buf_tag jmp_buf[1]; -void longjmp (struct __jmp_buf_tag __env[1], int __val); -#define setjmp(env) 0 +[[noreturn]] void longjmp(struct __jmp_buf_tag __env[1], int __val); +#define setjmp(env) 0 #endif From 786f747318bce4d540393b9340db201e4fb4fc37 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 11:33:18 +0100 Subject: [PATCH 394/628] Add str* functions to cstdlib/stdlib.h headers --- cpp/common/test/includes/standard-library/cstdlib | 7 +++++++ cpp/common/test/includes/standard-library/stdlib.h | 8 ++++++++ 2 files changed, 15 insertions(+) diff --git a/cpp/common/test/includes/standard-library/cstdlib b/cpp/common/test/includes/standard-library/cstdlib index 50c17d4ec0..1b7df173a1 100644 --- a/cpp/common/test/includes/standard-library/cstdlib +++ b/cpp/common/test/includes/standard-library/cstdlib @@ -15,5 +15,12 @@ using ::free; using ::malloc; using ::quick_exit; using ::rand; +using ::strtod; +using ::strtof; +using ::strtol; +using ::strtold; +using ::strtoll; +using ::strtoul; +using ::strtoull; } // namespace std #endif // _GHLIBCPP_CSTDLIB \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/stdlib.h b/cpp/common/test/includes/standard-library/stdlib.h index 7bfb3dc997..eb73db0627 100644 --- a/cpp/common/test/includes/standard-library/stdlib.h +++ b/cpp/common/test/includes/standard-library/stdlib.h @@ -26,6 +26,14 @@ long int atol(const char *str); long long int atoll(const char *str); double atof(const char *str); +long int strtol(const char *str, char **endptr, int base); +long long int strtoll(const char *str, char **endptr, int base); +unsigned long int strtoul(const char *str, char **endptr, int base); +unsigned long long int strtoull(const char *str, char **endptr, int base); +double strtod(const char *str, char **endptr); +float strtof(const char *str, char **endptr); +long double strtold(const char *str, char **endptr); + int rand(void); #endif // _GHLIBCPP_STDLIB \ No newline at end of file From 4ae6e326ba14eff4f681bc69637618be25521fcf Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 11:33:53 +0100 Subject: [PATCH 395/628] Add strerror to cstring/string.h And remove duplicate definitions --- cpp/common/test/includes/standard-library/cstring | 1 + cpp/common/test/includes/standard-library/string.h | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/common/test/includes/standard-library/cstring b/cpp/common/test/includes/standard-library/cstring index 2034c3963b..1df2276077 100644 --- a/cpp/common/test/includes/standard-library/cstring +++ b/cpp/common/test/includes/standard-library/cstring @@ -15,6 +15,7 @@ using ::strcmp; using ::strcoll; using ::strcpy; using ::strcspn; +using ::strerror; using ::strlen; using ::strncat; using ::strncmp; diff --git a/cpp/common/test/includes/standard-library/string.h b/cpp/common/test/includes/standard-library/string.h index d94a186f0e..b4b4d9b121 100644 --- a/cpp/common/test/includes/standard-library/string.h +++ b/cpp/common/test/includes/standard-library/string.h @@ -35,14 +35,13 @@ const char *strstr(const char *str1, const char *str2); char *strstr(char *str1, const char *str2); char *strtok(char *str, const char *delimiters); +char *strerror(int errnum); -char *strdup (const char *); +char *strdup(const char *); void *memcpy(void *dest, const void *src, size_t count); void *memset(void *dest, int ch, size_t count); void *memmove(void *dest, const void *src, size_t count); int memcmp(const void *lhs, const void *rhs, size_t count); -size_t strlen(const char *str); - #endif // _GHLIBCPP_STRINGH \ No newline at end of file From 1415a723fadc3c2b4bbb0697ea5feb3c3dd051b2 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 11:37:07 +0100 Subject: [PATCH 396/628] Add cwchar/wchar.h as stubs --- .../test/includes/standard-library/cwchar | 18 ++++++++++++++++++ .../test/includes/standard-library/wchar.h | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/cpp/common/test/includes/standard-library/cwchar b/cpp/common/test/includes/standard-library/cwchar index e69de29bb2..a3e70b8d2b 100644 --- a/cpp/common/test/includes/standard-library/cwchar +++ b/cpp/common/test/includes/standard-library/cwchar @@ -0,0 +1,18 @@ +#pragma once +#ifndef _GHLIBCPP_CWCHAR +#define _GHLIBCPP_CWCHAR +#include "wchar.h" + +namespace std { +using ::fgetwc; +using ::fputwc; +using ::wcstod; +using ::wcstof; +using ::wcstol; +using ::wcstold; +using ::wcstoll; +using ::wcstoul; +using ::wcstoull; +} // namespace std + +#endif // _GHLIBCPP_CWCHAR \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/wchar.h b/cpp/common/test/includes/standard-library/wchar.h index e69de29bb2..e2f2942453 100644 --- a/cpp/common/test/includes/standard-library/wchar.h +++ b/cpp/common/test/includes/standard-library/wchar.h @@ -0,0 +1,19 @@ +#ifndef _GHLIBCPP_WCHAR +#define _GHLIBCPP_WCHAR + +#include "stddef.h" + +// Wide character I/O functions +wchar_t fgetwc(void *stream); +wchar_t fputwc(wchar_t wc, void *stream); + +// Wide character string conversion functions +long wcstol(const wchar_t *str, wchar_t **endptr, int base); +long long wcstoll(const wchar_t *str, wchar_t **endptr, int base); +unsigned long wcstoul(const wchar_t *str, wchar_t **endptr, int base); +unsigned long long wcstoull(const wchar_t *str, wchar_t **endptr, int base); +double wcstod(const wchar_t *str, wchar_t **endptr); +float wcstof(const wchar_t *str, wchar_t **endptr); +long double wcstold(const wchar_t *str, wchar_t **endptr); + +#endif // _GHLIBCPP_WCHAR \ No newline at end of file From c15b516d8f6a7f4ef223112f2fff158a6ebb91a0 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 11:38:29 +0100 Subject: [PATCH 397/628] Add `stdint.h` as a header, and move cstdint definitions --- .../test/includes/standard-library/cstdint.h | 29 ++++++++++--------- .../test/includes/standard-library/stdint.h | 20 +++++++++++++ 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/cpp/common/test/includes/standard-library/cstdint.h b/cpp/common/test/includes/standard-library/cstdint.h index 6a691637ff..f84fe3e4bb 100644 --- a/cpp/common/test/includes/standard-library/cstdint.h +++ b/cpp/common/test/includes/standard-library/cstdint.h @@ -1,19 +1,20 @@ #ifndef _GHLIBCPP_CSTDINT #define _GHLIBCPP_CSTDINT +#include "stdint.h" namespace std { -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef signed short int int16_t; -typedef unsigned short int uint16_t; -typedef signed int int32_t; -typedef unsigned int uint32_t; -typedef signed long int int64_t; -typedef unsigned long int uint64_t; -typedef int intmax_t; - -typedef uint8_t uint_fast8_t; -typedef uint16_t uint_fast16_t; -typedef uint32_t uint_fast32_t; -typedef uint64_t uint_fast64_t; +using ::int16_t; +using ::int32_t; +using ::int64_t; +using ::int8_t; +using ::intmax_t; +using ::uint16_t; +using ::uint32_t; +using ::uint64_t; +using ::uint8_t; +using ::uint_fast16_t; +using ::uint_fast32_t; +using ::uint_fast64_t; +using ::uint_fast8_t; +using ::uintmax_t; } // namespace std #endif // _GHLIBCPP_CSTDINT \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/stdint.h b/cpp/common/test/includes/standard-library/stdint.h index e69de29bb2..ab57461648 100644 --- a/cpp/common/test/includes/standard-library/stdint.h +++ b/cpp/common/test/includes/standard-library/stdint.h @@ -0,0 +1,20 @@ +#ifndef _GHLIBCPP_STDINT +#define _GHLIBCPP_STDINT + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int int16_t; +typedef unsigned short int uint16_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +typedef signed long int int64_t; +typedef unsigned long int uint64_t; +typedef int intmax_t; +typedef unsigned int uintmax_t; + +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +#endif // _GHLIBCPP_STDINT \ No newline at end of file From ce58affab081b50e13326efde5da90af3308c312 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 11:39:55 +0100 Subject: [PATCH 398/628] Remove cstdint.h This is not a "real" header - definitions should be in stdint.h and cstdint. --- .../src/codingstandards/cpp/CommonTypes.qll | 2 +- .../test/includes/standard-library/cstdint | 26 ++++++++++++++----- .../test/includes/standard-library/cstdint.h | 20 -------------- .../test/includes/standard-library/random.h | 2 +- 4 files changed, 22 insertions(+), 28 deletions(-) delete mode 100644 cpp/common/test/includes/standard-library/cstdint.h diff --git a/cpp/autosar/src/codingstandards/cpp/CommonTypes.qll b/cpp/autosar/src/codingstandards/cpp/CommonTypes.qll index aafbe85433..3c8ea46b08 100644 --- a/cpp/autosar/src/codingstandards/cpp/CommonTypes.qll +++ b/cpp/autosar/src/codingstandards/cpp/CommonTypes.qll @@ -1,7 +1,7 @@ import cpp as default /* - * Implementations of the C/C++ Fixed Width Types from cstdint.h. + * Implementations of the C/C++ Fixed Width Types from cstdint. * * TODO: Deprecate once this is available in the CodeQL standard library. */ diff --git a/cpp/common/test/includes/standard-library/cstdint b/cpp/common/test/includes/standard-library/cstdint index fedf405ddb..f84fe3e4bb 100644 --- a/cpp/common/test/includes/standard-library/cstdint +++ b/cpp/common/test/includes/standard-library/cstdint @@ -1,6 +1,20 @@ -#ifndef _CPP_CSTDINT -#define _CPP_CSTDINT - -#define MAX_INT -#include -#endif \ No newline at end of file +#ifndef _GHLIBCPP_CSTDINT +#define _GHLIBCPP_CSTDINT +#include "stdint.h" +namespace std { +using ::int16_t; +using ::int32_t; +using ::int64_t; +using ::int8_t; +using ::intmax_t; +using ::uint16_t; +using ::uint32_t; +using ::uint64_t; +using ::uint8_t; +using ::uint_fast16_t; +using ::uint_fast32_t; +using ::uint_fast64_t; +using ::uint_fast8_t; +using ::uintmax_t; +} // namespace std +#endif // _GHLIBCPP_CSTDINT \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cstdint.h b/cpp/common/test/includes/standard-library/cstdint.h deleted file mode 100644 index f84fe3e4bb..0000000000 --- a/cpp/common/test/includes/standard-library/cstdint.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _GHLIBCPP_CSTDINT -#define _GHLIBCPP_CSTDINT -#include "stdint.h" -namespace std { -using ::int16_t; -using ::int32_t; -using ::int64_t; -using ::int8_t; -using ::intmax_t; -using ::uint16_t; -using ::uint32_t; -using ::uint64_t; -using ::uint8_t; -using ::uint_fast16_t; -using ::uint_fast32_t; -using ::uint_fast64_t; -using ::uint_fast8_t; -using ::uintmax_t; -} // namespace std -#endif // _GHLIBCPP_CSTDINT \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/random.h b/cpp/common/test/includes/standard-library/random.h index 1a2b341226..141b806b62 100644 --- a/cpp/common/test/includes/standard-library/random.h +++ b/cpp/common/test/includes/standard-library/random.h @@ -1,7 +1,7 @@ #ifndef _GHLIBCPP_RANDOM #define _GHLIBCPP_RANDOM -#include "cstdint.h" #include "stddef.h" +#include #include namespace std { From 99fa73b45e2850399338eae173c03a5a365756ea Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 11:47:48 +0100 Subject: [PATCH 399/628] Update cinttypes/inttypes.h - Replace int aliases with include of stdint.h - Add str/wcs function stubs - Add header guards --- .../test/includes/standard-library/cinttypes | 13 ++++++++++++- .../test/includes/standard-library/inttypes.h | 19 ++++++++++--------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/cpp/common/test/includes/standard-library/cinttypes b/cpp/common/test/includes/standard-library/cinttypes index 8adb84dd2f..e9f7d45144 100644 --- a/cpp/common/test/includes/standard-library/cinttypes +++ b/cpp/common/test/includes/standard-library/cinttypes @@ -1 +1,12 @@ -#include \ No newline at end of file +#ifndef _GHLIBCPP_CINTTYPES +#define _GHLIBCPP_CINTTYPES +#include "inttypes.h" + +namespace std { +using ::strtoimax; +using ::strtoumax; +using ::wcstoimax; +using ::wcstoumax; +} // namespace std + +#endif // _GHLIBCPP_CINTTYPES \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/inttypes.h b/cpp/common/test/includes/standard-library/inttypes.h index d613ea4dcc..2f32726a05 100644 --- a/cpp/common/test/includes/standard-library/inttypes.h +++ b/cpp/common/test/includes/standard-library/inttypes.h @@ -1,11 +1,12 @@ -#pragma once +#ifndef _GHLIBCPP_INTTYPES +#define _GHLIBCPP_INTTYPES +#include -typedef signed char int8_t; -typedef signed short int int16_t; -typedef signed long int int32_t; -typedef signed long long int int64_t; +// String conversion functions +intmax_t strtoimax(const char *str, char **endptr, int base); +uintmax_t strtoumax(const char *str, char **endptr, int base); -typedef unsigned char uint8_t; -typedef unsigned short int uint16_t; -typedef unsigned long int uint32_t; -typedef unsigned long long int uint64_t; \ No newline at end of file +// Wide character versions +intmax_t wcstoimax(const wchar_t *str, wchar_t **endptr, int base); +uintmax_t wcstoumax(const wchar_t *str, wchar_t **endptr, int base); +#endif // _GHLIBCPP_INTTYPES \ No newline at end of file From 84697e6605d7b8efad19c024510b5216a77b2a7f Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 12:49:19 +0100 Subject: [PATCH 400/628] Populate wint_t from wctype.h, and use it in wchar.h. --- cpp/common/test/includes/standard-library/cwctype | 8 ++++++++ cpp/common/test/includes/standard-library/wchar.h | 5 +++-- cpp/common/test/includes/standard-library/wctype.h | 6 ++++++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/cpp/common/test/includes/standard-library/cwctype b/cpp/common/test/includes/standard-library/cwctype index e69de29bb2..490ed4edf9 100644 --- a/cpp/common/test/includes/standard-library/cwctype +++ b/cpp/common/test/includes/standard-library/cwctype @@ -0,0 +1,8 @@ +#ifndef _GHLIBCPP_CWCTYPE +#define _GHLIBCPP_CWCTYPE + +namespace std { +using ::wint_t; +} // namespace std + +#endif // _GHLIBCPP_CWCTYPE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/wchar.h b/cpp/common/test/includes/standard-library/wchar.h index e2f2942453..6c79fb0dec 100644 --- a/cpp/common/test/includes/standard-library/wchar.h +++ b/cpp/common/test/includes/standard-library/wchar.h @@ -2,10 +2,11 @@ #define _GHLIBCPP_WCHAR #include "stddef.h" +#include "wctype.h" // Wide character I/O functions -wchar_t fgetwc(void *stream); -wchar_t fputwc(wchar_t wc, void *stream); +wint_t fgetwc(void *stream); +wint_t fputwc(wchar_t wc, void *stream); // Wide character string conversion functions long wcstol(const wchar_t *str, wchar_t **endptr, int base); diff --git a/cpp/common/test/includes/standard-library/wctype.h b/cpp/common/test/includes/standard-library/wctype.h index e69de29bb2..b82c7a13f7 100644 --- a/cpp/common/test/includes/standard-library/wctype.h +++ b/cpp/common/test/includes/standard-library/wctype.h @@ -0,0 +1,6 @@ +#ifndef _GHLIBCPP_WCTYPE +#define _GHLIBCPP_WCTYPE + +typedef long wint_t; + +#endif // _GHLIBCPP_WCTYPE \ No newline at end of file From 555fdecf8c3b4cab2ce9ce9ea13e9827a7e5667c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 12:51:02 +0100 Subject: [PATCH 401/628] Rule 21.2.2 - UnsafeStringHandlingFunctions.ql Add a query to detect uses of a number of common unsafe string handling functions. [a] --- .../UnsafeStringHandlingFunctions.ql | 45 +++ .../UnsafeStringHandlingFunctions.expected | 222 +++++++++++ .../UnsafeStringHandlingFunctions.qlref | 1 + cpp/misra/test/rules/RULE-21-2-2/test.cpp | 367 ++++++++++++++++++ 4 files changed, 635 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql create mode 100644 cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected create mode 100644 cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.qlref create mode 100644 cpp/misra/test/rules/RULE-21-2-2/test.cpp diff --git a/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql b/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql new file mode 100644 index 0000000000..6a2638d217 --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql @@ -0,0 +1,45 @@ +/** + * @id cpp/misra/unsafe-string-handling-functions + * @name RULE-21-2-2: The string handling functions from , , and shall not be used + * @description Using string handling functions from , , and + * headers may result in buffer overflows or unreliable error detection through errno. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-2-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +predicate isBannedStringFunction(Function f) { + f.hasGlobalName([ + "strcat", "strchr", "strcmp", "strcoll", "strcpy", "strcspn", + "strerror", "strlen", "strncat", "strncmp", "strncpy", "strpbrk", + "strrchr", "strspn", "strstr", "strtok", "strxfrm", + "strtol", "strtoll", "strtoul", "strtoull", "strtod", "strtof", "strtold", + "fgetwc", "fputwc", "wcstol", "wcstoll", "wcstoul", "wcstoull", + "wcstod", "wcstof", "wcstold", + "strtoumax", "strtoimax", "wcstoumax", "wcstoimax" + ]) +} + +from Expr e, Function f, string msg +where + not isExcluded(e, BannedAPIsPackage::unsafeStringHandlingFunctionsQuery()) and + ( + (e.(FunctionCall).getTarget() = f and isBannedStringFunction(f) and + msg = "Call to banned string handling function '" + f.getName() + "'.") + or + (e.(AddressOfExpr).getOperand().(FunctionAccess).getTarget() = f and isBannedStringFunction(f) and + msg = "Address taken of banned string handling function '" + f.getName() + "'.") + or + (e.(FunctionAccess).getTarget() = f and isBannedStringFunction(f) and + not e.getParent() instanceof FunctionCall and + not e.getParent() instanceof AddressOfExpr and + msg = "Reference to banned string handling function '" + f.getName() + "'.") + ) +select e, msg \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected new file mode 100644 index 0000000000..29e347adda --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected @@ -0,0 +1,222 @@ +| test.cpp:16:3:16:8 | call to strcat | Call to banned string handling function 'strcat'. | +| test.cpp:17:3:17:8 | call to strchr | Call to banned string handling function 'strchr'. | +| test.cpp:18:3:18:8 | call to strcmp | Call to banned string handling function 'strcmp'. | +| test.cpp:19:3:19:9 | call to strcoll | Call to banned string handling function 'strcoll'. | +| test.cpp:20:3:20:8 | call to strcpy | Call to banned string handling function 'strcpy'. | +| test.cpp:21:3:21:9 | call to strcspn | Call to banned string handling function 'strcspn'. | +| test.cpp:22:3:22:10 | call to strerror | Call to banned string handling function 'strerror'. | +| test.cpp:23:3:23:8 | call to strlen | Call to banned string handling function 'strlen'. | +| test.cpp:24:3:24:9 | call to strncat | Call to banned string handling function 'strncat'. | +| test.cpp:25:3:25:9 | call to strncmp | Call to banned string handling function 'strncmp'. | +| test.cpp:26:3:26:9 | call to strncpy | Call to banned string handling function 'strncpy'. | +| test.cpp:27:3:27:9 | call to strpbrk | Call to banned string handling function 'strpbrk'. | +| test.cpp:28:3:28:9 | call to strrchr | Call to banned string handling function 'strrchr'. | +| test.cpp:29:3:29:8 | call to strspn | Call to banned string handling function 'strspn'. | +| test.cpp:30:3:30:8 | call to strstr | Call to banned string handling function 'strstr'. | +| test.cpp:31:3:31:8 | call to strtok | Call to banned string handling function 'strtok'. | +| test.cpp:32:3:32:9 | call to strxfrm | Call to banned string handling function 'strxfrm'. | +| test.cpp:39:3:39:8 | call to strtol | Call to banned string handling function 'strtol'. | +| test.cpp:40:3:40:9 | call to strtoll | Call to banned string handling function 'strtoll'. | +| test.cpp:41:3:41:9 | call to strtoul | Call to banned string handling function 'strtoul'. | +| test.cpp:42:3:42:10 | call to strtoull | Call to banned string handling function 'strtoull'. | +| test.cpp:43:3:43:8 | call to strtod | Call to banned string handling function 'strtod'. | +| test.cpp:44:3:44:8 | call to strtof | Call to banned string handling function 'strtof'. | +| test.cpp:45:3:45:9 | call to strtold | Call to banned string handling function 'strtold'. | +| test.cpp:54:3:54:8 | call to fgetwc | Call to banned string handling function 'fgetwc'. | +| test.cpp:55:3:55:8 | call to fputwc | Call to banned string handling function 'fputwc'. | +| test.cpp:56:3:56:8 | call to wcstol | Call to banned string handling function 'wcstol'. | +| test.cpp:57:3:57:9 | call to wcstoll | Call to banned string handling function 'wcstoll'. | +| test.cpp:58:3:58:9 | call to wcstoul | Call to banned string handling function 'wcstoul'. | +| test.cpp:59:3:59:10 | call to wcstoull | Call to banned string handling function 'wcstoull'. | +| test.cpp:60:3:60:8 | call to wcstod | Call to banned string handling function 'wcstod'. | +| test.cpp:61:3:61:8 | call to wcstof | Call to banned string handling function 'wcstof'. | +| test.cpp:62:3:62:9 | call to wcstold | Call to banned string handling function 'wcstold'. | +| test.cpp:71:3:71:11 | call to strtoumax | Call to banned string handling function 'strtoumax'. | +| test.cpp:72:3:72:11 | call to strtoimax | Call to banned string handling function 'strtoimax'. | +| test.cpp:73:3:73:11 | call to wcstoumax | Call to banned string handling function 'wcstoumax'. | +| test.cpp:74:3:74:11 | call to wcstoimax | Call to banned string handling function 'wcstoimax'. | +| test.cpp:78:39:78:45 | & ... | Address taken of banned string handling function 'strcat'. | +| test.cpp:79:39:79:44 | strcat | Reference to banned string handling function 'strcat'. | +| test.cpp:80:42:80:48 | & ... | Address taken of banned string handling function 'strchr'. | +| test.cpp:81:42:81:47 | strchr | Reference to banned string handling function 'strchr'. | +| test.cpp:82:43:82:49 | & ... | Address taken of banned string handling function 'strcmp'. | +| test.cpp:83:43:83:48 | strcmp | Reference to banned string handling function 'strcmp'. | +| test.cpp:84:43:84:50 | & ... | Address taken of banned string handling function 'strcoll'. | +| test.cpp:85:43:85:49 | strcoll | Reference to banned string handling function 'strcoll'. | +| test.cpp:86:39:86:45 | & ... | Address taken of banned string handling function 'strcpy'. | +| test.cpp:87:40:87:45 | strcpy | Reference to banned string handling function 'strcpy'. | +| test.cpp:88:47:88:54 | & ... | Address taken of banned string handling function 'strcspn'. | +| test.cpp:89:47:89:53 | strcspn | Reference to banned string handling function 'strcspn'. | +| test.cpp:90:23:90:31 | & ... | Address taken of banned string handling function 'strerror'. | +| test.cpp:91:23:91:30 | strerror | Reference to banned string handling function 'strerror'. | +| test.cpp:92:33:92:39 | & ... | Address taken of banned string handling function 'strlen'. | +| test.cpp:93:33:93:38 | strlen | Reference to banned string handling function 'strlen'. | +| test.cpp:94:48:94:55 | & ... | Address taken of banned string handling function 'strncat'. | +| test.cpp:95:48:95:54 | strncat | Reference to banned string handling function 'strncat'. | +| test.cpp:96:52:96:59 | & ... | Address taken of banned string handling function 'strncmp'. | +| test.cpp:97:52:97:58 | strncmp | Reference to banned string handling function 'strncmp'. | +| test.cpp:98:48:98:55 | & ... | Address taken of banned string handling function 'strncpy'. | +| test.cpp:99:48:99:54 | strncpy | Reference to banned string handling function 'strncpy'. | +| test.cpp:100:52:100:59 | & ... | Address taken of banned string handling function 'strpbrk'. | +| test.cpp:101:52:101:58 | strpbrk | Reference to banned string handling function 'strpbrk'. | +| test.cpp:102:43:102:50 | & ... | Address taken of banned string handling function 'strrchr'. | +| test.cpp:103:43:103:49 | strrchr | Reference to banned string handling function 'strrchr'. | +| test.cpp:104:47:104:53 | & ... | Address taken of banned string handling function 'strspn'. | +| test.cpp:105:47:105:52 | strspn | Reference to banned string handling function 'strspn'. | +| test.cpp:106:52:106:58 | & ... | Address taken of banned string handling function 'strstr'. | +| test.cpp:107:52:107:57 | strstr | Reference to banned string handling function 'strstr'. | +| test.cpp:108:40:108:46 | & ... | Address taken of banned string handling function 'strtok'. | +| test.cpp:109:40:109:45 | strtok | Reference to banned string handling function 'strtok'. | +| test.cpp:110:49:110:56 | & ... | Address taken of banned string handling function 'strxfrm'. | +| test.cpp:111:49:111:55 | strxfrm | Reference to banned string handling function 'strxfrm'. | +| test.cpp:115:44:115:50 | & ... | Address taken of banned string handling function 'strtol'. | +| test.cpp:116:44:116:49 | strtol | Reference to banned string handling function 'strtol'. | +| test.cpp:117:49:117:56 | & ... | Address taken of banned string handling function 'strtoll'. | +| test.cpp:118:49:118:55 | strtoll | Reference to banned string handling function 'strtoll'. | +| test.cpp:119:53:119:60 | & ... | Address taken of banned string handling function 'strtoul'. | +| test.cpp:120:53:120:59 | strtoul | Reference to banned string handling function 'strtoul'. | +| test.cpp:122:7:122:15 | & ... | Address taken of banned string handling function 'strtoull'. | +| test.cpp:124:7:124:14 | strtoull | Reference to banned string handling function 'strtoull'. | +| test.cpp:125:41:125:47 | & ... | Address taken of banned string handling function 'strtod'. | +| test.cpp:126:42:126:47 | strtod | Reference to banned string handling function 'strtod'. | +| test.cpp:127:41:127:47 | & ... | Address taken of banned string handling function 'strtof'. | +| test.cpp:128:41:128:46 | strtof | Reference to banned string handling function 'strtof'. | +| test.cpp:129:47:129:54 | & ... | Address taken of banned string handling function 'strtold'. | +| test.cpp:130:47:130:53 | strtold | Reference to banned string handling function 'strtold'. | +| test.cpp:134:26:134:32 | & ... | Address taken of banned string handling function 'fgetwc'. | +| test.cpp:135:26:135:31 | fgetwc | Reference to banned string handling function 'fgetwc'. | +| test.cpp:136:35:136:41 | & ... | Address taken of banned string handling function 'fputwc'. | +| test.cpp:137:35:137:40 | fputwc | Reference to banned string handling function 'fputwc'. | +| test.cpp:138:50:138:56 | & ... | Address taken of banned string handling function 'wcstol'. | +| test.cpp:139:50:139:55 | wcstol | Reference to banned string handling function 'wcstol'. | +| test.cpp:140:55:140:62 | & ... | Address taken of banned string handling function 'wcstoll'. | +| test.cpp:141:55:141:61 | wcstoll | Reference to banned string handling function 'wcstoll'. | +| test.cpp:143:7:143:14 | & ... | Address taken of banned string handling function 'wcstoul'. | +| test.cpp:145:7:145:13 | wcstoul | Reference to banned string handling function 'wcstoul'. | +| test.cpp:147:7:147:15 | & ... | Address taken of banned string handling function 'wcstoull'. | +| test.cpp:149:7:149:14 | wcstoull | Reference to banned string handling function 'wcstoull'. | +| test.cpp:150:48:150:54 | & ... | Address taken of banned string handling function 'wcstod'. | +| test.cpp:151:48:151:53 | wcstod | Reference to banned string handling function 'wcstod'. | +| test.cpp:152:47:152:53 | & ... | Address taken of banned string handling function 'wcstof'. | +| test.cpp:153:47:153:52 | wcstof | Reference to banned string handling function 'wcstof'. | +| test.cpp:154:53:154:60 | & ... | Address taken of banned string handling function 'wcstold'. | +| test.cpp:155:53:155:59 | wcstold | Reference to banned string handling function 'wcstold'. | +| test.cpp:159:49:159:58 | & ... | Address taken of banned string handling function 'strtoumax'. | +| test.cpp:160:49:160:57 | strtoumax | Reference to banned string handling function 'strtoumax'. | +| test.cpp:161:48:161:57 | & ... | Address taken of banned string handling function 'strtoimax'. | +| test.cpp:162:48:162:56 | strtoimax | Reference to banned string handling function 'strtoimax'. | +| test.cpp:164:7:164:16 | & ... | Address taken of banned string handling function 'wcstoumax'. | +| test.cpp:166:7:166:15 | wcstoumax | Reference to banned string handling function 'wcstoumax'. | +| test.cpp:168:7:168:16 | & ... | Address taken of banned string handling function 'wcstoimax'. | +| test.cpp:169:54:169:62 | wcstoimax | Reference to banned string handling function 'wcstoimax'. | +| test.cpp:177:3:177:13 | call to strcat | Call to banned string handling function 'strcat'. | +| test.cpp:178:3:178:13 | call to strchr | Call to banned string handling function 'strchr'. | +| test.cpp:179:3:179:13 | call to strcmp | Call to banned string handling function 'strcmp'. | +| test.cpp:180:3:180:14 | call to strcoll | Call to banned string handling function 'strcoll'. | +| test.cpp:181:3:181:13 | call to strcpy | Call to banned string handling function 'strcpy'. | +| test.cpp:182:3:182:14 | call to strcspn | Call to banned string handling function 'strcspn'. | +| test.cpp:183:3:183:15 | call to strerror | Call to banned string handling function 'strerror'. | +| test.cpp:184:3:184:13 | call to strlen | Call to banned string handling function 'strlen'. | +| test.cpp:185:3:185:14 | call to strncat | Call to banned string handling function 'strncat'. | +| test.cpp:186:3:186:14 | call to strncmp | Call to banned string handling function 'strncmp'. | +| test.cpp:187:3:187:14 | call to strncpy | Call to banned string handling function 'strncpy'. | +| test.cpp:188:3:188:14 | call to strpbrk | Call to banned string handling function 'strpbrk'. | +| test.cpp:189:3:189:14 | call to strrchr | Call to banned string handling function 'strrchr'. | +| test.cpp:190:3:190:13 | call to strspn | Call to banned string handling function 'strspn'. | +| test.cpp:191:3:191:13 | call to strstr | Call to banned string handling function 'strstr'. | +| test.cpp:192:3:192:13 | call to strtok | Call to banned string handling function 'strtok'. | +| test.cpp:193:3:193:14 | call to strxfrm | Call to banned string handling function 'strxfrm'. | +| test.cpp:200:3:200:13 | call to strtol | Call to banned string handling function 'strtol'. | +| test.cpp:201:3:201:14 | call to strtoll | Call to banned string handling function 'strtoll'. | +| test.cpp:202:3:202:14 | call to strtoul | Call to banned string handling function 'strtoul'. | +| test.cpp:203:3:203:15 | call to strtoull | Call to banned string handling function 'strtoull'. | +| test.cpp:204:3:204:13 | call to strtod | Call to banned string handling function 'strtod'. | +| test.cpp:205:3:205:13 | call to strtof | Call to banned string handling function 'strtof'. | +| test.cpp:206:3:206:14 | call to strtold | Call to banned string handling function 'strtold'. | +| test.cpp:215:3:215:13 | call to fgetwc | Call to banned string handling function 'fgetwc'. | +| test.cpp:216:3:216:13 | call to fputwc | Call to banned string handling function 'fputwc'. | +| test.cpp:217:3:217:13 | call to wcstol | Call to banned string handling function 'wcstol'. | +| test.cpp:218:3:218:14 | call to wcstoll | Call to banned string handling function 'wcstoll'. | +| test.cpp:219:3:219:14 | call to wcstoul | Call to banned string handling function 'wcstoul'. | +| test.cpp:220:3:220:15 | call to wcstoull | Call to banned string handling function 'wcstoull'. | +| test.cpp:221:3:221:13 | call to wcstod | Call to banned string handling function 'wcstod'. | +| test.cpp:222:3:222:13 | call to wcstof | Call to banned string handling function 'wcstof'. | +| test.cpp:223:3:223:14 | call to wcstold | Call to banned string handling function 'wcstold'. | +| test.cpp:232:3:232:16 | call to strtoumax | Call to banned string handling function 'strtoumax'. | +| test.cpp:233:3:233:16 | call to strtoimax | Call to banned string handling function 'strtoimax'. | +| test.cpp:234:3:234:16 | call to wcstoumax | Call to banned string handling function 'wcstoumax'. | +| test.cpp:235:3:235:16 | call to wcstoimax | Call to banned string handling function 'wcstoimax'. | +| test.cpp:239:39:239:50 | & ... | Address taken of banned string handling function 'strcat'. | +| test.cpp:240:39:240:49 | strcat | Reference to banned string handling function 'strcat'. | +| test.cpp:241:42:241:53 | & ... | Address taken of banned string handling function 'strchr'. | +| test.cpp:242:42:242:52 | strchr | Reference to banned string handling function 'strchr'. | +| test.cpp:243:43:243:54 | & ... | Address taken of banned string handling function 'strcmp'. | +| test.cpp:244:43:244:53 | strcmp | Reference to banned string handling function 'strcmp'. | +| test.cpp:245:43:245:55 | & ... | Address taken of banned string handling function 'strcoll'. | +| test.cpp:246:43:246:54 | strcoll | Reference to banned string handling function 'strcoll'. | +| test.cpp:247:39:247:50 | & ... | Address taken of banned string handling function 'strcpy'. | +| test.cpp:248:40:248:50 | strcpy | Reference to banned string handling function 'strcpy'. | +| test.cpp:249:47:249:59 | & ... | Address taken of banned string handling function 'strcspn'. | +| test.cpp:250:47:250:58 | strcspn | Reference to banned string handling function 'strcspn'. | +| test.cpp:251:23:251:36 | & ... | Address taken of banned string handling function 'strerror'. | +| test.cpp:252:23:252:35 | strerror | Reference to banned string handling function 'strerror'. | +| test.cpp:253:33:253:44 | & ... | Address taken of banned string handling function 'strlen'. | +| test.cpp:254:33:254:43 | strlen | Reference to banned string handling function 'strlen'. | +| test.cpp:255:48:255:60 | & ... | Address taken of banned string handling function 'strncat'. | +| test.cpp:256:48:256:59 | strncat | Reference to banned string handling function 'strncat'. | +| test.cpp:258:7:258:19 | & ... | Address taken of banned string handling function 'strncmp'. | +| test.cpp:260:7:260:18 | strncmp | Reference to banned string handling function 'strncmp'. | +| test.cpp:261:48:261:60 | & ... | Address taken of banned string handling function 'strncpy'. | +| test.cpp:262:48:262:59 | strncpy | Reference to banned string handling function 'strncpy'. | +| test.cpp:264:7:264:19 | & ... | Address taken of banned string handling function 'strpbrk'. | +| test.cpp:266:7:266:18 | strpbrk | Reference to banned string handling function 'strpbrk'. | +| test.cpp:267:43:267:55 | & ... | Address taken of banned string handling function 'strrchr'. | +| test.cpp:268:43:268:54 | strrchr | Reference to banned string handling function 'strrchr'. | +| test.cpp:269:47:269:58 | & ... | Address taken of banned string handling function 'strspn'. | +| test.cpp:270:47:270:57 | strspn | Reference to banned string handling function 'strspn'. | +| test.cpp:272:7:272:18 | & ... | Address taken of banned string handling function 'strstr'. | +| test.cpp:273:52:273:62 | strstr | Reference to banned string handling function 'strstr'. | +| test.cpp:274:40:274:51 | & ... | Address taken of banned string handling function 'strtok'. | +| test.cpp:275:40:275:50 | strtok | Reference to banned string handling function 'strtok'. | +| test.cpp:276:49:276:61 | & ... | Address taken of banned string handling function 'strxfrm'. | +| test.cpp:277:49:277:60 | strxfrm | Reference to banned string handling function 'strxfrm'. | +| test.cpp:281:44:281:55 | & ... | Address taken of banned string handling function 'strtol'. | +| test.cpp:282:44:282:54 | strtol | Reference to banned string handling function 'strtol'. | +| test.cpp:283:49:283:61 | & ... | Address taken of banned string handling function 'strtoll'. | +| test.cpp:284:49:284:60 | strtoll | Reference to banned string handling function 'strtoll'. | +| test.cpp:286:7:286:19 | & ... | Address taken of banned string handling function 'strtoul'. | +| test.cpp:288:7:288:18 | strtoul | Reference to banned string handling function 'strtoul'. | +| test.cpp:290:7:290:20 | & ... | Address taken of banned string handling function 'strtoull'. | +| test.cpp:292:7:292:19 | strtoull | Reference to banned string handling function 'strtoull'. | +| test.cpp:293:41:293:52 | & ... | Address taken of banned string handling function 'strtod'. | +| test.cpp:294:42:294:52 | strtod | Reference to banned string handling function 'strtod'. | +| test.cpp:295:41:295:52 | & ... | Address taken of banned string handling function 'strtof'. | +| test.cpp:296:41:296:51 | strtof | Reference to banned string handling function 'strtof'. | +| test.cpp:297:47:297:59 | & ... | Address taken of banned string handling function 'strtold'. | +| test.cpp:298:47:298:58 | strtold | Reference to banned string handling function 'strtold'. | +| test.cpp:302:26:302:37 | & ... | Address taken of banned string handling function 'fgetwc'. | +| test.cpp:303:26:303:36 | fgetwc | Reference to banned string handling function 'fgetwc'. | +| test.cpp:304:35:304:46 | & ... | Address taken of banned string handling function 'fputwc'. | +| test.cpp:305:35:305:45 | fputwc | Reference to banned string handling function 'fputwc'. | +| test.cpp:306:50:306:61 | & ... | Address taken of banned string handling function 'wcstol'. | +| test.cpp:307:50:307:60 | wcstol | Reference to banned string handling function 'wcstol'. | +| test.cpp:309:7:309:19 | & ... | Address taken of banned string handling function 'wcstoll'. | +| test.cpp:311:7:311:18 | wcstoll | Reference to banned string handling function 'wcstoll'. | +| test.cpp:313:7:313:19 | & ... | Address taken of banned string handling function 'wcstoul'. | +| test.cpp:315:7:315:18 | wcstoul | Reference to banned string handling function 'wcstoul'. | +| test.cpp:317:7:317:20 | & ... | Address taken of banned string handling function 'wcstoull'. | +| test.cpp:319:7:319:19 | wcstoull | Reference to banned string handling function 'wcstoull'. | +| test.cpp:320:48:320:59 | & ... | Address taken of banned string handling function 'wcstod'. | +| test.cpp:321:48:321:58 | wcstod | Reference to banned string handling function 'wcstod'. | +| test.cpp:322:47:322:58 | & ... | Address taken of banned string handling function 'wcstof'. | +| test.cpp:323:47:323:57 | wcstof | Reference to banned string handling function 'wcstof'. | +| test.cpp:325:7:325:19 | & ... | Address taken of banned string handling function 'wcstold'. | +| test.cpp:327:7:327:18 | wcstold | Reference to banned string handling function 'wcstold'. | +| test.cpp:332:7:332:21 | & ... | Address taken of banned string handling function 'strtoumax'. | +| test.cpp:333:49:333:62 | strtoumax | Reference to banned string handling function 'strtoumax'. | +| test.cpp:334:48:334:62 | & ... | Address taken of banned string handling function 'strtoimax'. | +| test.cpp:335:48:335:61 | strtoimax | Reference to banned string handling function 'strtoimax'. | +| test.cpp:337:7:337:21 | & ... | Address taken of banned string handling function 'wcstoumax'. | +| test.cpp:339:7:339:20 | wcstoumax | Reference to banned string handling function 'wcstoumax'. | +| test.cpp:341:7:341:21 | & ... | Address taken of banned string handling function 'wcstoimax'. | +| test.cpp:343:7:343:20 | wcstoimax | Reference to banned string handling function 'wcstoimax'. | diff --git a/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.qlref b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.qlref new file mode 100644 index 0000000000..1b69df818c --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.qlref @@ -0,0 +1 @@ +rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-2-2/test.cpp b/cpp/misra/test/rules/RULE-21-2-2/test.cpp new file mode 100644 index 0000000000..a61639e6a5 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-2/test.cpp @@ -0,0 +1,367 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void test_cstring_functions() { + char l1[100]; + char l2[100]; + const char *l3 = "test"; + + strcat(l1, l2); // NON_COMPLIANT + strchr(l3, 'e'); // NON_COMPLIANT + strcmp(l1, l2); // NON_COMPLIANT + strcoll(l1, l2); // NON_COMPLIANT + strcpy(l1, l3); // NON_COMPLIANT + strcspn(l1, l2); // NON_COMPLIANT + strerror(0); // NON_COMPLIANT + strlen(l3); // NON_COMPLIANT + strncat(l1, l2, 10); // NON_COMPLIANT + strncmp(l1, l2, 10); // NON_COMPLIANT + strncpy(l1, l3, 10); // NON_COMPLIANT + strpbrk(l1, l2); // NON_COMPLIANT + strrchr(l3, 'e'); // NON_COMPLIANT + strspn(l1, l2); // NON_COMPLIANT + strstr(l1, l3); // NON_COMPLIANT + strtok(l1, l2); // NON_COMPLIANT + strxfrm(l1, l2, 50); // NON_COMPLIANT +} + +void test_cstdlib_string_functions() { + const char *l1 = "123"; + char *l2; + + strtol(l1, &l2, 10); // NON_COMPLIANT + strtoll(l1, &l2, 10); // NON_COMPLIANT + strtoul(l1, &l2, 10); // NON_COMPLIANT + strtoull(l1, &l2, 10); // NON_COMPLIANT + strtod(l1, &l2); // NON_COMPLIANT + strtof(l1, &l2); // NON_COMPLIANT + strtold(l1, &l2); // NON_COMPLIANT +} + +void test_cwchar_functions() { + wchar_t l1[100]; + const wchar_t *l2 = L"123"; + wchar_t *l3; + FILE *l4 = nullptr; + + fgetwc(l4); // NON_COMPLIANT + fputwc(L'a', l4); // NON_COMPLIANT + wcstol(l2, &l3, 10); // NON_COMPLIANT + wcstoll(l2, &l3, 10); // NON_COMPLIANT + wcstoul(l2, &l3, 10); // NON_COMPLIANT + wcstoull(l2, &l3, 10); // NON_COMPLIANT + wcstod(l2, &l3); // NON_COMPLIANT + wcstof(l2, &l3); // NON_COMPLIANT + wcstold(l2, &l3); // NON_COMPLIANT +} + +void test_cinttypes_functions() { + const char *l1 = "123"; + char *l2; + const wchar_t *l3 = L"123"; + wchar_t *l4; + + strtoumax(l1, &l2, 10); // NON_COMPLIANT + strtoimax(l1, &l2, 10); // NON_COMPLIANT + wcstoumax(l3, &l4, 10); // NON_COMPLIANT + wcstoimax(l3, &l4, 10); // NON_COMPLIANT +} + +void test_cstring_function_pointer_addresses() { + char *(*l1)(char *, const char *) = &strcat; // NON_COMPLIANT + char *(*l2)(char *, const char *) = strcat; // NON_COMPLIANT + const char *(*l3)(const char *, int) = &strchr; // NON_COMPLIANT + const char *(*l4)(const char *, int) = strchr; // NON_COMPLIANT + int (*l5)(const char *, const char *) = &strcmp; // NON_COMPLIANT + int (*l6)(const char *, const char *) = strcmp; // NON_COMPLIANT + int (*l7)(const char *, const char *) = &strcoll; // NON_COMPLIANT + int (*l8)(const char *, const char *) = strcoll; // NON_COMPLIANT + char *(*l9)(char *, const char *) = &strcpy; // NON_COMPLIANT + char *(*l10)(char *, const char *) = strcpy; // NON_COMPLIANT + size_t (*l11)(const char *, const char *) = &strcspn; // NON_COMPLIANT + size_t (*l12)(const char *, const char *) = strcspn; // NON_COMPLIANT + char *(*l13)(int) = &strerror; // NON_COMPLIANT + char *(*l14)(int) = strerror; // NON_COMPLIANT + size_t (*l15)(const char *) = &strlen; // NON_COMPLIANT + size_t (*l16)(const char *) = strlen; // NON_COMPLIANT + char *(*l17)(char *, const char *, size_t) = &strncat; // NON_COMPLIANT + char *(*l18)(char *, const char *, size_t) = strncat; // NON_COMPLIANT + int (*l19)(const char *, const char *, size_t) = &strncmp; // NON_COMPLIANT + int (*l20)(const char *, const char *, size_t) = strncmp; // NON_COMPLIANT + char *(*l21)(char *, const char *, size_t) = &strncpy; // NON_COMPLIANT + char *(*l22)(char *, const char *, size_t) = strncpy; // NON_COMPLIANT + const char *(*l23)(const char *, const char *) = &strpbrk; // NON_COMPLIANT + const char *(*l24)(const char *, const char *) = strpbrk; // NON_COMPLIANT + const char *(*l25)(const char *, int) = &strrchr; // NON_COMPLIANT + const char *(*l26)(const char *, int) = strrchr; // NON_COMPLIANT + size_t (*l27)(const char *, const char *) = &strspn; // NON_COMPLIANT + size_t (*l28)(const char *, const char *) = strspn; // NON_COMPLIANT + const char *(*l29)(const char *, const char *) = &strstr; // NON_COMPLIANT + const char *(*l30)(const char *, const char *) = strstr; // NON_COMPLIANT + char *(*l31)(char *, const char *) = &strtok; // NON_COMPLIANT + char *(*l32)(char *, const char *) = strtok; // NON_COMPLIANT + size_t (*l33)(char *, const char *, size_t) = &strxfrm; // NON_COMPLIANT + size_t (*l34)(char *, const char *, size_t) = strxfrm; // NON_COMPLIANT +} + +void test_cstdlib_function_pointer_addresses() { + long (*l1)(const char *, char **, int) = &strtol; // NON_COMPLIANT + long (*l2)(const char *, char **, int) = strtol; // NON_COMPLIANT + long long (*l3)(const char *, char **, int) = &strtoll; // NON_COMPLIANT + long long (*l4)(const char *, char **, int) = strtoll; // NON_COMPLIANT + unsigned long (*l5)(const char *, char **, int) = &strtoul; // NON_COMPLIANT + unsigned long (*l6)(const char *, char **, int) = strtoul; // NON_COMPLIANT + unsigned long long (*l7)(const char *, char **, int) = + &strtoull; // NON_COMPLIANT + unsigned long long (*l8)(const char *, char **, int) = + strtoull; // NON_COMPLIANT + double (*l9)(const char *, char **) = &strtod; // NON_COMPLIANT + double (*l10)(const char *, char **) = strtod; // NON_COMPLIANT + float (*l11)(const char *, char **) = &strtof; // NON_COMPLIANT + float (*l12)(const char *, char **) = strtof; // NON_COMPLIANT + long double (*l13)(const char *, char **) = &strtold; // NON_COMPLIANT + long double (*l14)(const char *, char **) = strtold; // NON_COMPLIANT +} + +void test_cwchar_function_pointer_addresses() { + wint_t (*l1)(FILE *) = &fgetwc; // NON_COMPLIANT + wint_t (*l2)(FILE *) = fgetwc; // NON_COMPLIANT + wint_t (*l3)(wchar_t, FILE *) = &fputwc; // NON_COMPLIANT + wint_t (*l4)(wchar_t, FILE *) = fputwc; // NON_COMPLIANT + long (*l5)(const wchar_t *, wchar_t **, int) = &wcstol; // NON_COMPLIANT + long (*l6)(const wchar_t *, wchar_t **, int) = wcstol; // NON_COMPLIANT + long long (*l7)(const wchar_t *, wchar_t **, int) = &wcstoll; // NON_COMPLIANT + long long (*l8)(const wchar_t *, wchar_t **, int) = wcstoll; // NON_COMPLIANT + unsigned long (*l9)(const wchar_t *, wchar_t **, int) = + &wcstoul; // NON_COMPLIANT + unsigned long (*l10)(const wchar_t *, wchar_t **, int) = + wcstoul; // NON_COMPLIANT + unsigned long long (*l11)(const wchar_t *, wchar_t **, int) = + &wcstoull; // NON_COMPLIANT + unsigned long long (*l12)(const wchar_t *, wchar_t **, int) = + wcstoull; // NON_COMPLIANT + double (*l13)(const wchar_t *, wchar_t **) = &wcstod; // NON_COMPLIANT + double (*l14)(const wchar_t *, wchar_t **) = wcstod; // NON_COMPLIANT + float (*l15)(const wchar_t *, wchar_t **) = &wcstof; // NON_COMPLIANT + float (*l16)(const wchar_t *, wchar_t **) = wcstof; // NON_COMPLIANT + long double (*l17)(const wchar_t *, wchar_t **) = &wcstold; // NON_COMPLIANT + long double (*l18)(const wchar_t *, wchar_t **) = wcstold; // NON_COMPLIANT +} + +void test_cinttypes_function_pointer_addresses() { + uintmax_t (*l1)(const char *, char **, int) = &strtoumax; // NON_COMPLIANT + uintmax_t (*l2)(const char *, char **, int) = strtoumax; // NON_COMPLIANT + intmax_t (*l3)(const char *, char **, int) = &strtoimax; // NON_COMPLIANT + intmax_t (*l4)(const char *, char **, int) = strtoimax; // NON_COMPLIANT + uintmax_t (*l5)(const wchar_t *, wchar_t **, int) = + &wcstoumax; // NON_COMPLIANT + uintmax_t (*l6)(const wchar_t *, wchar_t **, int) = + wcstoumax; // NON_COMPLIANT + intmax_t (*l7)(const wchar_t *, wchar_t **, int) = + &wcstoimax; // NON_COMPLIANT + intmax_t (*l8)(const wchar_t *, wchar_t **, int) = wcstoimax; // NON_COMPLIANT +} + +void test_std_cstring_functions() { + char l1[100]; + char l2[100]; + const char *l3 = "test"; + + std::strcat(l1, l2); // NON_COMPLIANT + std::strchr(l3, 'e'); // NON_COMPLIANT + std::strcmp(l1, l2); // NON_COMPLIANT + std::strcoll(l1, l2); // NON_COMPLIANT + std::strcpy(l1, l3); // NON_COMPLIANT + std::strcspn(l1, l2); // NON_COMPLIANT + std::strerror(0); // NON_COMPLIANT + std::strlen(l3); // NON_COMPLIANT + std::strncat(l1, l2, 10); // NON_COMPLIANT + std::strncmp(l1, l2, 10); // NON_COMPLIANT + std::strncpy(l1, l3, 10); // NON_COMPLIANT + std::strpbrk(l1, l2); // NON_COMPLIANT + std::strrchr(l3, 'e'); // NON_COMPLIANT + std::strspn(l1, l2); // NON_COMPLIANT + std::strstr(l1, l3); // NON_COMPLIANT + std::strtok(l1, l2); // NON_COMPLIANT + std::strxfrm(l1, l2, 50); // NON_COMPLIANT +} + +void test_std_cstdlib_string_functions() { + const char *l1 = "123"; + char *l2; + + std::strtol(l1, &l2, 10); // NON_COMPLIANT + std::strtoll(l1, &l2, 10); // NON_COMPLIANT + std::strtoul(l1, &l2, 10); // NON_COMPLIANT + std::strtoull(l1, &l2, 10); // NON_COMPLIANT + std::strtod(l1, &l2); // NON_COMPLIANT + std::strtof(l1, &l2); // NON_COMPLIANT + std::strtold(l1, &l2); // NON_COMPLIANT +} + +void test_std_cwchar_functions() { + wchar_t l1[100]; + const wchar_t *l2 = L"123"; + wchar_t *l3; + FILE *l4 = nullptr; + + std::fgetwc(l4); // NON_COMPLIANT + std::fputwc(L'a', l4); // NON_COMPLIANT + std::wcstol(l2, &l3, 10); // NON_COMPLIANT + std::wcstoll(l2, &l3, 10); // NON_COMPLIANT + std::wcstoul(l2, &l3, 10); // NON_COMPLIANT + std::wcstoull(l2, &l3, 10); // NON_COMPLIANT + std::wcstod(l2, &l3); // NON_COMPLIANT + std::wcstof(l2, &l3); // NON_COMPLIANT + std::wcstold(l2, &l3); // NON_COMPLIANT +} + +void test_std_cinttypes_functions() { + const char *l1 = "123"; + char *l2; + const wchar_t *l3 = L"123"; + wchar_t *l4; + + std::strtoumax(l1, &l2, 10); // NON_COMPLIANT + std::strtoimax(l1, &l2, 10); // NON_COMPLIANT + std::wcstoumax(l3, &l4, 10); // NON_COMPLIANT + std::wcstoimax(l3, &l4, 10); // NON_COMPLIANT +} + +void test_std_cstring_function_pointer_addresses() { + char *(*l1)(char *, const char *) = &std::strcat; // NON_COMPLIANT + char *(*l2)(char *, const char *) = std::strcat; // NON_COMPLIANT + const char *(*l3)(const char *, int) = &std::strchr; // NON_COMPLIANT + const char *(*l4)(const char *, int) = std::strchr; // NON_COMPLIANT + int (*l5)(const char *, const char *) = &std::strcmp; // NON_COMPLIANT + int (*l6)(const char *, const char *) = std::strcmp; // NON_COMPLIANT + int (*l7)(const char *, const char *) = &std::strcoll; // NON_COMPLIANT + int (*l8)(const char *, const char *) = std::strcoll; // NON_COMPLIANT + char *(*l9)(char *, const char *) = &std::strcpy; // NON_COMPLIANT + char *(*l10)(char *, const char *) = std::strcpy; // NON_COMPLIANT + size_t (*l11)(const char *, const char *) = &std::strcspn; // NON_COMPLIANT + size_t (*l12)(const char *, const char *) = std::strcspn; // NON_COMPLIANT + char *(*l13)(int) = &std::strerror; // NON_COMPLIANT + char *(*l14)(int) = std::strerror; // NON_COMPLIANT + size_t (*l15)(const char *) = &std::strlen; // NON_COMPLIANT + size_t (*l16)(const char *) = std::strlen; // NON_COMPLIANT + char *(*l17)(char *, const char *, size_t) = &std::strncat; // NON_COMPLIANT + char *(*l18)(char *, const char *, size_t) = std::strncat; // NON_COMPLIANT + int (*l19)(const char *, const char *, size_t) = + &std::strncmp; // NON_COMPLIANT + int (*l20)(const char *, const char *, size_t) = + std::strncmp; // NON_COMPLIANT + char *(*l21)(char *, const char *, size_t) = &std::strncpy; // NON_COMPLIANT + char *(*l22)(char *, const char *, size_t) = std::strncpy; // NON_COMPLIANT + const char *(*l23)(const char *, const char *) = + &std::strpbrk; // NON_COMPLIANT + const char *(*l24)(const char *, const char *) = + std::strpbrk; // NON_COMPLIANT + const char *(*l25)(const char *, int) = &std::strrchr; // NON_COMPLIANT + const char *(*l26)(const char *, int) = std::strrchr; // NON_COMPLIANT + size_t (*l27)(const char *, const char *) = &std::strspn; // NON_COMPLIANT + size_t (*l28)(const char *, const char *) = std::strspn; // NON_COMPLIANT + const char *(*l29)(const char *, const char *) = + &std::strstr; // NON_COMPLIANT + const char *(*l30)(const char *, const char *) = std::strstr; // NON_COMPLIANT + char *(*l31)(char *, const char *) = &std::strtok; // NON_COMPLIANT + char *(*l32)(char *, const char *) = std::strtok; // NON_COMPLIANT + size_t (*l33)(char *, const char *, size_t) = &std::strxfrm; // NON_COMPLIANT + size_t (*l34)(char *, const char *, size_t) = std::strxfrm; // NON_COMPLIANT +} + +void test_std_cstdlib_function_pointer_addresses() { + long (*l1)(const char *, char **, int) = &std::strtol; // NON_COMPLIANT + long (*l2)(const char *, char **, int) = std::strtol; // NON_COMPLIANT + long long (*l3)(const char *, char **, int) = &std::strtoll; // NON_COMPLIANT + long long (*l4)(const char *, char **, int) = std::strtoll; // NON_COMPLIANT + unsigned long (*l5)(const char *, char **, int) = + &std::strtoul; // NON_COMPLIANT + unsigned long (*l6)(const char *, char **, int) = + std::strtoul; // NON_COMPLIANT + unsigned long long (*l7)(const char *, char **, int) = + &std::strtoull; // NON_COMPLIANT + unsigned long long (*l8)(const char *, char **, int) = + std::strtoull; // NON_COMPLIANT + double (*l9)(const char *, char **) = &std::strtod; // NON_COMPLIANT + double (*l10)(const char *, char **) = std::strtod; // NON_COMPLIANT + float (*l11)(const char *, char **) = &std::strtof; // NON_COMPLIANT + float (*l12)(const char *, char **) = std::strtof; // NON_COMPLIANT + long double (*l13)(const char *, char **) = &std::strtold; // NON_COMPLIANT + long double (*l14)(const char *, char **) = std::strtold; // NON_COMPLIANT +} + +void test_std_cwchar_function_pointer_addresses() { + wint_t (*l1)(FILE *) = &std::fgetwc; // NON_COMPLIANT + wint_t (*l2)(FILE *) = std::fgetwc; // NON_COMPLIANT + wint_t (*l3)(wchar_t, FILE *) = &std::fputwc; // NON_COMPLIANT + wint_t (*l4)(wchar_t, FILE *) = std::fputwc; // NON_COMPLIANT + long (*l5)(const wchar_t *, wchar_t **, int) = &std::wcstol; // NON_COMPLIANT + long (*l6)(const wchar_t *, wchar_t **, int) = std::wcstol; // NON_COMPLIANT + long long (*l7)(const wchar_t *, wchar_t **, int) = + &std::wcstoll; // NON_COMPLIANT + long long (*l8)(const wchar_t *, wchar_t **, int) = + std::wcstoll; // NON_COMPLIANT + unsigned long (*l9)(const wchar_t *, wchar_t **, int) = + &std::wcstoul; // NON_COMPLIANT + unsigned long (*l10)(const wchar_t *, wchar_t **, int) = + std::wcstoul; // NON_COMPLIANT + unsigned long long (*l11)(const wchar_t *, wchar_t **, int) = + &std::wcstoull; // NON_COMPLIANT + unsigned long long (*l12)(const wchar_t *, wchar_t **, int) = + std::wcstoull; // NON_COMPLIANT + double (*l13)(const wchar_t *, wchar_t **) = &std::wcstod; // NON_COMPLIANT + double (*l14)(const wchar_t *, wchar_t **) = std::wcstod; // NON_COMPLIANT + float (*l15)(const wchar_t *, wchar_t **) = &std::wcstof; // NON_COMPLIANT + float (*l16)(const wchar_t *, wchar_t **) = std::wcstof; // NON_COMPLIANT + long double (*l17)(const wchar_t *, wchar_t **) = + &std::wcstold; // NON_COMPLIANT + long double (*l18)(const wchar_t *, wchar_t **) = + std::wcstold; // NON_COMPLIANT +} + +void test_std_cinttypes_function_pointer_addresses() { + uintmax_t (*l1)(const char *, char **, int) = + &std::strtoumax; // NON_COMPLIANT + uintmax_t (*l2)(const char *, char **, int) = std::strtoumax; // NON_COMPLIANT + intmax_t (*l3)(const char *, char **, int) = &std::strtoimax; // NON_COMPLIANT + intmax_t (*l4)(const char *, char **, int) = std::strtoimax; // NON_COMPLIANT + uintmax_t (*l5)(const wchar_t *, wchar_t **, int) = + &std::wcstoumax; // NON_COMPLIANT + uintmax_t (*l6)(const wchar_t *, wchar_t **, int) = + std::wcstoumax; // NON_COMPLIANT + intmax_t (*l7)(const wchar_t *, wchar_t **, int) = + &std::wcstoimax; // NON_COMPLIANT + intmax_t (*l8)(const wchar_t *, wchar_t **, int) = + std::wcstoimax; // NON_COMPLIANT +} + +void test_compliant_alternatives() { + char l1[100]; + const char *l2 = "test"; + std::size_t l3 = 50; + + // Using std::string_view instead of strlen + std::string_view l4 = l2; + if (l4.size() + 1u < l3) { // COMPLIANT + l4.copy(l1, l4.size()); // COMPLIANT + l1[l4.size()] = 0; // COMPLIANT + } + + // Using std::string for string operations + std::string l5 = "hello"; + std::string l6 = "world"; + std::string l7 = l5 + l6; // COMPLIANT + + // Using standard library numeric conversions + std::string l8 = "123"; + std::int32_t l9 = std::stoi(l8); // COMPLIANT + double l10 = std::stod(l8); // COMPLIANT +} \ No newline at end of file From c6077982efa4121997a8e99116a257e647d2b4e2 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 14:49:54 +0100 Subject: [PATCH 402/628] Add a library to support the detection of banned functions This supports accurate detection of usage of banned functions: - Detects both accesses and calls - Reports the macro definition if the use is within a macro defined in the users code. - Otherwise reports the location of the expression. --- .../codingstandards/cpp/BannedFunctions.qll | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/BannedFunctions.qll diff --git a/cpp/common/src/codingstandards/cpp/BannedFunctions.qll b/cpp/common/src/codingstandards/cpp/BannedFunctions.qll new file mode 100644 index 0000000000..174d0a8433 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/BannedFunctions.qll @@ -0,0 +1,69 @@ +/** + * A library for supporting the consistent detection of banned functions in C++ code. + */ + +import cpp +import AlertReporting + +/** + * A signature for a banned function. + */ +signature class BannedFunction extends Function; + +/** + * A module for detecting uses of banned functions in C++ code. + */ +module BannedFunctions { + final private class FinalExpr = Expr; + + /** + * An expression that uses a banned function. + * + * It can be either a function call or a function access (taking the address of the function). + */ + class UseExpr extends FinalExpr { + string action; + F bannedFunction; + + UseExpr() { + this.(FunctionCall).getTarget() = bannedFunction and + action = "Call to" + or + this.(FunctionAccess).getTarget() = bannedFunction and + action = "Address taken for" + } + + string getFunctionName() { result = bannedFunction.getName() } + + string getAction() { result = action } + + Element getPrimaryElement() { + // If this is defined in a macro in the users source location, then report the macro + // expansion, otherwise report the element itself. This ensures that we always report + // the use of the terminating function, but combine usages when the macro is defined + // by the user. + exists(Element e | e = MacroUnwrapper::unwrapElement(this) | + if exists(e.getFile().getRelativePath()) then result = e else result = this + ) + } + } + + final private class FinalElement = Element; + + /** + * A `Use` of a banned function. + * + * This is an `Element` in a program which represents the use of a banned function. + * For uses within macro expansions, this may report the location of the macro, if + * it is defined within the user's source code. + */ + class Use extends FinalElement { + UseExpr use; + + Use() { this = use.getPrimaryElement() } + + string getFunctionName() { result = use.getFunctionName() } + + string getAction() { result = use.getAction() } + } +} From 7a28f0264163870bf08d27866a1fdc8ab6f625ce Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 14:52:18 +0100 Subject: [PATCH 403/628] Rule 18.5.2 - Use BannedFunctions library Use library to avoid duplication. --- .../AvoidProgramTerminatingFunctions.ql | 44 +++---------------- 1 file changed, 7 insertions(+), 37 deletions(-) diff --git a/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql index c262030c9b..adafebd44c 100644 --- a/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql +++ b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql @@ -16,55 +16,25 @@ import cpp import codingstandards.cpp.misra import codingstandards.cpp.AlertReporting +import codingstandards.cpp.BannedFunctions -predicate isTerminatingFunction(Function f, string functionName) { - functionName = f.getName() and - ( - functionName in ["abort", "exit", "_Exit", "quick_exit"] and - (f.hasQualifiedName("", functionName) or f.hasQualifiedName("std", functionName)) +class TerminatingFunction extends Function { + TerminatingFunction() { + this.hasQualifiedName(["", "std"], ["abort", "exit", "_Exit", "quick_exit"]) or // std::terminate does not occur in the global namespace. - functionName = "terminate" and f.hasQualifiedName("std", functionName) - ) -} - -class TerminatingFunctionUse extends Expr { - string action; - string functionName; - - TerminatingFunctionUse() { - exists(Function f | isTerminatingFunction(f, functionName) | - this.(FunctionCall).getTarget() = f and - action = "Call to" - or - this.(FunctionAccess).getTarget() = f and - action = "Address taken for" - ) - } - - string getFunctionName() { result = functionName } - - string getAction() { result = action } - - Element getPrimaryElement() { - // If this is defined in a macro in the users source location, then report the macro - // expansion, otherwise report the element itself. This ensures that we always report - // the use of the terminating function, but combine usages when the macro is defined - // by the user. - exists(Element e | e = MacroUnwrapper::unwrapElement(this) | - if exists(e.getFile().getRelativePath()) then result = e else result = this - ) + this.hasQualifiedName("std", "terminate") } } -predicate isInAssertMacroInvocation(TerminatingFunctionUse use) { +predicate isInAssertMacroInvocation(BannedFunctions::UseExpr use) { exists(MacroInvocation mi | mi.getMacroName() = "assert" and mi.getAnExpandedElement() = use ) } -from TerminatingFunctionUse use +from BannedFunctions::UseExpr use where not isExcluded(use, BannedAPIsPackage::avoidProgramTerminatingFunctionsQuery()) and // Exclude the uses in the assert macro From 7fa6646738101ce0f6625a5b64953f9a279d407b Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 14:52:43 +0100 Subject: [PATCH 404/628] Rule 21.2.2 - use BannedFunction library --- .../UnsafeStringHandlingFunctions.ql | 40 +-- .../UnsafeStringHandlingFunctions.expected | 296 +++++++++--------- 2 files changed, 162 insertions(+), 174 deletions(-) diff --git a/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql b/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql index 6a2638d217..ff888c9c22 100644 --- a/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql +++ b/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql @@ -14,32 +14,20 @@ import cpp import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions -predicate isBannedStringFunction(Function f) { - f.hasGlobalName([ - "strcat", "strchr", "strcmp", "strcoll", "strcpy", "strcspn", - "strerror", "strlen", "strncat", "strncmp", "strncpy", "strpbrk", - "strrchr", "strspn", "strstr", "strtok", "strxfrm", - "strtol", "strtoll", "strtoul", "strtoull", "strtod", "strtof", "strtold", - "fgetwc", "fputwc", "wcstol", "wcstoll", "wcstoul", "wcstoull", - "wcstod", "wcstof", "wcstold", - "strtoumax", "strtoimax", "wcstoumax", "wcstoimax" - ]) +class StringFunction extends Function { + StringFunction() { + this.hasGlobalName([ + "strcat", "strchr", "strcmp", "strcoll", "strcpy", "strcspn", "strerror", "strlen", + "strncat", "strncmp", "strncpy", "strpbrk", "strrchr", "strspn", "strstr", "strtok", + "strxfrm", "strtol", "strtoll", "strtoul", "strtoull", "strtod", "strtof", "strtold", + "fgetwc", "fputwc", "wcstol", "wcstoll", "wcstoul", "wcstoull", "wcstod", "wcstof", + "wcstold", "strtoumax", "strtoimax", "wcstoumax", "wcstoimax" + ]) + } } -from Expr e, Function f, string msg -where - not isExcluded(e, BannedAPIsPackage::unsafeStringHandlingFunctionsQuery()) and - ( - (e.(FunctionCall).getTarget() = f and isBannedStringFunction(f) and - msg = "Call to banned string handling function '" + f.getName() + "'.") - or - (e.(AddressOfExpr).getOperand().(FunctionAccess).getTarget() = f and isBannedStringFunction(f) and - msg = "Address taken of banned string handling function '" + f.getName() + "'.") - or - (e.(FunctionAccess).getTarget() = f and isBannedStringFunction(f) and - not e.getParent() instanceof FunctionCall and - not e.getParent() instanceof AddressOfExpr and - msg = "Reference to banned string handling function '" + f.getName() + "'.") - ) -select e, msg \ No newline at end of file +from BannedFunctions::Use use +where not isExcluded(use, BannedAPIsPackage::unsafeStringHandlingFunctionsQuery()) +select use, use.getAction() + " banned string handling function '" + use.getFunctionName() + "'." diff --git a/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected index 29e347adda..fc0efb103b 100644 --- a/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected +++ b/cpp/misra/test/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.expected @@ -35,80 +35,80 @@ | test.cpp:72:3:72:11 | call to strtoimax | Call to banned string handling function 'strtoimax'. | | test.cpp:73:3:73:11 | call to wcstoumax | Call to banned string handling function 'wcstoumax'. | | test.cpp:74:3:74:11 | call to wcstoimax | Call to banned string handling function 'wcstoimax'. | -| test.cpp:78:39:78:45 | & ... | Address taken of banned string handling function 'strcat'. | -| test.cpp:79:39:79:44 | strcat | Reference to banned string handling function 'strcat'. | -| test.cpp:80:42:80:48 | & ... | Address taken of banned string handling function 'strchr'. | -| test.cpp:81:42:81:47 | strchr | Reference to banned string handling function 'strchr'. | -| test.cpp:82:43:82:49 | & ... | Address taken of banned string handling function 'strcmp'. | -| test.cpp:83:43:83:48 | strcmp | Reference to banned string handling function 'strcmp'. | -| test.cpp:84:43:84:50 | & ... | Address taken of banned string handling function 'strcoll'. | -| test.cpp:85:43:85:49 | strcoll | Reference to banned string handling function 'strcoll'. | -| test.cpp:86:39:86:45 | & ... | Address taken of banned string handling function 'strcpy'. | -| test.cpp:87:40:87:45 | strcpy | Reference to banned string handling function 'strcpy'. | -| test.cpp:88:47:88:54 | & ... | Address taken of banned string handling function 'strcspn'. | -| test.cpp:89:47:89:53 | strcspn | Reference to banned string handling function 'strcspn'. | -| test.cpp:90:23:90:31 | & ... | Address taken of banned string handling function 'strerror'. | -| test.cpp:91:23:91:30 | strerror | Reference to banned string handling function 'strerror'. | -| test.cpp:92:33:92:39 | & ... | Address taken of banned string handling function 'strlen'. | -| test.cpp:93:33:93:38 | strlen | Reference to banned string handling function 'strlen'. | -| test.cpp:94:48:94:55 | & ... | Address taken of banned string handling function 'strncat'. | -| test.cpp:95:48:95:54 | strncat | Reference to banned string handling function 'strncat'. | -| test.cpp:96:52:96:59 | & ... | Address taken of banned string handling function 'strncmp'. | -| test.cpp:97:52:97:58 | strncmp | Reference to banned string handling function 'strncmp'. | -| test.cpp:98:48:98:55 | & ... | Address taken of banned string handling function 'strncpy'. | -| test.cpp:99:48:99:54 | strncpy | Reference to banned string handling function 'strncpy'. | -| test.cpp:100:52:100:59 | & ... | Address taken of banned string handling function 'strpbrk'. | -| test.cpp:101:52:101:58 | strpbrk | Reference to banned string handling function 'strpbrk'. | -| test.cpp:102:43:102:50 | & ... | Address taken of banned string handling function 'strrchr'. | -| test.cpp:103:43:103:49 | strrchr | Reference to banned string handling function 'strrchr'. | -| test.cpp:104:47:104:53 | & ... | Address taken of banned string handling function 'strspn'. | -| test.cpp:105:47:105:52 | strspn | Reference to banned string handling function 'strspn'. | -| test.cpp:106:52:106:58 | & ... | Address taken of banned string handling function 'strstr'. | -| test.cpp:107:52:107:57 | strstr | Reference to banned string handling function 'strstr'. | -| test.cpp:108:40:108:46 | & ... | Address taken of banned string handling function 'strtok'. | -| test.cpp:109:40:109:45 | strtok | Reference to banned string handling function 'strtok'. | -| test.cpp:110:49:110:56 | & ... | Address taken of banned string handling function 'strxfrm'. | -| test.cpp:111:49:111:55 | strxfrm | Reference to banned string handling function 'strxfrm'. | -| test.cpp:115:44:115:50 | & ... | Address taken of banned string handling function 'strtol'. | -| test.cpp:116:44:116:49 | strtol | Reference to banned string handling function 'strtol'. | -| test.cpp:117:49:117:56 | & ... | Address taken of banned string handling function 'strtoll'. | -| test.cpp:118:49:118:55 | strtoll | Reference to banned string handling function 'strtoll'. | -| test.cpp:119:53:119:60 | & ... | Address taken of banned string handling function 'strtoul'. | -| test.cpp:120:53:120:59 | strtoul | Reference to banned string handling function 'strtoul'. | -| test.cpp:122:7:122:15 | & ... | Address taken of banned string handling function 'strtoull'. | -| test.cpp:124:7:124:14 | strtoull | Reference to banned string handling function 'strtoull'. | -| test.cpp:125:41:125:47 | & ... | Address taken of banned string handling function 'strtod'. | -| test.cpp:126:42:126:47 | strtod | Reference to banned string handling function 'strtod'. | -| test.cpp:127:41:127:47 | & ... | Address taken of banned string handling function 'strtof'. | -| test.cpp:128:41:128:46 | strtof | Reference to banned string handling function 'strtof'. | -| test.cpp:129:47:129:54 | & ... | Address taken of banned string handling function 'strtold'. | -| test.cpp:130:47:130:53 | strtold | Reference to banned string handling function 'strtold'. | -| test.cpp:134:26:134:32 | & ... | Address taken of banned string handling function 'fgetwc'. | -| test.cpp:135:26:135:31 | fgetwc | Reference to banned string handling function 'fgetwc'. | -| test.cpp:136:35:136:41 | & ... | Address taken of banned string handling function 'fputwc'. | -| test.cpp:137:35:137:40 | fputwc | Reference to banned string handling function 'fputwc'. | -| test.cpp:138:50:138:56 | & ... | Address taken of banned string handling function 'wcstol'. | -| test.cpp:139:50:139:55 | wcstol | Reference to banned string handling function 'wcstol'. | -| test.cpp:140:55:140:62 | & ... | Address taken of banned string handling function 'wcstoll'. | -| test.cpp:141:55:141:61 | wcstoll | Reference to banned string handling function 'wcstoll'. | -| test.cpp:143:7:143:14 | & ... | Address taken of banned string handling function 'wcstoul'. | -| test.cpp:145:7:145:13 | wcstoul | Reference to banned string handling function 'wcstoul'. | -| test.cpp:147:7:147:15 | & ... | Address taken of banned string handling function 'wcstoull'. | -| test.cpp:149:7:149:14 | wcstoull | Reference to banned string handling function 'wcstoull'. | -| test.cpp:150:48:150:54 | & ... | Address taken of banned string handling function 'wcstod'. | -| test.cpp:151:48:151:53 | wcstod | Reference to banned string handling function 'wcstod'. | -| test.cpp:152:47:152:53 | & ... | Address taken of banned string handling function 'wcstof'. | -| test.cpp:153:47:153:52 | wcstof | Reference to banned string handling function 'wcstof'. | -| test.cpp:154:53:154:60 | & ... | Address taken of banned string handling function 'wcstold'. | -| test.cpp:155:53:155:59 | wcstold | Reference to banned string handling function 'wcstold'. | -| test.cpp:159:49:159:58 | & ... | Address taken of banned string handling function 'strtoumax'. | -| test.cpp:160:49:160:57 | strtoumax | Reference to banned string handling function 'strtoumax'. | -| test.cpp:161:48:161:57 | & ... | Address taken of banned string handling function 'strtoimax'. | -| test.cpp:162:48:162:56 | strtoimax | Reference to banned string handling function 'strtoimax'. | -| test.cpp:164:7:164:16 | & ... | Address taken of banned string handling function 'wcstoumax'. | -| test.cpp:166:7:166:15 | wcstoumax | Reference to banned string handling function 'wcstoumax'. | -| test.cpp:168:7:168:16 | & ... | Address taken of banned string handling function 'wcstoimax'. | -| test.cpp:169:54:169:62 | wcstoimax | Reference to banned string handling function 'wcstoimax'. | +| test.cpp:78:40:78:45 | strcat | Address taken for banned string handling function 'strcat'. | +| test.cpp:79:39:79:44 | strcat | Address taken for banned string handling function 'strcat'. | +| test.cpp:80:42:80:48 | strchr | Address taken for banned string handling function 'strchr'. | +| test.cpp:81:42:81:47 | strchr | Address taken for banned string handling function 'strchr'. | +| test.cpp:82:44:82:49 | strcmp | Address taken for banned string handling function 'strcmp'. | +| test.cpp:83:43:83:48 | strcmp | Address taken for banned string handling function 'strcmp'. | +| test.cpp:84:44:84:50 | strcoll | Address taken for banned string handling function 'strcoll'. | +| test.cpp:85:43:85:49 | strcoll | Address taken for banned string handling function 'strcoll'. | +| test.cpp:86:40:86:45 | strcpy | Address taken for banned string handling function 'strcpy'. | +| test.cpp:87:40:87:45 | strcpy | Address taken for banned string handling function 'strcpy'. | +| test.cpp:88:48:88:54 | strcspn | Address taken for banned string handling function 'strcspn'. | +| test.cpp:89:47:89:53 | strcspn | Address taken for banned string handling function 'strcspn'. | +| test.cpp:90:24:90:31 | strerror | Address taken for banned string handling function 'strerror'. | +| test.cpp:91:23:91:30 | strerror | Address taken for banned string handling function 'strerror'. | +| test.cpp:92:34:92:39 | strlen | Address taken for banned string handling function 'strlen'. | +| test.cpp:93:33:93:38 | strlen | Address taken for banned string handling function 'strlen'. | +| test.cpp:94:49:94:55 | strncat | Address taken for banned string handling function 'strncat'. | +| test.cpp:95:48:95:54 | strncat | Address taken for banned string handling function 'strncat'. | +| test.cpp:96:53:96:59 | strncmp | Address taken for banned string handling function 'strncmp'. | +| test.cpp:97:52:97:58 | strncmp | Address taken for banned string handling function 'strncmp'. | +| test.cpp:98:49:98:55 | strncpy | Address taken for banned string handling function 'strncpy'. | +| test.cpp:99:48:99:54 | strncpy | Address taken for banned string handling function 'strncpy'. | +| test.cpp:100:52:100:59 | strpbrk | Address taken for banned string handling function 'strpbrk'. | +| test.cpp:101:52:101:58 | strpbrk | Address taken for banned string handling function 'strpbrk'. | +| test.cpp:102:43:102:50 | strrchr | Address taken for banned string handling function 'strrchr'. | +| test.cpp:103:43:103:49 | strrchr | Address taken for banned string handling function 'strrchr'. | +| test.cpp:104:48:104:53 | strspn | Address taken for banned string handling function 'strspn'. | +| test.cpp:105:47:105:52 | strspn | Address taken for banned string handling function 'strspn'. | +| test.cpp:106:52:106:58 | strstr | Address taken for banned string handling function 'strstr'. | +| test.cpp:107:52:107:57 | strstr | Address taken for banned string handling function 'strstr'. | +| test.cpp:108:41:108:46 | strtok | Address taken for banned string handling function 'strtok'. | +| test.cpp:109:40:109:45 | strtok | Address taken for banned string handling function 'strtok'. | +| test.cpp:110:50:110:56 | strxfrm | Address taken for banned string handling function 'strxfrm'. | +| test.cpp:111:49:111:55 | strxfrm | Address taken for banned string handling function 'strxfrm'. | +| test.cpp:115:45:115:50 | strtol | Address taken for banned string handling function 'strtol'. | +| test.cpp:116:44:116:49 | strtol | Address taken for banned string handling function 'strtol'. | +| test.cpp:117:50:117:56 | strtoll | Address taken for banned string handling function 'strtoll'. | +| test.cpp:118:49:118:55 | strtoll | Address taken for banned string handling function 'strtoll'. | +| test.cpp:119:54:119:60 | strtoul | Address taken for banned string handling function 'strtoul'. | +| test.cpp:120:53:120:59 | strtoul | Address taken for banned string handling function 'strtoul'. | +| test.cpp:122:8:122:15 | strtoull | Address taken for banned string handling function 'strtoull'. | +| test.cpp:124:7:124:14 | strtoull | Address taken for banned string handling function 'strtoull'. | +| test.cpp:125:42:125:47 | strtod | Address taken for banned string handling function 'strtod'. | +| test.cpp:126:42:126:47 | strtod | Address taken for banned string handling function 'strtod'. | +| test.cpp:127:42:127:47 | strtof | Address taken for banned string handling function 'strtof'. | +| test.cpp:128:41:128:46 | strtof | Address taken for banned string handling function 'strtof'. | +| test.cpp:129:48:129:54 | strtold | Address taken for banned string handling function 'strtold'. | +| test.cpp:130:47:130:53 | strtold | Address taken for banned string handling function 'strtold'. | +| test.cpp:134:27:134:32 | fgetwc | Address taken for banned string handling function 'fgetwc'. | +| test.cpp:135:26:135:31 | fgetwc | Address taken for banned string handling function 'fgetwc'. | +| test.cpp:136:36:136:41 | fputwc | Address taken for banned string handling function 'fputwc'. | +| test.cpp:137:35:137:40 | fputwc | Address taken for banned string handling function 'fputwc'. | +| test.cpp:138:51:138:56 | wcstol | Address taken for banned string handling function 'wcstol'. | +| test.cpp:139:50:139:55 | wcstol | Address taken for banned string handling function 'wcstol'. | +| test.cpp:140:56:140:62 | wcstoll | Address taken for banned string handling function 'wcstoll'. | +| test.cpp:141:55:141:61 | wcstoll | Address taken for banned string handling function 'wcstoll'. | +| test.cpp:143:8:143:14 | wcstoul | Address taken for banned string handling function 'wcstoul'. | +| test.cpp:145:7:145:13 | wcstoul | Address taken for banned string handling function 'wcstoul'. | +| test.cpp:147:8:147:15 | wcstoull | Address taken for banned string handling function 'wcstoull'. | +| test.cpp:149:7:149:14 | wcstoull | Address taken for banned string handling function 'wcstoull'. | +| test.cpp:150:49:150:54 | wcstod | Address taken for banned string handling function 'wcstod'. | +| test.cpp:151:48:151:53 | wcstod | Address taken for banned string handling function 'wcstod'. | +| test.cpp:152:48:152:53 | wcstof | Address taken for banned string handling function 'wcstof'. | +| test.cpp:153:47:153:52 | wcstof | Address taken for banned string handling function 'wcstof'. | +| test.cpp:154:54:154:60 | wcstold | Address taken for banned string handling function 'wcstold'. | +| test.cpp:155:53:155:59 | wcstold | Address taken for banned string handling function 'wcstold'. | +| test.cpp:159:50:159:58 | strtoumax | Address taken for banned string handling function 'strtoumax'. | +| test.cpp:160:49:160:57 | strtoumax | Address taken for banned string handling function 'strtoumax'. | +| test.cpp:161:49:161:57 | strtoimax | Address taken for banned string handling function 'strtoimax'. | +| test.cpp:162:48:162:56 | strtoimax | Address taken for banned string handling function 'strtoimax'. | +| test.cpp:164:8:164:16 | wcstoumax | Address taken for banned string handling function 'wcstoumax'. | +| test.cpp:166:7:166:15 | wcstoumax | Address taken for banned string handling function 'wcstoumax'. | +| test.cpp:168:8:168:16 | wcstoimax | Address taken for banned string handling function 'wcstoimax'. | +| test.cpp:169:54:169:62 | wcstoimax | Address taken for banned string handling function 'wcstoimax'. | | test.cpp:177:3:177:13 | call to strcat | Call to banned string handling function 'strcat'. | | test.cpp:178:3:178:13 | call to strchr | Call to banned string handling function 'strchr'. | | test.cpp:179:3:179:13 | call to strcmp | Call to banned string handling function 'strcmp'. | @@ -146,77 +146,77 @@ | test.cpp:233:3:233:16 | call to strtoimax | Call to banned string handling function 'strtoimax'. | | test.cpp:234:3:234:16 | call to wcstoumax | Call to banned string handling function 'wcstoumax'. | | test.cpp:235:3:235:16 | call to wcstoimax | Call to banned string handling function 'wcstoimax'. | -| test.cpp:239:39:239:50 | & ... | Address taken of banned string handling function 'strcat'. | -| test.cpp:240:39:240:49 | strcat | Reference to banned string handling function 'strcat'. | -| test.cpp:241:42:241:53 | & ... | Address taken of banned string handling function 'strchr'. | -| test.cpp:242:42:242:52 | strchr | Reference to banned string handling function 'strchr'. | -| test.cpp:243:43:243:54 | & ... | Address taken of banned string handling function 'strcmp'. | -| test.cpp:244:43:244:53 | strcmp | Reference to banned string handling function 'strcmp'. | -| test.cpp:245:43:245:55 | & ... | Address taken of banned string handling function 'strcoll'. | -| test.cpp:246:43:246:54 | strcoll | Reference to banned string handling function 'strcoll'. | -| test.cpp:247:39:247:50 | & ... | Address taken of banned string handling function 'strcpy'. | -| test.cpp:248:40:248:50 | strcpy | Reference to banned string handling function 'strcpy'. | -| test.cpp:249:47:249:59 | & ... | Address taken of banned string handling function 'strcspn'. | -| test.cpp:250:47:250:58 | strcspn | Reference to banned string handling function 'strcspn'. | -| test.cpp:251:23:251:36 | & ... | Address taken of banned string handling function 'strerror'. | -| test.cpp:252:23:252:35 | strerror | Reference to banned string handling function 'strerror'. | -| test.cpp:253:33:253:44 | & ... | Address taken of banned string handling function 'strlen'. | -| test.cpp:254:33:254:43 | strlen | Reference to banned string handling function 'strlen'. | -| test.cpp:255:48:255:60 | & ... | Address taken of banned string handling function 'strncat'. | -| test.cpp:256:48:256:59 | strncat | Reference to banned string handling function 'strncat'. | -| test.cpp:258:7:258:19 | & ... | Address taken of banned string handling function 'strncmp'. | -| test.cpp:260:7:260:18 | strncmp | Reference to banned string handling function 'strncmp'. | -| test.cpp:261:48:261:60 | & ... | Address taken of banned string handling function 'strncpy'. | -| test.cpp:262:48:262:59 | strncpy | Reference to banned string handling function 'strncpy'. | -| test.cpp:264:7:264:19 | & ... | Address taken of banned string handling function 'strpbrk'. | -| test.cpp:266:7:266:18 | strpbrk | Reference to banned string handling function 'strpbrk'. | -| test.cpp:267:43:267:55 | & ... | Address taken of banned string handling function 'strrchr'. | -| test.cpp:268:43:268:54 | strrchr | Reference to banned string handling function 'strrchr'. | -| test.cpp:269:47:269:58 | & ... | Address taken of banned string handling function 'strspn'. | -| test.cpp:270:47:270:57 | strspn | Reference to banned string handling function 'strspn'. | -| test.cpp:272:7:272:18 | & ... | Address taken of banned string handling function 'strstr'. | -| test.cpp:273:52:273:62 | strstr | Reference to banned string handling function 'strstr'. | -| test.cpp:274:40:274:51 | & ... | Address taken of banned string handling function 'strtok'. | -| test.cpp:275:40:275:50 | strtok | Reference to banned string handling function 'strtok'. | -| test.cpp:276:49:276:61 | & ... | Address taken of banned string handling function 'strxfrm'. | -| test.cpp:277:49:277:60 | strxfrm | Reference to banned string handling function 'strxfrm'. | -| test.cpp:281:44:281:55 | & ... | Address taken of banned string handling function 'strtol'. | -| test.cpp:282:44:282:54 | strtol | Reference to banned string handling function 'strtol'. | -| test.cpp:283:49:283:61 | & ... | Address taken of banned string handling function 'strtoll'. | -| test.cpp:284:49:284:60 | strtoll | Reference to banned string handling function 'strtoll'. | -| test.cpp:286:7:286:19 | & ... | Address taken of banned string handling function 'strtoul'. | -| test.cpp:288:7:288:18 | strtoul | Reference to banned string handling function 'strtoul'. | -| test.cpp:290:7:290:20 | & ... | Address taken of banned string handling function 'strtoull'. | -| test.cpp:292:7:292:19 | strtoull | Reference to banned string handling function 'strtoull'. | -| test.cpp:293:41:293:52 | & ... | Address taken of banned string handling function 'strtod'. | -| test.cpp:294:42:294:52 | strtod | Reference to banned string handling function 'strtod'. | -| test.cpp:295:41:295:52 | & ... | Address taken of banned string handling function 'strtof'. | -| test.cpp:296:41:296:51 | strtof | Reference to banned string handling function 'strtof'. | -| test.cpp:297:47:297:59 | & ... | Address taken of banned string handling function 'strtold'. | -| test.cpp:298:47:298:58 | strtold | Reference to banned string handling function 'strtold'. | -| test.cpp:302:26:302:37 | & ... | Address taken of banned string handling function 'fgetwc'. | -| test.cpp:303:26:303:36 | fgetwc | Reference to banned string handling function 'fgetwc'. | -| test.cpp:304:35:304:46 | & ... | Address taken of banned string handling function 'fputwc'. | -| test.cpp:305:35:305:45 | fputwc | Reference to banned string handling function 'fputwc'. | -| test.cpp:306:50:306:61 | & ... | Address taken of banned string handling function 'wcstol'. | -| test.cpp:307:50:307:60 | wcstol | Reference to banned string handling function 'wcstol'. | -| test.cpp:309:7:309:19 | & ... | Address taken of banned string handling function 'wcstoll'. | -| test.cpp:311:7:311:18 | wcstoll | Reference to banned string handling function 'wcstoll'. | -| test.cpp:313:7:313:19 | & ... | Address taken of banned string handling function 'wcstoul'. | -| test.cpp:315:7:315:18 | wcstoul | Reference to banned string handling function 'wcstoul'. | -| test.cpp:317:7:317:20 | & ... | Address taken of banned string handling function 'wcstoull'. | -| test.cpp:319:7:319:19 | wcstoull | Reference to banned string handling function 'wcstoull'. | -| test.cpp:320:48:320:59 | & ... | Address taken of banned string handling function 'wcstod'. | -| test.cpp:321:48:321:58 | wcstod | Reference to banned string handling function 'wcstod'. | -| test.cpp:322:47:322:58 | & ... | Address taken of banned string handling function 'wcstof'. | -| test.cpp:323:47:323:57 | wcstof | Reference to banned string handling function 'wcstof'. | -| test.cpp:325:7:325:19 | & ... | Address taken of banned string handling function 'wcstold'. | -| test.cpp:327:7:327:18 | wcstold | Reference to banned string handling function 'wcstold'. | -| test.cpp:332:7:332:21 | & ... | Address taken of banned string handling function 'strtoumax'. | -| test.cpp:333:49:333:62 | strtoumax | Reference to banned string handling function 'strtoumax'. | -| test.cpp:334:48:334:62 | & ... | Address taken of banned string handling function 'strtoimax'. | -| test.cpp:335:48:335:61 | strtoimax | Reference to banned string handling function 'strtoimax'. | -| test.cpp:337:7:337:21 | & ... | Address taken of banned string handling function 'wcstoumax'. | -| test.cpp:339:7:339:20 | wcstoumax | Reference to banned string handling function 'wcstoumax'. | -| test.cpp:341:7:341:21 | & ... | Address taken of banned string handling function 'wcstoimax'. | -| test.cpp:343:7:343:20 | wcstoimax | Reference to banned string handling function 'wcstoimax'. | +| test.cpp:239:40:239:50 | strcat | Address taken for banned string handling function 'strcat'. | +| test.cpp:240:39:240:49 | strcat | Address taken for banned string handling function 'strcat'. | +| test.cpp:241:42:241:53 | strchr | Address taken for banned string handling function 'strchr'. | +| test.cpp:242:42:242:52 | strchr | Address taken for banned string handling function 'strchr'. | +| test.cpp:243:44:243:54 | strcmp | Address taken for banned string handling function 'strcmp'. | +| test.cpp:244:43:244:53 | strcmp | Address taken for banned string handling function 'strcmp'. | +| test.cpp:245:44:245:55 | strcoll | Address taken for banned string handling function 'strcoll'. | +| test.cpp:246:43:246:54 | strcoll | Address taken for banned string handling function 'strcoll'. | +| test.cpp:247:40:247:50 | strcpy | Address taken for banned string handling function 'strcpy'. | +| test.cpp:248:40:248:50 | strcpy | Address taken for banned string handling function 'strcpy'. | +| test.cpp:249:48:249:59 | strcspn | Address taken for banned string handling function 'strcspn'. | +| test.cpp:250:47:250:58 | strcspn | Address taken for banned string handling function 'strcspn'. | +| test.cpp:251:24:251:36 | strerror | Address taken for banned string handling function 'strerror'. | +| test.cpp:252:23:252:35 | strerror | Address taken for banned string handling function 'strerror'. | +| test.cpp:253:34:253:44 | strlen | Address taken for banned string handling function 'strlen'. | +| test.cpp:254:33:254:43 | strlen | Address taken for banned string handling function 'strlen'. | +| test.cpp:255:49:255:60 | strncat | Address taken for banned string handling function 'strncat'. | +| test.cpp:256:48:256:59 | strncat | Address taken for banned string handling function 'strncat'. | +| test.cpp:258:8:258:19 | strncmp | Address taken for banned string handling function 'strncmp'. | +| test.cpp:260:7:260:18 | strncmp | Address taken for banned string handling function 'strncmp'. | +| test.cpp:261:49:261:60 | strncpy | Address taken for banned string handling function 'strncpy'. | +| test.cpp:262:48:262:59 | strncpy | Address taken for banned string handling function 'strncpy'. | +| test.cpp:264:7:264:19 | strpbrk | Address taken for banned string handling function 'strpbrk'. | +| test.cpp:266:7:266:18 | strpbrk | Address taken for banned string handling function 'strpbrk'. | +| test.cpp:267:43:267:55 | strrchr | Address taken for banned string handling function 'strrchr'. | +| test.cpp:268:43:268:54 | strrchr | Address taken for banned string handling function 'strrchr'. | +| test.cpp:269:48:269:58 | strspn | Address taken for banned string handling function 'strspn'. | +| test.cpp:270:47:270:57 | strspn | Address taken for banned string handling function 'strspn'. | +| test.cpp:272:7:272:18 | strstr | Address taken for banned string handling function 'strstr'. | +| test.cpp:273:52:273:62 | strstr | Address taken for banned string handling function 'strstr'. | +| test.cpp:274:41:274:51 | strtok | Address taken for banned string handling function 'strtok'. | +| test.cpp:275:40:275:50 | strtok | Address taken for banned string handling function 'strtok'. | +| test.cpp:276:50:276:61 | strxfrm | Address taken for banned string handling function 'strxfrm'. | +| test.cpp:277:49:277:60 | strxfrm | Address taken for banned string handling function 'strxfrm'. | +| test.cpp:281:45:281:55 | strtol | Address taken for banned string handling function 'strtol'. | +| test.cpp:282:44:282:54 | strtol | Address taken for banned string handling function 'strtol'. | +| test.cpp:283:50:283:61 | strtoll | Address taken for banned string handling function 'strtoll'. | +| test.cpp:284:49:284:60 | strtoll | Address taken for banned string handling function 'strtoll'. | +| test.cpp:286:8:286:19 | strtoul | Address taken for banned string handling function 'strtoul'. | +| test.cpp:288:7:288:18 | strtoul | Address taken for banned string handling function 'strtoul'. | +| test.cpp:290:8:290:20 | strtoull | Address taken for banned string handling function 'strtoull'. | +| test.cpp:292:7:292:19 | strtoull | Address taken for banned string handling function 'strtoull'. | +| test.cpp:293:42:293:52 | strtod | Address taken for banned string handling function 'strtod'. | +| test.cpp:294:42:294:52 | strtod | Address taken for banned string handling function 'strtod'. | +| test.cpp:295:42:295:52 | strtof | Address taken for banned string handling function 'strtof'. | +| test.cpp:296:41:296:51 | strtof | Address taken for banned string handling function 'strtof'. | +| test.cpp:297:48:297:59 | strtold | Address taken for banned string handling function 'strtold'. | +| test.cpp:298:47:298:58 | strtold | Address taken for banned string handling function 'strtold'. | +| test.cpp:302:27:302:37 | fgetwc | Address taken for banned string handling function 'fgetwc'. | +| test.cpp:303:26:303:36 | fgetwc | Address taken for banned string handling function 'fgetwc'. | +| test.cpp:304:36:304:46 | fputwc | Address taken for banned string handling function 'fputwc'. | +| test.cpp:305:35:305:45 | fputwc | Address taken for banned string handling function 'fputwc'. | +| test.cpp:306:51:306:61 | wcstol | Address taken for banned string handling function 'wcstol'. | +| test.cpp:307:50:307:60 | wcstol | Address taken for banned string handling function 'wcstol'. | +| test.cpp:309:8:309:19 | wcstoll | Address taken for banned string handling function 'wcstoll'. | +| test.cpp:311:7:311:18 | wcstoll | Address taken for banned string handling function 'wcstoll'. | +| test.cpp:313:8:313:19 | wcstoul | Address taken for banned string handling function 'wcstoul'. | +| test.cpp:315:7:315:18 | wcstoul | Address taken for banned string handling function 'wcstoul'. | +| test.cpp:317:8:317:20 | wcstoull | Address taken for banned string handling function 'wcstoull'. | +| test.cpp:319:7:319:19 | wcstoull | Address taken for banned string handling function 'wcstoull'. | +| test.cpp:320:49:320:59 | wcstod | Address taken for banned string handling function 'wcstod'. | +| test.cpp:321:48:321:58 | wcstod | Address taken for banned string handling function 'wcstod'. | +| test.cpp:322:48:322:58 | wcstof | Address taken for banned string handling function 'wcstof'. | +| test.cpp:323:47:323:57 | wcstof | Address taken for banned string handling function 'wcstof'. | +| test.cpp:325:8:325:19 | wcstold | Address taken for banned string handling function 'wcstold'. | +| test.cpp:327:7:327:18 | wcstold | Address taken for banned string handling function 'wcstold'. | +| test.cpp:332:8:332:21 | strtoumax | Address taken for banned string handling function 'strtoumax'. | +| test.cpp:333:49:333:62 | strtoumax | Address taken for banned string handling function 'strtoumax'. | +| test.cpp:334:49:334:62 | strtoimax | Address taken for banned string handling function 'strtoimax'. | +| test.cpp:335:48:335:61 | strtoimax | Address taken for banned string handling function 'strtoimax'. | +| test.cpp:337:8:337:21 | wcstoumax | Address taken for banned string handling function 'wcstoumax'. | +| test.cpp:339:7:339:20 | wcstoumax | Address taken for banned string handling function 'wcstoumax'. | +| test.cpp:341:8:341:21 | wcstoimax | Address taken for banned string handling function 'wcstoimax'. | +| test.cpp:343:7:343:20 | wcstoimax | Address taken for banned string handling function 'wcstoimax'. | From d33b4eb8d2456183e85f82404c79da221016c152 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 23:11:10 +0100 Subject: [PATCH 405/628] Add `system` to cstdlib --- cpp/common/test/includes/standard-library/cstdlib | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/common/test/includes/standard-library/cstdlib b/cpp/common/test/includes/standard-library/cstdlib index 1b7df173a1..3b1eefc4a9 100644 --- a/cpp/common/test/includes/standard-library/cstdlib +++ b/cpp/common/test/includes/standard-library/cstdlib @@ -22,5 +22,6 @@ using ::strtold; using ::strtoll; using ::strtoul; using ::strtoull; +using ::system; } // namespace std #endif // _GHLIBCPP_CSTDLIB \ No newline at end of file From 985a2d1ed43a32e2446317182627793050f74b36 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Wed, 4 Jun 2025 12:22:02 +0100 Subject: [PATCH 406/628] Fix poor performance of sameSource predicate --- .../IOFstreamMissingPositioning.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll b/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll index 547c90daf5..b26421c72c 100644 --- a/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll +++ b/cpp/common/src/codingstandards/cpp/rules/iofstreammissingpositioning/IOFstreamMissingPositioning.qll @@ -51,7 +51,8 @@ class WriteFunctionCall extends ReadWriteCall { } } -pragma[inline] +bindingset[a, b] +pragma[inline_late] predicate sameSource(FunctionCall a, FunctionCall b) { sameStreamSource(a, b) or sameFileSource(a, b) From e9e7cfa26931911e205f65a47245af6c550ef2e1 Mon Sep 17 00:00:00 2001 From: knewbury01 Date: Wed, 4 Jun 2025 14:12:21 +0000 Subject: [PATCH 407/628] Bump version to 2.47.0-dev --- c/cert/src/qlpack.yml | 2 +- c/cert/test/qlpack.yml | 2 +- c/common/src/qlpack.yml | 2 +- c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- c/misra/test/qlpack.yml | 2 +- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/qlpack.yml | 2 +- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- docs/user_manual.md | 12 ++++++------ 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 128ac606f8..26311dda18 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.46.0-dev +version: 2.47.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index 6920ec1771..91c2ea4a52 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.46.0-dev +version: 2.47.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 13a994e0a3..d088be5639 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.46.0-dev +version: 2.47.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index 09640c31c9..4688b3b1a9 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.46.0-dev +version: 2.47.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index d37d64c88a..0607e7456f 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.46.0-dev +version: 2.47.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index a22391774f..823d705e51 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.46.0-dev +version: 2.47.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index dd095ff354..061fcf8df8 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.46.0-dev +version: 2.47.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index 7182f771d5..735f300df4 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.46.0-dev +version: 2.47.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 792575ad6e..74fe860570 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.46.0-dev +version: 2.47.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index 7463027aaf..58d0db64f0 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.46.0-dev +version: 2.47.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index 1813fb7fe3..2454592ce7 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards -version: 2.46.0-dev +version: 2.47.0-dev license: MIT dependencies: codeql/cpp-all: 2.1.1 diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index 8912a9c683..86ad39d46a 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.46.0-dev +version: 2.47.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 5cb9d79b87..999116b3e0 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.46.0-dev +version: 2.47.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index 69cd110473..94cad70436 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.46.0-dev +version: 2.47.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index c6f5f7052f..4814c3e99b 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.46.0-dev +version: 2.47.0-dev license: MIT dependencies: codeql/cpp-all: 2.1.1 diff --git a/docs/user_manual.md b/docs/user_manual.md index a758d3678c..7482942dc5 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -36,14 +36,14 @@ ## Release information -This user manual documents release `2.46.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.47.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: - `coding-standards-codeql-packs-2.37.0-dev.zip`: CodeQL packs that can be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `code-scanning-cpp-query-pack-2.46.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.46.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.46.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.46.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.47.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.47.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.47.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.47.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -670,7 +670,7 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.46.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.47.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | From 7049558f18fabd7a6f515e9ada1cef4aa43b02b3 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 6 Jun 2025 09:52:33 +0100 Subject: [PATCH 408/628] Change note --- change_notes/2025-06-06-same-source-performance.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change_notes/2025-06-06-same-source-performance.md diff --git a/change_notes/2025-06-06-same-source-performance.md b/change_notes/2025-06-06-same-source-performance.md new file mode 100644 index 0000000000..e0dfc36dea --- /dev/null +++ b/change_notes/2025-06-06-same-source-performance.md @@ -0,0 +1,2 @@ + - `FIO39-C`, `FIO50-CPP`, `A27-0-3`, `RULE-30-0-2`: `IOFstreamMissingPositioning.ql`, `InterleavedInputOutputWithoutPosition.ql`, `InterleavedInputOutputWithoutFlush.ql`, `ReadsAndWritesOnStreamNotSeparatedByPositioning.ql`. + - Improved performance for codebases with large numbers of stream or file accesses. \ No newline at end of file From efa017fa0a0b7d14cfd85af410a3642450c62383 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 3 Jun 2025 23:11:56 +0100 Subject: [PATCH 409/628] Rule 21.2.3 - BannedSystemFunction.ql Add a new query for detecting uses of the banned function `system`. [a] --- .../rules/RULE-21-2-3/BannedSystemFunction.ql | 36 +++++++++++++++ .../RULE-21-2-3/BannedSystemFunction.expected | 9 ++++ .../RULE-21-2-3/BannedSystemFunction.qlref | 1 + cpp/misra/test/rules/RULE-21-2-3/test.cpp | 45 +++++++++++++++++++ 4 files changed, 91 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql create mode 100644 cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.expected create mode 100644 cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.qlref create mode 100644 cpp/misra/test/rules/RULE-21-2-3/test.cpp diff --git a/cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql b/cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql new file mode 100644 index 0000000000..b8cf0788f8 --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql @@ -0,0 +1,36 @@ +/** + * @id cpp/misra/banned-system-function + * @name RULE-21-2-3: The library function system from shall not be used + * @description Using the system() function from cstdlib or stdlib.h causes undefined behavior and + * potential security vulnerabilities. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-2-3 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class SystemFunction extends Function { + SystemFunction() { this.hasGlobalName("system") or this.hasQualifiedName("std", "system") } +} + +from Element element, string message +where + not isExcluded(element, BannedAPIsPackage::bannedSystemFunctionQuery()) and + ( + element instanceof BannedFunctions::Use and + message = + element.(BannedFunctions::Use).getAction() + " banned function '" + + element.(BannedFunctions::Use).getFunctionName() + "'." + or + element instanceof MacroInvocation and + element.(MacroInvocation).getMacroName() = "system" and + message = "Use of banned macro 'system'." + ) +select element, message diff --git a/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.expected b/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.expected new file mode 100644 index 0000000000..fcb5a8aeee --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.expected @@ -0,0 +1,9 @@ +| test.cpp:4:3:4:13 | call to system | Call to banned function 'system'. | +| test.cpp:8:14:8:24 | system | Address taken for banned function 'system'. | +| test.cpp:9:29:9:39 | system | Address taken for banned function 'system'. | +| test.cpp:13:40:13:50 | system | Address taken for banned function 'system'. | +| test.cpp:17:3:17:13 | call to system | Call to banned function 'system'. | +| test.cpp:22:3:22:13 | call to system | Call to banned function 'system'. | +| test.cpp:35:3:35:8 | call to system | Call to banned function 'system'. | +| test.cpp:39:29:39:34 | system | Address taken for banned function 'system'. | +| test.cpp:44:3:44:21 | system(x) | Use of banned macro 'system'. | diff --git a/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.qlref b/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.qlref new file mode 100644 index 0000000000..2580c7a6a9 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-3/BannedSystemFunction.qlref @@ -0,0 +1 @@ +rules/RULE-21-2-3/BannedSystemFunction.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-2-3/test.cpp b/cpp/misra/test/rules/RULE-21-2-3/test.cpp new file mode 100644 index 0000000000..89ed82d88f --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-2-3/test.cpp @@ -0,0 +1,45 @@ +#include + +void test_direct_call_to_system() { + std::system("echo hello"); // NON_COMPLIANT +} + +void test_system_function_pointer() { + auto l1 = &std::system; // NON_COMPLIANT + int (*l2)(const char *) = std::system; // NON_COMPLIANT +} + +void test_system_address_taken() { + void *l1 = reinterpret_cast(&std::system); // NON_COMPLIANT +} + +void test_system_call_with_null() { + std::system(nullptr); // NON_COMPLIANT +} + +void test_system_call_with_variable() { + const char *l1 = "ls"; + std::system(l1); // NON_COMPLIANT +} + +void test_compliant_alternative() { + // Using compliant alternatives instead of system() + const char *l1 = "some command"; // COMPLIANT + // Implementation-specific alternatives would be used here +} + +// Test with C-style header (rule also applies to ) +#include + +void test_c_style_header_system() { + system("echo hello"); // NON_COMPLIANT +} + +void test_c_style_header_function_pointer() { + int (*l1)(const char *) = system; // NON_COMPLIANT +} + +#define system(x) 0 +void test_system_macro_expansion() { + system("echo test"); // NON_COMPLIANT +} From eccc416f512ae347bf718c5f7962dfc954b80013 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 12:54:57 +0100 Subject: [PATCH 410/628] Rule 23.11.1 - UseSmarPtrFactoryFunctions.ql A new query to report uses of the raw pointer constructors of the std::unique_ptr and std::shared_ptr classes. [a] --- .../test/includes/standard-library/memory.h | 3 + .../UseSmartPtrFactoryFunctions.ql | 32 +++++++ .../UseSmartPtrFactoryFunctions.expected | 9 ++ .../UseSmartPtrFactoryFunctions.qlref | 1 + cpp/misra/test/rules/RULE-23-11-1/test.cpp | 84 +++++++++++++++++++ 5 files changed, 129 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql create mode 100644 cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.expected create mode 100644 cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.qlref create mode 100644 cpp/misra/test/rules/RULE-23-11-1/test.cpp diff --git a/cpp/common/test/includes/standard-library/memory.h b/cpp/common/test/includes/standard-library/memory.h index 985ee41602..494f428422 100644 --- a/cpp/common/test/includes/standard-library/memory.h +++ b/cpp/common/test/includes/standard-library/memory.h @@ -23,6 +23,7 @@ class unique_ptr { unique_ptr(T *ptr) {} unique_ptr(const unique_ptr &t) = delete; unique_ptr(unique_ptr &&t) {} + unique_ptr(pointer p, Deleter d) noexcept {} ~unique_ptr() {} T &operator*() const { return *ptr; } T *operator->() const noexcept { return ptr; } @@ -93,8 +94,10 @@ template class shared_ptr : public __shared_ptr { shared_ptr(T *ptr); shared_ptr(const shared_ptr &r) noexcept; template shared_ptr(const shared_ptr &r) noexcept; + template shared_ptr(const shared_ptr &r, T *p) noexcept; shared_ptr(shared_ptr &&r) noexcept; template shared_ptr(shared_ptr &&r) noexcept; + template shared_ptr(T *p, D d); shared_ptr(unique_ptr &&t) {} ~shared_ptr() {} T &operator*() const noexcept; diff --git a/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql b/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql new file mode 100644 index 0000000000..65faa9cfd8 --- /dev/null +++ b/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql @@ -0,0 +1,32 @@ +/** + * @id cpp/misra/use-smart-ptr-factory-functions + * @name RULE-23-11-1: The raw pointer constructors of std::shared_ptr and std::unique_ptr should not be used + * @description Using raw pointer constructors of std::shared_ptr and std::unique_ptr instead of + * make_shared/make_unique can lead to memory leaks if exceptions occur during + * construction. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-23-11-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra + +from ConstructorCall call, Class smartPtrClass +where + not isExcluded(call, BannedAPIsPackage::useSmartPtrFactoryFunctionsQuery()) and + smartPtrClass = call.getTarget().getDeclaringType() and + ( + smartPtrClass.hasQualifiedName("std", "shared_ptr") or + smartPtrClass.hasQualifiedName("std", "unique_ptr") + ) and + call.getNumberOfArguments() >= 1 and + exists(Type argType | + argType = call.getArgument(0).getType().getUnspecifiedType() and + argType instanceof PointerType + ) +select call, "Use of raw pointer constructor for 'std::" + smartPtrClass.getSimpleName() + "'." diff --git a/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.expected b/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.expected new file mode 100644 index 0000000000..a6d399c0d2 --- /dev/null +++ b/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.expected @@ -0,0 +1,9 @@ +| test.cpp:23:25:23:27 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:28:25:28:27 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. | +| test.cpp:34:3:34:32 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:40:3:40:32 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. | +| test.cpp:46:6:46:32 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:47:6:47:32 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:57:27:57:29 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. | +| test.cpp:67:25:67:31 | call to shared_ptr | Use of raw pointer constructor for 'std::shared_ptr'. | +| test.cpp:74:39:74:45 | call to unique_ptr | Use of raw pointer constructor for 'std::unique_ptr'. | diff --git a/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.qlref b/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.qlref new file mode 100644 index 0000000000..337d1b2ade --- /dev/null +++ b/cpp/misra/test/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.qlref @@ -0,0 +1 @@ +rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-23-11-1/test.cpp b/cpp/misra/test/rules/RULE-23-11-1/test.cpp new file mode 100644 index 0000000000..1f0cb2cf7a --- /dev/null +++ b/cpp/misra/test/rules/RULE-23-11-1/test.cpp @@ -0,0 +1,84 @@ +#include +#include + +struct A { + std::int8_t i; +}; + +class B {}; + +void test_make_shared_compliant() { + auto p = std::make_shared(); // COMPLIANT + std::int8_t *pi = &(p->i); + std::shared_ptr q( + p, pi); // COMPLIANT - aliasing constructor, not taking ownership +} + +void test_make_unique_compliant() { + auto p = std::make_unique(); // COMPLIANT +} + +void test_raw_pointer_shared_ptr_non_compliant() { + A *l1 = new A(); + std::shared_ptr l2(l1); // NON_COMPLIANT +} + +void test_raw_pointer_unique_ptr_non_compliant() { + A *l1 = new A(); + std::unique_ptr l2(l1); // NON_COMPLIANT +} + +auto test_exception_safety_issue() { + auto *l1 = new A(); + auto l2 = std::make_unique(); // may throw + return std::shared_ptr(l1); // NON_COMPLIANT - memory leak + // if make_unique throws +} + +auto test_double_delete_issue(std::unique_ptr p) { + auto l1 = p.get(); + return std::unique_ptr(l1); // NON_COMPLIANT - causes double delete +} + +void f1(std::shared_ptr a, std::shared_ptr b); + +void test_function_argument_non_compliant() { + f1(std::shared_ptr(new A()), // NON_COMPLIANT + std::shared_ptr(new B())); // NON_COMPLIANT +} + +void test_function_argument_compliant() { + f1(std::make_shared(), // COMPLIANT + std::make_shared()); // COMPLIANT +} + +void test_array_raw_pointer_non_compliant() { + A *l1 = new A[10]; + std::unique_ptr l2(l1); // NON_COMPLIANT +} + +void test_array_make_unique_compliant() { + auto l1 = std::make_unique(10); // COMPLIANT +} + +void test_custom_deleter_shared_ptr() { + A *l1 = new A(); + auto l2 = [](A *p) { delete p; }; + std::shared_ptr l3(l1, l2); // NON_COMPLIANT - still + // using raw pointer constructor +} + +void test_custom_deleter_unique_ptr() { + A *l1 = new A(); + auto l2 = [](A *p) { delete p; }; + std::unique_ptr l3(l1, l2); // NON_COMPLIANT - still + // using raw pointer constructor +} + +void test_nullptr_shared_ptr() { + std::shared_ptr l1(nullptr); // COMPLIANT - no ownership taken +} + +void test_nullptr_unique_ptr() { + std::unique_ptr l1(nullptr); // COMPLIANT - no ownership taken +} \ No newline at end of file From 8a8c33dda4ed84e6e4598f1345a9cd1f88f4818b Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 13:02:46 +0100 Subject: [PATCH 411/628] Update C++ stubs for ctype.h/cctype and wctype.h/cwctype --- .../test/includes/standard-library/cctype | 21 ++++++++++++- .../test/includes/standard-library/ctype.h | 5 ++-- .../test/includes/standard-library/cwctype | 30 +++++++++++++++++++ .../test/includes/standard-library/wctype.h | 28 +++++++++++++++++ 4 files changed, 81 insertions(+), 3 deletions(-) diff --git a/cpp/common/test/includes/standard-library/cctype b/cpp/common/test/includes/standard-library/cctype index 98e0805cfd..b45830acbe 100644 --- a/cpp/common/test/includes/standard-library/cctype +++ b/cpp/common/test/includes/standard-library/cctype @@ -1 +1,20 @@ -#include "ctype.h" \ No newline at end of file +#ifndef _GHLIBCPP_CCTYPE +#define _GHLIBCPP_CCTYPE +#include "ctype.h" +namespace std { +using ::isalnum; +using ::isalpha; +using ::isblank; +using ::iscntrl; +using ::isdigit; +using ::isgraph; +using ::islower; +using ::isprint; +using ::ispunct; +using ::isspace; +using ::isupper; +using ::isxdigit; +using ::tolower; +using ::toupper; +} // namespace std +#endif // _GHLIBCPP_CCTYPE diff --git a/cpp/common/test/includes/standard-library/ctype.h b/cpp/common/test/includes/standard-library/ctype.h index e9264fd7c6..d7dc851529 100644 --- a/cpp/common/test/includes/standard-library/ctype.h +++ b/cpp/common/test/includes/standard-library/ctype.h @@ -1,8 +1,9 @@ #ifndef _GHLIBCPP_CTYPE #define _GHLIBCPP_CTYPE -namespace std { + extern int isalnum(int); extern int isalpha(int); +extern int isblank(int); extern int iscntrl(int); extern int isdigit(int); extern int islower(int); @@ -14,5 +15,5 @@ extern int isupper(int); extern int isxdigit(int); extern int tolower(int); extern int toupper(int); -} // namespace std + #endif // _GHLIBCPP_CTYPE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/cwctype b/cpp/common/test/includes/standard-library/cwctype index 490ed4edf9..d2ce5c7e36 100644 --- a/cpp/common/test/includes/standard-library/cwctype +++ b/cpp/common/test/includes/standard-library/cwctype @@ -1,8 +1,38 @@ #ifndef _GHLIBCPP_CWCTYPE #define _GHLIBCPP_CWCTYPE +#include "wctype.h" namespace std { +// Types using ::wint_t; +using ::wctype_t; +using ::wctrans_t; + +// Wide character classification functions +using ::iswalnum; +using ::iswalpha; +using ::iswblank; +using ::iswcntrl; +using ::iswdigit; +using ::iswgraph; +using ::iswlower; +using ::iswprint; +using ::iswpunct; +using ::iswspace; +using ::iswupper; +using ::iswxdigit; + +// Wide character conversion functions +using ::towlower; +using ::towupper; + +// Generic wide character classification functions +using ::iswctype; +using ::wctype; + +// Generic wide character mapping functions +using ::towctrans; +using ::wctrans; } // namespace std #endif // _GHLIBCPP_CWCTYPE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/wctype.h b/cpp/common/test/includes/standard-library/wctype.h index b82c7a13f7..d66b63a75c 100644 --- a/cpp/common/test/includes/standard-library/wctype.h +++ b/cpp/common/test/includes/standard-library/wctype.h @@ -2,5 +2,33 @@ #define _GHLIBCPP_WCTYPE typedef long wint_t; +typedef long wctype_t; +typedef long wctrans_t; + +// Wide character classification functions +extern int iswalnum(wint_t wc); +extern int iswalpha(wint_t wc); +extern int iswblank(wint_t wc); +extern int iswcntrl(wint_t wc); +extern int iswdigit(wint_t wc); +extern int iswgraph(wint_t wc); +extern int iswlower(wint_t wc); +extern int iswprint(wint_t wc); +extern int iswpunct(wint_t wc); +extern int iswspace(wint_t wc); +extern int iswupper(wint_t wc); +extern int iswxdigit(wint_t wc); + +// Wide character conversion functions +extern wint_t towlower(wint_t wc); +extern wint_t towupper(wint_t wc); + +// Generic wide character classification functions +extern int iswctype(wint_t wc, wctype_t desc); +extern wctype_t wctype(const char *property); + +// Generic wide character mapping functions +extern wint_t towctrans(wint_t wc, wctrans_t desc); +extern wctrans_t wctrans(const char *property); #endif // _GHLIBCPP_WCTYPE \ No newline at end of file From b81423bc741d1f51e45cd760585270c00ec7a9ab Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 14:50:00 +0100 Subject: [PATCH 412/628] Improve C++ stubs for locales --- .../test/includes/standard-library/clocale | 5 +- .../test/includes/standard-library/locale | 25 ++++++++ .../test/includes/standard-library/locale.h | 59 +++++++++---------- 3 files changed, 58 insertions(+), 31 deletions(-) create mode 100644 cpp/common/test/includes/standard-library/locale diff --git a/cpp/common/test/includes/standard-library/clocale b/cpp/common/test/includes/standard-library/clocale index 430c36daa0..8ec16234b8 100644 --- a/cpp/common/test/includes/standard-library/clocale +++ b/cpp/common/test/includes/standard-library/clocale @@ -1,4 +1,5 @@ -#pragma once +#ifndef _GHLIBCPP_CLOCALE +#define _GHLIBCPP_CLOCALE #define NULL 0 #define LC_ALL 0 @@ -15,3 +16,5 @@ using ::lconv; using ::localeconv; using ::setlocale; } // namespace std + +#endif // _GHLIBCPP_CLOCALE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/locale b/cpp/common/test/includes/standard-library/locale new file mode 100644 index 0000000000..4d19e3dbaa --- /dev/null +++ b/cpp/common/test/includes/standard-library/locale @@ -0,0 +1,25 @@ + +#ifndef _GHLIBCPP_LOCALE +#define _GHLIBCPP_LOCALE + +namespace std { + +class locale {}; + +template bool isspace(charT c, const locale &loc); +template bool isprint(charT c, const locale &loc); +template bool iscntrl(charT c, const locale &loc); +template bool isupper(charT c, const locale &loc); +template bool islower(charT c, const locale &loc); +template bool isalpha(charT c, const locale &loc); +template bool isdigit(charT c, const locale &loc); +template bool ispunct(charT c, const locale &loc); +template bool isxdigit(charT c, const locale &loc); +template bool isalnum(charT c, const locale &loc); +template bool isgraph(charT c, const locale &loc); +template bool isblank(charT c, const locale &loc); +template charT toupper(charT c, const locale &loc); +template charT tolower(charT c, const locale &loc); +} // namespace std + +#endif // _GHLIBCPP_LOCALE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/locale.h b/cpp/common/test/includes/standard-library/locale.h index 19a8905531..2501c9c5d5 100644 --- a/cpp/common/test/includes/standard-library/locale.h +++ b/cpp/common/test/includes/standard-library/locale.h @@ -1,38 +1,37 @@ -#ifndef _GHLIBCPP_LOCALE -#define _GHLIBCPP_LOCALE +#ifndef _GHLIBCPP_LOCALE_H +#define _GHLIBCPP_LOCALE_H -#define LC_ALL 6 +#define LC_ALL 6 struct lconv { - char *decimal_point; - char *thousands_sep; - char *grouping; + char *decimal_point; + char *thousands_sep; + char *grouping; - char *int_curr_symbol; - char *currency_symbol; - char *mon_decimal_point; - char *mon_thousands_sep; - char *mon_grouping; - char *positive_sign; - char *negative_sign; - char int_frac_digits; - char frac_digits; - char p_cs_precedes; - char p_sep_by_space; - char n_cs_precedes; - char n_sep_by_space; - char p_sign_posn; - char n_sign_posn; - char int_p_cs_precedes; - char int_p_sep_by_space; - char int_n_cs_precedes; - char int_n_sep_by_space; - char int_p_sign_posn; - char int_n_sign_posn; + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + char int_p_cs_precedes; + char int_p_sep_by_space; + char int_n_cs_precedes; + char int_n_sep_by_space; + char int_p_sign_posn; + char int_n_sign_posn; }; - -char *setlocale (int, const char *); +char *setlocale(int, const char *); struct lconv *localeconv(void); -#endif // _GHLIBCPP_LOCALE \ No newline at end of file +#endif // _GHLIBCPP_LOCALE_H \ No newline at end of file From cfceb9bd96d96dbce497bb6227f1cf1828baa2be Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 15:11:25 +0100 Subject: [PATCH 413/628] Add C++ string_view stub --- .../includes/standard-library/string_view | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 cpp/common/test/includes/standard-library/string_view diff --git a/cpp/common/test/includes/standard-library/string_view b/cpp/common/test/includes/standard-library/string_view new file mode 100644 index 0000000000..7897d2cf78 --- /dev/null +++ b/cpp/common/test/includes/standard-library/string_view @@ -0,0 +1,79 @@ +#pragma once +#ifndef _GHLIBCPP_STRING_VIEW +#define _GHLIBCPP_STRING_VIEW + +#include "stddef.h" + +namespace std { + +template class basic_string_view { +public: + typedef CharT value_type; + typedef const CharT *pointer; + typedef const CharT *const_pointer; + typedef const CharT &reference; + typedef const CharT &const_reference; + typedef const CharT *const_iterator; + typedef const_iterator iterator; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + + // Constructors + basic_string_view() noexcept; + basic_string_view(const basic_string_view &) noexcept = default; + basic_string_view(const CharT *s, size_type count); + basic_string_view(const CharT *s); + + // Assignment + basic_string_view &operator=(const basic_string_view &) noexcept = default; + + // Element access + const_reference operator[](size_type pos) const; + const_reference at(size_type pos) const; + const_reference front() const; + const_reference back() const; + const_pointer data() const noexcept; + + // Capacity + size_type size() const noexcept; + size_type length() const noexcept; + size_type max_size() const noexcept; + bool empty() const noexcept; + + // Modifiers + void remove_prefix(size_type n); + void remove_suffix(size_type n); + void swap(basic_string_view &v) noexcept; + + // String operations + size_type copy(CharT *dest, size_type count, size_type pos = 0) const; + basic_string_view substr(size_type pos = 0, size_type len = npos) const; + + // Comparison + int compare(basic_string_view v) const noexcept; + int compare(size_type pos1, size_type n1, basic_string_view v) const; + int compare(const CharT *s) const; + + // Search + size_type find(basic_string_view v, size_type pos = 0) const noexcept; + size_type find(CharT c, size_type pos = 0) const noexcept; + size_type find(const CharT *s, size_type pos, size_type n) const; + size_type find(const CharT *s, size_type pos = 0) const; + + // Constants + static const size_type npos = static_cast(-1); + +private: + const CharT *data_; + size_type size_; +}; + +// Type aliases +typedef basic_string_view string_view; +typedef basic_string_view wstring_view; +typedef basic_string_view u16string_view; +typedef basic_string_view u32string_view; + +} // namespace std + +#endif // _GHLIBCPP_STRING_VIEW From 52b97e6e4fdaa230f389766e6a73e0e946b82f41 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 15:12:02 +0100 Subject: [PATCH 414/628] Rule 24.5.1 - CharacterHandlingFunctionRestrictions.ql Add a new query to detect uses of prohibited character handling functions. --- .../CharacterHandlingFunctionRestrictions.ql | 42 ++++ ...acterHandlingFunctionRestrictions.expected | 132 +++++++++++ ...haracterHandlingFunctionRestrictions.qlref | 1 + cpp/misra/test/rules/RULE-24-5-1/test.cpp | 219 ++++++++++++++++++ 4 files changed, 394 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql create mode 100644 cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.expected create mode 100644 cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.qlref create mode 100644 cpp/misra/test/rules/RULE-24-5-1/test.cpp diff --git a/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql b/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql new file mode 100644 index 0000000000..6a779b0e6c --- /dev/null +++ b/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql @@ -0,0 +1,42 @@ +/** + * @id cpp/misra/character-handling-function-restrictions + * @name RULE-24-5-1: The character handling functions from and shall not be used + * @description Using character classification and case mapping functions from and + * causes undefined behavior when arguments are not representable as unsigned + * char or not equal to EOF. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-24-5-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class BannedCharacterHandlingFunction extends Function { + BannedCharacterHandlingFunction() { + this.hasGlobalOrStdName([ + "isalnum", "isalpha", "isblank", "iscntrl", "isdigit", "isgraph", "islower", "isprint", + "ispunct", "isspace", "isupper", "isxdigit", "tolower", "toupper", + "iswalnum", "iswalpha", "iswblank", "iswcntrl", "iswctype", "iswdigit", "iswgraph", + "iswlower", "iswprint", "iswpunct", "iswspace", "iswupper", "iswxdigit", "towctrans", + "towlower", "towupper", "wctrans", "wctype" + ]) and + not ( + this.hasGlobalOrStdName([ + "isalnum", "isalpha", "isblank", "iscntrl", "isdigit", "isgraph", "islower", "isprint", + "ispunct", "isspace", "isupper", "isxdigit", "tolower", "toupper" + ]) and + this.getACallToThisFunction().(FunctionCall).getNumberOfArguments() = 2 + ) + } +} + +from BannedFunctions::Use use +where + not isExcluded(use, BannedAPIsPackage::characterHandlingFunctionRestrictionsQuery()) +select use, use.getAction() + " banned character handling function '" + use.getFunctionName() + "' from or ." \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.expected b/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.expected new file mode 100644 index 0000000000..1c02073fb9 --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.expected @@ -0,0 +1,132 @@ +| test.cpp:11:3:11:14 | call to isalnum | Call to banned character handling function 'isalnum' from or . | +| test.cpp:12:3:12:14 | call to isalpha | Call to banned character handling function 'isalpha' from or . | +| test.cpp:13:3:13:14 | call to isblank | Call to banned character handling function 'isblank' from or . | +| test.cpp:14:3:14:14 | call to iscntrl | Call to banned character handling function 'iscntrl' from or . | +| test.cpp:15:3:15:14 | call to isdigit | Call to banned character handling function 'isdigit' from or . | +| test.cpp:16:3:16:14 | call to isgraph | Call to banned character handling function 'isgraph' from or . | +| test.cpp:17:3:17:14 | call to islower | Call to banned character handling function 'islower' from or . | +| test.cpp:18:3:18:14 | call to isprint | Call to banned character handling function 'isprint' from or . | +| test.cpp:19:3:19:14 | call to ispunct | Call to banned character handling function 'ispunct' from or . | +| test.cpp:20:3:20:14 | call to isspace | Call to banned character handling function 'isspace' from or . | +| test.cpp:21:3:21:14 | call to isupper | Call to banned character handling function 'isupper' from or . | +| test.cpp:22:3:22:15 | call to isxdigit | Call to banned character handling function 'isxdigit' from or . | +| test.cpp:25:3:25:14 | call to tolower | Call to banned character handling function 'tolower' from or . | +| test.cpp:26:3:26:14 | call to toupper | Call to banned character handling function 'toupper' from or . | +| test.cpp:33:3:33:9 | call to isalnum | Call to banned character handling function 'isalnum' from or . | +| test.cpp:34:3:34:9 | call to isalpha | Call to banned character handling function 'isalpha' from or . | +| test.cpp:35:3:35:9 | call to isblank | Call to banned character handling function 'isblank' from or . | +| test.cpp:36:3:36:9 | call to iscntrl | Call to banned character handling function 'iscntrl' from or . | +| test.cpp:37:3:37:9 | call to isdigit | Call to banned character handling function 'isdigit' from or . | +| test.cpp:38:3:38:9 | call to isgraph | Call to banned character handling function 'isgraph' from or . | +| test.cpp:39:3:39:9 | call to islower | Call to banned character handling function 'islower' from or . | +| test.cpp:40:3:40:9 | call to isprint | Call to banned character handling function 'isprint' from or . | +| test.cpp:41:3:41:9 | call to ispunct | Call to banned character handling function 'ispunct' from or . | +| test.cpp:42:3:42:9 | call to isspace | Call to banned character handling function 'isspace' from or . | +| test.cpp:43:3:43:9 | call to isupper | Call to banned character handling function 'isupper' from or . | +| test.cpp:44:3:44:10 | call to isxdigit | Call to banned character handling function 'isxdigit' from or . | +| test.cpp:47:3:47:9 | call to tolower | Call to banned character handling function 'tolower' from or . | +| test.cpp:48:3:48:9 | call to toupper | Call to banned character handling function 'toupper' from or . | +| test.cpp:55:3:55:15 | call to iswalnum | Call to banned character handling function 'iswalnum' from or . | +| test.cpp:56:3:56:15 | call to iswalpha | Call to banned character handling function 'iswalpha' from or . | +| test.cpp:57:3:57:15 | call to iswblank | Call to banned character handling function 'iswblank' from or . | +| test.cpp:58:3:58:15 | call to iswcntrl | Call to banned character handling function 'iswcntrl' from or . | +| test.cpp:59:3:59:15 | call to iswdigit | Call to banned character handling function 'iswdigit' from or . | +| test.cpp:60:3:60:15 | call to iswgraph | Call to banned character handling function 'iswgraph' from or . | +| test.cpp:61:3:61:15 | call to iswlower | Call to banned character handling function 'iswlower' from or . | +| test.cpp:62:3:62:15 | call to iswprint | Call to banned character handling function 'iswprint' from or . | +| test.cpp:63:3:63:15 | call to iswpunct | Call to banned character handling function 'iswpunct' from or . | +| test.cpp:64:3:64:15 | call to iswspace | Call to banned character handling function 'iswspace' from or . | +| test.cpp:65:3:65:15 | call to iswupper | Call to banned character handling function 'iswupper' from or . | +| test.cpp:66:3:66:16 | call to iswxdigit | Call to banned character handling function 'iswxdigit' from or . | +| test.cpp:69:3:69:15 | call to towlower | Call to banned character handling function 'towlower' from or . | +| test.cpp:70:3:70:15 | call to towupper | Call to banned character handling function 'towupper' from or . | +| test.cpp:73:3:73:13 | call to wctype | Call to banned character handling function 'wctype' from or . | +| test.cpp:74:3:74:15 | call to iswctype | Call to banned character handling function 'iswctype' from or . | +| test.cpp:74:21:74:31 | call to wctype | Call to banned character handling function 'wctype' from or . | +| test.cpp:75:3:75:14 | call to wctrans | Call to banned character handling function 'wctrans' from or . | +| test.cpp:76:3:76:16 | call to towctrans | Call to banned character handling function 'towctrans' from or . | +| test.cpp:76:22:76:33 | call to wctrans | Call to banned character handling function 'wctrans' from or . | +| test.cpp:83:3:83:10 | call to iswalnum | Call to banned character handling function 'iswalnum' from or . | +| test.cpp:84:3:84:10 | call to iswalpha | Call to banned character handling function 'iswalpha' from or . | +| test.cpp:85:3:85:10 | call to iswblank | Call to banned character handling function 'iswblank' from or . | +| test.cpp:86:3:86:10 | call to iswcntrl | Call to banned character handling function 'iswcntrl' from or . | +| test.cpp:87:3:87:10 | call to iswdigit | Call to banned character handling function 'iswdigit' from or . | +| test.cpp:88:3:88:10 | call to iswgraph | Call to banned character handling function 'iswgraph' from or . | +| test.cpp:89:3:89:10 | call to iswlower | Call to banned character handling function 'iswlower' from or . | +| test.cpp:90:3:90:10 | call to iswprint | Call to banned character handling function 'iswprint' from or . | +| test.cpp:91:3:91:10 | call to iswpunct | Call to banned character handling function 'iswpunct' from or . | +| test.cpp:92:3:92:10 | call to iswspace | Call to banned character handling function 'iswspace' from or . | +| test.cpp:93:3:93:10 | call to iswupper | Call to banned character handling function 'iswupper' from or . | +| test.cpp:94:3:94:11 | call to iswxdigit | Call to banned character handling function 'iswxdigit' from or . | +| test.cpp:97:3:97:10 | call to towlower | Call to banned character handling function 'towlower' from or . | +| test.cpp:98:3:98:10 | call to towupper | Call to banned character handling function 'towupper' from or . | +| test.cpp:101:3:101:8 | call to wctype | Call to banned character handling function 'wctype' from or . | +| test.cpp:102:3:102:10 | call to iswctype | Call to banned character handling function 'iswctype' from or . | +| test.cpp:102:16:102:21 | call to wctype | Call to banned character handling function 'wctype' from or . | +| test.cpp:103:3:103:9 | call to wctrans | Call to banned character handling function 'wctrans' from or . | +| test.cpp:104:3:104:11 | call to towctrans | Call to banned character handling function 'towctrans' from or . | +| test.cpp:104:17:104:23 | call to wctrans | Call to banned character handling function 'wctrans' from or . | +| test.cpp:109:20:109:32 | isalnum | Address taken for banned character handling function 'isalnum' from or . | +| test.cpp:110:20:110:32 | isalpha | Address taken for banned character handling function 'isalpha' from or . | +| test.cpp:111:20:111:32 | isblank | Address taken for banned character handling function 'isblank' from or . | +| test.cpp:112:20:112:32 | iscntrl | Address taken for banned character handling function 'iscntrl' from or . | +| test.cpp:113:20:113:32 | isdigit | Address taken for banned character handling function 'isdigit' from or . | +| test.cpp:114:20:114:32 | isgraph | Address taken for banned character handling function 'isgraph' from or . | +| test.cpp:115:20:115:32 | islower | Address taken for banned character handling function 'islower' from or . | +| test.cpp:116:20:116:32 | isprint | Address taken for banned character handling function 'isprint' from or . | +| test.cpp:117:20:117:32 | ispunct | Address taken for banned character handling function 'ispunct' from or . | +| test.cpp:118:21:118:33 | isspace | Address taken for banned character handling function 'isspace' from or . | +| test.cpp:119:21:119:33 | isupper | Address taken for banned character handling function 'isupper' from or . | +| test.cpp:120:21:120:34 | isxdigit | Address taken for banned character handling function 'isxdigit' from or . | +| test.cpp:121:21:121:33 | tolower | Address taken for banned character handling function 'tolower' from or . | +| test.cpp:122:21:122:33 | toupper | Address taken for banned character handling function 'toupper' from or . | +| test.cpp:125:22:125:28 | isalnum | Address taken for banned character handling function 'isalnum' from or . | +| test.cpp:126:22:126:28 | isalpha | Address taken for banned character handling function 'isalpha' from or . | +| test.cpp:127:22:127:28 | isblank | Address taken for banned character handling function 'isblank' from or . | +| test.cpp:128:22:128:28 | iscntrl | Address taken for banned character handling function 'iscntrl' from or . | +| test.cpp:129:22:129:28 | isdigit | Address taken for banned character handling function 'isdigit' from or . | +| test.cpp:130:22:130:28 | isgraph | Address taken for banned character handling function 'isgraph' from or . | +| test.cpp:131:22:131:28 | islower | Address taken for banned character handling function 'islower' from or . | +| test.cpp:132:22:132:28 | isprint | Address taken for banned character handling function 'isprint' from or . | +| test.cpp:133:22:133:28 | ispunct | Address taken for banned character handling function 'ispunct' from or . | +| test.cpp:134:22:134:28 | isspace | Address taken for banned character handling function 'isspace' from or . | +| test.cpp:135:22:135:28 | isupper | Address taken for banned character handling function 'isupper' from or . | +| test.cpp:136:22:136:29 | isxdigit | Address taken for banned character handling function 'isxdigit' from or . | +| test.cpp:137:22:137:28 | tolower | Address taken for banned character handling function 'tolower' from or . | +| test.cpp:138:22:138:28 | toupper | Address taken for banned character handling function 'toupper' from or . | +| test.cpp:141:25:141:37 | iswalnum | Address taken for banned character handling function 'iswalnum' from or . | +| test.cpp:142:25:142:37 | iswalpha | Address taken for banned character handling function 'iswalpha' from or . | +| test.cpp:143:25:143:37 | iswblank | Address taken for banned character handling function 'iswblank' from or . | +| test.cpp:144:25:144:37 | iswcntrl | Address taken for banned character handling function 'iswcntrl' from or . | +| test.cpp:145:25:145:37 | iswdigit | Address taken for banned character handling function 'iswdigit' from or . | +| test.cpp:146:25:146:37 | iswgraph | Address taken for banned character handling function 'iswgraph' from or . | +| test.cpp:147:25:147:37 | iswlower | Address taken for banned character handling function 'iswlower' from or . | +| test.cpp:148:25:148:37 | iswprint | Address taken for banned character handling function 'iswprint' from or . | +| test.cpp:149:25:149:37 | iswpunct | Address taken for banned character handling function 'iswpunct' from or . | +| test.cpp:150:25:150:37 | iswspace | Address taken for banned character handling function 'iswspace' from or . | +| test.cpp:151:25:151:37 | iswupper | Address taken for banned character handling function 'iswupper' from or . | +| test.cpp:152:25:152:38 | iswxdigit | Address taken for banned character handling function 'iswxdigit' from or . | +| test.cpp:153:28:153:40 | towlower | Address taken for banned character handling function 'towlower' from or . | +| test.cpp:154:28:154:40 | towupper | Address taken for banned character handling function 'towupper' from or . | +| test.cpp:155:36:155:46 | wctype | Address taken for banned character handling function 'wctype' from or . | +| test.cpp:156:35:156:47 | iswctype | Address taken for banned character handling function 'iswctype' from or . | +| test.cpp:157:37:157:48 | wctrans | Address taken for banned character handling function 'wctrans' from or . | +| test.cpp:158:39:158:52 | towctrans | Address taken for banned character handling function 'towctrans' from or . | +| test.cpp:161:25:161:32 | iswalnum | Address taken for banned character handling function 'iswalnum' from or . | +| test.cpp:162:25:162:32 | iswalpha | Address taken for banned character handling function 'iswalpha' from or . | +| test.cpp:163:25:163:32 | iswblank | Address taken for banned character handling function 'iswblank' from or . | +| test.cpp:164:25:164:32 | iswcntrl | Address taken for banned character handling function 'iswcntrl' from or . | +| test.cpp:165:25:165:32 | iswdigit | Address taken for banned character handling function 'iswdigit' from or . | +| test.cpp:166:25:166:32 | iswgraph | Address taken for banned character handling function 'iswgraph' from or . | +| test.cpp:167:25:167:32 | iswlower | Address taken for banned character handling function 'iswlower' from or . | +| test.cpp:168:25:168:32 | iswprint | Address taken for banned character handling function 'iswprint' from or . | +| test.cpp:169:25:169:32 | iswpunct | Address taken for banned character handling function 'iswpunct' from or . | +| test.cpp:170:25:170:32 | iswspace | Address taken for banned character handling function 'iswspace' from or . | +| test.cpp:171:25:171:32 | iswupper | Address taken for banned character handling function 'iswupper' from or . | +| test.cpp:172:25:172:33 | iswxdigit | Address taken for banned character handling function 'iswxdigit' from or . | +| test.cpp:173:28:173:35 | towlower | Address taken for banned character handling function 'towlower' from or . | +| test.cpp:174:28:174:35 | towupper | Address taken for banned character handling function 'towupper' from or . | +| test.cpp:175:36:175:41 | wctype | Address taken for banned character handling function 'wctype' from or . | +| test.cpp:176:35:176:42 | iswctype | Address taken for banned character handling function 'iswctype' from or . | +| test.cpp:177:37:177:43 | wctrans | Address taken for banned character handling function 'wctrans' from or . | +| test.cpp:178:39:178:47 | towctrans | Address taken for banned character handling function 'towctrans' from or . | diff --git a/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.qlref b/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.qlref new file mode 100644 index 0000000000..a2ac2abeab --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.qlref @@ -0,0 +1 @@ +rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-24-5-1/test.cpp b/cpp/misra/test/rules/RULE-24-5-1/test.cpp new file mode 100644 index 0000000000..6c06441c8d --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-1/test.cpp @@ -0,0 +1,219 @@ +#include +#include +#include +#include +#include + +void test_cctype_functions() { + char l1 = 'A'; + + // Character classification functions from + std::isalnum(l1); // NON_COMPLIANT + std::isalpha(l1); // NON_COMPLIANT + std::isblank(l1); // NON_COMPLIANT + std::iscntrl(l1); // NON_COMPLIANT + std::isdigit(l1); // NON_COMPLIANT + std::isgraph(l1); // NON_COMPLIANT + std::islower(l1); // NON_COMPLIANT + std::isprint(l1); // NON_COMPLIANT + std::ispunct(l1); // NON_COMPLIANT + std::isspace(l1); // NON_COMPLIANT + std::isupper(l1); // NON_COMPLIANT + std::isxdigit(l1); // NON_COMPLIANT + + // Character case mapping functions from + std::tolower(l1); // NON_COMPLIANT + std::toupper(l1); // NON_COMPLIANT +} + +void test_ctype_h_functions() { + char l1 = 'A'; + + // Character classification functions from + isalnum(l1); // NON_COMPLIANT + isalpha(l1); // NON_COMPLIANT + isblank(l1); // NON_COMPLIANT + iscntrl(l1); // NON_COMPLIANT + isdigit(l1); // NON_COMPLIANT + isgraph(l1); // NON_COMPLIANT + islower(l1); // NON_COMPLIANT + isprint(l1); // NON_COMPLIANT + ispunct(l1); // NON_COMPLIANT + isspace(l1); // NON_COMPLIANT + isupper(l1); // NON_COMPLIANT + isxdigit(l1); // NON_COMPLIANT + + // Character case mapping functions from + tolower(l1); // NON_COMPLIANT + toupper(l1); // NON_COMPLIANT +} + +void test_cwctype_functions() { + wchar_t l1 = L'A'; + + // Wide character classification functions from + std::iswalnum(l1); // NON_COMPLIANT + std::iswalpha(l1); // NON_COMPLIANT + std::iswblank(l1); // NON_COMPLIANT + std::iswcntrl(l1); // NON_COMPLIANT + std::iswdigit(l1); // NON_COMPLIANT + std::iswgraph(l1); // NON_COMPLIANT + std::iswlower(l1); // NON_COMPLIANT + std::iswprint(l1); // NON_COMPLIANT + std::iswpunct(l1); // NON_COMPLIANT + std::iswspace(l1); // NON_COMPLIANT + std::iswupper(l1); // NON_COMPLIANT + std::iswxdigit(l1); // NON_COMPLIANT + + // Wide character case mapping functions from + std::towlower(l1); // NON_COMPLIANT + std::towupper(l1); // NON_COMPLIANT + + // Wide character type functions from + std::wctype("alpha"); // NON_COMPLIANT + std::iswctype(l1, std::wctype("alpha")); // NON_COMPLIANT + std::wctrans("tolower"); // NON_COMPLIANT + std::towctrans(l1, std::wctrans("tolower")); // NON_COMPLIANT +} + +void test_wctype_h_functions() { + wchar_t l1 = L'A'; + + // Wide character classification functions from + iswalnum(l1); // NON_COMPLIANT + iswalpha(l1); // NON_COMPLIANT + iswblank(l1); // NON_COMPLIANT + iswcntrl(l1); // NON_COMPLIANT + iswdigit(l1); // NON_COMPLIANT + iswgraph(l1); // NON_COMPLIANT + iswlower(l1); // NON_COMPLIANT + iswprint(l1); // NON_COMPLIANT + iswpunct(l1); // NON_COMPLIANT + iswspace(l1); // NON_COMPLIANT + iswupper(l1); // NON_COMPLIANT + iswxdigit(l1); // NON_COMPLIANT + + // Wide character case mapping functions from + towlower(l1); // NON_COMPLIANT + towupper(l1); // NON_COMPLIANT + + // Wide character type functions from + wctype("alpha"); // NON_COMPLIANT + iswctype(l1, wctype("alpha")); // NON_COMPLIANT + wctrans("tolower"); // NON_COMPLIANT + towctrans(l1, wctrans("tolower")); // NON_COMPLIANT +} + +void test_function_addresses() { + // Taking addresses of functions from + int (*l1)(int) = &std::isalnum; // NON_COMPLIANT + int (*l2)(int) = &std::isalpha; // NON_COMPLIANT + int (*l3)(int) = &std::isblank; // NON_COMPLIANT + int (*l4)(int) = &std::iscntrl; // NON_COMPLIANT + int (*l5)(int) = &std::isdigit; // NON_COMPLIANT + int (*l6)(int) = &std::isgraph; // NON_COMPLIANT + int (*l7)(int) = &std::islower; // NON_COMPLIANT + int (*l8)(int) = &std::isprint; // NON_COMPLIANT + int (*l9)(int) = &std::ispunct; // NON_COMPLIANT + int (*l10)(int) = &std::isspace; // NON_COMPLIANT + int (*l11)(int) = &std::isupper; // NON_COMPLIANT + int (*l12)(int) = &std::isxdigit; // NON_COMPLIANT + int (*l13)(int) = &std::tolower; // NON_COMPLIANT + int (*l14)(int) = &std::toupper; // NON_COMPLIANT + + // Taking addresses of functions from + int (*l15)(int) = &isalnum; // NON_COMPLIANT + int (*l16)(int) = &isalpha; // NON_COMPLIANT + int (*l17)(int) = &isblank; // NON_COMPLIANT + int (*l18)(int) = &iscntrl; // NON_COMPLIANT + int (*l19)(int) = &isdigit; // NON_COMPLIANT + int (*l20)(int) = &isgraph; // NON_COMPLIANT + int (*l21)(int) = &islower; // NON_COMPLIANT + int (*l22)(int) = &isprint; // NON_COMPLIANT + int (*l23)(int) = &ispunct; // NON_COMPLIANT + int (*l24)(int) = &isspace; // NON_COMPLIANT + int (*l25)(int) = &isupper; // NON_COMPLIANT + int (*l26)(int) = &isxdigit; // NON_COMPLIANT + int (*l27)(int) = &tolower; // NON_COMPLIANT + int (*l28)(int) = &toupper; // NON_COMPLIANT + + // Taking addresses of functions from + int (*l29)(wint_t) = &std::iswalnum; // NON_COMPLIANT + int (*l30)(wint_t) = &std::iswalpha; // NON_COMPLIANT + int (*l31)(wint_t) = &std::iswblank; // NON_COMPLIANT + int (*l32)(wint_t) = &std::iswcntrl; // NON_COMPLIANT + int (*l33)(wint_t) = &std::iswdigit; // NON_COMPLIANT + int (*l34)(wint_t) = &std::iswgraph; // NON_COMPLIANT + int (*l35)(wint_t) = &std::iswlower; // NON_COMPLIANT + int (*l36)(wint_t) = &std::iswprint; // NON_COMPLIANT + int (*l37)(wint_t) = &std::iswpunct; // NON_COMPLIANT + int (*l38)(wint_t) = &std::iswspace; // NON_COMPLIANT + int (*l39)(wint_t) = &std::iswupper; // NON_COMPLIANT + int (*l40)(wint_t) = &std::iswxdigit; // NON_COMPLIANT + wint_t (*l41)(wint_t) = &std::towlower; // NON_COMPLIANT + wint_t (*l42)(wint_t) = &std::towupper; // NON_COMPLIANT + wctype_t (*l43)(const char *) = &std::wctype; // NON_COMPLIANT + int (*l44)(wint_t, wctype_t) = &std::iswctype; // NON_COMPLIANT + wctrans_t (*l45)(const char *) = &std::wctrans; // NON_COMPLIANT + wint_t (*l46)(wint_t, wctrans_t) = &std::towctrans; // NON_COMPLIANT + + // Taking addresses of functions from + int (*l47)(wint_t) = &iswalnum; // NON_COMPLIANT + int (*l48)(wint_t) = &iswalpha; // NON_COMPLIANT + int (*l49)(wint_t) = &iswblank; // NON_COMPLIANT + int (*l50)(wint_t) = &iswcntrl; // NON_COMPLIANT + int (*l51)(wint_t) = &iswdigit; // NON_COMPLIANT + int (*l52)(wint_t) = &iswgraph; // NON_COMPLIANT + int (*l53)(wint_t) = &iswlower; // NON_COMPLIANT + int (*l54)(wint_t) = &iswprint; // NON_COMPLIANT + int (*l55)(wint_t) = &iswpunct; // NON_COMPLIANT + int (*l56)(wint_t) = &iswspace; // NON_COMPLIANT + int (*l57)(wint_t) = &iswupper; // NON_COMPLIANT + int (*l58)(wint_t) = &iswxdigit; // NON_COMPLIANT + wint_t (*l59)(wint_t) = &towlower; // NON_COMPLIANT + wint_t (*l60)(wint_t) = &towupper; // NON_COMPLIANT + wctype_t (*l61)(const char *) = &wctype; // NON_COMPLIANT + int (*l62)(wint_t, wctype_t) = &iswctype; // NON_COMPLIANT + wctrans_t (*l63)(const char *) = &wctrans; // NON_COMPLIANT + wint_t (*l64)(wint_t, wctrans_t) = &towctrans; // NON_COMPLIANT +} + +void test_compliant_locale_usage() { + char l1 = 'A'; + wchar_t l2 = L'A'; + std::locale l3{}; + + // Compliant usage with locale parameter + std::isalnum(l1, l3); // COMPLIANT + std::isalpha(l1, l3); // COMPLIANT + std::isblank(l1, l3); // COMPLIANT + std::iscntrl(l1, l3); // COMPLIANT + std::isdigit(l1, l3); // COMPLIANT + std::isgraph(l1, l3); // COMPLIANT + std::islower(l1, l3); // COMPLIANT + std::isprint(l1, l3); // COMPLIANT + std::ispunct(l1, l3); // COMPLIANT + std::isspace(l1, l3); // COMPLIANT + std::isupper(l1, l3); // COMPLIANT + std::isxdigit(l1, l3); // COMPLIANT + + std::tolower(l1, l3); // COMPLIANT + std::toupper(l1, l3); // COMPLIANT + + // Compliant wide character usage with locale parameter + std::isalnum(l2, l3); // COMPLIANT + std::isalpha(l2, l3); // COMPLIANT + std::isblank(l2, l3); // COMPLIANT + std::iscntrl(l2, l3); // COMPLIANT + std::isdigit(l2, l3); // COMPLIANT + std::isgraph(l2, l3); // COMPLIANT + std::islower(l2, l3); // COMPLIANT + std::isprint(l2, l3); // COMPLIANT + std::ispunct(l2, l3); // COMPLIANT + std::isspace(l2, l3); // COMPLIANT + std::isupper(l2, l3); // COMPLIANT + std::isxdigit(l2, l3); // COMPLIANT + + std::tolower(l2, l3); // COMPLIANT + std::toupper(l2, l3); // COMPLIANT +} \ No newline at end of file From ed16770370f7683f7b4fdd798188dd718ce51341 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 15:20:46 +0100 Subject: [PATCH 415/628] Rule 24.5.1 - improve structure/consistency of query --- .../CharacterHandlingFunctionRestrictions.ql | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql b/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql index 6a779b0e6c..d3dba3c347 100644 --- a/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql +++ b/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql @@ -20,23 +20,25 @@ import codingstandards.cpp.BannedFunctions class BannedCharacterHandlingFunction extends Function { BannedCharacterHandlingFunction() { this.hasGlobalOrStdName([ - "isalnum", "isalpha", "isblank", "iscntrl", "isdigit", "isgraph", "islower", "isprint", - "ispunct", "isspace", "isupper", "isxdigit", "tolower", "toupper", - "iswalnum", "iswalpha", "iswblank", "iswcntrl", "iswctype", "iswdigit", "iswgraph", - "iswlower", "iswprint", "iswpunct", "iswspace", "iswupper", "iswxdigit", "towctrans", - "towlower", "towupper", "wctrans", "wctype" - ]) and - not ( - this.hasGlobalOrStdName([ "isalnum", "isalpha", "isblank", "iscntrl", "isdigit", "isgraph", "islower", "isprint", - "ispunct", "isspace", "isupper", "isxdigit", "tolower", "toupper" + "ispunct", "isspace", "isupper", "isxdigit", "tolower", "toupper", "iswalnum", "iswalpha", + "iswblank", "iswcntrl", "iswctype", "iswdigit", "iswgraph", "iswlower", "iswprint", + "iswpunct", "iswspace", "iswupper", "iswxdigit", "towctrans", "towlower", "towupper", + "wctrans", "wctype" ]) and - this.getACallToThisFunction().(FunctionCall).getNumberOfArguments() = 2 - ) + // Exclude the functions which pass a reference to a std::locale as the second parameter + not this.getParameter(1) + .getType() + .getUnspecifiedType() + .(ReferenceType) + .getBaseType() + .(UserType) + .hasQualifiedName("std", "locale") } } from BannedFunctions::Use use -where - not isExcluded(use, BannedAPIsPackage::characterHandlingFunctionRestrictionsQuery()) -select use, use.getAction() + " banned character handling function '" + use.getFunctionName() + "' from or ." \ No newline at end of file +where not isExcluded(use, BannedAPIsPackage::characterHandlingFunctionRestrictionsQuery()) +select use, + use.getAction() + " banned character handling function '" + use.getFunctionName() + + "' from or ." From 18e014316df844ee6b94935c7171e2485a2d796b Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 17:24:47 +0100 Subject: [PATCH 416/628] Extend C++ stubs for locale --- .../test/includes/standard-library/locale | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/cpp/common/test/includes/standard-library/locale b/cpp/common/test/includes/standard-library/locale index 4d19e3dbaa..755c5f6ee1 100644 --- a/cpp/common/test/includes/standard-library/locale +++ b/cpp/common/test/includes/standard-library/locale @@ -2,9 +2,45 @@ #ifndef _GHLIBCPP_LOCALE #define _GHLIBCPP_LOCALE +#include + namespace std { -class locale {}; +class locale { +public: + class facet; + class id; + typedef int category; + + static const category none = 0, collate = 0x010, ctype = 0x020, + monetary = 0x040, numeric = 0x080, time = 0x100, + messages = 0x200, + all = collate | ctype | monetary | numeric | time | + messages; + + locale() noexcept; + locale(const locale &other) noexcept; + explicit locale(const char *std_name); + explicit locale(const string &std_name); + locale(const locale &other, const char *std_name, category); + locale(const locale &other, const string &std_name, category); + template locale(const locale &other, Facet *f); + locale(const locale &other, const locale &one, category); + ~locale(); + const locale &operator=(const locale &other) noexcept; + template locale combine(const locale &other) const; + + basic_string name() const; + + bool operator==(const locale &other) const; + bool operator!=(const locale &other) const; + template + bool operator()(const basic_string &s1, + const basic_string &s2) const; + + static locale global(const locale &); + static const locale &classic(); +}; template bool isspace(charT c, const locale &loc); template bool isprint(charT c, const locale &loc); From 367a18a889055f3f6ef7fd3dce12499ecbad84cd Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 17:26:39 +0100 Subject: [PATCH 417/628] Rule 25.5.1 - LocaleGlobalFunctionNotAllowed.ql Add query for banned locale functions. [a] --- .../LocaleGlobalFunctionNotAllowed.ql | 28 +++++++++++ .../LocaleGlobalFunctionNotAllowed.expected | 9 ++++ .../LocaleGlobalFunctionNotAllowed.qlref | 1 + cpp/misra/test/rules/RULE-25-5-1/test.cpp | 47 +++++++++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql create mode 100644 cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.expected create mode 100644 cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.qlref create mode 100644 cpp/misra/test/rules/RULE-25-5-1/test.cpp diff --git a/cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql b/cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql new file mode 100644 index 0000000000..5072da9789 --- /dev/null +++ b/cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql @@ -0,0 +1,28 @@ +/** + * @id cpp/misra/locale-global-function-not-allowed + * @name RULE-25-5-1: The setlocale and std::locale::global functions shall not be called + * @description Calling setlocale or std::locale::global functions can introduce data races with + * functions that use the locale, leading to undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-25-5-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class BannedLocaleFunction extends Function { + BannedLocaleFunction() { + this.hasGlobalOrStdName("setlocale") or + this.hasQualifiedName("std", "locale", "global") + } +} + +from BannedFunctions::Use use +where not isExcluded(use, BannedAPIsPackage::localeGlobalFunctionNotAllowedQuery()) +select use, use.getAction() + " banned function '" + use.getFunctionName() + "' from ." diff --git a/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.expected b/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.expected new file mode 100644 index 0000000000..fde7f610e8 --- /dev/null +++ b/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.expected @@ -0,0 +1,9 @@ +| test.cpp:6:3:6:16 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:7:3:7:16 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:8:3:8:16 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:12:3:12:21 | call to global | Call to banned function 'global' from . | +| test.cpp:13:3:13:21 | call to global | Call to banned function 'global' from . | +| test.cpp:36:5:36:18 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:40:5:40:18 | call to setlocale | Call to banned function 'setlocale' from . | +| test.cpp:45:3:45:21 | call to global | Call to banned function 'global' from . | +| test.cpp:46:3:46:21 | call to global | Call to banned function 'global' from . | diff --git a/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.qlref b/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.qlref new file mode 100644 index 0000000000..f28199a5aa --- /dev/null +++ b/cpp/misra/test/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.qlref @@ -0,0 +1 @@ +rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-25-5-1/test.cpp b/cpp/misra/test/rules/RULE-25-5-1/test.cpp new file mode 100644 index 0000000000..b45be36f70 --- /dev/null +++ b/cpp/misra/test/rules/RULE-25-5-1/test.cpp @@ -0,0 +1,47 @@ +#include +#include +#include + +void test_setlocale_call() { + std::setlocale(LC_ALL, "C"); // NON_COMPLIANT + std::setlocale(LC_NUMERIC, "C"); // NON_COMPLIANT + std::setlocale(LC_TIME, "en_US.UTF-8"); // NON_COMPLIANT +} + +void test_locale_global_call() { + std::locale::global(std::locale("C")); // NON_COMPLIANT + std::locale::global(std::locale::classic()); // NON_COMPLIANT +} + +void test_compliant_locale_usage() { + wchar_t l1 = L'\u2002'; + std::locale l2("C"); + + if (std::isspace(l1, l2)) { // COMPLIANT + } + if (std::isalpha(l1, l2)) { // COMPLIANT + } + if (std::isdigit(l1, l2)) { // COMPLIANT + } +} + +void test_compliant_locale_construction() { + std::locale l3("C"); // COMPLIANT + std::locale l4 = std::locale::classic(); // COMPLIANT + std::locale l5; // COMPLIANT +} + +void test_nested_setlocale_calls() { + if (true) { + std::setlocale(LC_ALL, "ja_JP.utf8"); // NON_COMPLIANT + } + + for (int l6 = 0; l6 < 1; ++l6) { + std::setlocale(LC_CTYPE, "C"); // NON_COMPLIANT + } +} + +void test_locale_global_with_different_locales() { + std::locale::global(std::locale("en_US.UTF-8")); // NON_COMPLIANT + std::locale::global(std::locale("ja_JP.utf8")); // NON_COMPLIANT +} \ No newline at end of file From 8485924bf6f377357344010d9b7337eadaca7c4e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 17:28:13 +0100 Subject: [PATCH 418/628] Rule 24-5-2 - NoMemoryFunctionsFromCString.ql Adds a new query to detect use of banned cstring functions. [a] --- .../NoMemoryFunctionsFromCString.ql | 26 ++++++ .../NoMemoryFunctionsFromCString.expected | 23 +++++ .../NoMemoryFunctionsFromCString.qlref | 1 + cpp/misra/test/rules/RULE-24-5-2/test.cpp | 89 +++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql create mode 100644 cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.expected create mode 100644 cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.qlref create mode 100644 cpp/misra/test/rules/RULE-24-5-2/test.cpp diff --git a/cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql b/cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql new file mode 100644 index 0000000000..17bca5c0eb --- /dev/null +++ b/cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql @@ -0,0 +1,26 @@ +/** + * @id cpp/misra/no-memory-functions-from-c-string + * @name RULE-24-5-2: The C++ Standard Library functions memcpy, memmove and memcmp from shall not be used + * @description Using memcpy, memmove or memcmp from can result in undefined behavior due + * to overlapping memory, non-trivially copyable objects, or unequal comparison of + * logically equal objects. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-24-5-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class BannedMemoryFunction extends Function { + BannedMemoryFunction() { this.hasGlobalOrStdName(["memcpy", "memmove", "memcmp"]) } +} + +from BannedFunctions::Use use +where not isExcluded(use, BannedAPIsPackage::noMemoryFunctionsFromCStringQuery()) +select use, use.getAction() + " banned function '" + use.getFunctionName() + "' from ." diff --git a/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.expected b/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.expected new file mode 100644 index 0000000000..49ce89347c --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.expected @@ -0,0 +1,23 @@ +| test.cpp:9:3:9:8 | call to memcpy | Call to banned function 'memcpy' from . | +| test.cpp:10:3:10:13 | call to memcpy | Call to banned function 'memcpy' from . | +| test.cpp:17:3:17:9 | call to memmove | Call to banned function 'memmove' from . | +| test.cpp:18:3:18:14 | call to memmove | Call to banned function 'memmove' from . | +| test.cpp:25:12:25:17 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:26:12:26:22 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:30:52:30:57 | memcpy | Address taken for banned function 'memcpy' from . | +| test.cpp:31:52:31:58 | memmove | Address taken for banned function 'memmove' from . | +| test.cpp:32:56:32:61 | memcmp | Address taken for banned function 'memcmp' from . | +| test.cpp:34:52:34:62 | memcpy | Address taken for banned function 'memcpy' from . | +| test.cpp:36:7:36:18 | memmove | Address taken for banned function 'memmove' from . | +| test.cpp:38:7:38:17 | memcmp | Address taken for banned function 'memcmp' from . | +| test.cpp:50:7:50:12 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:53:7:53:17 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:61:7:61:12 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:64:7:64:17 | call to memcmp | Call to banned function 'memcmp' from . | +| test.cpp:71:3:71:8 | call to memcpy | Call to banned function 'memcpy' from . | +| test.cpp:72:3:72:9 | call to memmove | Call to banned function 'memmove' from . | +| test.cpp:74:3:74:13 | call to memcpy | Call to banned function 'memcpy' from . | +| test.cpp:75:3:75:14 | call to memmove | Call to banned function 'memmove' from . | +| test.cpp:78:1:78:28 | #define CUSTOM_MEMCPY memcpy | Call to banned function 'memcpy' from . | +| test.cpp:79:1:79:30 | #define CUSTOM_MEMMOVE memmove | Call to banned function 'memmove' from . | +| test.cpp:80:1:80:28 | #define CUSTOM_MEMCMP memcmp | Call to banned function 'memcmp' from . | diff --git a/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.qlref b/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.qlref new file mode 100644 index 0000000000..53307ad85f --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.qlref @@ -0,0 +1 @@ +rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-24-5-2/test.cpp b/cpp/misra/test/rules/RULE-24-5-2/test.cpp new file mode 100644 index 0000000000..f189afdbc6 --- /dev/null +++ b/cpp/misra/test/rules/RULE-24-5-2/test.cpp @@ -0,0 +1,89 @@ +#include +#include +#include + +void test_memcpy_usage() { + std::uint8_t l1[10]; + std::uint8_t l2[10]; + + memcpy(l1, l2, 10); // NON_COMPLIANT + std::memcpy(l1, l2, 10); // NON_COMPLIANT +} + +void test_memmove_usage() { + std::uint8_t l1[10]; + std::uint8_t l2[10]; + + memmove(l1, l2, 10); // NON_COMPLIANT + std::memmove(l1, l2, 10); // NON_COMPLIANT +} + +void test_memcmp_usage() { + std::uint8_t l1[10]; + std::uint8_t l2[10]; + + int l3 = memcmp(l1, l2, 10); // NON_COMPLIANT + int l4 = std::memcmp(l1, l2, 10); // NON_COMPLIANT +} + +void test_function_pointers() { + void *(*l1)(void *, const void *, std::size_t) = memcpy; // NON_COMPLIANT + void *(*l2)(void *, const void *, std::size_t) = memmove; // NON_COMPLIANT + int (*l3)(const void *, const void *, std::size_t) = memcmp; // NON_COMPLIANT + + void *(*l4)(void *, const void *, std::size_t) = std::memcpy; // NON_COMPLIANT + void *(*l5)(void *, const void *, std::size_t) = + std::memmove; // NON_COMPLIANT + int (*l6)(const void *, const void *, std::size_t) = + std::memcmp; // NON_COMPLIANT +} + +struct S { + bool m1; + std::int64_t m2; +}; + +void test_struct_comparison() { + S l1{true, 42}; + S l2{true, 42}; + + if (memcmp(&l1, &l2, sizeof(S)) != 0) { // NON_COMPLIANT + } + + if (std::memcmp(&l1, &l2, sizeof(S)) != 0) { // NON_COMPLIANT + } +} + +void test_buffer_comparison() { + char l1[12]; + char l2[12]; + + if (memcmp(l1, l2, sizeof(l1)) != 0) { // NON_COMPLIANT + } + + if (std::memcmp(l1, l2, sizeof(l1)) != 0) { // NON_COMPLIANT + } +} + +void test_overlapping_memory() { + std::uint8_t l1[20]; + + memcpy(l1 + 5, l1, 10); // NON_COMPLIANT + memmove(l1 + 5, l1, 10); // NON_COMPLIANT + + std::memcpy(l1 + 5, l1, 10); // NON_COMPLIANT + std::memmove(l1 + 5, l1, 10); // NON_COMPLIANT +} + +#define CUSTOM_MEMCPY memcpy // NON_COMPLIANT +#define CUSTOM_MEMMOVE memmove // NON_COMPLIANT +#define CUSTOM_MEMCMP memcmp // NON_COMPLIANT + +void test_macro_expansion() { + std::uint8_t l1[10]; + std::uint8_t l2[10]; + + CUSTOM_MEMCPY(l1, l2, 10); + CUSTOM_MEMMOVE(l1, l2, 10); + int l3 = CUSTOM_MEMCMP(l1, l2, 10); +} \ No newline at end of file From e26f32afacc866e9eb2370e008ccf19b98cff71e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 18:08:23 +0100 Subject: [PATCH 419/628] Rule 21.10.2 - NoCsetjmpHeader.ql New query to detect banned uses of the csetjmp header. [a] --- .../src/rules/RULE-21-10-2/NoCsetjmpHeader.ql | 53 +++++++++++++++++++ .../RULE-21-10-2/NoCsetjmpHeader.expected | 14 +++++ .../rules/RULE-21-10-2/NoCsetjmpHeader.qlref | 1 + cpp/misra/test/rules/RULE-21-10-2/test.cpp | 38 +++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql create mode 100644 cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected create mode 100644 cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.qlref create mode 100644 cpp/misra/test/rules/RULE-21-10-2/test.cpp diff --git a/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql b/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql new file mode 100644 index 0000000000..4cfc7770a1 --- /dev/null +++ b/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql @@ -0,0 +1,53 @@ +/** + * @id cpp/misra/no-csetjmp-header + * @name RULE-21-10-2: The standard header file shall not be used + * @description Using facilities from the header causes undefined behavior by bypassing + * normal function return mechanisms and may result in non-trivial object destruction + * being omitted. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-21-10-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.BannedFunctions + +class CSetJmpHeader extends Include { + CSetJmpHeader() { this.getIncludeText().regexpMatch("[<\\\"](csetjmp|setjmp.h)[>\\\"]") } +} + +class JmpBufVariable extends Variable { + JmpBufVariable() { this.getType().(UserType).hasGlobalOrStdName("jmp_buf") } +} + +class LongjmpFunction extends Function { + LongjmpFunction() { this.hasGlobalOrStdName("longjmp") } +} + +class SetjmpMacroInvocation extends MacroInvocation { + SetjmpMacroInvocation() { this.getMacroName() = "setjmp" } +} + +from Element element, string message +where + not isExcluded(element, BannedAPIsPackage::noCsetjmpHeaderQuery()) and + ( + message = "Use of banned header " + element.(CSetJmpHeader).getIncludeText() + "." + or + message = + "Declaration of variable '" + element.(JmpBufVariable).getName() + + "' with banned type 'jmp_buf'." + or + message = + element.(BannedFunctions::Use).getAction() + " banned function '" + + element.(BannedFunctions::Use).getFunctionName() + "'." + or + element instanceof SetjmpMacroInvocation and + message = "Use of banned macro 'setjmp'." + ) +select element, message diff --git a/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected b/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected new file mode 100644 index 0000000000..6ac8e41484 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected @@ -0,0 +1,14 @@ +| test.cpp:1:1:1:18 | #include "csetjmp" | Use of banned header "csetjmp". | +| test.cpp:2:1:2:19 | #include "setjmp.h" | Use of banned header "setjmp.h". | +| test.cpp:3:1:3:18 | #include | Use of banned header . | +| test.cpp:4:1:4:19 | #include | Use of banned header . | +| test.cpp:8:9:8:10 | g1 | Declaration of variable 'g1' with banned type 'jmp_buf'. | +| test.cpp:9:14:9:15 | g2 | Declaration of variable 'g2' with banned type 'jmp_buf'. | +| test.cpp:12:11:12:12 | l1 | Declaration of variable 'l1' with banned type 'jmp_buf'. | +| test.cpp:13:7:13:16 | setjmp(env) | Use of banned macro 'setjmp'. | +| test.cpp:14:5:14:11 | call to longjmp | Call to banned function 'longjmp'. | +| test.cpp:19:16:19:17 | l1 | Declaration of variable 'l1' with banned type 'jmp_buf'. | +| test.cpp:20:7:20:16 | setjmp(env) | Use of banned macro 'setjmp'. | +| test.cpp:21:5:21:16 | call to longjmp | Call to banned function 'longjmp'. | +| test.cpp:26:11:26:12 | l1 | Declaration of variable 'l1' with banned type 'jmp_buf'. | +| test.cpp:27:16:27:17 | l2 | Declaration of variable 'l2' with banned type 'jmp_buf'. | diff --git a/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.qlref b/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.qlref new file mode 100644 index 0000000000..8e0712349f --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.qlref @@ -0,0 +1 @@ +rules/RULE-21-10-2/NoCsetjmpHeader.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-21-10-2/test.cpp b/cpp/misra/test/rules/RULE-21-10-2/test.cpp new file mode 100644 index 0000000000..8fbed19530 --- /dev/null +++ b/cpp/misra/test/rules/RULE-21-10-2/test.cpp @@ -0,0 +1,38 @@ +#include "csetjmp" // NON_COMPLIANT +#include "setjmp.h" // NON_COMPLIANT +#include // NON_COMPLIANT +#include // NON_COMPLIANT +#include + +// Global variables for testing +jmp_buf g1; // NON_COMPLIANT +std::jmp_buf g2; // NON_COMPLIANT + +void test_setjmp_usage() { + jmp_buf l1; // NON_COMPLIANT + if (setjmp(l1) == 0) { // NON_COMPLIANT + longjmp(l1, 1); // NON_COMPLIANT + } +} + +void test_std_setjmp_usage() { + std::jmp_buf l1; // NON_COMPLIANT + if (setjmp(l1) == 0) { // NON_COMPLIANT + std::longjmp(l1, 1); // NON_COMPLIANT + } +} + +void test_jmp_buf_declaration() { + jmp_buf l1; // NON_COMPLIANT + std::jmp_buf l2; // NON_COMPLIANT +} + +void test_compliant_alternative() { + // Using structured exception handling or other alternatives + // instead of setjmp/longjmp + try { + throw std::runtime_error("error"); + } catch (const std::runtime_error &) { // COMPLIANT + // Handle error properly + } +} \ No newline at end of file From c603dba8c9fb0127b9f5cac5adc183df642e6b41 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 23:14:19 +0100 Subject: [PATCH 420/628] Rule 21.10.1 - Formatting and reporting improvements --- .../RULE-21-10-1/NoVariadicFunctionMacros.ql | 16 ++++++++++------ .../NoVariadicFunctionMacros.expected | 1 - 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql b/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql index 7e96f70222..fbe82d45c6 100644 --- a/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql +++ b/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql @@ -18,7 +18,6 @@ import codingstandards.cpp.misra class VaListType extends Type { VaListType() { this.getName() = "va_list" or - this.getName() = "__va_list_tag" or this.(SpecifiedType).getBaseType() instanceof VaListType or this.(TypedefType).getBaseType() instanceof VaListType } @@ -29,10 +28,15 @@ where not isExcluded(element, BannedAPIsPackage::noVariadicFunctionMacrosQuery()) and ( element.(Variable).getType() instanceof VaListType and - message = "Declaration of variable '" + element.(Variable).getName() + "' of type 'va_list'." - or - element.(Parameter).getType() instanceof VaListType and - message = "Declaration of parameter '" + element.(Parameter).getName() + "' of type 'va_list'." + ( + if element instanceof Parameter + then + message = + "Declaration of parameter '" + element.(Parameter).getName() + "' of type 'va_list'." + else + message = + "Declaration of variable '" + element.(Variable).getName() + "' of type 'va_list'." + ) or element instanceof BuiltInVarArgsStart and message = "Call to 'va_start'." @@ -50,4 +54,4 @@ where message = "Declaration of typedef '" + element.(TypedefType).getName() + "' aliasing 'va_list' type." ) -select element, message \ No newline at end of file +select element, message diff --git a/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected index 3c47cc4aa5..bb52ced03a 100644 --- a/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected +++ b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected @@ -16,7 +16,6 @@ | test.cpp:31:3:31:12 | __builtin_va_end | Call to 'va_end'. | | test.cpp:32:3:32:12 | __builtin_va_end | Call to 'va_end'. | | test.cpp:35:37:35:38 | l1 | Declaration of parameter 'l1' of type 'va_list'. | -| test.cpp:35:37:35:38 | l1 | Declaration of variable 'l1' of type 'va_list'. | | test.cpp:36:15:36:32 | __builtin_va_arg | Call to 'va_arg'. | | test.cpp:40:11:40:12 | l2 | Declaration of variable 'l2' of type 'va_list'. | | test.cpp:41:3:41:18 | __builtin_va_start | Call to 'va_start'. | From 55cebdbb247827e5dc10d148e27555f37db3606f Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 23:19:12 +0100 Subject: [PATCH 421/628] Move Rule-6-9-2 to FixedWidthInt. --- rules.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules.csv b/rules.csv index 68049625e6..0af18d1f20 100644 --- a/rules.csv +++ b/rules.csv @@ -869,7 +869,7 @@ cpp,MISRA-C++-2023,RULE-6-8-2,Yes,Mandatory,Decidable,Single Translation Unit,A cpp,MISRA-C++-2023,RULE-6-8-3,Yes,Required,Decidable,Single Translation Unit,An assignment operator shall not assign the address of an object with automatic storage duration to an object with a greater lifetime,,Lifetime,Medium, cpp,MISRA-C++-2023,RULE-6-8-4,Yes,Advisory,Decidable,Single Translation Unit,Member functions returning references to their object should be refqualified appropriately,,Declarations2,Medium, cpp,MISRA-C++-2023,RULE-6-9-1,Yes,Required,Decidable,Single Translation Unit,The same type aliases shall be used in all declarations of the same entity,,Declarations2,Medium, -cpp,MISRA-C++-2023,RULE-6-9-2,Yes,Advisory,Decidable,Single Translation Unit,The names of the standard signed integer types and standard unsigned integer types should not be used,A3-9-1,BannedAPIs,Easy, +cpp,MISRA-C++-2023,RULE-6-9-2,Yes,Advisory,Decidable,Single Translation Unit,The names of the standard signed integer types and standard unsigned integer types should not be used,A3-9-1,FixedWithInt,Easy, cpp,MISRA-C++-2023,RULE-7-0-1,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion from type bool,,Conversions,Easy, cpp,MISRA-C++-2023,RULE-7-0-2,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion to type bool,,Conversions,Easy, cpp,MISRA-C++-2023,RULE-7-0-3,Yes,Required,Decidable,Single Translation Unit,The numerical value of a character shall not be used,M5-0-11,Conversions,Medium, From 54fe5ea5d6754f90c394886aa5b6c322c0ab678e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 10 Jun 2025 10:03:52 +0100 Subject: [PATCH 422/628] A3-9-1: Convert to shared query Convert AUTOSAR rule A3-9-1 to a shared query to reuse the implementation for MISRA C++ 2023 Rule 6.9.2. --- .../A3-9-1/VariableWidthIntegerTypesUsed.ql | 28 ++---- .../VariableWidthIntegerTypesUsed.qlref | 1 - .../VariableWidthIntegerTypesUsed.testref | 1 + .../VariableWidthPlainCharTypeUsed.expected | 4 +- cpp/autosar/test/rules/A3-9-1/test.cpp | 86 ++---------------- .../VariableWidthIntegerTypesUsed.qll | 38 ++++++++ .../VariableWidthIntegerTypesUsed.expected | 0 .../VariableWidthIntegerTypesUsed.ql | 4 + .../variablewidthintegertypesused/test.cpp | 89 +++++++++++++++++++ rule_packages/cpp/Declarations.json | 3 +- 10 files changed, 149 insertions(+), 105 deletions(-) delete mode 100644 cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.qlref create mode 100644 cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.testref create mode 100644 cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll rename cpp/{autosar/test/rules/A3-9-1 => common/test/rules/variablewidthintegertypesused}/VariableWidthIntegerTypesUsed.expected (100%) create mode 100644 cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql create mode 100644 cpp/common/test/rules/variablewidthintegertypesused/test.cpp diff --git a/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql b/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql index fa19ad998f..dfc73cebc8 100644 --- a/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql +++ b/cpp/autosar/src/rules/A3-9-1/VariableWidthIntegerTypesUsed.ql @@ -17,26 +17,10 @@ import cpp import codingstandards.cpp.autosar -import codingstandards.cpp.EncapsulatingFunctions -import codingstandards.cpp.BuiltInNumericTypes -import codingstandards.cpp.Type -import codingstandards.cpp.Operator +import codingstandards.cpp.rules.variablewidthintegertypesused.VariableWidthIntegerTypesUsed -from Variable v, Type typeStrippedOfSpecifiers -where - not isExcluded(v, DeclarationsPackage::variableWidthIntegerTypesUsedQuery()) and - typeStrippedOfSpecifiers = stripSpecifiers(v.getType()) and - ( - typeStrippedOfSpecifiers instanceof BuiltInIntegerType or - typeStrippedOfSpecifiers instanceof UnsignedCharType or - typeStrippedOfSpecifiers instanceof SignedCharType - ) and - not v instanceof ExcludedVariable and - // Dont consider template instantiations because instantiations with - // Fixed Width Types are recorded after stripping their typedef'd type, - // thereby, causing false positives (#540). - not v.isFromTemplateInstantiation(_) and - //post-increment/post-decrement operators are required by the standard to have a dummy int parameter - not v.(Parameter).getFunction() instanceof PostIncrementOperator and - not v.(Parameter).getFunction() instanceof PostDecrementOperator -select v, "Variable '" + v.getName() + "' has variable-width type." +class VariableWidthIntegerTypesUsedQuery extends VariableWidthIntegerTypesUsedSharedQuery { + VariableWidthIntegerTypesUsedQuery() { + this = DeclarationsPackage::variableWidthIntegerTypesUsedQuery() + } +} diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.qlref b/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.qlref deleted file mode 100644 index 797bbacc94..0000000000 --- a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/A3-9-1/VariableWidthIntegerTypesUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.testref b/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.testref new file mode 100644 index 0000000000..bb41437be6 --- /dev/null +++ b/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.testref @@ -0,0 +1 @@ +cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql \ No newline at end of file diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected b/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected index 6631606cbf..8602920f1e 100644 --- a/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected +++ b/cpp/autosar/test/rules/A3-9-1/VariableWidthPlainCharTypeUsed.expected @@ -1,3 +1,3 @@ | test.cpp:4:8:4:8 | c | Variable 'c' has variable-width char type. | -| test.cpp:38:14:38:15 | c1 | Variable 'c1' has variable-width char type. | -| test.cpp:56:17:56:18 | c2 | Variable 'c2' has variable-width char type. | +| test.cpp:10:14:10:15 | c1 | Variable 'c1' has variable-width char type. | +| test.cpp:14:17:14:18 | c2 | Variable 'c2' has variable-width char type. | diff --git a/cpp/autosar/test/rules/A3-9-1/test.cpp b/cpp/autosar/test/rules/A3-9-1/test.cpp index 7ffb87ca39..96ef45142f 100644 --- a/cpp/autosar/test/rules/A3-9-1/test.cpp +++ b/cpp/autosar/test/rules/A3-9-1/test.cpp @@ -2,88 +2,16 @@ void test_variable_width_type_variables() { char c; // NON_COMPLIANT - unsigned char uc; // NON_COMPLIANT - signed char sc; // NON_COMPLIANT - - int i; // NON_COMPLIANT - unsigned int ui; // NON_COMPLIANT - unsigned u; // NON_COMPLIANT - signed int si; // NON_COMPLIANT - signed s; // NON_COMPLIANT - - short sh; // NON_COMPLIANT - unsigned short ush; // NON_COMPLIANT - signed short ssh; // NON_COMPLIANT - - long l; // NON_COMPLIANT - unsigned long ul; // NON_COMPLIANT - signed long sl; // NON_COMPLIANT - - std::int8_t i8; // COMPLIANT - std::int16_t i16; // COMPLIANT - std::int32_t i32; // COMPLIANT - std::int64_t i64; // COMPLIANT - - std::uint8_t u8; // COMPLIANT - std::uint16_t u16; // COMPLIANT - std::uint32_t u32; // COMPLIANT - std::uint64_t u64; // COMPLIANT -} - -int main(int argc, char *argv[]) { // COMPLIANT - // main as an exception + unsigned char uc; // COMPLIANT - covered by VariableWidthIntegerTypesUsed + signed char sc; // COMPLIANT - covered by VariableWidthIntegerTypesUsed } void test_variable_width_type_qualified_variables() { const char c1 = 0; // NON_COMPLIANT - const unsigned char uc1 = 0; // NON_COMPLIANT - const signed char sc1 = 0; // NON_COMPLIANt - - const int i1 = 0; // NON_COMPLIANT - const unsigned int ui1 = 0; // NON_COMPLIANT - const unsigned u1 = 0; // NON_COMPLIANT - const signed int si1 = 0; // NON_COMPLIANT - const signed s1 = 0; // NON_COMPLIANT - - const short sh1 = 0; // NON_COMPLIANT - const unsigned short ush1 = 0; // NON_COMPLIANT - const signed short ssh1 = 0; // NON_COMPLIANT - - const long l1 = 0; // NON_COMPLIANT - const unsigned long ul1 = 0; // NON_COMPLIANT - const signed long sl1 = 0; // NON_COMPLIANT + const unsigned char uc1 = 0; // COMPLIANT - (VariableWidthIntegerTypesUsed) + const signed char sc1 = 0; // COMPLIANT - (VariableWidthIntegerTypesUsed) volatile char c2; // NON_COMPLIANT - volatile unsigned char uc2; // NON_COMPLIANT - volatile signed char sc2; // NON_COMPLIANt - - volatile int i2; // NON_COMPLIANT - volatile unsigned int ui2; // NON_COMPLIANT - volatile unsigned u2; // NON_COMPLIANT - volatile signed int si2; // NON_COMPLIANT - volatile signed s2; // NON_COMPLIANT - - volatile short sh2; // NON_COMPLIANT - volatile unsigned short ush2; // NON_COMPLIANT - volatile signed short ssh2; // NON_COMPLIANT - - volatile long l2; // NON_COMPLIANT - volatile unsigned long ul2; // NON_COMPLIANT - volatile signed long sl2; // NON_COMPLIANT -} - -struct test_fix_fp_614 { - test_fix_fp_614 operator++(int); // COMPLIANT - test_fix_fp_614 operator--(int); // COMPLIANT -}; - -// COMPLIANT - instantiated with Fixed Width Types. -template constexpr void test_fix_fp_540(MyType value) { - value++; -} - -int call_test_fix_fp_540() { - test_fix_fp_540(19); - test_fix_fp_540(20); - return 0; -} + volatile unsigned char uc2; // COMPLIANT - (VariableWidthIntegerTypesUsed) + volatile signed char sc2; // COMPLIANT - (VariableWidthIntegerTypesUsed) +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll b/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll new file mode 100644 index 0000000000..ce9aaf5feb --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll @@ -0,0 +1,38 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * The basic numerical types of signed/unsigned char, int, short, long are not supposed + * to be used. The specific-length types from header need be used instead. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.EncapsulatingFunctions +import codingstandards.cpp.BuiltInNumericTypes +import codingstandards.cpp.Type +import codingstandards.cpp.Operator + +abstract class VariableWidthIntegerTypesUsedSharedQuery extends Query { } + +Query getQuery() { result instanceof VariableWidthIntegerTypesUsedSharedQuery } + +query predicate problems(Variable v, string message) { + not isExcluded(v, getQuery()) and + exists(Type typeStrippedOfSpecifiers | + typeStrippedOfSpecifiers = stripSpecifiers(v.getType()) and + ( + typeStrippedOfSpecifiers instanceof BuiltInIntegerType or + typeStrippedOfSpecifiers instanceof UnsignedCharType or + typeStrippedOfSpecifiers instanceof SignedCharType + ) and + not v instanceof ExcludedVariable and + // Dont consider template instantiations because instantiations with + // Fixed Width Types are recorded after stripping their typedef'd type, + // thereby, causing false positives (#540). + not v.isFromTemplateInstantiation(_) and + //post-increment/post-decrement operators are required by the standard to have a dummy int parameter + not v.(Parameter).getFunction() instanceof PostIncrementOperator and + not v.(Parameter).getFunction() instanceof PostDecrementOperator + ) and + message = "Variable '" + v.getName() + "' has variable-width type." +} \ No newline at end of file diff --git a/cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.expected b/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.expected similarity index 100% rename from cpp/autosar/test/rules/A3-9-1/VariableWidthIntegerTypesUsed.expected rename to cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.expected diff --git a/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql b/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql new file mode 100644 index 0000000000..1c86ca86d7 --- /dev/null +++ b/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.variablewidthintegertypesused.VariableWidthIntegerTypesUsed + +class TestFileQuery extends VariableWidthIntegerTypesUsedSharedQuery, TestQuery { } diff --git a/cpp/common/test/rules/variablewidthintegertypesused/test.cpp b/cpp/common/test/rules/variablewidthintegertypesused/test.cpp new file mode 100644 index 0000000000..b5b390cd92 --- /dev/null +++ b/cpp/common/test/rules/variablewidthintegertypesused/test.cpp @@ -0,0 +1,89 @@ +#include + +void test_variable_width_type_variables() { + char c; // COMPLIANT + unsigned char uc; // NON_COMPLIANT + signed char sc; // NON_COMPLIANT + + int i; // NON_COMPLIANT + unsigned int ui; // NON_COMPLIANT + unsigned u; // NON_COMPLIANT + signed int si; // NON_COMPLIANT + signed s; // NON_COMPLIANT + + short sh; // NON_COMPLIANT + unsigned short ush; // NON_COMPLIANT + signed short ssh; // NON_COMPLIANT + + long l; // NON_COMPLIANT + unsigned long ul; // NON_COMPLIANT + signed long sl; // NON_COMPLIANT + + std::int8_t i8; // COMPLIANT + std::int16_t i16; // COMPLIANT + std::int32_t i32; // COMPLIANT + std::int64_t i64; // COMPLIANT + + std::uint8_t u8; // COMPLIANT + std::uint16_t u16; // COMPLIANT + std::uint32_t u32; // COMPLIANT + std::uint64_t u64; // COMPLIANT +} + +int main(int argc, char *argv[]) { // COMPLIANT + // main as an exception +} + +void test_variable_width_type_qualified_variables() { + const char c1 = 0; // COMPLIANT + const unsigned char uc1 = 0; // NON_COMPLIANT + const signed char sc1 = 0; // NON_COMPLIANt + + const int i1 = 0; // NON_COMPLIANT + const unsigned int ui1 = 0; // NON_COMPLIANT + const unsigned u1 = 0; // NON_COMPLIANT + const signed int si1 = 0; // NON_COMPLIANT + const signed s1 = 0; // NON_COMPLIANT + + const short sh1 = 0; // NON_COMPLIANT + const unsigned short ush1 = 0; // NON_COMPLIANT + const signed short ssh1 = 0; // NON_COMPLIANT + + const long l1 = 0; // NON_COMPLIANT + const unsigned long ul1 = 0; // NON_COMPLIANT + const signed long sl1 = 0; // NON_COMPLIANT + + volatile char c2; // COMPLIANT + volatile unsigned char uc2; // NON_COMPLIANT + volatile signed char sc2; // NON_COMPLIANt + + volatile int i2; // NON_COMPLIANT + volatile unsigned int ui2; // NON_COMPLIANT + volatile unsigned u2; // NON_COMPLIANT + volatile signed int si2; // NON_COMPLIANT + volatile signed s2; // NON_COMPLIANT + + volatile short sh2; // NON_COMPLIANT + volatile unsigned short ush2; // NON_COMPLIANT + volatile signed short ssh2; // NON_COMPLIANT + + volatile long l2; // NON_COMPLIANT + volatile unsigned long ul2; // NON_COMPLIANT + volatile signed long sl2; // NON_COMPLIANT +} + +struct test_fix_fp_614 { + test_fix_fp_614 operator++(int); // COMPLIANT + test_fix_fp_614 operator--(int); // COMPLIANT +}; + +// COMPLIANT - instantiated with Fixed Width Types. +template constexpr void test_fix_fp_540(MyType value) { + value++; +} + +int call_test_fix_fp_540() { + test_fix_fp_540(19); + test_fix_fp_540(20); + return 0; +} diff --git a/rule_packages/cpp/Declarations.json b/rule_packages/cpp/Declarations.json index a5b8ebeec3..2f9651e198 100644 --- a/rule_packages/cpp/Declarations.json +++ b/rule_packages/cpp/Declarations.json @@ -93,7 +93,8 @@ ], "implementation_scope": { "description": "This implementation excludes the plain char type from consideration." - } + }, + "shared_implementation_short_name": "VariableWidthIntegerTypesUsed" }, { "description": "The basic numerical type char is not supposed to be used. The specific-length types from header need be used instead.", From 5b37d13bede9c1eeabb963edf3541d7255f5acc2 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 10 Jun 2025 10:10:11 +0100 Subject: [PATCH 423/628] Rule 6.9.2: AvoidStandardIntegerTypeNames.ql Adds a new query for detecting the use of the standard integer types. --- .../cpp/exclusions/cpp/BannedAPIs.qll | 19 ++++++++++++++- .../AvoidStandardIntegerTypeNames.ql | 23 +++++++++++++++++++ .../AvoidStandardIntegerTypeNames.testref | 1 + rule_packages/cpp/BannedAPIs.json | 21 +++++++++++++++++ rules.csv | 2 +- 5 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql create mode 100644 cpp/misra/test/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.testref diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll index 571a48a625..ea4f78841b 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/BannedAPIs.qll @@ -12,7 +12,8 @@ newtype BannedAPIsQuery = TUseSmartPtrFactoryFunctionsQuery() or TCharacterHandlingFunctionRestrictionsQuery() or TNoMemoryFunctionsFromCStringQuery() or - TLocaleGlobalFunctionNotAllowedQuery() + TLocaleGlobalFunctionNotAllowedQuery() or + TAvoidStandardIntegerTypeNamesQuery() predicate isBannedAPIsQueryMetadata(Query query, string queryId, string ruleId, string category) { query = @@ -95,6 +96,15 @@ predicate isBannedAPIsQueryMetadata(Query query, string queryId, string ruleId, "cpp/misra/locale-global-function-not-allowed" and ruleId = "RULE-25-5-1" and category = "required" + or + query = + // `Query` instance for the `avoidStandardIntegerTypeNames` query + BannedAPIsPackage::avoidStandardIntegerTypeNamesQuery() and + queryId = + // `@id` for the `avoidStandardIntegerTypeNames` query + "cpp/misra/avoid-standard-integer-type-names" and + ruleId = "RULE-6-9-2" and + category = "advisory" } module BannedAPIsPackage { @@ -160,4 +170,11 @@ module BannedAPIsPackage { // `Query` type for `localeGlobalFunctionNotAllowed` query TQueryCPP(TBannedAPIsPackageQuery(TLocaleGlobalFunctionNotAllowedQuery())) } + + Query avoidStandardIntegerTypeNamesQuery() { + //autogenerate `Query` type + result = + // `Query` type for `avoidStandardIntegerTypeNames` query + TQueryCPP(TBannedAPIsPackageQuery(TAvoidStandardIntegerTypeNamesQuery())) + } } diff --git a/cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql b/cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql new file mode 100644 index 0000000000..ef02deb899 --- /dev/null +++ b/cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/avoid-standard-integer-type-names + * @name RULE-6-9-2: The names of the standard signed integer types and standard unsigned integer types should not be + * @description Using standard signed and unsigned integer type names instead of specified width + * types makes storage requirements unclear and implementation-dependent. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-6-9-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.variablewidthintegertypesused.VariableWidthIntegerTypesUsed + +class AvoidStandardIntegerTypeNamesQuery extends VariableWidthIntegerTypesUsedSharedQuery { + AvoidStandardIntegerTypeNamesQuery() { + this = BannedAPIsPackage::avoidStandardIntegerTypeNamesQuery() + } +} diff --git a/cpp/misra/test/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.testref b/cpp/misra/test/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.testref new file mode 100644 index 0000000000..bb41437be6 --- /dev/null +++ b/cpp/misra/test/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.testref @@ -0,0 +1 @@ +cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.ql \ No newline at end of file diff --git a/rule_packages/cpp/BannedAPIs.json b/rule_packages/cpp/BannedAPIs.json index 591f50b5e6..313b513315 100644 --- a/rule_packages/cpp/BannedAPIs.json +++ b/rule_packages/cpp/BannedAPIs.json @@ -179,6 +179,27 @@ } ], "title": "The setlocale and std::locale::global functions shall not be called" + }, + "RULE-6-9-2": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Using standard signed and unsigned integer type names instead of specified width types makes storage requirements unclear and implementation-dependent.", + "kind": "problem", + "name": "The names of the standard signed integer types and standard unsigned integer types should not be", + "precision": "very-high", + "severity": "error", + "short_name": "AvoidStandardIntegerTypeNames", + "shared_implementation_short_name": "VariableWidthIntegerTypesUsed", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The names of the standard signed integer types and standard unsigned integer types should not be used" } } } \ No newline at end of file diff --git a/rules.csv b/rules.csv index 0af18d1f20..68049625e6 100644 --- a/rules.csv +++ b/rules.csv @@ -869,7 +869,7 @@ cpp,MISRA-C++-2023,RULE-6-8-2,Yes,Mandatory,Decidable,Single Translation Unit,A cpp,MISRA-C++-2023,RULE-6-8-3,Yes,Required,Decidable,Single Translation Unit,An assignment operator shall not assign the address of an object with automatic storage duration to an object with a greater lifetime,,Lifetime,Medium, cpp,MISRA-C++-2023,RULE-6-8-4,Yes,Advisory,Decidable,Single Translation Unit,Member functions returning references to their object should be refqualified appropriately,,Declarations2,Medium, cpp,MISRA-C++-2023,RULE-6-9-1,Yes,Required,Decidable,Single Translation Unit,The same type aliases shall be used in all declarations of the same entity,,Declarations2,Medium, -cpp,MISRA-C++-2023,RULE-6-9-2,Yes,Advisory,Decidable,Single Translation Unit,The names of the standard signed integer types and standard unsigned integer types should not be used,A3-9-1,FixedWithInt,Easy, +cpp,MISRA-C++-2023,RULE-6-9-2,Yes,Advisory,Decidable,Single Translation Unit,The names of the standard signed integer types and standard unsigned integer types should not be used,A3-9-1,BannedAPIs,Easy, cpp,MISRA-C++-2023,RULE-7-0-1,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion from type bool,,Conversions,Easy, cpp,MISRA-C++-2023,RULE-7-0-2,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion to type bool,,Conversions,Easy, cpp,MISRA-C++-2023,RULE-7-0-3,Yes,Required,Decidable,Single Translation Unit,The numerical value of a character shall not be used,M5-0-11,Conversions,Medium, From f43336a0296afa52509ef69bea32cceb38064789 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 10 Jun 2025 10:44:36 +0100 Subject: [PATCH 424/628] VariableWidthIntegerTypesUsed - support function return types Expand support for A3-9-1 and MISRA C++ 2023 6.9.2 to include the use of integers in function return types. --- change_notes/2025-06-10-a3-9-1-functions.md | 2 + .../cpp/BuiltInNumericTypes.qll | 7 ++ .../VariableWidthIntegerTypesUsed.qll | 46 +++++++----- .../variablewidthintegertypesused/test.cpp | 70 ++++++++++++++++++- rule_packages/cpp/Declarations.json | 2 +- 5 files changed, 108 insertions(+), 19 deletions(-) create mode 100644 change_notes/2025-06-10-a3-9-1-functions.md diff --git a/change_notes/2025-06-10-a3-9-1-functions.md b/change_notes/2025-06-10-a3-9-1-functions.md new file mode 100644 index 0000000000..8366d2172f --- /dev/null +++ b/change_notes/2025-06-10-a3-9-1-functions.md @@ -0,0 +1,2 @@ + - `A3-9-1` - `VariableWidthIntegerTypesUsed.ql`: + - This query now reports the use of non-fixed width integer types in function return types, with the exception of `char` types and for `main` functions. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/BuiltInNumericTypes.qll b/cpp/common/src/codingstandards/cpp/BuiltInNumericTypes.qll index b145428a57..b156930810 100644 --- a/cpp/common/src/codingstandards/cpp/BuiltInNumericTypes.qll +++ b/cpp/common/src/codingstandards/cpp/BuiltInNumericTypes.qll @@ -20,3 +20,10 @@ class BuiltInIntegerType extends BuiltInType { class ExcludedVariable extends Parameter { ExcludedVariable() { getFunction() instanceof MainFunction } } + +/** + * Any main function. + */ +class ExcludedFunction extends Function { + ExcludedFunction() { this instanceof MainFunction } +} diff --git a/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll b/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll index ce9aaf5feb..047d501a22 100644 --- a/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll +++ b/cpp/common/src/codingstandards/cpp/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.qll @@ -16,23 +16,37 @@ abstract class VariableWidthIntegerTypesUsedSharedQuery extends Query { } Query getQuery() { result instanceof VariableWidthIntegerTypesUsedSharedQuery } -query predicate problems(Variable v, string message) { - not isExcluded(v, getQuery()) and - exists(Type typeStrippedOfSpecifiers | - typeStrippedOfSpecifiers = stripSpecifiers(v.getType()) and +query predicate problems(Element e, string message) { + not isExcluded(e, getQuery()) and + exists(Type typeStrippedOfSpecifiers, Type rawType | + typeStrippedOfSpecifiers = stripSpecifiers(rawType) and ( typeStrippedOfSpecifiers instanceof BuiltInIntegerType or typeStrippedOfSpecifiers instanceof UnsignedCharType or typeStrippedOfSpecifiers instanceof SignedCharType - ) and - not v instanceof ExcludedVariable and - // Dont consider template instantiations because instantiations with - // Fixed Width Types are recorded after stripping their typedef'd type, - // thereby, causing false positives (#540). - not v.isFromTemplateInstantiation(_) and - //post-increment/post-decrement operators are required by the standard to have a dummy int parameter - not v.(Parameter).getFunction() instanceof PostIncrementOperator and - not v.(Parameter).getFunction() instanceof PostDecrementOperator - ) and - message = "Variable '" + v.getName() + "' has variable-width type." -} \ No newline at end of file + ) + | + exists(Variable v | v = e | + v.getType() = rawType and + not v instanceof ExcludedVariable and + // Dont consider template instantiations because instantiations with + // Fixed Width Types are recorded after stripping their typedef'd type, + // thereby, causing false positives (#540). + not v.isFromTemplateInstantiation(_) and + //post-increment/post-decrement operators are required by the standard to have a dummy int parameter + not v.(Parameter).getFunction() instanceof PostIncrementOperator and + not v.(Parameter).getFunction() instanceof PostDecrementOperator and + message = "Variable '" + v.getName() + "' has variable-width type." + ) + or + exists(Function f | f = e | + f.getType() = rawType and + not f instanceof ExcludedFunction and + // Dont consider template instantiations because instantiations with + // Fixed Width Types are recorded after stripping their typedef'd type, + // thereby, causing false positives (#540). + not f.isFromTemplateInstantiation(_) and + message = "Function '" + f.getName() + "' has variable-width return type." + ) + ) +} diff --git a/cpp/common/test/rules/variablewidthintegertypesused/test.cpp b/cpp/common/test/rules/variablewidthintegertypesused/test.cpp index b5b390cd92..bee63342e2 100644 --- a/cpp/common/test/rules/variablewidthintegertypesused/test.cpp +++ b/cpp/common/test/rules/variablewidthintegertypesused/test.cpp @@ -82,8 +82,74 @@ template constexpr void test_fix_fp_540(MyType value) { value++; } -int call_test_fix_fp_540() { +void call_test_fix_fp_540() { test_fix_fp_540(19); test_fix_fp_540(20); - return 0; +} + +char test_char_return() { // COMPLIANT + return 'a'; +} +unsigned char test_unsigned_char_return() { // NON_COMPLIANT + return 'b'; +} +signed char test_signed_char_return() { // NON_COMPLIANT + return 'c'; +} +int test_int_return() { // NON_COMPLIANT + return 42; +} +unsigned int test_unsigned_int_return() { // NON_COMPLIANT + return 43; +} +unsigned test_unsigned_return() { // NON_COMPLIANT + return 44; +} +signed int test_signed_int_return() { // NON_COMPLIANT + return 45; +} +signed test_signed_return() { // NON_COMPLIANT + return 46; +} +short test_short_return() { // NON_COMPLIANT + return 47; +} +unsigned short test_unsigned_short_return() { // NON_COMPLIANT + return 48; +} +signed short test_signed_short_return() { // NON_COMPLIANT + return 49; +} +long test_long_return() { // NON_COMPLIANT + return 50; +} +unsigned long test_unsigned_long_return() { // NON_COMPLIANT + return 51; +} +signed long test_signed_long_return() { // NON_COMPLIANT + return 52; +} +std::int8_t test_int8_t_return() { // COMPLIANT + return 53; +} +std::int16_t test_int16_t_return() { // COMPLIANT + return 54; +} +std::int32_t test_int32_t_return() { // COMPLIANT + return 55; +} +std::int64_t test_int64_t_return() { // COMPLIANT + return 56; +} +std::uint8_t test_uint8_t_return() { // COMPLIANT + return 57; +} +std::uint16_t test_uint16_t_return() { // COMPLIANT + return 58; +} +std::uint32_t test_uint32_t_return() { // COMPLIANT + return 59; +} +std::uint64_t test_uint64_t_return() { // COMPLIANT + return 60; } diff --git a/rule_packages/cpp/Declarations.json b/rule_packages/cpp/Declarations.json index 2f9651e198..61d286026a 100644 --- a/rule_packages/cpp/Declarations.json +++ b/rule_packages/cpp/Declarations.json @@ -92,7 +92,7 @@ "maintainability" ], "implementation_scope": { - "description": "This implementation excludes the plain char type from consideration." + "description": "This implementation excludes the plain char type. It also excludes the use of standard integer types in the definition of main functions, and the use of an integer parameter in the declaration of postfix operators." }, "shared_implementation_short_name": "VariableWidthIntegerTypesUsed" }, From 1d2aa2e2d13524a9c1f4533eefacc46c1d853d2a Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 10 Jun 2025 12:34:13 +0100 Subject: [PATCH 425/628] RULE-7-0-1 - NoConversionFromBool Detects implicit and explicit conversions from type bool to other types, preventing potential confusion between bitwise and logical operators and ensuring clear type usage. [a] --- .../rules/RULE-7-0-1/NoConversionFromBool.ql | 47 +++++++++ .../RULE-7-0-1/NoConversionFromBool.expected | 29 ++++++ .../RULE-7-0-1/NoConversionFromBool.qlref | 1 + cpp/misra/test/rules/RULE-7-0-1/test.cpp | 97 +++++++++++++++++++ 4 files changed, 174 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql create mode 100644 cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected create mode 100644 cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.qlref create mode 100644 cpp/misra/test/rules/RULE-7-0-1/test.cpp diff --git a/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql b/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql new file mode 100644 index 0000000000..0c2cab56f4 --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql @@ -0,0 +1,47 @@ +/** + * @id cpp/misra/no-conversion-from-bool + * @name RULE-7-0-1: There shall be no conversion from type bool + * @description Converting a bool type (implicitly or explicitly) to another type can lead to + * unintended behavior and code obfuscation, particularly when using bitwise operators + * instead of logical operators. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-0-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +from Expr e, Conversion conv +where + not isExcluded(e, ConversionsPackage::noConversionFromBoolQuery()) and + conv = e.getConversion() and + conv.getExpr().getType().stripTopLevelSpecifiers() instanceof BoolType and + not conv.getType().stripTopLevelSpecifiers() instanceof BoolType and + // Exclude cases that are explicitly allowed + not ( + // Exception: equality operators with both bool operands + exists(EQExpr eq | + eq.getAnOperand() = e and + eq.getLeftOperand().getType().stripTopLevelSpecifiers() instanceof BoolType and + eq.getRightOperand().getType().stripTopLevelSpecifiers() instanceof BoolType + ) or + exists(NEExpr ne | + ne.getAnOperand() = e and + ne.getLeftOperand().getType().stripTopLevelSpecifiers() instanceof BoolType and + ne.getRightOperand().getType().stripTopLevelSpecifiers() instanceof BoolType + ) or + // Exception: explicit constructor calls + exists(ConstructorCall cc | cc.getAnArgument() = e) or + // Exception: assignment to bit-field of length 1 + exists(AssignExpr assign | + assign.getRValue() = e and + assign.getLValue().(ValueFieldAccess).getTarget() instanceof BitField and + assign.getLValue().(ValueFieldAccess).getTarget().(BitField).getNumBits() = 1 + ) + ) +select e, "Conversion from 'bool' to '" + conv.getType().toString() + "'." \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected b/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected new file mode 100644 index 0000000000..badfe7f049 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected @@ -0,0 +1,29 @@ +| test.cpp:23:9:23:10 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:23:14:23:15 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:24:9:24:10 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:24:14:24:15 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:25:9:25:10 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:25:14:25:15 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:26:10:26:11 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:29:9:29:10 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:29:14:29:15 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:30:9:30:10 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:30:14:30:15 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:31:9:31:10 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:31:15:31:16 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:32:9:32:10 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:32:15:32:16 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:35:9:35:10 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:36:9:36:10 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:37:9:37:10 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:40:22:40:23 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:41:22:41:23 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:42:30:42:31 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:45:36:45:37 | b1 | Conversion from 'bool' to 'int8_t'. | +| test.cpp:46:38:46:39 | b1 | Conversion from 'bool' to 'int32_t'. | +| test.cpp:49:8:49:9 | b1 | Conversion from 'bool' to 'int32_t'. | +| test.cpp:50:8:50:9 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:53:13:53:14 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:59:11:59:12 | b1 | Conversion from 'bool' to 'int8_t'. | +| test.cpp:60:12:60:13 | b1 | Conversion from 'bool' to 'int32_t'. | +| test.cpp:61:10:61:11 | b1 | Conversion from 'bool' to 'double'. | diff --git a/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.qlref b/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.qlref new file mode 100644 index 0000000000..6d66f51484 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.qlref @@ -0,0 +1 @@ +rules/RULE-7-0-1/NoConversionFromBool.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-1/test.cpp b/cpp/misra/test/rules/RULE-7-0-1/test.cpp new file mode 100644 index 0000000000..15a366a281 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-1/test.cpp @@ -0,0 +1,97 @@ +#include + +struct A { + explicit A(bool) {} +}; + +struct BitField { + std::uint8_t bit : 1; +}; + +void f1(std::int32_t n) {} +void f2(double d) {} + +void test_bool_conversion_violations() { + bool b1 = true; + bool b2 = false; + double d1 = 1.0; + std::int8_t s8a = 0; + std::int32_t s32a = 0; + BitField bf; + + // Bitwise operations - non-compliant + if (b1 & b2) {} // NON_COMPLIANT + if (b1 | b2) {} // NON_COMPLIANT + if (b1 ^ b2) {} // NON_COMPLIANT + if (~b1) {} // NON_COMPLIANT + + // Relational operations - non-compliant + if (b1 < b2) {} // NON_COMPLIANT + if (b1 > b2) {} // NON_COMPLIANT + if (b1 <= b2) {} // NON_COMPLIANT + if (b1 >= b2) {} // NON_COMPLIANT + + // Comparison with integer literals - non-compliant + if (b1 == 0) {} // NON_COMPLIANT + if (b1 == 1) {} // NON_COMPLIANT + if (b1 != 0) {} // NON_COMPLIANT + + // Arithmetic operations - non-compliant + double l1 = d1 * b1; // NON_COMPLIANT + double l2 = d1 + b1; // NON_COMPLIANT + std::int32_t l3 = s32a + b1; // NON_COMPLIANT + + // Explicit casts to integral types - non-compliant + s8a = static_cast(b1); // NON_COMPLIANT + s32a = static_cast(b1); // NON_COMPLIANT + + // Function parameter conversion - non-compliant + f1(b1); // NON_COMPLIANT + f2(b1); // NON_COMPLIANT + + // Switch statement - non-compliant + switch (b1) { // NON_COMPLIANT + case 0: break; + case 1: break; + } + + // Assignment to integral types - non-compliant + s8a = b1; // NON_COMPLIANT + s32a = b1; // NON_COMPLIANT + d1 = b1; // NON_COMPLIANT +} + +void test_bool_conversion_compliant() { + bool b1 = true; + bool b2 = false; + std::int8_t s8a = 0; + BitField bf; + + // Boolean equality operations - compliant + if (b1 == false) {} // COMPLIANT + if (b1 == true) {} // COMPLIANT + if (b1 == b2) {} // COMPLIANT + if (b1 != b2) {} // COMPLIANT + + // Logical operations - compliant + if (b1 && b2) {} // COMPLIANT + if (b1 || b2) {} // COMPLIANT + if (!b1) {} // COMPLIANT + + // Conditional operator without conversion - compliant + s8a = b1 ? 3 : 7; // COMPLIANT + + // Function parameter without conversion - compliant + f1(b1 ? 1 : 0); // COMPLIANT + + // Explicit constructor calls - compliant + A l1{true}; // COMPLIANT + A l2(false); // COMPLIANT + A l3 = static_cast(true); // COMPLIANT + + // Assignment to constructor - compliant + A l4 = A{false}; // COMPLIANT + + // Bit-field assignment exception - compliant + bf.bit = b1; // COMPLIANT +} \ No newline at end of file From 5b810c33d8a53e9272bc210e2fd1887fc7df78fc Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 10 Jun 2025 12:41:38 +0100 Subject: [PATCH 426/628] Rule 7.0.1: Address review issues - Simplify query implementation - Format test code --- .../cpp/exclusions/cpp/RuleMetadata.qll | 3 + .../rules/RULE-7-0-1/NoConversionFromBool.ql | 16 +- .../RULE-7-0-1/NoConversionFromBool.expected | 58 +++--- cpp/misra/test/rules/RULE-7-0-1/test.cpp | 182 ++++++++++-------- 4 files changed, 139 insertions(+), 120 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index abd6aeff96..88e4d55358 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -12,6 +12,7 @@ import Comments import Concurrency import Conditionals import Const +import Conversions import DeadCode import Declarations import ExceptionSafety @@ -67,6 +68,7 @@ newtype TCPPQuery = TConcurrencyPackageQuery(ConcurrencyQuery q) or TConditionalsPackageQuery(ConditionalsQuery q) or TConstPackageQuery(ConstQuery q) or + TConversionsPackageQuery(ConversionsQuery q) or TDeadCodePackageQuery(DeadCodeQuery q) or TDeclarationsPackageQuery(DeclarationsQuery q) or TExceptionSafetyPackageQuery(ExceptionSafetyQuery q) or @@ -122,6 +124,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isConcurrencyQueryMetadata(query, queryId, ruleId, category) or isConditionalsQueryMetadata(query, queryId, ruleId, category) or isConstQueryMetadata(query, queryId, ruleId, category) or + isConversionsQueryMetadata(query, queryId, ruleId, category) or isDeadCodeQueryMetadata(query, queryId, ruleId, category) or isDeclarationsQueryMetadata(query, queryId, ruleId, category) or isExceptionSafetyQueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql b/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql index 0c2cab56f4..600d454863 100644 --- a/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql +++ b/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql @@ -25,23 +25,19 @@ where // Exclude cases that are explicitly allowed not ( // Exception: equality operators with both bool operands - exists(EQExpr eq | + exists(EqualityOperation eq | eq.getAnOperand() = e and eq.getLeftOperand().getType().stripTopLevelSpecifiers() instanceof BoolType and eq.getRightOperand().getType().stripTopLevelSpecifiers() instanceof BoolType - ) or - exists(NEExpr ne | - ne.getAnOperand() = e and - ne.getLeftOperand().getType().stripTopLevelSpecifiers() instanceof BoolType and - ne.getRightOperand().getType().stripTopLevelSpecifiers() instanceof BoolType - ) or + ) + or // Exception: explicit constructor calls - exists(ConstructorCall cc | cc.getAnArgument() = e) or + exists(ConstructorCall cc | cc.getAnArgument() = e) + or // Exception: assignment to bit-field of length 1 exists(AssignExpr assign | assign.getRValue() = e and - assign.getLValue().(ValueFieldAccess).getTarget() instanceof BitField and assign.getLValue().(ValueFieldAccess).getTarget().(BitField).getNumBits() = 1 ) ) -select e, "Conversion from 'bool' to '" + conv.getType().toString() + "'." \ No newline at end of file +select e, "Conversion from 'bool' to '" + conv.getType().toString() + "'." diff --git a/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected b/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected index badfe7f049..8e0795fc6a 100644 --- a/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected +++ b/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected @@ -1,29 +1,29 @@ -| test.cpp:23:9:23:10 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:23:14:23:15 | b2 | Conversion from 'bool' to 'int'. | -| test.cpp:24:9:24:10 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:24:14:24:15 | b2 | Conversion from 'bool' to 'int'. | -| test.cpp:25:9:25:10 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:25:14:25:15 | b2 | Conversion from 'bool' to 'int'. | -| test.cpp:26:10:26:11 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:29:9:29:10 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:29:14:29:15 | b2 | Conversion from 'bool' to 'int'. | -| test.cpp:30:9:30:10 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:30:14:30:15 | b2 | Conversion from 'bool' to 'int'. | -| test.cpp:31:9:31:10 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:31:15:31:16 | b2 | Conversion from 'bool' to 'int'. | -| test.cpp:32:9:32:10 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:32:15:32:16 | b2 | Conversion from 'bool' to 'int'. | -| test.cpp:35:9:35:10 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:36:9:36:10 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:37:9:37:10 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:40:22:40:23 | b1 | Conversion from 'bool' to 'double'. | -| test.cpp:41:22:41:23 | b1 | Conversion from 'bool' to 'double'. | -| test.cpp:42:30:42:31 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:45:36:45:37 | b1 | Conversion from 'bool' to 'int8_t'. | -| test.cpp:46:38:46:39 | b1 | Conversion from 'bool' to 'int32_t'. | -| test.cpp:49:8:49:9 | b1 | Conversion from 'bool' to 'int32_t'. | -| test.cpp:50:8:50:9 | b1 | Conversion from 'bool' to 'double'. | -| test.cpp:53:13:53:14 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:59:11:59:12 | b1 | Conversion from 'bool' to 'int8_t'. | -| test.cpp:60:12:60:13 | b1 | Conversion from 'bool' to 'int32_t'. | -| test.cpp:61:10:61:11 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:23:7:23:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:23:12:23:13 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:25:7:25:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:25:12:25:13 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:27:7:27:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:27:12:27:13 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:29:8:29:9 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:33:7:33:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:33:12:33:13 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:35:7:35:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:35:12:35:13 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:37:7:37:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:37:13:37:14 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:39:7:39:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:39:13:39:14 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:43:7:43:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:45:7:45:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:47:7:47:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:51:20:51:21 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:52:20:52:21 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:53:28:53:29 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:56:34:56:35 | b1 | Conversion from 'bool' to 'int8_t'. | +| test.cpp:57:36:57:37 | b1 | Conversion from 'bool' to 'int32_t'. | +| test.cpp:60:6:60:7 | b1 | Conversion from 'bool' to 'int32_t'. | +| test.cpp:61:6:61:7 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:64:11:64:12 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:72:9:72:10 | b1 | Conversion from 'bool' to 'int8_t'. | +| test.cpp:73:10:73:11 | b1 | Conversion from 'bool' to 'int32_t'. | +| test.cpp:74:8:74:9 | b1 | Conversion from 'bool' to 'double'. | diff --git a/cpp/misra/test/rules/RULE-7-0-1/test.cpp b/cpp/misra/test/rules/RULE-7-0-1/test.cpp index 15a366a281..57243e1c9a 100644 --- a/cpp/misra/test/rules/RULE-7-0-1/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-1/test.cpp @@ -1,97 +1,117 @@ #include struct A { - explicit A(bool) {} + explicit A(bool) {} }; struct BitField { - std::uint8_t bit : 1; + std::uint8_t bit : 1; }; void f1(std::int32_t n) {} void f2(double d) {} void test_bool_conversion_violations() { - bool b1 = true; - bool b2 = false; - double d1 = 1.0; - std::int8_t s8a = 0; - std::int32_t s32a = 0; - BitField bf; - - // Bitwise operations - non-compliant - if (b1 & b2) {} // NON_COMPLIANT - if (b1 | b2) {} // NON_COMPLIANT - if (b1 ^ b2) {} // NON_COMPLIANT - if (~b1) {} // NON_COMPLIANT - - // Relational operations - non-compliant - if (b1 < b2) {} // NON_COMPLIANT - if (b1 > b2) {} // NON_COMPLIANT - if (b1 <= b2) {} // NON_COMPLIANT - if (b1 >= b2) {} // NON_COMPLIANT - - // Comparison with integer literals - non-compliant - if (b1 == 0) {} // NON_COMPLIANT - if (b1 == 1) {} // NON_COMPLIANT - if (b1 != 0) {} // NON_COMPLIANT - - // Arithmetic operations - non-compliant - double l1 = d1 * b1; // NON_COMPLIANT - double l2 = d1 + b1; // NON_COMPLIANT - std::int32_t l3 = s32a + b1; // NON_COMPLIANT - - // Explicit casts to integral types - non-compliant - s8a = static_cast(b1); // NON_COMPLIANT - s32a = static_cast(b1); // NON_COMPLIANT - - // Function parameter conversion - non-compliant - f1(b1); // NON_COMPLIANT - f2(b1); // NON_COMPLIANT - - // Switch statement - non-compliant - switch (b1) { // NON_COMPLIANT - case 0: break; - case 1: break; - } - - // Assignment to integral types - non-compliant - s8a = b1; // NON_COMPLIANT - s32a = b1; // NON_COMPLIANT - d1 = b1; // NON_COMPLIANT + bool b1 = true; + bool b2 = false; + double d1 = 1.0; + std::int8_t s8a = 0; + std::int32_t s32a = 0; + BitField bf; + + // Bitwise operations - non-compliant + if (b1 & b2) { // NON_COMPLIANT + } + if (b1 | b2) { // NON_COMPLIANT + } + if (b1 ^ b2) { // NON_COMPLIANT + } + if (~b1) { // NON_COMPLIANT + } + + // Relational operations - non-compliant + if (b1 < b2) { // NON_COMPLIANT + } + if (b1 > b2) { // NON_COMPLIANT + } + if (b1 <= b2) { // NON_COMPLIANT + } + if (b1 >= b2) { // NON_COMPLIANT + } + + // Comparison with integer literals - non-compliant + if (b1 == 0) { // NON_COMPLIANT + } + if (b1 == 1) { // NON_COMPLIANT + } + if (b1 != 0) { // NON_COMPLIANT + } + + // Arithmetic operations - non-compliant + double l1 = d1 * b1; // NON_COMPLIANT + double l2 = d1 + b1; // NON_COMPLIANT + std::int32_t l3 = s32a + b1; // NON_COMPLIANT + + // Explicit casts to integral types - non-compliant + s8a = static_cast(b1); // NON_COMPLIANT + s32a = static_cast(b1); // NON_COMPLIANT + + // Function parameter conversion - non-compliant + f1(b1); // NON_COMPLIANT + f2(b1); // NON_COMPLIANT + + // Switch statement - non-compliant + switch (b1) { // NON_COMPLIANT + case 0: + break; + case 1: + break; + } + + // Assignment to integral types - non-compliant + s8a = b1; // NON_COMPLIANT + s32a = b1; // NON_COMPLIANT + d1 = b1; // NON_COMPLIANT } void test_bool_conversion_compliant() { - bool b1 = true; - bool b2 = false; - std::int8_t s8a = 0; - BitField bf; - - // Boolean equality operations - compliant - if (b1 == false) {} // COMPLIANT - if (b1 == true) {} // COMPLIANT - if (b1 == b2) {} // COMPLIANT - if (b1 != b2) {} // COMPLIANT - - // Logical operations - compliant - if (b1 && b2) {} // COMPLIANT - if (b1 || b2) {} // COMPLIANT - if (!b1) {} // COMPLIANT - - // Conditional operator without conversion - compliant - s8a = b1 ? 3 : 7; // COMPLIANT - - // Function parameter without conversion - compliant - f1(b1 ? 1 : 0); // COMPLIANT - - // Explicit constructor calls - compliant - A l1{true}; // COMPLIANT - A l2(false); // COMPLIANT - A l3 = static_cast(true); // COMPLIANT - - // Assignment to constructor - compliant - A l4 = A{false}; // COMPLIANT - - // Bit-field assignment exception - compliant - bf.bit = b1; // COMPLIANT + bool b1 = true; + bool b2 = false; + std::int8_t s8a = 0; + BitField bf; + + // Boolean equality operations - compliant + if (b1 == false) { // COMPLIANT + } + if (b1 == true) { // COMPLIANT + } + if (b1 == b2) { // COMPLIANT + } + if (b1 != b2) { // COMPLIANT + } + + // Logical operations - compliant + if (b1 && b2) { // COMPLIANT + } + if (b1 || b2) { // COMPLIANT + } + if (!b1) { // COMPLIANT + } + + // Conditional operator without conversion - compliant + s8a = b1 ? 3 : 7; // COMPLIANT + + // Function parameter without conversion - compliant + f1(b1 ? 1 : 0); // COMPLIANT + + // Explicit constructor calls - compliant + A l1{true}; // COMPLIANT + A l2(false); // COMPLIANT + A l3 = static_cast(true); // COMPLIANT + + // Assignment to constructor - compliant + A l4 = A{false}; // COMPLIANT + + // Bit-field assignment exception - compliant + bf.bit = b1; // COMPLIANT } \ No newline at end of file From 62d5dccade18b5175b2fb8162147a7c92be69256 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 11 Jun 2025 10:35:07 +0100 Subject: [PATCH 427/628] RULE-7-0-2 - NoImplicitBoolConversion Detects implicit conversions to bool type from fundamental types, unscoped enumerations, and pointers that may lead to unintended behavior in conditional expressions. --- .../RULE-7-0-2/NoImplicitBoolConversion.ql | 92 +++++++++++ .../NoImplicitBoolConversion.expected | 15 ++ .../RULE-7-0-2/NoImplicitBoolConversion.qlref | 1 + cpp/misra/test/rules/RULE-7-0-2/test.cpp | 145 ++++++++++++++++++ 4 files changed, 253 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql create mode 100644 cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected create mode 100644 cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.qlref create mode 100644 cpp/misra/test/rules/RULE-7-0-2/test.cpp diff --git a/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql b/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql new file mode 100644 index 0000000000..3ee3693a3a --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql @@ -0,0 +1,92 @@ +/** + * @id cpp/misra/no-implicit-bool-conversion + * @name RULE-7-0-2: There shall be no conversion to type bool + * @description Implicit and contextual conversions to bool from fundamental types, unscoped enums, + * or pointers may lead to unintended behavior, except for specific cases like pointer + * checks and explicit operator bool conversions. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-0-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +predicate isInContextualBoolContext(Expr expr) { + exists(IfStmt ifStmt | ifStmt.getCondition() = expr) or + exists(WhileStmt whileStmt | whileStmt.getCondition() = expr) or + exists(ForStmt forStmt | forStmt.getCondition() = expr) or + exists(DoStmt doStmt | doStmt.getCondition() = expr) or + exists(ConditionalExpr condExpr | condExpr.getCondition() = expr) or + exists(LogicalAndExpr logicalAnd | logicalAnd.getAnOperand() = expr) or + exists(LogicalOrExpr logicalOr | logicalOr.getAnOperand() = expr) or + exists(NotExpr notExpr | notExpr.getOperand() = expr) +} + +predicate isInWhileConditionDeclaration(Expr expr) { + exists(WhileStmt whileStmt, ConditionDeclExpr condDecl | + whileStmt.getCondition() = condDecl and + condDecl.getExpr() = expr + ) +} + +predicate isBitFieldOfSizeOne(Expr expr) { + exists(BitField bf | + expr = bf.getAnAccess() and + bf.getNumBits() = 1 + ) +} + +from Element e, string reason +where + not isExcluded(e, ConversionsPackage::noImplicitBoolConversionQuery()) and + ( + // Conversions to bool + exists(Conversion conv | + e = conv and + conv.getType().getUnspecifiedType() instanceof BoolType and + not conv.getExpr().getType().getUnspecifiedType() instanceof BoolType and + // Exception 2: Contextual conversion from pointer + not ( + conv.getExpr().getType().getUnspecifiedType() instanceof PointerType and + isInContextualBoolContext(conv.getExpr()) + ) and + // Exception 3: Bit-field of size 1 + not isBitFieldOfSizeOne(conv.getExpr()) and + // Exception 4: While condition declaration + not isInWhileConditionDeclaration(conv.getExpr()) and + reason = "Conversion from '" + conv.getExpr().getType().toString() + "' to 'bool'" + ) + or + // Calls to conversion operators to bool + // + // Note: we flag these separately because: + // 1. If the conversion via the operator is implicit, there is no `Conversion` - only a call to + // the `ConversionOperator`. + // 2. If the conversion is explicit, the `Conversion` is from `bool` to `bool`, which is not + // flagged in the previous `Conversion` case above. + exists(Call conversionCall, ConversionOperator op | + e = conversionCall and + conversionCall.getTarget() = op and + op.getType().getUnspecifiedType() instanceof BoolType and + // Exception 1: Static cast to bool from class with explicit operator bool + not exists(StaticCast conv | + op.isExplicit() and + conv.getExpr() = conversionCall and + conv.getType().getUnspecifiedType() instanceof BoolType + ) and + // Exception 2: Contextual conversion from class with explicit operator bool is allowed + not ( + op.isExplicit() and + isInContextualBoolContext(conversionCall) + ) and + reason = + "Conversion operator call from '" + conversionCall.getQualifier().getType().toString() + + "' to 'bool'" + ) + ) +select e, reason + "." diff --git a/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected new file mode 100644 index 0000000000..e3ce3929c2 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected @@ -0,0 +1,15 @@ +| test.cpp:46:20:46:28 | (bool)... | Conversion from 'int' to 'bool'. | +| test.cpp:50:7:50:7 | (bool)... | Conversion from 'int' to 'bool'. | +| test.cpp:52:7:52:8 | (bool)... | Conversion from 'uint8_t' to 'bool'. | +| test.cpp:54:8:54:8 | (bool)... | Conversion from 'int' to 'bool'. | +| test.cpp:58:7:58:8 | (bool)... | Conversion from 'uint8_t' to 'bool'. | +| test.cpp:69:8:69:9 | (bool)... | Conversion from 'int16_t' to 'bool'. | +| test.cpp:78:20:78:21 | (bool)... | Conversion from 'int32_t' to 'bool'. | +| test.cpp:84:31:84:32 | (bool)... | Conversion from 'int32_t' to 'bool'. | +| test.cpp:92:30:92:31 | (bool)... | Conversion from 'int32_t' to 'bool'. | +| test.cpp:103:13:103:16 | (bool)... | Conversion from 'int32_t *' to 'bool'. | +| test.cpp:108:13:108:32 | static_cast... | Conversion from 'int' to 'bool'. | +| test.cpp:109:13:109:14 | (bool)... | Conversion from 'uint8_t' to 'bool'. | +| test.cpp:121:13:121:13 | call to operator bool | Conversion operator call from 'TestClassImplicit' to 'bool'. | +| test.cpp:134:13:134:14 | (bool)... | Conversion from 'Color' to 'bool'. | +| test.cpp:135:7:135:8 | (bool)... | Conversion from 'Color' to 'bool'. | diff --git a/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.qlref b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.qlref new file mode 100644 index 0000000000..a7b86d71f8 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.qlref @@ -0,0 +1 @@ +rules/RULE-7-0-2/NoImplicitBoolConversion.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-2/test.cpp b/cpp/misra/test/rules/RULE-7-0-2/test.cpp new file mode 100644 index 0000000000..baeb772d27 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-2/test.cpp @@ -0,0 +1,145 @@ +#include +#include + +// Global variables for testing +std::uint8_t g1 = 5; +std::uint8_t g2 = 10; +std::uint8_t g3 = 15; +std::uint8_t g4 = 20; +std::int16_t g5 = 100; +std::int32_t g6 = 200; +bool g7 = true; + +// Function declarations +std::int32_t f1(); +bool f2(); +std::int32_t *f3(); + +// Class with explicit operator bool +class TestClassExplicit { + std::int32_t m1; + +public: + explicit operator bool() const { return m1 < 0; } +}; + +class TestClassImplicit { + std::int32_t m1; + +public: + operator bool() const { return m1 < 0; } // Implicit conversion +}; + +// Bit-field struct for exception #3 +struct BitFieldStruct { + unsigned int m1 : 1; +}; + +void test_logical_operators() { + std::uint8_t l1 = 5; + std::uint8_t l2 = 10; + std::uint8_t l3 = 15; + std::uint8_t l4 = 20; + + if ((l1 < l2) && (l3 < l4)) { // COMPLIANT + } + if ((l1 < l2) && (l3 + l4)) { // NON_COMPLIANT + } + if (true && (l3 < l4)) { // COMPLIANT + } + if (1 && (l3 < l4)) { // NON_COMPLIANT + } + if (l1 && (l3 < l4)) { // NON_COMPLIANT + } + if (!0) { // NON_COMPLIANT + } + if (!false) { // COMPLIANT + } + if (l1) { // NON_COMPLIANT + } +} + +void test_conditional_operator() { + std::int32_t l1 = 100; + std::int32_t l2 = 200; + std::int32_t l3 = 300; + std::int16_t l4 = 50; + bool l5 = true; + + l1 = l4 ? l2 : l3; // NON_COMPLIANT + l1 = l5 ? l2 : l3; // COMPLIANT + l1 = (l4 < 5) ? l2 : l3; // COMPLIANT +} + +void test_if_statements() { + std::int32_t l1; + bool l2 = f2(); + + if (std::int32_t l3 = f1()) { // NON_COMPLIANT + } + if (std::int32_t l4 = f1(); l4 != 0) { // COMPLIANT + } + if (bool l5 = f2()) { // COMPLIANT + } + if (std::int32_t l6 = f1(); l6) { // NON_COMPLIANT + } +} + +void test_while_loops() { + while (std::int32_t l1 = f1()) { // COMPLIANT - exception #4 + } + + for (std::int32_t l2 = 10; l2; --l2) { // NON_COMPLIANT + } + + while (std::cin) { // COMPLIANT - exception #2 + } +} + +void test_pointer_conversions() { + if (f3()) { // COMPLIANT - exception #2 + } + + bool l1 = f3(); // NON_COMPLIANT + bool l2 = f3() != nullptr; // COMPLIANT +} + +void test_assignment_to_bool() { + bool l1 = static_cast(4); // NON_COMPLIANT + bool l2 = g1; // NON_COMPLIANT + bool l3 = (g1 < g2); // COMPLIANT + bool l4 = g7; // COMPLIANT +} + +void test_class_with_explicit_bool_operator() { + TestClassExplicit l1; + + bool l2 = static_cast(l1); // COMPLIANT - exception #1 + if (l1) { // COMPLIANT - exception #2 + } + TestClassImplicit l3; + bool l4 = l3; // NON_COMPLIANT +} + +void test_bitfield_conversion() { + BitFieldStruct l1; + + bool l2 = l1.m1; // COMPLIANT - exception #3 +} + +void test_unscoped_enum_conversion() { + enum Color { RED, GREEN, BLUE }; + Color l1 = RED; + + bool l2 = l1; // NON_COMPLIANT + if (l1) { // NON_COMPLIANT + } + bool l3 = (l1 == RED); // COMPLIANT +} + +void test_scoped_enum_conversion() { + enum class Status { ACTIVE, INACTIVE }; + Status l1 = Status::ACTIVE; + + bool l2 = (l1 == Status::ACTIVE); // COMPLIANT +} \ No newline at end of file From f92a2c97af609b7d3bf7cf03bfd57f235fcdc2d6 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 11 Jun 2025 15:04:51 +0100 Subject: [PATCH 428/628] Rule 7.0.2: Extend test case, support member function pointers --- .../RULE-7-0-2/NoImplicitBoolConversion.ql | 8 ++- .../NoImplicitBoolConversion.expected | 43 +++++++---- cpp/misra/test/rules/RULE-7-0-2/test.cpp | 71 ++++++++++++++++++- 3 files changed, 105 insertions(+), 17 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql b/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql index 3ee3693a3a..308f879f1d 100644 --- a/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql +++ b/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql @@ -41,6 +41,12 @@ predicate isBitFieldOfSizeOne(Expr expr) { ) } +predicate isPointerType(Type t) { + t.getUnspecifiedType() instanceof PointerType or + t.getUnspecifiedType() instanceof ArrayType or + t.getUnspecifiedType() instanceof PointerToMemberType +} + from Element e, string reason where not isExcluded(e, ConversionsPackage::noImplicitBoolConversionQuery()) and @@ -52,7 +58,7 @@ where not conv.getExpr().getType().getUnspecifiedType() instanceof BoolType and // Exception 2: Contextual conversion from pointer not ( - conv.getExpr().getType().getUnspecifiedType() instanceof PointerType and + isPointerType(conv.getExpr().getType()) and isInContextualBoolContext(conv.getExpr()) ) and // Exception 3: Bit-field of size 1 diff --git a/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected index e3ce3929c2..c000a23dd2 100644 --- a/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected +++ b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected @@ -1,15 +1,28 @@ -| test.cpp:46:20:46:28 | (bool)... | Conversion from 'int' to 'bool'. | -| test.cpp:50:7:50:7 | (bool)... | Conversion from 'int' to 'bool'. | -| test.cpp:52:7:52:8 | (bool)... | Conversion from 'uint8_t' to 'bool'. | -| test.cpp:54:8:54:8 | (bool)... | Conversion from 'int' to 'bool'. | -| test.cpp:58:7:58:8 | (bool)... | Conversion from 'uint8_t' to 'bool'. | -| test.cpp:69:8:69:9 | (bool)... | Conversion from 'int16_t' to 'bool'. | -| test.cpp:78:20:78:21 | (bool)... | Conversion from 'int32_t' to 'bool'. | -| test.cpp:84:31:84:32 | (bool)... | Conversion from 'int32_t' to 'bool'. | -| test.cpp:92:30:92:31 | (bool)... | Conversion from 'int32_t' to 'bool'. | -| test.cpp:103:13:103:16 | (bool)... | Conversion from 'int32_t *' to 'bool'. | -| test.cpp:108:13:108:32 | static_cast... | Conversion from 'int' to 'bool'. | -| test.cpp:109:13:109:14 | (bool)... | Conversion from 'uint8_t' to 'bool'. | -| test.cpp:121:13:121:13 | call to operator bool | Conversion operator call from 'TestClassImplicit' to 'bool'. | -| test.cpp:134:13:134:14 | (bool)... | Conversion from 'Color' to 'bool'. | -| test.cpp:135:7:135:8 | (bool)... | Conversion from 'Color' to 'bool'. | +| test.cpp:53:20:53:28 | (bool)... | Conversion from 'int' to 'bool'. | +| test.cpp:57:7:57:7 | (bool)... | Conversion from 'int' to 'bool'. | +| test.cpp:59:7:59:8 | (bool)... | Conversion from 'uint8_t' to 'bool'. | +| test.cpp:61:8:61:8 | (bool)... | Conversion from 'int' to 'bool'. | +| test.cpp:65:7:65:8 | (bool)... | Conversion from 'uint8_t' to 'bool'. | +| test.cpp:76:8:76:9 | (bool)... | Conversion from 'int16_t' to 'bool'. | +| test.cpp:85:20:85:21 | (bool)... | Conversion from 'int32_t' to 'bool'. | +| test.cpp:91:31:91:32 | (bool)... | Conversion from 'int32_t' to 'bool'. | +| test.cpp:99:30:99:31 | (bool)... | Conversion from 'int32_t' to 'bool'. | +| test.cpp:112:12:112:13 | (bool)... | Conversion from 'int32_t' to 'bool'. | +| test.cpp:127:13:127:16 | (bool)... | Conversion from 'int32_t *' to 'bool'. | +| test.cpp:130:7:130:13 | (bool)... | Conversion from 'decltype(nullptr)' to 'bool'. | +| test.cpp:135:13:135:32 | static_cast... | Conversion from 'int' to 'bool'. | +| test.cpp:136:13:136:14 | (bool)... | Conversion from 'uint8_t' to 'bool'. | +| test.cpp:148:13:148:13 | call to operator bool | Conversion operator call from 'TestClassImplicit' to 'bool'. | +| test.cpp:161:13:161:14 | (bool)... | Conversion from 'Color' to 'bool'. | +| test.cpp:162:7:162:8 | (bool)... | Conversion from 'Color' to 'bool'. | +| test.cpp:179:13:179:14 | (bool)... | Conversion from 'float' to 'bool'. | +| test.cpp:180:13:180:14 | (bool)... | Conversion from 'double' to 'bool'. | +| test.cpp:181:13:181:14 | (bool)... | Conversion from 'long double' to 'bool'. | +| test.cpp:182:7:182:8 | (bool)... | Conversion from 'float' to 'bool'. | +| test.cpp:184:7:184:8 | (bool)... | Conversion from 'double' to 'bool'. | +| test.cpp:186:7:186:8 | (bool)... | Conversion from 'long double' to 'bool'. | +| test.cpp:195:7:195:8 | (bool)... | Conversion from 'int32_t *' to 'bool'. | +| test.cpp:197:7:197:8 | (bool)... | Conversion from 'int32_t *' to 'bool'. | +| test.cpp:199:13:199:14 | (bool)... | Conversion from 'int32_t *' to 'bool'. | +| test.cpp:211:13:211:14 | (bool)... | Conversion from '..:: *' to 'bool'. | +| test.cpp:212:13:212:14 | (bool)... | Conversion from '..:: *' to 'bool'. | diff --git a/cpp/misra/test/rules/RULE-7-0-2/test.cpp b/cpp/misra/test/rules/RULE-7-0-2/test.cpp index baeb772d27..568980dea3 100644 --- a/cpp/misra/test/rules/RULE-7-0-2/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-2/test.cpp @@ -9,6 +9,7 @@ std::uint8_t g4 = 20; std::int16_t g5 = 100; std::int32_t g6 = 200; bool g7 = true; +std::int32_t g8[5] = {1, 2, 3, 4, 5}; // Function declarations std::int32_t f1(); @@ -30,6 +31,12 @@ class TestClassImplicit { operator bool() const { return m1 < 0; } // Implicit conversion }; +// Class with member function pointer +class TestClassMemberFunc { +public: + void memberFunc() {} +}; + // Bit-field struct for exception #3 struct BitFieldStruct { unsigned int m1 : 1; @@ -96,12 +103,32 @@ void test_while_loops() { } } +void test_do_while_loops() { + std::int32_t l1 = 5; + bool l2 = true; + + do { + --l1; + } while (l1); // NON_COMPLIANT + + do { + --l1; + } while (l2); // COMPLIANT + + do { + --l1; + } while (l1 > 0); // COMPLIANT +} + void test_pointer_conversions() { if (f3()) { // COMPLIANT - exception #2 } bool l1 = f3(); // NON_COMPLIANT bool l2 = f3() != nullptr; // COMPLIANT + + if (nullptr) { // NON_COMPLIANT + } } void test_assignment_to_bool() { @@ -111,7 +138,7 @@ void test_assignment_to_bool() { bool l4 = g7; // COMPLIANT } -void test_class_with_explicit_bool_operator() { +void test_classes_with_bool_operators() { TestClassExplicit l1; bool l2 = static_cast(l1); // COMPLIANT - exception #1 @@ -142,4 +169,46 @@ void test_scoped_enum_conversion() { Status l1 = Status::ACTIVE; bool l2 = (l1 == Status::ACTIVE); // COMPLIANT +} + +void test_floating_point_conversion() { + float l1 = 3.14f; + double l2 = 2.71; + long double l3 = 1.41L; + + bool l4 = l1; // NON_COMPLIANT + bool l5 = l2; // NON_COMPLIANT + bool l6 = l3; // NON_COMPLIANT + if (l1) { // NON_COMPLIANT + } + if (l2) { // NON_COMPLIANT + } + if (l3) { // NON_COMPLIANT + } + bool l7 = (l1 > 0.0f); // COMPLIANT + bool l8 = (l2 != 0.0); // COMPLIANT +} + +void test_array_conversion() { + std::int32_t l1[5] = {1, 2, 3, 4, 5}; + + if (l1) { // NON_COMPLIANT + } + if (g8) { // NON_COMPLIANT + } + bool l2 = l1; // NON_COMPLIANT + bool l3 = (l1 != nullptr); // COMPLIANT +} + +void test_member_function_pointer_conversion() { + void (TestClassMemberFunc::*l1)() = &TestClassMemberFunc::memberFunc; + void (TestClassMemberFunc::*l2)() = nullptr; + + if (l1) { // COMPLIANT - exception #2 + } + if (l2) { // COMPLIANT - exception #2 + } + bool l3 = l1; // NON_COMPLIANT + bool l4 = l2; // NON_COMPLIANT + bool l5 = (l1 != nullptr); // COMPLIANT } \ No newline at end of file From b62394a0ab9e7fd991df71072b00df777ea08f9b Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 12 Jun 2025 16:18:37 +0100 Subject: [PATCH 429/628] Add Conversions exclusions file --- .../cpp/exclusions/cpp/Conversions.qll | 214 ++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions.qll diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions.qll new file mode 100644 index 0000000000..f151565d11 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions.qll @@ -0,0 +1,214 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype ConversionsQuery = + TNoConversionFromBoolQuery() or + TNoImplicitBoolConversionQuery() or + TNoCharacterNumericalValueQuery() or + TNoSignednessChangeFromPromotionQuery() or + TNumericAssignmentTypeMismatchQuery() or + TFunctionPointerConversionContextQuery() or + TVirtualBaseClassCastToDerivedQuery() or + TNoCStyleOrFunctionalCastsQuery() or + TIntToPointerCastProhibitedQuery() or + TNoPointerToIntegralCastQuery() or + TPointerToIntegralCastQuery() or + TNoStandaloneTypeCastExpressionQuery() + +predicate isConversionsQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `noConversionFromBool` query + ConversionsPackage::noConversionFromBoolQuery() and + queryId = + // `@id` for the `noConversionFromBool` query + "cpp/misra/no-conversion-from-bool" and + ruleId = "RULE-7-0-1" and + category = "required" + or + query = + // `Query` instance for the `noImplicitBoolConversion` query + ConversionsPackage::noImplicitBoolConversionQuery() and + queryId = + // `@id` for the `noImplicitBoolConversion` query + "cpp/misra/no-implicit-bool-conversion" and + ruleId = "RULE-7-0-2" and + category = "required" + or + query = + // `Query` instance for the `noCharacterNumericalValue` query + ConversionsPackage::noCharacterNumericalValueQuery() and + queryId = + // `@id` for the `noCharacterNumericalValue` query + "cpp/misra/no-character-numerical-value" and + ruleId = "RULE-7-0-3" and + category = "required" + or + query = + // `Query` instance for the `noSignednessChangeFromPromotion` query + ConversionsPackage::noSignednessChangeFromPromotionQuery() and + queryId = + // `@id` for the `noSignednessChangeFromPromotion` query + "cpp/misra/no-signedness-change-from-promotion" and + ruleId = "RULE-7-0-5" and + category = "required" + or + query = + // `Query` instance for the `numericAssignmentTypeMismatch` query + ConversionsPackage::numericAssignmentTypeMismatchQuery() and + queryId = + // `@id` for the `numericAssignmentTypeMismatch` query + "cpp/misra/numeric-assignment-type-mismatch" and + ruleId = "RULE-7-0-6" and + category = "required" + or + query = + // `Query` instance for the `functionPointerConversionContext` query + ConversionsPackage::functionPointerConversionContextQuery() and + queryId = + // `@id` for the `functionPointerConversionContext` query + "cpp/misra/function-pointer-conversion-context" and + ruleId = "RULE-7-11-3" and + category = "required" + or + query = + // `Query` instance for the `virtualBaseClassCastToDerived` query + ConversionsPackage::virtualBaseClassCastToDerivedQuery() and + queryId = + // `@id` for the `virtualBaseClassCastToDerived` query + "cpp/misra/virtual-base-class-cast-to-derived" and + ruleId = "RULE-8-2-1" and + category = "required" + or + query = + // `Query` instance for the `noCStyleOrFunctionalCasts` query + ConversionsPackage::noCStyleOrFunctionalCastsQuery() and + queryId = + // `@id` for the `noCStyleOrFunctionalCasts` query + "cpp/misra/no-c-style-or-functional-casts" and + ruleId = "RULE-8-2-2" and + category = "required" + or + query = + // `Query` instance for the `intToPointerCastProhibited` query + ConversionsPackage::intToPointerCastProhibitedQuery() and + queryId = + // `@id` for the `intToPointerCastProhibited` query + "cpp/misra/int-to-pointer-cast-prohibited" and + ruleId = "RULE-8-2-6" and + category = "required" + or + query = + // `Query` instance for the `noPointerToIntegralCast` query + ConversionsPackage::noPointerToIntegralCastQuery() and + queryId = + // `@id` for the `noPointerToIntegralCast` query + "cpp/misra/no-pointer-to-integral-cast" and + ruleId = "RULE-8-2-7" and + category = "advisory" + or + query = + // `Query` instance for the `pointerToIntegralCast` query + ConversionsPackage::pointerToIntegralCastQuery() and + queryId = + // `@id` for the `pointerToIntegralCast` query + "cpp/misra/pointer-to-integral-cast" and + ruleId = "RULE-8-2-8" and + category = "required" + or + query = + // `Query` instance for the `noStandaloneTypeCastExpression` query + ConversionsPackage::noStandaloneTypeCastExpressionQuery() and + queryId = + // `@id` for the `noStandaloneTypeCastExpression` query + "cpp/misra/no-standalone-type-cast-expression" and + ruleId = "RULE-9-2-1" and + category = "required" +} + +module ConversionsPackage { + Query noConversionFromBoolQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noConversionFromBool` query + TQueryCPP(TConversionsPackageQuery(TNoConversionFromBoolQuery())) + } + + Query noImplicitBoolConversionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noImplicitBoolConversion` query + TQueryCPP(TConversionsPackageQuery(TNoImplicitBoolConversionQuery())) + } + + Query noCharacterNumericalValueQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noCharacterNumericalValue` query + TQueryCPP(TConversionsPackageQuery(TNoCharacterNumericalValueQuery())) + } + + Query noSignednessChangeFromPromotionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noSignednessChangeFromPromotion` query + TQueryCPP(TConversionsPackageQuery(TNoSignednessChangeFromPromotionQuery())) + } + + Query numericAssignmentTypeMismatchQuery() { + //autogenerate `Query` type + result = + // `Query` type for `numericAssignmentTypeMismatch` query + TQueryCPP(TConversionsPackageQuery(TNumericAssignmentTypeMismatchQuery())) + } + + Query functionPointerConversionContextQuery() { + //autogenerate `Query` type + result = + // `Query` type for `functionPointerConversionContext` query + TQueryCPP(TConversionsPackageQuery(TFunctionPointerConversionContextQuery())) + } + + Query virtualBaseClassCastToDerivedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `virtualBaseClassCastToDerived` query + TQueryCPP(TConversionsPackageQuery(TVirtualBaseClassCastToDerivedQuery())) + } + + Query noCStyleOrFunctionalCastsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noCStyleOrFunctionalCasts` query + TQueryCPP(TConversionsPackageQuery(TNoCStyleOrFunctionalCastsQuery())) + } + + Query intToPointerCastProhibitedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `intToPointerCastProhibited` query + TQueryCPP(TConversionsPackageQuery(TIntToPointerCastProhibitedQuery())) + } + + Query noPointerToIntegralCastQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noPointerToIntegralCast` query + TQueryCPP(TConversionsPackageQuery(TNoPointerToIntegralCastQuery())) + } + + Query pointerToIntegralCastQuery() { + //autogenerate `Query` type + result = + // `Query` type for `pointerToIntegralCast` query + TQueryCPP(TConversionsPackageQuery(TPointerToIntegralCastQuery())) + } + + Query noStandaloneTypeCastExpressionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noStandaloneTypeCastExpression` query + TQueryCPP(TConversionsPackageQuery(TNoStandaloneTypeCastExpressionQuery())) + } +} From 6a5aa1f09699c6f1259adf4cc7c2b57bc087e007 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 13 Jun 2025 08:30:34 -0700 Subject: [PATCH 430/628] Fix compilation error --- .../codingstandards/cpp/types/Compatible.qll | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll index 3b77d5caf3..eb0e13101a 100644 --- a/cpp/common/src/codingstandards/cpp/types/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -522,29 +522,3 @@ module FunctionDeclarationTypeEquivalence< .getType(), f2.getParameterDeclarationEntry(pragma[only_bind_into](i)).getType()) } } - -/** - * Convenience class to reduce the awkwardness of how `RoutineType` and `FunctionPointerIshType` - * don't have a common ancestor. - */ -private class FunctionType extends Type { - FunctionType() { this instanceof RoutineType or this instanceof FunctionPointerIshType } - - Type getReturnType() { - result = this.(RoutineType).getReturnType() or - result = this.(FunctionPointerIshType).getReturnType() - } - - Type getParameterType(int i) { - result = this.(RoutineType).getParameterType(i) or - result = this.(FunctionPointerIshType).getParameterType(i) - } -} - -private class LeafType extends Type { - LeafType() { - not this instanceof DerivedType and - not this instanceof FunctionType and - not this instanceof FunctionType - } -} From df1bd3a084718b0b554d613dd9f4a7614a95e4d9 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 15 Jun 2025 21:16:11 -0700 Subject: [PATCH 431/628] Add missing CERT-C query tags --- .../DoNotCompareFunctionPointersToConstantValues.ql | 6 ++++++ rule_packages/c/Expressions2.json | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql index d9622b03b9..fecd5450d0 100644 --- a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql +++ b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql @@ -9,6 +9,12 @@ * @tags external/cert/id/exp16-c * correctness * external/cert/obligation/recommendation + * external/cert/severity/low + * external/cert/likelihood/likely + * external/cert/remediation-cost/ + * external/cert/priority/p6 + * external/cert/level/l2 + * external/cert/obligation/recommendation */ import cpp diff --git a/rule_packages/c/Expressions2.json b/rule_packages/c/Expressions2.json index 7eaa2ff2ec..c9e2434f80 100644 --- a/rule_packages/c/Expressions2.json +++ b/rule_packages/c/Expressions2.json @@ -13,7 +13,13 @@ "severity": "error", "short_name": "DoNotCompareFunctionPointersToConstantValues", "tags": [ - "correctness" + "correctness", + "external/cert/obligation/recommendation", + "external/cert/severity/low", + "external/cert/likelihood/likely", + "external/cert/remediation-cost/", + "external/cert/priority/p6", + "external/cert/level/l2" ] } ], From bb7c913eea8391f110f6289db379fea0d96cbd4d Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 15 Jun 2025 21:36:45 -0700 Subject: [PATCH 432/628] Fix remediation cost --- .../EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql | 2 +- rule_packages/c/Expressions2.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql index fecd5450d0..bd2167c925 100644 --- a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql +++ b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql @@ -11,7 +11,7 @@ * external/cert/obligation/recommendation * external/cert/severity/low * external/cert/likelihood/likely - * external/cert/remediation-cost/ + * external/cert/remediation-cost/medium * external/cert/priority/p6 * external/cert/level/l2 * external/cert/obligation/recommendation diff --git a/rule_packages/c/Expressions2.json b/rule_packages/c/Expressions2.json index c9e2434f80..7c78e02fd9 100644 --- a/rule_packages/c/Expressions2.json +++ b/rule_packages/c/Expressions2.json @@ -17,7 +17,7 @@ "external/cert/obligation/recommendation", "external/cert/severity/low", "external/cert/likelihood/likely", - "external/cert/remediation-cost/", + "external/cert/remediation-cost/medium", "external/cert/priority/p6", "external/cert/level/l2" ] From fbf21bd3ae4b630f39b15e2c86866ac0db0772e2 Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 15 Jun 2025 21:37:32 -0700 Subject: [PATCH 433/628] Undo accidental deletion of LeafType --- cpp/common/src/codingstandards/cpp/types/Compatible.qll | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll index eb0e13101a..83983e1df4 100644 --- a/cpp/common/src/codingstandards/cpp/types/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -522,3 +522,11 @@ module FunctionDeclarationTypeEquivalence< .getType(), f2.getParameterDeclarationEntry(pragma[only_bind_into](i)).getType()) } } + +private class LeafType extends Type { + LeafType() { + not this instanceof DerivedType and + not this instanceof FunctionType and + not this instanceof FunctionType + } +} From e4121eeb044129a2205162b2dc20326b72491ffe Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Sun, 15 Jun 2025 21:41:35 -0700 Subject: [PATCH 434/628] Remove cert c obligation tag --- .../EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql | 1 - rule_packages/c/Expressions2.json | 1 - 2 files changed, 2 deletions(-) diff --git a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql index bd2167c925..bdd4f1b375 100644 --- a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql +++ b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql @@ -8,7 +8,6 @@ * @problem.severity error * @tags external/cert/id/exp16-c * correctness - * external/cert/obligation/recommendation * external/cert/severity/low * external/cert/likelihood/likely * external/cert/remediation-cost/medium diff --git a/rule_packages/c/Expressions2.json b/rule_packages/c/Expressions2.json index 7c78e02fd9..d639ae2c34 100644 --- a/rule_packages/c/Expressions2.json +++ b/rule_packages/c/Expressions2.json @@ -14,7 +14,6 @@ "short_name": "DoNotCompareFunctionPointersToConstantValues", "tags": [ "correctness", - "external/cert/obligation/recommendation", "external/cert/severity/low", "external/cert/likelihood/likely", "external/cert/remediation-cost/medium", From 0fd3a88fa6ed3317d05243fdf6044fda7cb461ab Mon Sep 17 00:00:00 2001 From: knewbury01 Date: Mon, 16 Jun 2025 19:38:57 +0000 Subject: [PATCH 435/628] Bump version to 2.48.0-dev --- c/cert/src/qlpack.yml | 2 +- c/cert/test/qlpack.yml | 2 +- c/common/src/qlpack.yml | 2 +- c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- c/misra/test/qlpack.yml | 2 +- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/qlpack.yml | 2 +- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- docs/user_manual.md | 12 ++++++------ 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 26311dda18..d2ba0816a3 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.47.0-dev +version: 2.48.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index 91c2ea4a52..98268c5636 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.47.0-dev +version: 2.48.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index d088be5639..4bbcb5c730 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.47.0-dev +version: 2.48.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index 4688b3b1a9..ce8d7b3ce7 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.47.0-dev +version: 2.48.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 0607e7456f..02f9dceb48 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.47.0-dev +version: 2.48.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index 823d705e51..a720d41779 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.47.0-dev +version: 2.48.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index 061fcf8df8..65ec603f59 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.47.0-dev +version: 2.48.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index 735f300df4..f7b3f9ef3f 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.47.0-dev +version: 2.48.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 74fe860570..999faded05 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.47.0-dev +version: 2.48.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index 58d0db64f0..b1c634258a 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.47.0-dev +version: 2.48.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index 2454592ce7..f7938fef71 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards -version: 2.47.0-dev +version: 2.48.0-dev license: MIT dependencies: codeql/cpp-all: 2.1.1 diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index 86ad39d46a..84a581eda1 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.47.0-dev +version: 2.48.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 999116b3e0..f6a4e21428 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.47.0-dev +version: 2.48.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index 94cad70436..565c630696 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.47.0-dev +version: 2.48.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index 4814c3e99b..c8a6dd08f8 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.47.0-dev +version: 2.48.0-dev license: MIT dependencies: codeql/cpp-all: 2.1.1 diff --git a/docs/user_manual.md b/docs/user_manual.md index 7482942dc5..fae4623443 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -36,14 +36,14 @@ ## Release information -This user manual documents release `2.47.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.48.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: - `coding-standards-codeql-packs-2.37.0-dev.zip`: CodeQL packs that can be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `code-scanning-cpp-query-pack-2.47.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.47.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.47.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.47.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.48.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.48.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.48.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.48.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -670,7 +670,7 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.47.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.48.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | From a2c991214a954e78ee79c309bf3e4de1066101e5 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 17 Jun 2025 11:20:10 +0100 Subject: [PATCH 436/628] RULE-7-0-6 - NumericAssignmentTypeMismatch Detects inappropriate assignments between numeric types that violate type compatibility requirements, including implicit conversions that may cause information loss or unexpected behavior changes. [a] --- .../NumericAssignmentTypeMismatch.ql | 300 ++++++++++++++++++ .../NumericAssignmentTypeMismatch.expected | 23 ++ .../NumericAssignmentTypeMismatch.qlref | 1 + cpp/misra/test/rules/RULE-7-0-6/test.cpp | 217 +++++++++++++ 4 files changed, 541 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql create mode 100644 cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected create mode 100644 cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.qlref create mode 100644 cpp/misra/test/rules/RULE-7-0-6/test.cpp diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql new file mode 100644 index 0000000000..eff5361d7f --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -0,0 +1,300 @@ +/** + * @id cpp/misra/numeric-assignment-type-mismatch + * @name RULE-7-0-6: Assignment between numeric types shall be appropriate + * @description Assignment between numeric types with different sizes, signedness, or type + * categories can lead to unexpected information loss, undefined behavior, or silent + * overload resolution changes. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-7-0-6 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis + +/** + * The signedness of a numeric type. + */ +newtype Signedness = + Signed() or + Unsigned() + +/** + * The type category of a numeric type - either integral or floating-point. + */ +newtype TypeCategory = + Integral() or + FloatingPoint() + +/** + * A numeric type is a type that represents a number, either an integral or a floating-point. + * + * In addition to the basic integral and floating-point types, it includes: + * - Enum types with an explicit underlying type that is a numeric type. + * - Typedef'd types that are numeric types. + * - Numeric types with specifiers (e.g., `const`, `volatile`, `restrict`). + */ +class NumericType extends Type { + Type realType; + + NumericType() { + realType = this.getUnspecifiedType().(IntegralType) or + realType = this.getUnspecifiedType().(FloatingPointType) or + realType = this.getUnspecifiedType().(Enum).getExplicitUnderlyingType().getUnspecifiedType() + } + + Signedness getSignedness() { + if realType.(IntegralType).isUnsigned() then result = Unsigned() else result = Signed() + } + + TypeCategory getTypeCategory() { + realType instanceof IntegralType and result = Integral() + or + realType instanceof FloatingPointType and result = FloatingPoint() + } + + float getUpperBound() { result = typeUpperBound(realType) } + + float getLowerBound() { result = typeLowerBound(realType) } + + Type getRealType() { result = realType } +} + +predicate isAssignment(Expr source, NumericType targetType, string context) { + // Assignment operator + exists(Assignment assign | + assign.getRValue() = source and + context = "assignment" + | + // TODO generalize to variable init (do we need this for bitfields?) and extract + if isAssignedToBitfield(source, _) + then + exists(BitField bf | + isAssignedToBitfield(source, bf) and + targetType.(IntegralType).(NumericType).getSignedness() = + bf.getType().(NumericType).getSignedness() and + // smallest integral type that can hold the bit field value + targetType.getSize() * 8 >= bf.getNumBits() and + not exists(IntegralType other | + other.getSize() * 8 >= bf.getNumBits() and + other.(NumericType).getSignedness() = targetType.getSignedness() and + other.getSize() < targetType.getSize() + ) + ) + else targetType = assign.getLValue().getType() + ) + or + // Variable initialization + exists(Variable v, Initializer init | + init.getExpr() = source and + v.getInitializer() = init and + targetType = v.getType() and + context = "initialization" + ) + or + exists(Call call, int i | + call.getArgument(i) = source and + not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and + context = "function argument" + | + targetType = call.getTarget().getParameter(i).getType() + or + // Handle varargs - use the fully converted type of the argument + call.getTarget().getNumberOfParameters() <= i and + targetType = source.getFullyConverted().getType() + ) + or + // Return statement + exists(ReturnStmt ret, Function f | + ret.getExpr() = source and + ret.getEnclosingFunction() = f and + targetType = f.getType() and + not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and + context = "return" + ) + or + // Switch case + exists(SwitchCase case, SwitchStmt switch | + case.getExpr() = source and + case.getSwitchStmt() = switch and + targetType = switch.getExpr().getFullyConverted().getType() and + context = "switch case" + ) +} + +predicate isAssignedToBitfield(Expr source, BitField bf) { + exists(Assignment assign | + assign.getRValue() = source and + assign.getLValue() = bf.getAnAccess() + ) +} + +predicate isValidConstantAssignment(Expr source, NumericType targetType) { + isAssignment(source, targetType, _) and + // Source is an integer constant expression + source.isConstant() and + source.getType().(NumericType).getTypeCategory() = Integral() and + exists(float val | val = source.getValue().toFloat() | + // Bit field assignment: check if the value fits in the bit field + exists(BitField bf, int numBits | + isAssignedToBitfield(source, bf) and + numBits = bf.getNumBits() and + val >= 0 and + val < 2.pow(numBits) + ) + or + // Regular assignment: check if the value fits in the target type range + not isAssignedToBitfield(source, _) and + targetType.getLowerBound() <= val and + val <= targetType.getUpperBound() + ) +} + +predicate isValidTypeMatch(NumericType sourceType, NumericType targetType) { + // Same type category, signedness and size + sourceType.getTypeCategory() = targetType.getTypeCategory() and + sourceType.getSignedness() = targetType.getSignedness() and + sourceType.getSize() = targetType.getSize() +} + +predicate hasConstructorException(FunctionCall call) { + exists(Constructor ctor, Class c | + call.getTarget() = ctor and + c = ctor.getDeclaringType() and + // Constructor callable with single numeric argument + ctor.getNumberOfParameters() = 1 and + ctor.getParameter(0).getType() instanceof NumericType and + // No other single-argument constructors except copy/move + not exists(Constructor other | + other.getDeclaringType() = c and + other != ctor and + other.getNumberOfParameters() = 1 and + not other instanceof CopyConstructor and + not other instanceof MoveConstructor + ) + ) +} + +/** + * An id-expression that has a numeric type. + * + * This is restricted to variable accesses, that are not explicitly qualified in any way. + */ +class IdExpression extends VariableAccess { + IdExpression() { + // Not a member variable + ( + not exists(this.getQualifier()) + or + // Member variable, but the qualifier is not explicit + this.getQualifier().isCompilerGenerated() + ) and + // No name qualifiers + not exists(NameQualifier qual | qual.getExpr() = this) + } +} + +predicate isValidWidening(Expr source, NumericType sourceType, NumericType targetType) { + isAssignment(source, targetType, _) and + source.getType() = sourceType and + // Same type category and signedness, source size smaller, source is id-expression or has constructor exception + ( + source instanceof IdExpression or + hasConstructorException(any(Call call | call.getAnArgument() = source)) + ) and + sourceType.getTypeCategory() = targetType.getTypeCategory() and + sourceType.getSignedness() = targetType.getSignedness() and + sourceType.getSize() < targetType.getSize() +} + +/** + * A non-extensible call is a call that cannot be extended by adding new overloads. + */ +predicate isNonExtensible(Call c) { + exists(NameQualifier qual | qual.getExpr() = c and c.getTarget() instanceof MemberFunction) + or + exists(c.getQualifier()) and not c.getQualifier().isCompilerGenerated() + or + c.getTarget() instanceof Operator +} + +predicate isOverloadIndependent(Call call, Expr arg) { + arg = call.getAnArgument() and + ( + // Call through function pointer + call instanceof ExprCall + or + isNonExtensible(call) and + forall(Function target, Function overload, int i | + target = call.getTarget() and + ( + overload = target.getAnOverload() + or + // Instantiated function templates don't directly participate in overload resolution + // so check the templates overloads + overload = target.(FunctionTemplateInstantiation).getTemplate().getAnOverload() + ) and + overload.getNumberOfParameters() = call.getNumberOfArguments() and + call.getArgument(i) = arg + | + // Check that the parameter types match + overload.getParameter(i).getType().getUnspecifiedType() = + target.getParameter(i).getType().getUnspecifiedType() + ) + ) +} + +/** + * Check if the source expression should have the same type as the target type. + */ +predicate shouldHaveSameType(Expr source) { + exists(Call call | + call.getAnArgument() = source and + isAssignment(source, _, _) and + not hasConstructorException(call) + | + not isOverloadIndependent(call, source) + or + // Passed as a varargs parameter + exists(int i | + call.getTarget().isVarargs() and + call.getArgument(i) = source and + // Argument is greater than the number of parameters + call.getTarget().getNumberOfParameters() <= i + ) + ) +} + +predicate isValidAssignment(Expr source, NumericType targetType, string context) { + isAssignment(source, targetType, context) and + exists(NumericType sourceType | sourceType = source.getType() | + if shouldHaveSameType(source) + then sourceType.getRealType() = targetType.getRealType() + else ( + // Valid type match + isValidTypeMatch(sourceType, targetType) + or + // Valid widening assignment + isValidWidening(source, sourceType, targetType) + or + // Valid constant assignment (integer constants) + isValidConstantAssignment(source, targetType) + ) + ) +} + +from Expr source, NumericType sourceType, NumericType targetType, string context +where + not isExcluded(source, ConversionsPackage::numericAssignmentTypeMismatchQuery()) and + isAssignment(source, targetType, context) and + // The assignment must be between numeric types + sourceType = source.getType() and + not isValidAssignment(source, targetType, context) +select source, + "Assignment between incompatible numeric types from '" + sourceType.getName() + "' to '" + + targetType.getName() + "'." diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected new file mode 100644 index 0000000000..fa0bdb487d --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -0,0 +1,23 @@ +| test.cpp:21:8:21:11 | 300 | Assignment between incompatible numeric types from 'unsigned int' to 'uint8_t'. | +| test.cpp:24:9:24:12 | 0.0 | Assignment between incompatible numeric types from 'float' to 'double'. | +| test.cpp:30:8:30:9 | g4 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | +| test.cpp:31:8:31:9 | g3 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | +| test.cpp:36:8:36:9 | g5 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test.cpp:37:8:37:9 | g7 | Assignment between incompatible numeric types from 'uint64_t' to 'uint16_t'. | +| test.cpp:42:8:42:9 | g2 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test.cpp:43:8:43:9 | g9 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test.cpp:55:8:55:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:56:21:56:27 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:67:11:67:13 | 32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned char'. | +| test.cpp:69:11:69:12 | g5 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:81:8:81:9 | l1 | Assignment between incompatible numeric types from 'Colour' to 'uint8_t'. | +| test.cpp:91:6:91:7 | g2 | Assignment between incompatible numeric types from 'int32_t' to 'int64_t'. | +| test.cpp:94:6:94:7 | g8 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:96:6:96:7 | l1 | Assignment between incompatible numeric types from 'int' to 'int32_t'. | +| test.cpp:109:6:109:7 | g4 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | +| test.cpp:118:6:118:6 | 2 | Assignment between incompatible numeric types from 'int' to 'long'. | +| test.cpp:126:14:126:15 | g3 | Assignment between incompatible numeric types from 'uint8_t' to 'int'. | +| test.cpp:138:6:138:7 | g1 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. | +| test.cpp:160:9:160:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | +| test.cpp:189:23:189:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. | +| test.cpp:199:19:199:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.qlref b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.qlref new file mode 100644 index 0000000000..967340a41e --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.qlref @@ -0,0 +1 @@ +rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp new file mode 100644 index 0000000000..ad9aa716fb --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -0,0 +1,217 @@ +#include +#include + +// Global variables for testing +std::uint32_t g1; +std::int32_t g2; +std::uint8_t g3; +std::int8_t g4; +std::uint16_t g5; +std::int16_t g6; +std::uint64_t g7; +std::int64_t g8; +float g9; +double g10; + +// Test basic constant assignments +void test_constant_assignments() { + g1 = 1; // COMPLIANT + g2 = 4u * 2u; // COMPLIANT + g3 = 3u; // COMPLIANT + g3 = 300u; // NON_COMPLIANT + g9 = 1; // COMPLIANT + g9 = 9999999999; // COMPLIANT + g10 = 0.0f; // NON_COMPLIANT + g9 = 0.0f; // COMPLIANT +} + +// Test signedness violations +void test_signedness_violations() { + g3 = g4; // NON_COMPLIANT + g4 = g3; // NON_COMPLIANT +} + +// Test size violations +void test_size_violations() { + g3 = g5; // NON_COMPLIANT + g5 = g7; // NON_COMPLIANT +} + +// Test type category violations +void test_type_category_violations() { + g9 = g2; // NON_COMPLIANT + g2 = g9; // NON_COMPLIANT +} + +// Test widening of id-expressions +void test_widening_id_expressions() { + g1 = g3; // COMPLIANT + g8 = g4; // COMPLIANT + g7 = g5; // COMPLIANT +} + +// Test expression results +void test_expression_results() { + g3 = g3 + g3; // NON_COMPLIANT + std::int16_t l1 = g4 + g4; // NON_COMPLIANT +} + +// Test bit-fields +struct S { + std::uint32_t m1 : 2; +}; + +void test_bitfields() { + S l1; + l1.m1 = 2; // COMPLIANT + l1.m1 = 32u; // NON_COMPLIANT + l1.m1 = g3; // COMPLIANT + l1.m1 = g5; // NON_COMPLIANT +} + +// Test enums +enum Colour : std::uint16_t { red, green, blue }; + +enum States { enabled, disabled }; + +void test_enums() { + Colour l1 = red; + g3 = red; // COMPLIANT + g1 = red; // COMPLIANT + g3 = l1; // NON_COMPLIANT + g1 = l1; // COMPLIANT + g3 = enabled; // COMPLIANT - enabled is not numeric +} + +// Test function parameters - non-overload-independent +void f1(std::int64_t l1) {} +void f2(std::int32_t l1) {} + +void test_function_parameters_non_overload_independent() { + f1(g2); // NON_COMPLIANT + f1(g8); // COMPLIANT + f2(g2); // COMPLIANT + f2(g8); // NON_COMPLIANT + int l1 = 42; + f2(l1); // NON_COMPLIANT - needs to be the same type as the parameter + signed int l2 = 42; + f2(l2); // COMPLIANT - int32_t is defined as `signed int` in this database +} + +// Test overloaded functions, but still non-overload-independent +// because they are "extensible" (i.e., they can be extended with new +// overloads). +void f3(std::int64_t l1) {} +void f3(std::int32_t l1) {} + +void test_overloaded_functions() { + f3(g2); // COMPLIANT + f3(g4); // NON_COMPLIANT + f3(g8); // COMPLIANT +} + +// Test function pointers - always "overload-independent" +void f4(long l1) {} + +void test_function_pointers() { + void (*l1)(long) = &f4; + f4(2); // NON_COMPLIANT + l1(2); // COMPLIANT +} + +// Test variadic functions +void f5(const char *l1, ...) {} + +void test_variadic_functions() { + f5("test", g3); // NON_COMPLIANT - will be promoted to `int` + f5("test", g2); // COMPLIANT - already `int`, no promotion needed +} + +// Test member function calls - not overload-independent +struct A { + void f6(std::size_t l1, int l2) {} + void f6(std::size_t l1, std::string l2) {} + void f7(); +}; + +void A::f7() { + f6(g1, "answer"); // NON_COMPLIANT - extensible, could call a global + // function instead - e.g. `void f6(std::uint32_t l1, + // std::string l2)` + this->f6(g1, "answer"); // COMPLIANT + this->f6(g1, 42); // COMPLIANT +} + +void test_member_function_overload_independent() { + A l1; + l1.f6(42, "answer"); // COMPLIANT + A *l2 = &l1; + l2->f6(42, "answer"); // COMPLIANT +} + +// Test member function calls - not overload-independent +struct B { + void f8(int l1, int l2) {} + void f8(long l1, std::string l2) {} +}; + +void test_member_function_not_overload_independent() { + B l1; + l1.f8(42, "answer"); // NON_COMPLIANT +} + +// Test constructor exception +struct MyInt { + explicit MyInt(std::int32_t l1) {} + MyInt(std::int32_t l1, std::int32_t l2) {} +}; + +void f9(MyInt l1) {} + +void test_constructor_exception() { + f9(MyInt{g4}); // COMPLIANT + MyInt l1{g4}; // COMPLIANT +} + +// Test template functions - not overload-independent +template struct D { + void f10(T l1, int l2) {} + void f10(T l1, std::string l2) {} + template void f11(S1 l1, int l2) {} + template void f11(S2 l1, std::string l2) {} + void f11(std::int32_t l1, float f) {} +}; + +void test_template_functions() { + D l1; + l1.f10(42, "X"); // COMPLIANT + l1.f10(42, 1); // COMPLIANT + l1.f11(42, "X"); // NON_COMPLIANT - int not size_t + l1.f11(42, 1); // COMPLIANT - same as specialized type + l1.f11(42, 0.0f); // COMPLIANT - same as specialized type +} + +// Test initialization forms +std::int32_t f12(std::int8_t l1) { + std::int16_t l2 = l1; // COMPLIANT + std::int16_t l3{l1}; // COMPLIANT + std::int16_t l4(l1); // COMPLIANT + std::int16_t l5{l1 + l1}; // NON_COMPLIANT + return l1; // COMPLIANT +} + +// Test switch cases +void test_switch_cases() { + switch (g4) { + case 1: // COMPLIANT + break; + case 0x7F: // COMPLIANT + break; + case 0x80: // COMPLIANT - condition subject to promotion + break; + // Our extractor and supported compilers prohibit the below + // narrowing conversion. + // case 0xFFFF'FFFF'FFFF: + // break; + } +} \ No newline at end of file From 229705f672e8a6da59761dbeabdf7e79ebd8a79e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 17 Jun 2025 11:28:49 +0100 Subject: [PATCH 437/628] Rule 7.0.6: Update test with better variable names --- .../NumericAssignmentTypeMismatch.expected | 26 ++--- cpp/misra/test/rules/RULE-7-0-6/test.cpp | 102 +++++++++--------- 2 files changed, 64 insertions(+), 64 deletions(-) diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index fa0bdb487d..c854bd78fb 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -1,23 +1,23 @@ | test.cpp:21:8:21:11 | 300 | Assignment between incompatible numeric types from 'unsigned int' to 'uint8_t'. | -| test.cpp:24:9:24:12 | 0.0 | Assignment between incompatible numeric types from 'float' to 'double'. | -| test.cpp:30:8:30:9 | g4 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | -| test.cpp:31:8:31:9 | g3 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | -| test.cpp:36:8:36:9 | g5 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | -| test.cpp:37:8:37:9 | g7 | Assignment between incompatible numeric types from 'uint64_t' to 'uint16_t'. | -| test.cpp:42:8:42:9 | g2 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | -| test.cpp:43:8:43:9 | g9 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test.cpp:24:7:24:10 | 0.0 | Assignment between incompatible numeric types from 'float' to 'double'. | +| test.cpp:30:8:30:9 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | +| test.cpp:31:8:31:9 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | +| test.cpp:36:8:36:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test.cpp:37:9:37:11 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'uint16_t'. | +| test.cpp:42:7:42:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test.cpp:43:9:43:9 | f | Assignment between incompatible numeric types from 'float' to 'int32_t'. | | test.cpp:55:8:55:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | | test.cpp:56:21:56:27 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | | test.cpp:67:11:67:13 | 32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned char'. | -| test.cpp:69:11:69:12 | g5 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:69:11:69:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | | test.cpp:81:8:81:9 | l1 | Assignment between incompatible numeric types from 'Colour' to 'uint8_t'. | -| test.cpp:91:6:91:7 | g2 | Assignment between incompatible numeric types from 'int32_t' to 'int64_t'. | -| test.cpp:94:6:94:7 | g8 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:91:6:91:8 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'int64_t'. | +| test.cpp:94:6:94:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | | test.cpp:96:6:96:7 | l1 | Assignment between incompatible numeric types from 'int' to 'int32_t'. | -| test.cpp:109:6:109:7 | g4 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | +| test.cpp:109:6:109:7 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | | test.cpp:118:6:118:6 | 2 | Assignment between incompatible numeric types from 'int' to 'long'. | -| test.cpp:126:14:126:15 | g3 | Assignment between incompatible numeric types from 'uint8_t' to 'int'. | -| test.cpp:138:6:138:7 | g1 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. | +| test.cpp:126:14:126:15 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int'. | +| test.cpp:138:6:138:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. | | test.cpp:160:9:160:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | | test.cpp:189:23:189:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. | | test.cpp:199:19:199:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index ad9aa716fb..c600c91a22 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -2,58 +2,58 @@ #include // Global variables for testing -std::uint32_t g1; -std::int32_t g2; -std::uint8_t g3; -std::int8_t g4; -std::uint16_t g5; -std::int16_t g6; -std::uint64_t g7; -std::int64_t g8; -float g9; -double g10; +std::uint32_t u32; +std::int32_t s32; +std::uint8_t u8; +std::int8_t s8; +std::uint16_t u16; +std::int16_t s16; +std::uint64_t u64; +std::int64_t s64; +float f; +double d; // Test basic constant assignments void test_constant_assignments() { - g1 = 1; // COMPLIANT - g2 = 4u * 2u; // COMPLIANT - g3 = 3u; // COMPLIANT - g3 = 300u; // NON_COMPLIANT - g9 = 1; // COMPLIANT - g9 = 9999999999; // COMPLIANT - g10 = 0.0f; // NON_COMPLIANT - g9 = 0.0f; // COMPLIANT + u32 = 1; // COMPLIANT + s32 = 4u * 2u; // COMPLIANT + u8 = 3u; // COMPLIANT + u8 = 300u; // NON_COMPLIANT + f = 1; // COMPLIANT + f = 9999999999; // COMPLIANT + d = 0.0f; // NON_COMPLIANT + f = 0.0f; // COMPLIANT } // Test signedness violations void test_signedness_violations() { - g3 = g4; // NON_COMPLIANT - g4 = g3; // NON_COMPLIANT + u8 = s8; // NON_COMPLIANT + s8 = u8; // NON_COMPLIANT } // Test size violations void test_size_violations() { - g3 = g5; // NON_COMPLIANT - g5 = g7; // NON_COMPLIANT + u8 = u16; // NON_COMPLIANT + u16 = u64; // NON_COMPLIANT } // Test type category violations void test_type_category_violations() { - g9 = g2; // NON_COMPLIANT - g2 = g9; // NON_COMPLIANT + f = s32; // NON_COMPLIANT + s32 = f; // NON_COMPLIANT } // Test widening of id-expressions void test_widening_id_expressions() { - g1 = g3; // COMPLIANT - g8 = g4; // COMPLIANT - g7 = g5; // COMPLIANT + u32 = u8; // COMPLIANT + s64 = s8; // COMPLIANT + u64 = u16; // COMPLIANT } // Test expression results void test_expression_results() { - g3 = g3 + g3; // NON_COMPLIANT - std::int16_t l1 = g4 + g4; // NON_COMPLIANT + u8 = u8 + u8; // NON_COMPLIANT + std::int16_t l1 = s8 + s8; // NON_COMPLIANT } // Test bit-fields @@ -65,8 +65,8 @@ void test_bitfields() { S l1; l1.m1 = 2; // COMPLIANT l1.m1 = 32u; // NON_COMPLIANT - l1.m1 = g3; // COMPLIANT - l1.m1 = g5; // NON_COMPLIANT + l1.m1 = u8; // COMPLIANT + l1.m1 = u16; // NON_COMPLIANT } // Test enums @@ -76,11 +76,11 @@ enum States { enabled, disabled }; void test_enums() { Colour l1 = red; - g3 = red; // COMPLIANT - g1 = red; // COMPLIANT - g3 = l1; // NON_COMPLIANT - g1 = l1; // COMPLIANT - g3 = enabled; // COMPLIANT - enabled is not numeric + u8 = red; // COMPLIANT + u32 = red; // COMPLIANT + u8 = l1; // NON_COMPLIANT + u32 = l1; // COMPLIANT + u8 = enabled; // COMPLIANT - enabled is not numeric } // Test function parameters - non-overload-independent @@ -88,10 +88,10 @@ void f1(std::int64_t l1) {} void f2(std::int32_t l1) {} void test_function_parameters_non_overload_independent() { - f1(g2); // NON_COMPLIANT - f1(g8); // COMPLIANT - f2(g2); // COMPLIANT - f2(g8); // NON_COMPLIANT + f1(s32); // NON_COMPLIANT + f1(s64); // COMPLIANT + f2(s32); // COMPLIANT + f2(s64); // NON_COMPLIANT int l1 = 42; f2(l1); // NON_COMPLIANT - needs to be the same type as the parameter signed int l2 = 42; @@ -105,9 +105,9 @@ void f3(std::int64_t l1) {} void f3(std::int32_t l1) {} void test_overloaded_functions() { - f3(g2); // COMPLIANT - f3(g4); // NON_COMPLIANT - f3(g8); // COMPLIANT + f3(s32); // COMPLIANT + f3(s8); // NON_COMPLIANT + f3(s64); // COMPLIANT } // Test function pointers - always "overload-independent" @@ -123,8 +123,8 @@ void test_function_pointers() { void f5(const char *l1, ...) {} void test_variadic_functions() { - f5("test", g3); // NON_COMPLIANT - will be promoted to `int` - f5("test", g2); // COMPLIANT - already `int`, no promotion needed + f5("test", u8); // NON_COMPLIANT - will be promoted to `int` + f5("test", s32); // COMPLIANT - already `int`, no promotion needed } // Test member function calls - not overload-independent @@ -135,11 +135,11 @@ struct A { }; void A::f7() { - f6(g1, "answer"); // NON_COMPLIANT - extensible, could call a global + f6(u32, "answer"); // NON_COMPLIANT - extensible, could call a global // function instead - e.g. `void f6(std::uint32_t l1, // std::string l2)` - this->f6(g1, "answer"); // COMPLIANT - this->f6(g1, 42); // COMPLIANT + this->f6(u32, "answer"); // COMPLIANT + this->f6(u32, 42); // COMPLIANT } void test_member_function_overload_independent() { @@ -169,8 +169,8 @@ struct MyInt { void f9(MyInt l1) {} void test_constructor_exception() { - f9(MyInt{g4}); // COMPLIANT - MyInt l1{g4}; // COMPLIANT + f9(MyInt{s8}); // COMPLIANT + MyInt l1{s8}; // COMPLIANT } // Test template functions - not overload-independent @@ -202,7 +202,7 @@ std::int32_t f12(std::int8_t l1) { // Test switch cases void test_switch_cases() { - switch (g4) { + switch (s8) { case 1: // COMPLIANT break; case 0x7F: // COMPLIANT From f870023aa44b3f24f58e9f0e91d85d482d9ed3dd Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 17 Jun 2025 12:13:55 +0100 Subject: [PATCH 438/628] Rule 7.0.6: Fix id-expression detection - Add additional test cases - Allow name qualifiers - Prohibit explicit casts (inc. parameters) --- .../NumericAssignmentTypeMismatch.ql | 4 +- .../NumericAssignmentTypeMismatch.expected | 53 ++++++----- cpp/misra/test/rules/RULE-7-0-6/test.cpp | 87 +++++++++++++++---- 3 files changed, 103 insertions(+), 41 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index eff5361d7f..b310da8cd4 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -194,8 +194,8 @@ class IdExpression extends VariableAccess { // Member variable, but the qualifier is not explicit this.getQualifier().isCompilerGenerated() ) and - // No name qualifiers - not exists(NameQualifier qual | qual.getExpr() = this) + // Not an id-expression if it's an explicit conversion + not this.hasExplicitConversion() } } diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index c854bd78fb..75492f12bf 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -1,23 +1,30 @@ -| test.cpp:21:8:21:11 | 300 | Assignment between incompatible numeric types from 'unsigned int' to 'uint8_t'. | -| test.cpp:24:7:24:10 | 0.0 | Assignment between incompatible numeric types from 'float' to 'double'. | -| test.cpp:30:8:30:9 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | -| test.cpp:31:8:31:9 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | -| test.cpp:36:8:36:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | -| test.cpp:37:9:37:11 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'uint16_t'. | -| test.cpp:42:7:42:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | -| test.cpp:43:9:43:9 | f | Assignment between incompatible numeric types from 'float' to 'int32_t'. | -| test.cpp:55:8:55:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test.cpp:56:21:56:27 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | -| test.cpp:67:11:67:13 | 32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned char'. | -| test.cpp:69:11:69:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | -| test.cpp:81:8:81:9 | l1 | Assignment between incompatible numeric types from 'Colour' to 'uint8_t'. | -| test.cpp:91:6:91:8 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'int64_t'. | -| test.cpp:94:6:94:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:96:6:96:7 | l1 | Assignment between incompatible numeric types from 'int' to 'int32_t'. | -| test.cpp:109:6:109:7 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | -| test.cpp:118:6:118:6 | 2 | Assignment between incompatible numeric types from 'int' to 'long'. | -| test.cpp:126:14:126:15 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int'. | -| test.cpp:138:6:138:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. | -| test.cpp:160:9:160:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | -| test.cpp:189:23:189:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. | -| test.cpp:199:19:199:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:36:8:36:11 | 300 | Assignment between incompatible numeric types from 'unsigned int' to 'uint8_t'. | +| test.cpp:39:7:39:10 | 0.0 | Assignment between incompatible numeric types from 'float' to 'double'. | +| test.cpp:45:8:45:9 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | +| test.cpp:46:8:46:9 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | +| test.cpp:51:8:51:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test.cpp:52:9:52:11 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'uint16_t'. | +| test.cpp:57:7:57:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test.cpp:58:9:58:9 | f | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test.cpp:95:12:95:13 | m1 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test.cpp:96:12:96:13 | m2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint64_t'. | +| test.cpp:97:13:97:14 | m1 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test.cpp:98:13:98:14 | m2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint64_t'. | +| test.cpp:103:9:103:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint32_t'. | +| test.cpp:104:10:104:11 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test.cpp:105:35:105:36 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test.cpp:110:8:110:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:111:21:111:27 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:122:11:122:13 | 32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned char'. | +| test.cpp:124:11:124:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:136:8:136:9 | l1 | Assignment between incompatible numeric types from 'Colour' to 'uint8_t'. | +| test.cpp:146:6:146:8 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'int64_t'. | +| test.cpp:149:6:149:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:151:6:151:7 | l1 | Assignment between incompatible numeric types from 'int' to 'int32_t'. | +| test.cpp:164:6:164:7 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | +| test.cpp:173:6:173:6 | 2 | Assignment between incompatible numeric types from 'int' to 'long'. | +| test.cpp:181:14:181:15 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int'. | +| test.cpp:193:6:193:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. | +| test.cpp:215:9:215:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | +| test.cpp:244:23:244:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. | +| test.cpp:254:19:254:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index c600c91a22..5be5efa198 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -13,15 +13,30 @@ std::int64_t s64; float f; double d; +namespace TestNamespace { +std::uint8_t g1; +std::uint16_t g2; +} // namespace TestNamespace + +struct TestStruct { + std::uint8_t m1; + std::uint16_t m2; + static std::uint8_t s1; + static std::uint16_t s2; +}; + +std::uint8_t TestStruct::s1; +std::uint16_t TestStruct::s2; + // Test basic constant assignments void test_constant_assignments() { - u32 = 1; // COMPLIANT - s32 = 4u * 2u; // COMPLIANT - u8 = 3u; // COMPLIANT - u8 = 300u; // NON_COMPLIANT + u32 = 1; // COMPLIANT + s32 = 4u * 2u; // COMPLIANT + u8 = 3u; // COMPLIANT + u8 = 300u; // NON_COMPLIANT f = 1; // COMPLIANT f = 9999999999; // COMPLIANT - d = 0.0f; // NON_COMPLIANT + d = 0.0f; // NON_COMPLIANT f = 0.0f; // COMPLIANT } @@ -33,7 +48,7 @@ void test_signedness_violations() { // Test size violations void test_size_violations() { - u8 = u16; // NON_COMPLIANT + u8 = u16; // NON_COMPLIANT u16 = u64; // NON_COMPLIANT } @@ -45,9 +60,49 @@ void test_type_category_violations() { // Test widening of id-expressions void test_widening_id_expressions() { - u32 = u8; // COMPLIANT - s64 = s8; // COMPLIANT - u64 = u16; // COMPLIANT + u32 = u8; // COMPLIANT - widening of id-expression + s64 = s8; // COMPLIANT - widening of id-expression + u64 = u16; // COMPLIANT - widening of id-expression +} + +// Test widening with namespace qualifiers (allowed) +void test_widening_namespace_qualified() { + u32 = TestNamespace::g1; // COMPLIANT - namespace qualified id-expression + u64 = TestNamespace::g2; // COMPLIANT - namespace qualified id-expression +} + +// Test widening with type qualifiers (allowed) +void test_widening_type_qualified() { + u32 = TestStruct::s1; // COMPLIANT - type qualified id-expression + u64 = TestStruct::s2; // COMPLIANT - type qualified id-expression +} + +// Test widening with decltype (allowed) +void test_widening_decltype_qualified() { + std::uint8_t l1 = 42; + std::uint16_t l2 = 42; + u32 = decltype(l1){}; // COMPLIANT - treated as a constant + u64 = decltype(l2){}; // COMPLIANT - treated as a constant + TestStruct l3; + u32 = decltype(l3)::s1; // COMPLIANT - decltype qualified + u64 = decltype(l3)::s2; // COMPLIANT - decltype qualified +} + +// Test widening with object member access (not allowed) +void test_widening_object_member_access() { + TestStruct l1; + TestStruct *l2 = &l1; + u32 = l1.m1; // NON_COMPLIANT - object member access, not id-expression + u64 = l1.m2; // NON_COMPLIANT - object member access, not id-expression + u32 = l2->m1; // NON_COMPLIANT - object member access, not id-expression + u64 = l2->m2; // NON_COMPLIANT - object member access, not id-expression +} + +// Test widening with expressions (not allowed) +void test_widening_expressions() { + u32 = u8 + 0; // NON_COMPLIANT - not id-expression + u32 = (u8); // NON_COMPLIANT - not id-expression (parenthesized) + u32 = static_cast(u8); // NON_COMPLIANT - not id-expression } // Test expression results @@ -66,7 +121,7 @@ void test_bitfields() { l1.m1 = 2; // COMPLIANT l1.m1 = 32u; // NON_COMPLIANT l1.m1 = u8; // COMPLIANT - l1.m1 = u16; // NON_COMPLIANT + l1.m1 = u16; // NON_COMPLIANT } // Test enums @@ -77,9 +132,9 @@ enum States { enabled, disabled }; void test_enums() { Colour l1 = red; u8 = red; // COMPLIANT - u32 = red; // COMPLIANT + u32 = red; // COMPLIANT u8 = l1; // NON_COMPLIANT - u32 = l1; // COMPLIANT + u32 = l1; // COMPLIANT u8 = enabled; // COMPLIANT - enabled is not numeric } @@ -106,7 +161,7 @@ void f3(std::int32_t l1) {} void test_overloaded_functions() { f3(s32); // COMPLIANT - f3(s8); // NON_COMPLIANT + f3(s8); // NON_COMPLIANT f3(s64); // COMPLIANT } @@ -123,7 +178,7 @@ void test_function_pointers() { void f5(const char *l1, ...) {} void test_variadic_functions() { - f5("test", u8); // NON_COMPLIANT - will be promoted to `int` + f5("test", u8); // NON_COMPLIANT - will be promoted to `int` f5("test", s32); // COMPLIANT - already `int`, no promotion needed } @@ -136,8 +191,8 @@ struct A { void A::f7() { f6(u32, "answer"); // NON_COMPLIANT - extensible, could call a global - // function instead - e.g. `void f6(std::uint32_t l1, - // std::string l2)` + // function instead - e.g. `void f6(std::uint32_t l1, + // std::string l2)` this->f6(u32, "answer"); // COMPLIANT this->f6(u32, 42); // COMPLIANT } From 0ed1689ac4afe8bd039ce3b9b7b335d3eaa5fa27 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 17 Jun 2025 13:23:32 +0100 Subject: [PATCH 439/628] Rule 7.0.6: Support reference types Reference types can be numeric types according to the rule. In addition to making NumericTypes reference types, we also add a helper predicate which gets the size of the real type (rather than the size of the reference). --- .../NumericAssignmentTypeMismatch.ql | 12 ++- .../NumericAssignmentTypeMismatch.expected | 13 +++ cpp/misra/test/rules/RULE-7-0-6/test.cpp | 90 +++++++++++++++++++ 3 files changed, 111 insertions(+), 4 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index b310da8cd4..3a30f878df 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -43,6 +43,7 @@ class NumericType extends Type { Type realType; NumericType() { + realType = this.getUnspecifiedType().(ReferenceType).getBaseType().(NumericType).getRealType() or realType = this.getUnspecifiedType().(IntegralType) or realType = this.getUnspecifiedType().(FloatingPointType) or realType = this.getUnspecifiedType().(Enum).getExplicitUnderlyingType().getUnspecifiedType() @@ -52,6 +53,8 @@ class NumericType extends Type { if realType.(IntegralType).isUnsigned() then result = Unsigned() else result = Signed() } + int getRealSize() { result = realType.getSize() } + TypeCategory getTypeCategory() { realType instanceof IntegralType and result = Integral() or @@ -76,14 +79,15 @@ predicate isAssignment(Expr source, NumericType targetType, string context) { then exists(BitField bf | isAssignedToBitfield(source, bf) and + // TODO integral after numeric? targetType.(IntegralType).(NumericType).getSignedness() = bf.getType().(NumericType).getSignedness() and // smallest integral type that can hold the bit field value - targetType.getSize() * 8 >= bf.getNumBits() and + targetType.getRealSize() * 8 >= bf.getNumBits() and not exists(IntegralType other | other.getSize() * 8 >= bf.getNumBits() and other.(NumericType).getSignedness() = targetType.getSignedness() and - other.getSize() < targetType.getSize() + other.getSize() < targetType.getRealSize() ) ) else targetType = assign.getLValue().getType() @@ -159,7 +163,7 @@ predicate isValidTypeMatch(NumericType sourceType, NumericType targetType) { // Same type category, signedness and size sourceType.getTypeCategory() = targetType.getTypeCategory() and sourceType.getSignedness() = targetType.getSignedness() and - sourceType.getSize() = targetType.getSize() + sourceType.getRealSize() = targetType.getRealSize() } predicate hasConstructorException(FunctionCall call) { @@ -209,7 +213,7 @@ predicate isValidWidening(Expr source, NumericType sourceType, NumericType targe ) and sourceType.getTypeCategory() = targetType.getTypeCategory() and sourceType.getSignedness() = targetType.getSignedness() and - sourceType.getSize() < targetType.getSize() + sourceType.getRealSize() < targetType.getRealSize() } /** diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index 75492f12bf..eb97d1b605 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -28,3 +28,16 @@ | test.cpp:215:9:215:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | | test.cpp:244:23:244:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. | | test.cpp:254:19:254:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:288:8:288:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. | +| test.cpp:289:8:289:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:290:9:290:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:301:6:301:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. | +| test.cpp:302:6:302:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. | +| test.cpp:313:8:313:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. | +| test.cpp:314:8:314:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:327:9:327:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:328:7:328:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. | +| test.cpp:329:7:329:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. | +| test.cpp:340:8:340:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:358:7:358:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | +| test.cpp:361:7:361:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index 5be5efa198..2f24a1c5bb 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -269,4 +269,94 @@ void test_switch_cases() { // case 0xFFFF'FFFF'FFFF: // break; } +} + +// Test reference types - references to numeric types are considered numeric +void test_reference_types_basic() { + std::uint8_t l1 = 42; + std::uint32_t l2 = 100; + std::int8_t l3 = -5; + float l4 = 3.14f; + + std::uint8_t &l5 = l1; // COMPLIANT + std::uint32_t &l6 = l2; // COMPLIANT + std::int8_t &l7 = l3; // COMPLIANT + float &l8 = l4; // COMPLIANT + + // Reference types follow same rules as their referred types + u32 = l5; // COMPLIANT - widening of id-expression (reference) + u8 = l6; // NON_COMPLIANT - narrowing from reference + u8 = l7; // NON_COMPLIANT - different signedness from reference + s32 = l8; // NON_COMPLIANT - different type category from reference +} + +void test_reference_types_function_parameters() { + std::uint8_t l1 = 42; + std::uint16_t l2 = 1000; + + std::uint8_t &l3 = l1; + std::uint16_t &l4 = l2; + + // Function calls with reference arguments + f1(l3); // NON_COMPLIANT - widening conversion through reference + f2(l4); // NON_COMPLIANT - narrowing conversion through reference +} + +void test_reference_types_signedness() { + std::uint8_t l1 = 42; + std::int8_t l2 = -5; + + std::uint8_t &l3 = l1; + std::int8_t &l4 = l2; + + // Signedness violations through references + s8 = l3; // NON_COMPLIANT - different signedness through reference + u8 = l4; // NON_COMPLIANT - different signedness through reference +} + +void test_reference_types_floating_point() { + float l1 = 3.14f; + double l2 = 2.718; + std::int32_t l3 = 42; + + float &l4 = l1; + double &l5 = l2; + std::int32_t &l6 = l3; + + // Type category violations through references + s32 = l4; // NON_COMPLIANT - different type category through reference + f = l5; // NON_COMPLIANT - different size through reference + f = l6; // NON_COMPLIANT - different type category through reference +} + +void test_reference_types_expressions() { + std::uint8_t l1 = 42; + std::uint8_t l2 = 24; + + std::uint8_t &l3 = l1; + std::uint8_t &l4 = l2; + + // Expression results with references still follow expression rules + u8 = l3 + l4; // NON_COMPLIANT - addition promotes to int + s32 = l3 + l4; // COMPLIANT - promotion to int +} + +// Test reference parameters in functions +void f13(std::uint8_t &l1) {} +void f13(std::uint16_t &l1) {} + +void f14(std::uint32_t l1) {} + +void test_references() { + std::uint8_t l1 = 42; + std::uint16_t l2 = 1000; + + f13(l1); // COMPLIANT - exact match + f13(l2); // COMPLIANT - exact match + + std::uint16_t &l3 = l2; + f14(l3); // NON_COMPLIANT - must be the same type, as non-overload-independent + std::uint64_t l4 = 1000; + std::uint64_t &l5 = l4; + f14(l5); // NON_COMPLIANT - narrowing conversion through reference } \ No newline at end of file From 778b344bf787725d871f3624974ec7b549c0026a Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 17 Jun 2025 13:34:02 +0100 Subject: [PATCH 440/628] Rule 7.0.6: Ignore compound expressions --- .../NumericAssignmentTypeMismatch.ql | 6 +++--- cpp/misra/test/rules/RULE-7-0-6/test.cpp | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index 3a30f878df..009cc67ff6 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -69,8 +69,8 @@ class NumericType extends Type { } predicate isAssignment(Expr source, NumericType targetType, string context) { - // Assignment operator - exists(Assignment assign | + // Assignment operator (but not compound assignment) + exists(AssignExpr assign | assign.getRValue() = source and context = "assignment" | @@ -191,7 +191,7 @@ predicate hasConstructorException(FunctionCall call) { */ class IdExpression extends VariableAccess { IdExpression() { - // Not a member variable + // Not a member variable access (no dot or arrow) ( not exists(this.getQualifier()) or diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index 2f24a1c5bb..ce494309c0 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -359,4 +359,25 @@ void test_references() { std::uint64_t l4 = 1000; std::uint64_t &l5 = l4; f14(l5); // NON_COMPLIANT - narrowing conversion through reference +} + +// Test compound assignments - rule does not apply to compound assignments +void test_compound_assignments() { + std::uint8_t l1 = 10; + std::uint16_t l2 = 100; + std::int8_t l3 = 5; + float l4 = 1.5f; + + l1 += l2; // COMPLIANT - compound assignment, rule does not apply + l1 -= l3; // COMPLIANT - compound assignment, rule does not apply + l2 *= l1; // COMPLIANT - compound assignment, rule does not apply + l2 /= l3; // COMPLIANT - compound assignment, rule does not apply + l1 %= l3; // COMPLIANT - compound assignment, rule does not apply + l2 &= l1; // COMPLIANT - compound assignment, rule does not apply + l2 |= l3; // COMPLIANT - compound assignment, rule does not apply + l2 ^= l1; // COMPLIANT - compound assignment, rule does not apply + l2 <<= 2; // COMPLIANT - compound assignment, rule does not apply + l2 >>= 1; // COMPLIANT - compound assignment, rule does not apply + l4 += l1; // COMPLIANT - compound assignment, rule does not apply + l4 -= s32; // COMPLIANT - compound assignment, rule does not apply } \ No newline at end of file From acfb25380e5e701e08745a02642a8edc9e22b185 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 17 Jun 2025 13:38:14 +0100 Subject: [PATCH 441/628] Rule 7.0.6: Additional function return test cases --- .../NumericAssignmentTypeMismatch.expected | 27 ++++++++++--------- cpp/misra/test/rules/RULE-7-0-6/test.cpp | 4 +++ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index eb97d1b605..4e1c07ef34 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -28,16 +28,17 @@ | test.cpp:215:9:215:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | | test.cpp:244:23:244:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. | | test.cpp:254:19:254:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | -| test.cpp:288:8:288:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. | -| test.cpp:289:8:289:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | -| test.cpp:290:9:290:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | -| test.cpp:301:6:301:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. | -| test.cpp:302:6:302:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. | -| test.cpp:313:8:313:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. | -| test.cpp:314:8:314:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | -| test.cpp:327:9:327:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | -| test.cpp:328:7:328:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. | -| test.cpp:329:7:329:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. | -| test.cpp:340:8:340:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test.cpp:358:7:358:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | -| test.cpp:361:7:361:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | +| test.cpp:259:10:259:12 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:292:8:292:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. | +| test.cpp:293:8:293:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:294:9:294:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:305:6:305:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. | +| test.cpp:306:6:306:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. | +| test.cpp:317:8:317:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. | +| test.cpp:318:8:318:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:331:9:331:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:332:7:332:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. | +| test.cpp:333:7:333:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. | +| test.cpp:344:8:344:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:362:7:362:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | +| test.cpp:365:7:365:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index ce494309c0..32b5520f95 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -255,6 +255,10 @@ std::int32_t f12(std::int8_t l1) { return l1; // COMPLIANT } +std::int32_t test_return() { + return u32; // NON_COMPLIANT - wrong signedness +} + // Test switch cases void test_switch_cases() { switch (s8) { From 9dbc39f720362136327db51f18ec19fd7292b852 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 17 Jun 2025 13:41:18 +0100 Subject: [PATCH 442/628] Rule 7.0.6: Clarify pass-by-value on parameters --- .../src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql | 1 + cpp/misra/test/rules/RULE-7-0-6/test.cpp | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index 009cc67ff6..04d4548962 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -101,6 +101,7 @@ predicate isAssignment(Expr source, NumericType targetType, string context) { context = "initialization" ) or + // Passing a function parameter by value exists(Call call, int i | call.getArgument(i) = source and not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index 32b5520f95..dc4faf5ef0 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -351,12 +351,12 @@ void f13(std::uint16_t &l1) {} void f14(std::uint32_t l1) {} -void test_references() { +void test_references_to_parameters() { std::uint8_t l1 = 42; std::uint16_t l2 = 1000; - f13(l1); // COMPLIANT - exact match - f13(l2); // COMPLIANT - exact match + f13(l1); // COMPLIANT - not covered by rule, as pass-by-ref + f13(l2); // COMPLIANT - not covered by rule, as pass-by-ref std::uint16_t &l3 = l2; f14(l3); // NON_COMPLIANT - must be the same type, as non-overload-independent From b310e14390541abbef3e35a9d4ea05f767804662 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 17 Jun 2025 22:13:58 +0100 Subject: [PATCH 443/628] Rule 7.0.6: Add user defined operator tests --- .../NumericAssignmentTypeMismatch.expected | 73 +++++ cpp/misra/test/rules/RULE-7-0-6/test.cpp | 294 ++++++++++++++++++ 2 files changed, 367 insertions(+) diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index 4e1c07ef34..75cdf0c69f 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -42,3 +42,76 @@ | test.cpp:344:8:344:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | | test.cpp:362:7:362:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | | test.cpp:365:7:365:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | +| test.cpp:485:8:485:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:486:8:486:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:490:8:490:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:491:8:491:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:495:7:495:8 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:496:7:496:8 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:500:8:500:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:501:8:501:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:505:8:505:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:506:8:506:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:510:8:510:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:511:8:511:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:515:8:515:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:516:8:516:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:520:8:520:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:521:8:521:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:525:9:525:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:526:9:526:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:530:9:530:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:531:9:531:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:536:9:536:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:537:9:537:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:541:9:541:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:542:9:542:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:546:8:546:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:547:8:547:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:551:9:551:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:552:9:552:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:556:8:556:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:557:8:557:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:561:9:561:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:562:9:562:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:567:6:567:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:568:6:568:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:573:6:573:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:574:6:574:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:576:10:576:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:577:6:577:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:578:6:578:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:578:10:578:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:583:8:583:9 | l3 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test.cpp:584:8:584:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:585:8:585:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:589:9:589:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:590:9:590:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:594:9:594:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:595:9:595:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:599:9:599:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:600:9:600:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:604:9:604:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:605:9:605:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:609:9:609:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:610:9:610:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:614:9:614:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:615:9:615:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:619:9:619:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:620:9:620:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:624:9:624:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:625:9:625:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:629:10:629:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:630:10:630:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:634:10:634:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:635:10:635:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:640:3:640:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:641:3:641:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:645:3:645:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:646:3:646:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:650:3:650:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:651:3:651:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:663:8:663:12 | 42.0 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test.cpp:678:8:678:10 | 42 | Assignment between incompatible numeric types from 'long' to 'int32_t'. | +| test.cpp:679:8:679:11 | 42 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | +| test.cpp:680:8:680:10 | 42 | Assignment between incompatible numeric types from 'unsigned int' to 'int32_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index dc4faf5ef0..7747a1130e 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -384,4 +384,298 @@ void test_compound_assignments() { l2 >>= 1; // COMPLIANT - compound assignment, rule does not apply l4 += l1; // COMPLIANT - compound assignment, rule does not apply l4 -= s32; // COMPLIANT - compound assignment, rule does not apply +} + +// Test user-defined operators - always non-extensible +struct UserDefinedOperators { + UserDefinedOperators(std::int32_t l1) {} + + // Binary operators + UserDefinedOperators operator+(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator-(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator*(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator/(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator%(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator&(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator|(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator^(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator<<(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator>>(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + + // Comparison operators + bool operator==(std::int32_t l1) const { return true; } + bool operator!=(std::int32_t l1) const { return false; } + bool operator<(std::int32_t l1) const { return false; } + bool operator<=(std::int32_t l1) const { return false; } + bool operator>(std::int32_t l1) const { return false; } + bool operator>=(std::int32_t l1) const { return false; } + + // Subscript operator + std::int32_t operator[](std::int32_t l1) const { return 0; } + + // Function call operator + std::int32_t operator()(std::int32_t l1) const { return 0; } + std::int32_t operator()(std::int32_t l1, std::int32_t l2) const { return 0; } + + // Assignment operators + UserDefinedOperators &operator=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator+=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator-=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator*=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator/=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator%=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator&=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator|=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator^=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator<<=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator>>=(std::int32_t l1) { return *this; } + + // Increment/decrement operators + UserDefinedOperators &operator++() { return *this; } + UserDefinedOperators operator++(int) { return UserDefinedOperators{0}; } + UserDefinedOperators &operator--() { return *this; } + UserDefinedOperators operator--(int) { return UserDefinedOperators{0}; } +}; + +// Global user-defined operators +UserDefinedOperators operator+(std::int32_t l1, + const UserDefinedOperators &l2) { + return UserDefinedOperators{0}; +} + +UserDefinedOperators operator-(std::int32_t l1, + const UserDefinedOperators &l2) { + return UserDefinedOperators{0}; +} + +bool operator==(std::int32_t l1, const UserDefinedOperators &l2) { + return true; +} + +void test_user_defined_operators() { + UserDefinedOperators l1{42}; + std::int32_t l2 = 10; + std::int16_t l3 = 5; + std::int64_t l4 = 100; + std::uint32_t l5 = 20; + + // Member operators - non-extensible, exact type match required + l1 + l2; // COMPLIANT - exact type match + l1 + l3; // COMPLIANT - widening conversion is allowed + l1 + l4; // NON_COMPLIANT - different type + l1 + l5; // NON_COMPLIANT - different signedness + + l1 - l2; // COMPLIANT - exact type match + l1 - l3; // COMPLIANT - widening conversion is allowed + l1 - l4; // NON_COMPLIANT - different type + l1 - l5; // NON_COMPLIANT - different signedness + + l1 *l2; // COMPLIANT - exact type match + l1 *l3; // COMPLIANT - widening conversion is allowed + l1 *l4; // NON_COMPLIANT - different type + l1 *l5; // NON_COMPLIANT - different signedness + + l1 / l2; // COMPLIANT - exact type match + l1 / l3; // COMPLIANT - widening conversion is allowed + l1 / l4; // NON_COMPLIANT - different type + l1 / l5; // NON_COMPLIANT - different signedness + + l1 % l2; // COMPLIANT - exact type match + l1 % l3; // COMPLIANT - widening conversion is allowed + l1 % l4; // NON_COMPLIANT - different type + l1 % l5; // NON_COMPLIANT - different signedness + + l1 & l2; // COMPLIANT - exact type match + l1 & l3; // COMPLIANT - widening conversion is allowed + l1 & l4; // NON_COMPLIANT - different type + l1 & l5; // NON_COMPLIANT - different signedness + + l1 | l2; // COMPLIANT - exact type match + l1 | l3; // COMPLIANT - widening conversion is allowed + l1 | l4; // NON_COMPLIANT - different type + l1 | l5; // NON_COMPLIANT - different signedness + + l1 ^ l2; // COMPLIANT - exact type match + l1 ^ l3; // COMPLIANT - widening conversion is allowed + l1 ^ l4; // NON_COMPLIANT - different type + l1 ^ l5; // NON_COMPLIANT - different signedness + + l1 << l2; // COMPLIANT - exact type match + l1 << l3; // COMPLIANT - widening conversion is allowed + l1 << l4; // NON_COMPLIANT - different type + l1 << l5; // NON_COMPLIANT - different signedness + + l1 >> l2; // COMPLIANT - exact type match + l1 >> l3; // COMPLIANT - widening conversion is allowed + l1 >> l4; // NON_COMPLIANT - different type + l1 >> l5; // NON_COMPLIANT - different signedness + + // Comparison operators + l1 == l2; // COMPLIANT - exact type match + l1 == l3; // COMPLIANT - widening conversion is allowed + l1 == l4; // NON_COMPLIANT - different type + l1 == l5; // NON_COMPLIANT - different signedness + + l1 != l2; // COMPLIANT - exact type match + l1 != l3; // COMPLIANT - widening conversion is allowed + l1 != l4; // NON_COMPLIANT - different type + l1 != l5; // NON_COMPLIANT - different signedness + + l1 < l2; // COMPLIANT - exact type match + l1 < l3; // COMPLIANT - widening conversion is allowed + l1 < l4; // NON_COMPLIANT - different type + l1 < l5; // NON_COMPLIANT - different signedness + + l1 <= l2; // COMPLIANT - exact type match + l1 <= l3; // COMPLIANT - widening conversion is allowed + l1 <= l4; // NON_COMPLIANT - different type + l1 <= l5; // NON_COMPLIANT + + l1 > l2; // COMPLIANT - exact type match + l1 > l3; // COMPLIANT - widening conversion is allowed + l1 > l4; // NON_COMPLIANT + l1 > l5; // NON_COMPLIANT - different signedness + + l1 >= l2; // COMPLIANT - exact type match + l1 >= l3; // COMPLIANT - widening conversion is allowed + l1 >= l4; // NON_COMPLIANT + l1 >= l5; // NON_COMPLIANT - different signedness + + // Subscript operator + l1[l2]; // COMPLIANT - exact type match + l1[l3]; // COMPLIANT - widening conversion is allowed + l1[l4]; // NON_COMPLIANT - different type + l1[l5]; // NON_COMPLIANT - different signedness + + // Function call operator + l1(l2); // COMPLIANT - exact type match + l1(l3); // COMPLIANT - widening conversion is allowed + l1(l4); // NON_COMPLIANT - different type + l1(l5); // NON_COMPLIANT - different signedness + l1(l2, l2); // COMPLIANT - both exact type match + l1(l2, l4); // NON_COMPLIANT - second parameter different type + l1(l4, l2); // NON_COMPLIANT - first parameter different type + l1(l4, l5); // NON_COMPLIANT - both parameters different type + + // The presence of a default copy constructor for UserDefinedOperators means + // that assignments through operator= must be exact type matches. + l1 = l2; // COMPLIANT - exact type match + l1 = l3; // NON_COMPLIANT + l1 = l4; // NON_COMPLIANT + l1 = l5; // NON_COMPLIANT + + l1 += l2; // COMPLIANT - exact type match + l1 += l3; // COMPLIANT - widening conversion is allowed + l1 += l4; // NON_COMPLIANT - different type + l1 += l5; // NON_COMPLIANT - different signedness + + l1 -= l2; // COMPLIANT - exact type match + l1 -= l3; // COMPLIANT - widening conversion is allowed + l1 -= l4; // NON_COMPLIANT - different type + l1 -= l5; // NON_COMPLIANT - different signedness + + l1 *= l2; // COMPLIANT - exact type match + l1 *= l3; // COMPLIANT - widening conversion is allowed + l1 *= l4; // NON_COMPLIANT - different type + l1 *= l5; // NON_COMPLIANT - different signedness + + l1 /= l2; // COMPLIANT - exact type match + l1 /= l3; // COMPLIANT - widening conversion is allowed + l1 /= l4; // NON_COMPLIANT - different type + l1 /= l5; // NON_COMPLIANT - different signedness + + l1 %= l2; // COMPLIANT - exact type match + l1 %= l3; // COMPLIANT - widening conversion is allowed + l1 %= l4; // NON_COMPLIANT - different type + l1 %= l5; // NON_COMPLIANT - different signedness + + l1 &= l2; // COMPLIANT - exact type match + l1 &= l3; // COMPLIANT - widening conversion is allowed + l1 &= l4; // NON_COMPLIANT - different type + l1 &= l5; // NON_COMPLIANT - different signedness + + l1 |= l2; // COMPLIANT - exact type match + l1 |= l3; // COMPLIANT - widening conversion is allowed + l1 |= l4; // NON_COMPLIANT - different type + l1 |= l5; // NON_COMPLIANT - different signedness + + l1 ^= l2; // COMPLIANT - exact type match + l1 ^= l3; // COMPLIANT - widening conversion is allowed + l1 ^= l4; // NON_COMPLIANT - different type + l1 ^= l5; // NON_COMPLIANT - different signedness + + l1 <<= l2; // COMPLIANT - exact type match + l1 <<= l3; // COMPLIANT - widening conversion is allowed + l1 <<= l4; // NON_COMPLIANT - different type + l1 <<= l5; // NON_COMPLIANT - different signedness + + l1 >>= l2; // COMPLIANT - exact type match + l1 >>= l3; // COMPLIANT - widening conversion is allowed + l1 >>= l4; // NON_COMPLIANT - different type + l1 >>= l5; // NON_COMPLIANT - different signedness + + // Global operators + l2 + l1; // COMPLIANT - exact type match + l3 + l1; // COMPLIANT - widening conversion is allowed + l4 + l1; // NON_COMPLIANT - different type + l5 + l1; // NON_COMPLIANT - different signedness + + l2 - l1; // COMPLIANT - exact type match + l3 - l1; // COMPLIANT - widening conversion is allowed + l4 - l1; // NON_COMPLIANT - different type + l5 - l1; // NON_COMPLIANT - different signedness + + l2 == l1; // COMPLIANT - exact type match + l3 == l1; // COMPLIANT - widening conversion is allowed + l4 == l1; // NON_COMPLIANT - different type + l5 == l1; // NON_COMPLIANT - different signedness +} + +// Test user-defined operators with constants +void test_user_defined_operators_constants() { + UserDefinedOperators l1{42}; + + // Constants with exact type match + l1 + 42; // COMPLIANT + l1 + 42L; // COMPLIANT + l1 + 42LL; // COMPLIANT + l1 + 42U; // COMPLIANT + l1 + 42.0f; // NON_COMPLIANT - float constant + + l1 == 42; // COMPLIANT - integer constant is int/int32_t + l1 == 42L; // COMPLIANT - long constant + l1 == 42LL; // COMPLIANT - long long constant + l1 == 42U; // COMPLIANT - unsigned constant + + l1[42]; // COMPLIANT - integer constant is int/int32_t + l1[42L]; // COMPLIANT - long constant + l1[42LL]; // COMPLIANT - long long constant + l1[42U]; // COMPLIANT - unsigned constant + + // The presence of a default copy constructor for UserDefinedOperators means + // that assignments through operator= must be exact type matches. + l1 = 42; // COMPLIANT - integer constant is int/int32_t + l1 = 42L; // NON_COMPLIANT + l1 = 42LL; // NON_COMPLIANT + l1 = 42U; // NON_COMPLIANT } \ No newline at end of file From af2ff95dc40fe1eefe01104d1f973b22f10fc4fb Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 17 Jun 2025 22:30:38 +0100 Subject: [PATCH 444/628] MISRA C++ 2023: Create StandardConversions library Migrate conversion generic code to a shared library. --- .../cpp/misra/StandardConversions.qll | 125 ++++++++++++++++++ .../NumericAssignmentTypeMismatch.ql | 124 +---------------- 2 files changed, 126 insertions(+), 123 deletions(-) create mode 100644 cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll diff --git a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll new file mode 100644 index 0000000000..34de2e36ad --- /dev/null +++ b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll @@ -0,0 +1,125 @@ +import cpp +import codingstandards.cpp.misra + +/** + * The signedness of a numeric type. + */ +newtype Signedness = + Signed() or + Unsigned() + +/** + * The type category of a numeric type - either integral or floating-point. + */ +newtype TypeCategory = + Integral() or + FloatingPoint() + +/** + * A numeric type is a type that represents a number, either an integral or a floating-point. + * + * In addition to the basic integral and floating-point types, it includes: + * - Enum types with an explicit underlying type that is a numeric type. + * - Typedef'd types that are numeric types. + * - Numeric types with specifiers (e.g., `const`, `volatile`, `restrict`). + */ +class NumericType extends Type { + Type realType; + + NumericType() { + realType = this.getUnspecifiedType().(ReferenceType).getBaseType().(NumericType).getRealType() or + realType = this.getUnspecifiedType().(IntegralType) or + realType = this.getUnspecifiedType().(FloatingPointType) or + realType = this.getUnspecifiedType().(Enum).getExplicitUnderlyingType().getUnspecifiedType() + } + + Signedness getSignedness() { + if realType.(IntegralType).isUnsigned() then result = Unsigned() else result = Signed() + } + + /** Gets the size of the actual numeric type */ + int getRealSize() { result = realType.getSize() } + + TypeCategory getTypeCategory() { + realType instanceof IntegralType and result = Integral() + or + realType instanceof FloatingPointType and result = FloatingPoint() + } + + float getUpperBound() { result = typeUpperBound(realType) } + + float getLowerBound() { result = typeLowerBound(realType) } + + Type getRealType() { result = realType } +} + +predicate isAssignment(Expr source, NumericType targetType, string context) { + // Assignment operator (but not compound assignment) + exists(AssignExpr assign | + assign.getRValue() = source and + context = "assignment" + | + // TODO generalize to variable init (do we need this for bitfields?) and extract + if isAssignedToBitfield(source, _) + then + exists(BitField bf | + isAssignedToBitfield(source, bf) and + // TODO integral after numeric? + targetType.(IntegralType).(NumericType).getSignedness() = + bf.getType().(NumericType).getSignedness() and + // smallest integral type that can hold the bit field value + targetType.getRealSize() * 8 >= bf.getNumBits() and + not exists(IntegralType other | + other.getSize() * 8 >= bf.getNumBits() and + other.(NumericType).getSignedness() = targetType.getSignedness() and + other.getSize() < targetType.getRealSize() + ) + ) + else targetType = assign.getLValue().getType() + ) + or + // Variable initialization + exists(Variable v, Initializer init | + init.getExpr() = source and + v.getInitializer() = init and + targetType = v.getType() and + context = "initialization" + ) + or + // Passing a function parameter by value + exists(Call call, int i | + call.getArgument(i) = source and + not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and + context = "function argument" + | + targetType = call.getTarget().getParameter(i).getType() + or + // Handle varargs - use the fully converted type of the argument + call.getTarget().getNumberOfParameters() <= i and + targetType = source.getFullyConverted().getType() + ) + or + // Return statement + exists(ReturnStmt ret, Function f | + ret.getExpr() = source and + ret.getEnclosingFunction() = f and + targetType = f.getType() and + not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and + context = "return" + ) + or + // Switch case + exists(SwitchCase case, SwitchStmt switch | + case.getExpr() = source and + case.getSwitchStmt() = switch and + targetType = switch.getExpr().getFullyConverted().getType() and + context = "switch case" + ) +} + +predicate isAssignedToBitfield(Expr source, BitField bf) { + exists(Assignment assign | + assign.getRValue() = source and + assign.getLValue() = bf.getAnAccess() + ) +} diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index 04d4548962..e8f65ed00f 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -15,129 +15,7 @@ import cpp import codingstandards.cpp.misra -import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis - -/** - * The signedness of a numeric type. - */ -newtype Signedness = - Signed() or - Unsigned() - -/** - * The type category of a numeric type - either integral or floating-point. - */ -newtype TypeCategory = - Integral() or - FloatingPoint() - -/** - * A numeric type is a type that represents a number, either an integral or a floating-point. - * - * In addition to the basic integral and floating-point types, it includes: - * - Enum types with an explicit underlying type that is a numeric type. - * - Typedef'd types that are numeric types. - * - Numeric types with specifiers (e.g., `const`, `volatile`, `restrict`). - */ -class NumericType extends Type { - Type realType; - - NumericType() { - realType = this.getUnspecifiedType().(ReferenceType).getBaseType().(NumericType).getRealType() or - realType = this.getUnspecifiedType().(IntegralType) or - realType = this.getUnspecifiedType().(FloatingPointType) or - realType = this.getUnspecifiedType().(Enum).getExplicitUnderlyingType().getUnspecifiedType() - } - - Signedness getSignedness() { - if realType.(IntegralType).isUnsigned() then result = Unsigned() else result = Signed() - } - - int getRealSize() { result = realType.getSize() } - - TypeCategory getTypeCategory() { - realType instanceof IntegralType and result = Integral() - or - realType instanceof FloatingPointType and result = FloatingPoint() - } - - float getUpperBound() { result = typeUpperBound(realType) } - - float getLowerBound() { result = typeLowerBound(realType) } - - Type getRealType() { result = realType } -} - -predicate isAssignment(Expr source, NumericType targetType, string context) { - // Assignment operator (but not compound assignment) - exists(AssignExpr assign | - assign.getRValue() = source and - context = "assignment" - | - // TODO generalize to variable init (do we need this for bitfields?) and extract - if isAssignedToBitfield(source, _) - then - exists(BitField bf | - isAssignedToBitfield(source, bf) and - // TODO integral after numeric? - targetType.(IntegralType).(NumericType).getSignedness() = - bf.getType().(NumericType).getSignedness() and - // smallest integral type that can hold the bit field value - targetType.getRealSize() * 8 >= bf.getNumBits() and - not exists(IntegralType other | - other.getSize() * 8 >= bf.getNumBits() and - other.(NumericType).getSignedness() = targetType.getSignedness() and - other.getSize() < targetType.getRealSize() - ) - ) - else targetType = assign.getLValue().getType() - ) - or - // Variable initialization - exists(Variable v, Initializer init | - init.getExpr() = source and - v.getInitializer() = init and - targetType = v.getType() and - context = "initialization" - ) - or - // Passing a function parameter by value - exists(Call call, int i | - call.getArgument(i) = source and - not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and - context = "function argument" - | - targetType = call.getTarget().getParameter(i).getType() - or - // Handle varargs - use the fully converted type of the argument - call.getTarget().getNumberOfParameters() <= i and - targetType = source.getFullyConverted().getType() - ) - or - // Return statement - exists(ReturnStmt ret, Function f | - ret.getExpr() = source and - ret.getEnclosingFunction() = f and - targetType = f.getType() and - not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and - context = "return" - ) - or - // Switch case - exists(SwitchCase case, SwitchStmt switch | - case.getExpr() = source and - case.getSwitchStmt() = switch and - targetType = switch.getExpr().getFullyConverted().getType() and - context = "switch case" - ) -} - -predicate isAssignedToBitfield(Expr source, BitField bf) { - exists(Assignment assign | - assign.getRValue() = source and - assign.getLValue() = bf.getAnAccess() - ) -} +import codingstandards.cpp.misra.StandardConversions predicate isValidConstantAssignment(Expr source, NumericType targetType) { isAssignment(source, targetType, _) and From ea7d168c2fa025cfa248f60a9b9917360aaf1e5b Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 17 Jun 2025 22:42:40 +0100 Subject: [PATCH 445/628] MISRA C++ StandardConversions - improve detection of bitfield types --- .../cpp/misra/StandardConversions.qll | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll index 34de2e36ad..944f90f278 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll @@ -54,26 +54,17 @@ class NumericType extends Type { } predicate isAssignment(Expr source, NumericType targetType, string context) { - // Assignment operator (but not compound assignment) + // Assignment expression (which excludes compound assignments) exists(AssignExpr assign | assign.getRValue() = source and context = "assignment" | - // TODO generalize to variable init (do we need this for bitfields?) and extract if isAssignedToBitfield(source, _) then + // For the MISRA type rules we treat bit fields as a special case exists(BitField bf | isAssignedToBitfield(source, bf) and - // TODO integral after numeric? - targetType.(IntegralType).(NumericType).getSignedness() = - bf.getType().(NumericType).getSignedness() and - // smallest integral type that can hold the bit field value - targetType.getRealSize() * 8 >= bf.getNumBits() and - not exists(IntegralType other | - other.getSize() * 8 >= bf.getNumBits() and - other.(NumericType).getSignedness() = targetType.getSignedness() and - other.getSize() < targetType.getRealSize() - ) + targetType = getBitFieldType(bf) ) else targetType = assign.getLValue().getType() ) @@ -82,8 +73,14 @@ predicate isAssignment(Expr source, NumericType targetType, string context) { exists(Variable v, Initializer init | init.getExpr() = source and v.getInitializer() = init and - targetType = v.getType() and context = "initialization" + | + // For the MISRA type rules we treat bit fields as a special case + if v instanceof BitField + then targetType = getBitFieldType(v) + else + // Regular variable initialization + targetType = v.getType() ) or // Passing a function parameter by value @@ -117,6 +114,30 @@ predicate isAssignment(Expr source, NumericType targetType, string context) { ) } +/** + * Gets the smallest integral type that can hold the value of a bit field. + * + * The type is determined by the signedness of the bit field and the number of bits. + */ +NumericType getBitFieldType(BitField bf) { + exists(NumericType bitfieldActualType | + bitfieldActualType = bf.getType() and + // Integral type with the same signedness as the bit field, and big enough to hold the bit field value + result instanceof IntegralType and + result.getSignedness() = bitfieldActualType.getSignedness() and + result.getSize() * 8 >= bf.getNumBits() and + // No smaller integral type can hold the bit field value + not exists(IntegralType other | + other.getSize() * 8 >= bf.getNumBits() and + other.(NumericType).getSignedness() = result.getSignedness() and + other.getSize() < result.getRealSize() + ) + ) +} + +/** + * Holds if the `source` expression is assigned to a bit field. + */ predicate isAssignedToBitfield(Expr source, BitField bf) { exists(Assignment assign | assign.getRValue() = source and From 58432583654ee143b0e8f00de7f65c703fcd357c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 18 Jun 2025 09:27:37 +0100 Subject: [PATCH 446/628] Rule 7.0.6: Improve bitfield support - Add extra testing - Support signed bitfields --- .../NumericAssignmentTypeMismatch.ql | 12 +- .../NumericAssignmentTypeMismatch.expected | 240 +++++++++++------- cpp/misra/test/rules/RULE-7-0-6/test.cpp | 100 +++++++- 3 files changed, 246 insertions(+), 106 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index e8f65ed00f..23409abcb3 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -27,8 +27,16 @@ predicate isValidConstantAssignment(Expr source, NumericType targetType) { exists(BitField bf, int numBits | isAssignedToBitfield(source, bf) and numBits = bf.getNumBits() and - val >= 0 and - val < 2.pow(numBits) + if targetType.getSignedness() = Signed() + then + // Signed bit field: value must be in the range of signed bit field + val >= -2.pow(numBits - 1) and + val < 2.pow(numBits - 1) + else ( + // Unsigned bit field: value must be in the range of unsigned bit field + val >= 0 and + val < 2.pow(numBits) + ) ) or // Regular assignment: check if the value fits in the target type range diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index 75cdf0c69f..4159b78b2d 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -15,103 +15,147 @@ | test.cpp:105:35:105:36 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | | test.cpp:110:8:110:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | | test.cpp:111:21:111:27 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | -| test.cpp:122:11:122:13 | 32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned char'. | -| test.cpp:124:11:124:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | -| test.cpp:136:8:136:9 | l1 | Assignment between incompatible numeric types from 'Colour' to 'uint8_t'. | -| test.cpp:146:6:146:8 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'int64_t'. | -| test.cpp:149:6:149:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:151:6:151:7 | l1 | Assignment between incompatible numeric types from 'int' to 'int32_t'. | -| test.cpp:164:6:164:7 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | -| test.cpp:173:6:173:6 | 2 | Assignment between incompatible numeric types from 'int' to 'long'. | -| test.cpp:181:14:181:15 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int'. | -| test.cpp:193:6:193:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. | -| test.cpp:215:9:215:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | -| test.cpp:244:23:244:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. | -| test.cpp:254:19:254:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | -| test.cpp:259:10:259:12 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:292:8:292:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. | -| test.cpp:293:8:293:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | -| test.cpp:294:9:294:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | -| test.cpp:305:6:305:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. | -| test.cpp:306:6:306:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. | -| test.cpp:317:8:317:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. | -| test.cpp:318:8:318:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | -| test.cpp:331:9:331:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | -| test.cpp:332:7:332:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. | -| test.cpp:333:7:333:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. | -| test.cpp:344:8:344:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test.cpp:362:7:362:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | -| test.cpp:365:7:365:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | -| test.cpp:485:8:485:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:486:8:486:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:490:8:490:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:491:8:491:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:495:7:495:8 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:496:7:496:8 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:500:8:500:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:501:8:501:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:505:8:505:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:506:8:506:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:510:8:510:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:511:8:511:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:515:8:515:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:516:8:516:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:520:8:520:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:521:8:521:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:525:9:525:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:526:9:526:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:530:9:530:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:531:9:531:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:536:9:536:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:537:9:537:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:541:9:541:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:542:9:542:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:546:8:546:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:547:8:547:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:551:9:551:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:552:9:552:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:556:8:556:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:557:8:557:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:561:9:561:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:562:9:562:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:567:6:567:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:568:6:568:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:573:6:573:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:574:6:574:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:576:10:576:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:577:6:577:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:578:6:578:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:578:10:578:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:583:8:583:9 | l3 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | -| test.cpp:584:8:584:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:585:8:585:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:589:9:589:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:590:9:590:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:594:9:594:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:595:9:595:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:599:9:599:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:600:9:600:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:604:9:604:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:605:9:605:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:609:9:609:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:610:9:610:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:614:9:614:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:615:9:615:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:619:9:619:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:620:9:620:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:134:11:134:11 | 4 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test.cpp:137:11:137:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:141:11:141:13 | 256 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test.cpp:143:11:143:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:144:11:144:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned char'. | +| test.cpp:148:11:148:13 | 512 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test.cpp:149:11:149:15 | 65535 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test.cpp:150:11:150:15 | 65536 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test.cpp:153:11:153:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | +| test.cpp:157:11:157:15 | 65536 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test.cpp:160:11:160:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | +| test.cpp:164:11:164:16 | 131072 | Assignment between incompatible numeric types from 'int' to 'unsigned int'. | +| test.cpp:168:11:168:13 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'unsigned int'. | +| test.cpp:172:11:172:22 | 4294967296 | Assignment between incompatible numeric types from 'unsigned long' to 'unsigned int'. | +| test.cpp:176:11:176:13 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'unsigned int'. | +| test.cpp:180:11:180:21 | 8589934592 | Assignment between incompatible numeric types from 'long' to 'unsigned long long'. | +| test.cpp:180:11:180:21 | 8589934592 | Assignment between incompatible numeric types from 'long' to 'unsigned long'. | +| test.cpp:193:11:193:12 | 16 | Assignment between incompatible numeric types from 'int32_t' to 'bool'. | +| test.cpp:193:11:193:12 | 16 | Assignment between incompatible numeric types from 'int32_t' to 'char8_t'. | +| test.cpp:193:11:193:12 | 16 | Assignment between incompatible numeric types from 'int32_t' to 'char'. | +| test.cpp:193:11:193:12 | 16 | Assignment between incompatible numeric types from 'int32_t' to 'signed char'. | +| test.cpp:194:11:194:13 | - ... | Assignment between incompatible numeric types from 'int' to 'bool'. | +| test.cpp:194:11:194:13 | - ... | Assignment between incompatible numeric types from 'int' to 'char8_t'. | +| test.cpp:194:11:194:13 | - ... | Assignment between incompatible numeric types from 'int' to 'char'. | +| test.cpp:194:11:194:13 | - ... | Assignment between incompatible numeric types from 'int' to 'signed char'. | +| test.cpp:196:11:196:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'bool'. | +| test.cpp:196:11:196:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'char8_t'. | +| test.cpp:196:11:196:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'char'. | +| test.cpp:196:11:196:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'signed char'. | +| test.cpp:200:11:200:14 | 2048 | Assignment between incompatible numeric types from 'int32_t' to 'char16_t'. | +| test.cpp:200:11:200:14 | 2048 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test.cpp:200:11:200:14 | 2048 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test.cpp:201:11:201:15 | - ... | Assignment between incompatible numeric types from 'int' to 'char16_t'. | +| test.cpp:201:11:201:15 | - ... | Assignment between incompatible numeric types from 'int' to 'short'. | +| test.cpp:201:11:201:15 | - ... | Assignment between incompatible numeric types from 'int' to 'signed short'. | +| test.cpp:204:11:204:13 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'char16_t'. | +| test.cpp:204:11:204:13 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test.cpp:204:11:204:13 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test.cpp:208:12:208:22 | 134217728 | Assignment between incompatible numeric types from 'long long' to 'char32_t'. | +| test.cpp:208:12:208:22 | 134217728 | Assignment between incompatible numeric types from 'long long' to 'int'. | +| test.cpp:208:12:208:22 | 134217728 | Assignment between incompatible numeric types from 'long long' to 'signed int'. | +| test.cpp:208:12:208:22 | 134217728 | Assignment between incompatible numeric types from 'long long' to 'wchar_t'. | +| test.cpp:209:12:209:23 | - ... | Assignment between incompatible numeric types from 'long long' to 'char32_t'. | +| test.cpp:209:12:209:23 | - ... | Assignment between incompatible numeric types from 'long long' to 'int'. | +| test.cpp:209:12:209:23 | - ... | Assignment between incompatible numeric types from 'long long' to 'signed int'. | +| test.cpp:209:12:209:23 | - ... | Assignment between incompatible numeric types from 'long long' to 'wchar_t'. | +| test.cpp:224:8:224:9 | l1 | Assignment between incompatible numeric types from 'Colour' to 'uint8_t'. | +| test.cpp:234:6:234:8 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'int64_t'. | +| test.cpp:237:6:237:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:239:6:239:7 | l1 | Assignment between incompatible numeric types from 'int' to 'int32_t'. | +| test.cpp:252:6:252:7 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | +| test.cpp:261:6:261:6 | 2 | Assignment between incompatible numeric types from 'int' to 'long'. | +| test.cpp:269:14:269:15 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int'. | +| test.cpp:281:6:281:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. | +| test.cpp:303:9:303:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | +| test.cpp:332:23:332:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. | +| test.cpp:342:19:342:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:347:10:347:12 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:380:8:380:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. | +| test.cpp:381:8:381:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:382:9:382:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:393:6:393:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. | +| test.cpp:394:6:394:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. | +| test.cpp:405:8:405:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. | +| test.cpp:406:8:406:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:419:9:419:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:420:7:420:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. | +| test.cpp:421:7:421:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. | +| test.cpp:432:8:432:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:450:7:450:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | +| test.cpp:453:7:453:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | +| test.cpp:573:8:573:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:574:8:574:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:578:8:578:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:579:8:579:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:583:7:583:8 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:584:7:584:8 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:588:8:588:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:589:8:589:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:593:8:593:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:594:8:594:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:598:8:598:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:599:8:599:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:603:8:603:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:604:8:604:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:608:8:608:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:609:8:609:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:613:9:613:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:614:9:614:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:618:9:618:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:619:9:619:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | | test.cpp:624:9:624:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | | test.cpp:625:9:625:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:629:10:629:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:630:10:630:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:634:10:634:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:635:10:635:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:640:3:640:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:641:3:641:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:645:3:645:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:646:3:646:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:650:3:650:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:651:3:651:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:663:8:663:12 | 42.0 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | -| test.cpp:678:8:678:10 | 42 | Assignment between incompatible numeric types from 'long' to 'int32_t'. | -| test.cpp:679:8:679:11 | 42 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | -| test.cpp:680:8:680:10 | 42 | Assignment between incompatible numeric types from 'unsigned int' to 'int32_t'. | +| test.cpp:629:9:629:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:630:9:630:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:634:8:634:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:635:8:635:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:639:9:639:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:640:9:640:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:644:8:644:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:645:8:645:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:649:9:649:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:650:9:650:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:655:6:655:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:656:6:656:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:661:6:661:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:662:6:662:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:664:10:664:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:665:6:665:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:666:6:666:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:666:10:666:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:671:8:671:9 | l3 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test.cpp:672:8:672:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:673:8:673:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:677:9:677:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:678:9:678:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:682:9:682:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:683:9:683:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:687:9:687:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:688:9:688:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:692:9:692:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:693:9:693:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:697:9:697:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:698:9:698:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:702:9:702:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:703:9:703:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:707:9:707:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:708:9:708:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:712:9:712:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:713:9:713:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:717:10:717:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:718:10:718:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:722:10:722:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:723:10:723:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:728:3:728:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:729:3:729:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:733:3:733:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:734:3:734:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:738:3:738:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:739:3:739:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:751:8:751:12 | 42.0 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test.cpp:766:8:766:10 | 42 | Assignment between incompatible numeric types from 'long' to 'int32_t'. | +| test.cpp:767:8:767:11 | 42 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | +| test.cpp:768:8:768:10 | 42 | Assignment between incompatible numeric types from 'unsigned int' to 'int32_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index 7747a1130e..740129a4b8 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -111,17 +111,105 @@ void test_expression_results() { std::int16_t l1 = s8 + s8; // NON_COMPLIANT } -// Test bit-fields +// Test bit-fields with various sizes around boundaries struct S { - std::uint32_t m1 : 2; + std::uint32_t m1 : 2; // 2-bit field + std::uint32_t m2 : 8; // 8-bit field (boundary) + std::uint32_t m3 : 9; // 9-bit field (boundary + 1) + std::uint32_t m4 : 16; // 16-bit field (boundary) + std::uint32_t m5 : 17; // 17-bit field (boundary + 1) + std::uint32_t m6 : 32; // 32-bit field (boundary) + std::uint64_t m7 : 33; // 33-bit field (boundary + 1) + std::int32_t m8 : 5; // Signed 5-bit field + std::int32_t m9 : 12; // Signed 12-bit field + std::int32_t m10 : 28; // Signed 28-bit field }; void test_bitfields() { S l1; - l1.m1 = 2; // COMPLIANT - l1.m1 = 32u; // NON_COMPLIANT - l1.m1 = u8; // COMPLIANT - l1.m1 = u16; // NON_COMPLIANT + + // 2-bit field tests + l1.m1 = 2; // COMPLIANT - value fits in 2 bits + l1.m1 = 3; // COMPLIANT - value fits in 2 bits + l1.m1 = 4; // NON_COMPLIANT - constant does not fit in 2 bits + + l1.m1 = u8; // COMPLIANT - u8 is fine, not integer constant + l1.m1 = u16; // NON_COMPLIANT - narrowing from uint16_t + + // 8-bit boundary field tests + l1.m2 = 255; // COMPLIANT - value fits in uint8_t + l1.m2 = 256; // NON_COMPLIANT - value does not fit in unint8_t + l1.m2 = u8; // COMPLIANT - same width as uint8_t + l1.m2 = u16; // NON_COMPLIANT - narrowing from uint16_t + l1.m2 = u32; // NON_COMPLIANT - narrowing from uint32_t + + // 9-bit boundary + 1 field tests + l1.m3 = 511; // COMPLIANT + l1.m3 = 512; // NON_COMPLIANT - value does not fit in 9 bits + l1.m3 = 65535; // NON_COMPLIANT - value does not fit in 9 bits + l1.m3 = 65536; // NON_COMPLIANT - value does not fit in 9 bits + l1.m3 = u8; // COMPLIANT - widening from uint8_t to uint16_t + l1.m3 = u16; // COMPLIANT + l1.m3 = u32; // NON_COMPLIANT - narrowing from uint32_t + + // 16-bit boundary field tests + l1.m4 = 65535; // COMPLIANT - value fits in 16 bits + l1.m4 = 65536; // NON_COMPLIANT - value does not fit in 16 bits + l1.m4 = u8; // COMPLIANT - widening from uint8_t + l1.m4 = u16; // COMPLIANT - same width as uint16_t + l1.m4 = u32; // NON_COMPLIANT - narrowing from uint32_t + + // 17-bit boundary + 1 field tests + l1.m5 = 131071; // COMPLIANT - value fits in 17 bits + l1.m5 = 131072; // NON_COMPLIANT - value does not fit in 17 bits + l1.m5 = u8; // COMPLIANT - widening from uint8_t + l1.m5 = u16; // COMPLIANT - widening from uint16_t + l1.m5 = u32; // COMPLIANT + l1.m5 = u64; // NON_COMPLIANT - narrowing from uint64_t + + // 32-bit boundary field tests + l1.m6 = 4294967295U; // COMPLIANT - value fits in 32 bits + l1.m6 = 4294967296UL; // NON_COMPLIANT - value does not fit in 32 bits + l1.m6 = u8; // COMPLIANT - widening from uint8_t + l1.m6 = u16; // COMPLIANT - widening from uint16_t + l1.m6 = u32; // COMPLIANT - same width as uint32_t + l1.m6 = u64; // NON_COMPLIANT - narrowing from uint64_t + + // 33-bit boundary + 1 field tests + l1.m7 = 8589934591ULL; // COMPLIANT + l1.m7 = 8589934592L; // NON_COMPLIANT - value does not fit in 33 bits + l1.m7 = 8589934592ULL; // COMPLIANT - integer constant does not satisfy + // conditions, but the type matches the deduced type of + // the bitfield (unsigned long long), so is considered + // compliant by the rule(!) + l1.m7 = u8; // COMPLIANT - widening from uint8_t + l1.m7 = u16; // COMPLIANT - widening from uint16_t + l1.m7 = u32; // COMPLIANT - widening from uint32_t + l1.m7 = u64; // COMPLIANT - narrowing from uint64_t + + // Signed bitfield tests + l1.m8 = 15; // COMPLIANT + l1.m8 = -16; // COMPLIANT + l1.m8 = 16; // NON_COMPLIANT - value does not fit in signed 5-bit type + l1.m8 = -17; // NON_COMPLIANT - value does not fit in signed 5-bit type + l1.m8 = s8; // COMPLIANT - same width as int8_t + l1.m8 = s16; // NON_COMPLIANT - narrowing from int16_t + + l1.m9 = 2047; // COMPLIANT - value fits in signed 12-bit type + l1.m9 = -2048; // COMPLIANT - value fits in signed 12-bit type + l1.m9 = 2048; // NON_COMPLIANT - value does not fit in signed 12-bit type + l1.m9 = -2049; // NON_COMPLIANT - value does not fit in signed 12-bit type + l1.m9 = s8; // COMPLIANT - widening from int8_t + l1.m9 = s16; // COMPLIANT - same width as int16_t + l1.m9 = s32; // NON_COMPLIANT - narrowing from int32_t + + l1.m10 = 134217727; // COMPLIANT - value fits in signed 28-bit type + l1.m10 = -134217728; // COMPLIANT - value fits in signed 28-bit type + l1.m10 = 134217728LL; // NON_COMPLIANT - does not fit in signed 28-bit type + l1.m10 = -134217729LL; // NON_COMPLIANT - does not fit in signed 28-bit type + l1.m10 = s8; // COMPLIANT - widening from int8_t + l1.m10 = s16; // COMPLIANT - widening from int16_t + l1.m10 = s32; // COMPLIANT } // Test enums From 01b517d3c8b05348871c7b81490ef78b6f713181 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 18 Jun 2025 10:17:32 +0100 Subject: [PATCH 447/628] StandardConversions: Improve detection of numeric type category - Exclude booleans and chars from our determination of numeric types. - Deduplicate integer types deduced for bitfields - identifying a canonical set of integer types. --- .../cpp/misra/StandardConversions.qll | 108 ++++++++++++++---- .../NumericAssignmentTypeMismatch.expected | 22 ---- 2 files changed, 85 insertions(+), 45 deletions(-) diff --git a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll index 944f90f278..287eb44094 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll @@ -2,21 +2,65 @@ import cpp import codingstandards.cpp.misra /** - * The signedness of a numeric type. + * A MISRA C++ 2023 type category. */ -newtype Signedness = - Signed() or - Unsigned() +newtype TypeCategory = + Integral() or + FloatingPoint() or + Character() or + Other() /** - * The type category of a numeric type - either integral or floating-point. + * Gets the type category of a built-in type. + * + * This does not apply the rules related to stripping specifiers or typedefs, or references. */ -newtype TypeCategory = - Integral() or - FloatingPoint() +TypeCategory getTypeCategory(BuiltInType t) { + ( + t instanceof CharType or + t instanceof WideCharType or + t instanceof Char16Type or + t instanceof Char32Type or + t instanceof Char8Type + ) and + result = Character() + or + ( + // The 5 standard integral types, covering both signed/unsigned variants + // Explicitly list the signed/unsigned `char` to avoid capturing plain `char`, which is of character type category + t instanceof SignedCharType or + t instanceof UnsignedCharType or + t instanceof ShortType or + t instanceof IntType or + t instanceof LongType or + t instanceof LongLongType + ) and + result = Integral() + or + ( + t instanceof FloatType or + t instanceof DoubleType or + t instanceof LongDoubleType + ) and + result = FloatingPoint() + or + ( + t instanceof BoolType or + t instanceof VoidType or + t instanceof NullPointerType + ) and + result = Other() +} /** - * A numeric type is a type that represents a number, either an integral or a floating-point. + * The signedness of a MISRA C++ 2023 numeric type + */ +newtype Signedness = + Signed() or + Unsigned() + +/** + * A MISRA C++ 2023 numeric type is a type that represents a number, either an integral or a floating-point. * * In addition to the basic integral and floating-point types, it includes: * - Enum types with an explicit underlying type that is a numeric type. @@ -24,27 +68,32 @@ newtype TypeCategory = * - Numeric types with specifiers (e.g., `const`, `volatile`, `restrict`). */ class NumericType extends Type { + // The actual numeric type, which is either an integral or a floating-point type. Type realType; NumericType() { - realType = this.getUnspecifiedType().(ReferenceType).getBaseType().(NumericType).getRealType() or - realType = this.getUnspecifiedType().(IntegralType) or - realType = this.getUnspecifiedType().(FloatingPointType) or - realType = this.getUnspecifiedType().(Enum).getExplicitUnderlyingType().getUnspecifiedType() + // A type which is either an integral or a floating-point type category + getTypeCategory(this) = [Integral().(TypeCategory), FloatingPoint()] and + realType = this + or + // Any type which, after stripping specifiers and typedefs, is a numeric type + realType = this.getUnspecifiedType().(NumericType).getRealType() + or + // Any reference type where the base type is a numeric type + realType = this.(ReferenceType).getBaseType().(NumericType).getRealType() + or + // Any Enum type with an explicit underlying type that is a numeric type + realType = this.(Enum).getExplicitUnderlyingType().(NumericType).getRealType() } Signedness getSignedness() { if realType.(IntegralType).isUnsigned() then result = Unsigned() else result = Signed() } - /** Gets the size of the actual numeric type */ + /** Gets the size of the actual numeric type. */ int getRealSize() { result = realType.getSize() } - TypeCategory getTypeCategory() { - realType instanceof IntegralType and result = Integral() - or - realType instanceof FloatingPointType and result = FloatingPoint() - } + TypeCategory getTypeCategory() { result = getTypeCategory(realType) } float getUpperBound() { result = typeUpperBound(realType) } @@ -53,6 +102,13 @@ class NumericType extends Type { Type getRealType() { result = realType } } +/** + * One of the 10 canonical integer types, which are the standard integer types. + */ +class CanonicalIntegerTypes extends NumericType, IntegralType { + CanonicalIntegerTypes() { this = this.getCanonicalArithmeticType() } +} + predicate isAssignment(Expr source, NumericType targetType, string context) { // Assignment expression (which excludes compound assignments) exists(AssignExpr assign | @@ -119,18 +175,24 @@ predicate isAssignment(Expr source, NumericType targetType, string context) { * * The type is determined by the signedness of the bit field and the number of bits. */ -NumericType getBitFieldType(BitField bf) { +CanonicalIntegerTypes getBitFieldType(BitField bf) { exists(NumericType bitfieldActualType | bitfieldActualType = bf.getType() and // Integral type with the same signedness as the bit field, and big enough to hold the bit field value - result instanceof IntegralType and result.getSignedness() = bitfieldActualType.getSignedness() and result.getSize() * 8 >= bf.getNumBits() and // No smaller integral type can hold the bit field value - not exists(IntegralType other | + not exists(CanonicalIntegerTypes other | other.getSize() * 8 >= bf.getNumBits() and - other.(NumericType).getSignedness() = result.getSignedness() and + other.getSignedness() = result.getSignedness() + | other.getSize() < result.getRealSize() + or + // Where multiple types exist with the same size and signedness, prefer shorter names - mainly + // to disambiguate between `unsigned long` and `unsigned long long` on platforms where they + // are the same size + other.getSize() = result.getRealSize() and + other.getName().length() < result.getName().length() ) ) } diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index 4159b78b2d..19518bf1fa 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -30,37 +30,15 @@ | test.cpp:168:11:168:13 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'unsigned int'. | | test.cpp:172:11:172:22 | 4294967296 | Assignment between incompatible numeric types from 'unsigned long' to 'unsigned int'. | | test.cpp:176:11:176:13 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'unsigned int'. | -| test.cpp:180:11:180:21 | 8589934592 | Assignment between incompatible numeric types from 'long' to 'unsigned long long'. | | test.cpp:180:11:180:21 | 8589934592 | Assignment between incompatible numeric types from 'long' to 'unsigned long'. | -| test.cpp:193:11:193:12 | 16 | Assignment between incompatible numeric types from 'int32_t' to 'bool'. | -| test.cpp:193:11:193:12 | 16 | Assignment between incompatible numeric types from 'int32_t' to 'char8_t'. | -| test.cpp:193:11:193:12 | 16 | Assignment between incompatible numeric types from 'int32_t' to 'char'. | | test.cpp:193:11:193:12 | 16 | Assignment between incompatible numeric types from 'int32_t' to 'signed char'. | -| test.cpp:194:11:194:13 | - ... | Assignment between incompatible numeric types from 'int' to 'bool'. | -| test.cpp:194:11:194:13 | - ... | Assignment between incompatible numeric types from 'int' to 'char8_t'. | -| test.cpp:194:11:194:13 | - ... | Assignment between incompatible numeric types from 'int' to 'char'. | | test.cpp:194:11:194:13 | - ... | Assignment between incompatible numeric types from 'int' to 'signed char'. | -| test.cpp:196:11:196:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'bool'. | -| test.cpp:196:11:196:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'char8_t'. | -| test.cpp:196:11:196:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'char'. | | test.cpp:196:11:196:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'signed char'. | -| test.cpp:200:11:200:14 | 2048 | Assignment between incompatible numeric types from 'int32_t' to 'char16_t'. | | test.cpp:200:11:200:14 | 2048 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | -| test.cpp:200:11:200:14 | 2048 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | -| test.cpp:201:11:201:15 | - ... | Assignment between incompatible numeric types from 'int' to 'char16_t'. | | test.cpp:201:11:201:15 | - ... | Assignment between incompatible numeric types from 'int' to 'short'. | -| test.cpp:201:11:201:15 | - ... | Assignment between incompatible numeric types from 'int' to 'signed short'. | -| test.cpp:204:11:204:13 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'char16_t'. | | test.cpp:204:11:204:13 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | -| test.cpp:204:11:204:13 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | -| test.cpp:208:12:208:22 | 134217728 | Assignment between incompatible numeric types from 'long long' to 'char32_t'. | | test.cpp:208:12:208:22 | 134217728 | Assignment between incompatible numeric types from 'long long' to 'int'. | -| test.cpp:208:12:208:22 | 134217728 | Assignment between incompatible numeric types from 'long long' to 'signed int'. | -| test.cpp:208:12:208:22 | 134217728 | Assignment between incompatible numeric types from 'long long' to 'wchar_t'. | -| test.cpp:209:12:209:23 | - ... | Assignment between incompatible numeric types from 'long long' to 'char32_t'. | | test.cpp:209:12:209:23 | - ... | Assignment between incompatible numeric types from 'long long' to 'int'. | -| test.cpp:209:12:209:23 | - ... | Assignment between incompatible numeric types from 'long long' to 'signed int'. | -| test.cpp:209:12:209:23 | - ... | Assignment between incompatible numeric types from 'long long' to 'wchar_t'. | | test.cpp:224:8:224:9 | l1 | Assignment between incompatible numeric types from 'Colour' to 'uint8_t'. | | test.cpp:234:6:234:8 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'int64_t'. | | test.cpp:237:6:237:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | From 06eddfaa9aceefddaf6af67e9fbbbeaffe2fb572 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 18 Jun 2025 10:30:19 +0100 Subject: [PATCH 448/628] Rule 7.0.6: Add a test case for non-numeric (not covered) --- .../rules/RULE-7-0-6/test_non_numeric.cpp | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 cpp/misra/test/rules/RULE-7-0-6/test_non_numeric.cpp diff --git a/cpp/misra/test/rules/RULE-7-0-6/test_non_numeric.cpp b/cpp/misra/test/rules/RULE-7-0-6/test_non_numeric.cpp new file mode 100644 index 0000000000..3da5c21c81 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/test_non_numeric.cpp @@ -0,0 +1,138 @@ +#include +#include + +// Test non-numeric type categories - these should not trigger rule violations +void test_non_numeric_type_categories() { + // Character category types + char l1 = 'a'; + wchar_t l2 = L'b'; + char16_t l3 = u'c'; + char32_t l4 = U'd'; + + // Other category types + bool l5 = true; + void *l6 = nullptr; + std::nullptr_t l7 = nullptr; + + // Assignments between character types and numeric types + // Rule should not apply since source/target involve non-numeric types + std::uint8_t l8 = 42; + std::int32_t l9 = 100; + float l10 = 3.14f; + + // Character to numeric - rule does not apply + l8 = l1; // COMPLIANT - char is character category, not numeric + l9 = l2; // COMPLIANT - wchar_t is character category, not numeric + l8 = l3; // COMPLIANT - char16_t is character category, not numeric + l9 = l4; // COMPLIANT - char32_t is character category, not numeric + l10 = l1; // COMPLIANT - char is character category, not numeric + + // Numeric to character - rule does not apply + l1 = l8; // COMPLIANT - char is character category, not numeric + l2 = l9; // COMPLIANT - wchar_t is character category, not numeric + l3 = l8; // COMPLIANT - char16_t is character category, not numeric + l4 = l9; // COMPLIANT - char32_t is character category, not numeric + l1 = l10; // COMPLIANT - char is character category, not numeric + + // Other category to numeric - rule does not apply + l8 = l5; // COMPLIANT - bool is other category, not numeric + l9 = l5; // COMPLIANT - bool is other category, not numeric + l10 = l5; // COMPLIANT - bool is other category, not numeric + + // Numeric to other category - rule does not apply + l5 = l8; // COMPLIANT - bool is other category, not numeric + l5 = l9; // COMPLIANT - bool is other category, not numeric + l5 = l10; // COMPLIANT - bool is other category, not numeric + + // Character to character - rule does not apply + l1 = l2; // COMPLIANT - both character category, not numeric + l3 = l4; // COMPLIANT - both character category, not numeric + l1 = l3; // COMPLIANT - both character category, not numeric + + // Other to other - rule does not apply + std::nullptr_t l11 = l7; // COMPLIANT - both other category, not numeric + l6 = l7; // COMPLIANT - both other category, not numeric + + // Character to other - rule does not apply + l5 = l1; // COMPLIANT - neither is numeric category + l6 = nullptr; // COMPLIANT - neither is numeric category + + // Other to character - rule does not apply + l1 = l5; // COMPLIANT - neither is numeric category +} + +// Test function parameters with non-numeric types +void f15(char l1) {} +void f16(bool l1) {} +void f17(wchar_t l1) {} + +void test_non_numeric_function_parameters() { + std::uint8_t l1 = 42; + std::int32_t l2 = 100; + char l3 = 'x'; + bool l4 = true; + wchar_t l5 = L'y'; + + // Function calls with non-numeric parameters - rule does not apply + f15(l1); // COMPLIANT - parameter is character category, not numeric + f15(l2); // COMPLIANT - parameter is character category, not numeric + f15(l3); // COMPLIANT - parameter is character category, not numeric + + f16(l1); // COMPLIANT - parameter is other category, not numeric + f16(l2); // COMPLIANT - parameter is other category, not numeric + f16(l4); // COMPLIANT - parameter is other category, not numeric + + f17(l1); // COMPLIANT - parameter is character category, not numeric + f17(l2); // COMPLIANT - parameter is character category, not numeric + f17(l5); // COMPLIANT - parameter is character category, not numeric +} + +// Test references to non-numeric types +void test_non_numeric_references() { + char l1 = 'a'; + bool l2 = true; + wchar_t l3 = L'b'; + std::uint8_t l4 = 42; + std::int32_t l5 = 100; + + char &l6 = l1; + bool &l7 = l2; + wchar_t &l8 = l3; + + // Assignments involving references to non-numeric types - rule does not apply + l4 = l6; // COMPLIANT - reference to character category, not numeric + l5 = l7; // COMPLIANT - reference to other category, not numeric + l4 = l8; // COMPLIANT - reference to character category, not numeric + + l6 = l4; // COMPLIANT - reference to character category, not numeric + l7 = l5; // COMPLIANT - reference to other category, not numeric + l8 = l4; // COMPLIANT - reference to character category, not numeric +} + +// Test bit-fields with non-numeric types (though these are rare in practice) +struct NonNumericBitFields { + bool m1 : 1; // Other category + char m2 : 7; // Character category + wchar_t m3 : 16; // Character category +}; + +void test_non_numeric_bitfields() { + NonNumericBitFields l1; + std::uint8_t l2 = 42; + std::int32_t l3 = 100; + bool l4 = true; + char l5 = 'x'; + + // Assignments to/from non-numeric bit-fields - rule does not apply + l1.m1 = l2; // COMPLIANT - bit-field is other category, not numeric + l1.m1 = l4; // COMPLIANT - bit-field is other category, not numeric + l1.m2 = l2; // COMPLIANT - bit-field is character category, not numeric + l1.m2 = l5; // COMPLIANT - bit-field is character category, not numeric + l1.m3 = l3; // COMPLIANT - bit-field is character category, not numeric + + l2 = l1.m1; // COMPLIANT - bit-field is other category, not numeric + l4 = l1.m1; // COMPLIANT - bit-field is other category, not numeric + l2 = l1.m2; // COMPLIANT - bit-field is character category, not numeric + l5 = l1.m2; // COMPLIANT - bit-field is character category, not numeric + l3 = l1.m3; // COMPLIANT - bit-field is character category, not numeric +} \ No newline at end of file From a65c4cce47dde7b2176bda68917a99f43654320e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 18 Jun 2025 11:07:37 +0100 Subject: [PATCH 449/628] StandardConversions: Handle aggregate initialization --- .../cpp/misra/StandardConversions.qll | 27 +++-- .../NumericAssignmentTypeMismatch.expected | 33 +++++++ cpp/misra/test/rules/RULE-7-0-6/test.cpp | 99 +++++++++++++++++++ 3 files changed, 153 insertions(+), 6 deletions(-) diff --git a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll index 287eb44094..76ee93f2ae 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll @@ -168,6 +168,26 @@ predicate isAssignment(Expr source, NumericType targetType, string context) { targetType = switch.getExpr().getFullyConverted().getType() and context = "switch case" ) + or + // Class aggregate literal initialization + exists(ClassAggregateLiteral al, Field f | + source = al.getAFieldExpr(f) and + context = "class aggregate literal" + | + // For the MISRA type rules we treat bit fields as a special case + if f instanceof BitField + then targetType = getBitFieldType(f) + else + // Regular variable initialization + targetType = f.getType() + ) + or + // Array or vector aggregate literal initialization + exists(ArrayOrVectorAggregateLiteral vl | + source = vl.getAnElementExpr(_) and + targetType = vl.getElementType() and + context = "array or vector aggregate literal" + ) } /** @@ -200,9 +220,4 @@ CanonicalIntegerTypes getBitFieldType(BitField bf) { /** * Holds if the `source` expression is assigned to a bit field. */ -predicate isAssignedToBitfield(Expr source, BitField bf) { - exists(Assignment assign | - assign.getRValue() = source and - assign.getLValue() = bf.getAnAccess() - ) -} +predicate isAssignedToBitfield(Expr source, BitField bf) { source = bf.getAnAssignedValue() } diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index 19518bf1fa..8f9cbfe24c 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -137,3 +137,36 @@ | test.cpp:766:8:766:10 | 42 | Assignment between incompatible numeric types from 'long' to 'int32_t'. | | test.cpp:767:8:767:11 | 42 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | | test.cpp:768:8:768:10 | 42 | Assignment between incompatible numeric types from 'unsigned int' to 'int32_t'. | +| test.cpp:786:22:786:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test.cpp:788:26:788:28 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | +| test.cpp:790:31:790:33 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:792:22:792:24 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test.cpp:795:22:795:24 | 256 | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:795:27:795:31 | 65536 | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | +| test.cpp:796:22:796:33 | 2147483648 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | +| test.cpp:808:22:808:24 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test.cpp:808:27:808:29 | 400 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test.cpp:808:32:808:34 | 500 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test.cpp:809:22:809:23 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | +| test.cpp:809:26:809:27 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | +| test.cpp:809:30:809:31 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | +| test.cpp:810:22:810:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:810:27:810:29 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:810:32:810:34 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:815:26:815:28 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test.cpp:815:31:815:33 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test.cpp:815:38:815:40 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test.cpp:815:43:815:45 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test.cpp:816:26:816:27 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test.cpp:816:30:816:31 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test.cpp:817:26:817:27 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test.cpp:817:30:817:31 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test.cpp:833:8:833:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test.cpp:837:7:837:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | +| test.cpp:853:24:853:26 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test.cpp:853:29:853:33 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test.cpp:853:36:853:39 | 5000 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test.cpp:854:24:854:26 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:854:29:854:31 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | +| test.cpp:854:34:854:36 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test.cpp:864:28:864:30 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index 740129a4b8..f74ce3050c 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -766,4 +766,103 @@ void test_user_defined_operators_constants() { l1 = 42L; // NON_COMPLIANT l1 = 42LL; // NON_COMPLIANT l1 = 42U; // NON_COMPLIANT +} + +// Test aggregate initialization - struct with multiple members +struct SimpleAggregate { + std::uint8_t m1; + std::uint16_t m2; + std::int32_t m3; + float m4; +}; + +void test_aggregate_initialization_basic() { + // Compliant cases - exact types or constants that fit + SimpleAggregate l1{42, 1000, -50, 3.14f}; // COMPLIANT + SimpleAggregate l2{u8, u16, s32, f}; // COMPLIANT + SimpleAggregate l3{255, 65535, 2147483647, 0.0f}; // COMPLIANT + + // Non-compliant cases - type violations + SimpleAggregate l4{u16, u8, s32, // NON_COMPLIANT - narrowing u16 to uint8_t + f}; + SimpleAggregate l5{u8, u32, s32, // NON_COMPLIANT - narrowing u32 to uint16_t + f}; + SimpleAggregate l6{u8, u16, u32, f}; // NON_COMPLIANT - different signedness + SimpleAggregate l7{u8, u16, s32, + s32}; // NON_COMPLIANT - different type category + + // Constants that don't fit + SimpleAggregate l8{256, 65536, // NON_COMPLIANT - constants don't fit + 2147483648LL, // NON_COMPLIANT - constants don't fit + 0.0f}; + + // Widening of id-expressions is allowed + SimpleAggregate l9{u8, u8, s8, f}; // COMPLIANT - widening allowed +} + +// Test aggregate initialization - arrays +void test_aggregate_initialization_arrays() { + // Basic arrays + std::uint8_t l1[3]{10, 20, 30}; // COMPLIANT + std::uint8_t l2[3]{u8, u8, u8}; // COMPLIANT + std::uint8_t l3[3]{300, 400, 500}; // NON_COMPLIANT - constants don't fit + std::uint8_t l4[3]{s8, s8, s8}; // NON_COMPLIANT - signedness mismatch + std::uint8_t l5[3]{u16, u16, u16}; // NON_COMPLIANT - narrowing + + // Multi-dimensional arrays + std::int16_t l6[2][2]{{1, 2}, {3, 4}}; // COMPLIANT + std::int16_t l7[2][2]{{s8, s8}, {s8, s8}}; // COMPLIANT - widening allowed + std::int16_t l8[2][2]{{s32, s32}, {s32, s32}}; // NON_COMPLIANT - narrowing + std::int16_t l9[2][2]{{u8, u8}, // NON_COMPLIANT - signedness mismatch + {u8, u8}}; // NON_COMPLIANT - signedness mismatch +} + +// Test aggregate initialization - nested structs +struct NestedAggregate { + SimpleAggregate m1; + std::uint32_t m2; +}; + +void test_aggregate_initialization_nested() { + // Compliant nested initialization + NestedAggregate l1{{10, 100, -5, 1.0f}, 500}; // COMPLIANT + NestedAggregate l2{{u8, u16, s32, f}, u32}; // COMPLIANT + + // Non-compliant nested initialization + NestedAggregate l3{ + {u16, u8, s32, f}, // NON_COMPLIANT - narrowing in nested struct + u32}; + NestedAggregate l4{ + {u8, u16, s32, f}, + s32}; // NON_COMPLIANT - signedness mismatch in outer member +} + +// Test aggregate initialization - struct with bit-fields +struct BitfieldAggregate { + std::uint32_t m1 : 8; + std::uint32_t m2 : 16; + std::int32_t m3 : 12; +}; + +void test_aggregate_initialization_bitfields() { + // Compliant cases + BitfieldAggregate l1{100, 30000, -500}; // COMPLIANT + BitfieldAggregate l2{u8, u16, s16}; // COMPLIANT - appropriate sizes + + // Non-compliant cases + BitfieldAggregate l3{300, 70000, 5000}; // NON_COMPLIANT - constants don't fit + BitfieldAggregate l4{u16, u32, s32}; // NON_COMPLIANT - narrowing +} + +// Test aggregate initialization with designated initializers (C++20 feature, +// but test for basic cases) +void test_aggregate_initialization_designated() { + // Note: Designated initializers are C++20, but we can test basic aggregate + // init patterns + SimpleAggregate l1{.m1 = 10, .m2 = 100, .m3 = -5, .m4 = 1.0f}; // COMPLIANT + SimpleAggregate l2{.m1 = u8, .m2 = u16, .m3 = s32, .m4 = f}; // COMPLIANT + SimpleAggregate l3{.m1 = u16, // NON_COMPLIANT - type violation + .m2 = u8, + .m3 = s32, + .m4 = f}; } \ No newline at end of file From 4006b7c5bd4e581865c8134dd4bfa40b210f83d0 Mon Sep 17 00:00:00 2001 From: lcartey <5377966+lcartey@users.noreply.github.com> Date: Thu, 19 Jun 2025 10:05:13 +0000 Subject: [PATCH 450/628] Upgrading `github/codeql` dependency to 2.20.7 --- c/cert/src/codeql-pack.lock.yml | 20 +++++++++---------- c/cert/src/qlpack.yml | 2 +- c/cert/test/codeql-pack.lock.yml | 20 +++++++++---------- c/common/src/codeql-pack.lock.yml | 20 +++++++++---------- c/common/src/qlpack.yml | 2 +- c/common/test/codeql-pack.lock.yml | 20 +++++++++---------- c/misra/src/codeql-pack.lock.yml | 20 +++++++++---------- c/misra/src/qlpack.yml | 2 +- c/misra/test/codeql-pack.lock.yml | 20 +++++++++---------- cpp/autosar/src/codeql-pack.lock.yml | 20 +++++++++---------- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/codeql-pack.lock.yml | 20 +++++++++---------- cpp/cert/src/codeql-pack.lock.yml | 20 +++++++++---------- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/codeql-pack.lock.yml | 20 +++++++++---------- cpp/common/src/codeql-pack.lock.yml | 20 +++++++++---------- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/codeql-pack.lock.yml | 20 +++++++++---------- cpp/misra/src/codeql-pack.lock.yml | 20 +++++++++---------- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/codeql-pack.lock.yml | 20 +++++++++---------- cpp/report/src/codeql-pack.lock.yml | 20 +++++++++---------- cpp/report/src/qlpack.yml | 2 +- .../queries/codeql-pack.lock.yml | 20 +++++++++---------- scripts/generate_modules/queries/qlpack.yml | 2 +- supported_codeql_configs.json | 6 +++--- 26 files changed, 172 insertions(+), 172 deletions(-) diff --git a/c/cert/src/codeql-pack.lock.yml b/c/cert/src/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/c/cert/src/codeql-pack.lock.yml +++ b/c/cert/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index d2ba0816a3..732a855928 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -6,4 +6,4 @@ license: MIT default-suite-file: codeql-suites/cert-c-default.qls dependencies: codeql/common-c-coding-standards: '*' - codeql/cpp-all: 2.1.1 + codeql/cpp-all: 4.0.3 diff --git a/c/cert/test/codeql-pack.lock.yml b/c/cert/test/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/c/cert/test/codeql-pack.lock.yml +++ b/c/cert/test/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/c/common/src/codeql-pack.lock.yml b/c/common/src/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/c/common/src/codeql-pack.lock.yml +++ b/c/common/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 4bbcb5c730..f59d784995 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -3,4 +3,4 @@ version: 2.48.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' - codeql/cpp-all: 2.1.1 + codeql/cpp-all: 4.0.3 diff --git a/c/common/test/codeql-pack.lock.yml b/c/common/test/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/c/common/test/codeql-pack.lock.yml +++ b/c/common/test/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/c/misra/src/codeql-pack.lock.yml b/c/misra/src/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/c/misra/src/codeql-pack.lock.yml +++ b/c/misra/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 02f9dceb48..a10b00fb51 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -6,4 +6,4 @@ license: MIT default-suite-file: codeql-suites/misra-c-default.qls dependencies: codeql/common-c-coding-standards: '*' - codeql/cpp-all: 2.1.1 + codeql/cpp-all: 4.0.3 diff --git a/c/misra/test/codeql-pack.lock.yml b/c/misra/test/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/c/misra/test/codeql-pack.lock.yml +++ b/c/misra/test/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/cpp/autosar/src/codeql-pack.lock.yml b/cpp/autosar/src/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/cpp/autosar/src/codeql-pack.lock.yml +++ b/cpp/autosar/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index 65ec603f59..2352408016 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -5,4 +5,4 @@ suites: codeql-suites license: MIT dependencies: codeql/common-cpp-coding-standards: '*' - codeql/cpp-all: 2.1.1 + codeql/cpp-all: 4.0.3 diff --git a/cpp/autosar/test/codeql-pack.lock.yml b/cpp/autosar/test/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/cpp/autosar/test/codeql-pack.lock.yml +++ b/cpp/autosar/test/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/cpp/cert/src/codeql-pack.lock.yml b/cpp/cert/src/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/cpp/cert/src/codeql-pack.lock.yml +++ b/cpp/cert/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 999faded05..4c74256dc9 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -5,5 +5,5 @@ suites: codeql-suites license: MIT default-suite-file: codeql-suites/cert-cpp-default.qls dependencies: - codeql/cpp-all: 2.1.1 + codeql/cpp-all: 4.0.3 codeql/common-cpp-coding-standards: '*' diff --git a/cpp/cert/test/codeql-pack.lock.yml b/cpp/cert/test/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/cpp/cert/test/codeql-pack.lock.yml +++ b/cpp/cert/test/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/cpp/common/src/codeql-pack.lock.yml b/cpp/common/src/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/cpp/common/src/codeql-pack.lock.yml +++ b/cpp/common/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index f7938fef71..c62e045962 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -2,6 +2,6 @@ name: codeql/common-cpp-coding-standards version: 2.48.0-dev license: MIT dependencies: - codeql/cpp-all: 2.1.1 + codeql/cpp-all: 4.0.3 dataExtensions: - ext/*.model.yml diff --git a/cpp/common/test/codeql-pack.lock.yml b/cpp/common/test/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/cpp/common/test/codeql-pack.lock.yml +++ b/cpp/common/test/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/cpp/misra/src/codeql-pack.lock.yml b/cpp/misra/src/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/cpp/misra/src/codeql-pack.lock.yml +++ b/cpp/misra/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index f6a4e21428..2c9262fd10 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -5,4 +5,4 @@ default-suite: codeql-suites/misra-cpp-default.qls license: MIT dependencies: codeql/common-cpp-coding-standards: '*' - codeql/cpp-all: 2.1.1 + codeql/cpp-all: 4.0.3 diff --git a/cpp/misra/test/codeql-pack.lock.yml b/cpp/misra/test/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/cpp/misra/test/codeql-pack.lock.yml +++ b/cpp/misra/test/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/cpp/report/src/codeql-pack.lock.yml b/cpp/report/src/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/cpp/report/src/codeql-pack.lock.yml +++ b/cpp/report/src/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index c8a6dd08f8..268820cc33 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -2,4 +2,4 @@ name: codeql/report-cpp-coding-standards version: 2.48.0-dev license: MIT dependencies: - codeql/cpp-all: 2.1.1 + codeql/cpp-all: 4.0.3 diff --git a/scripts/generate_modules/queries/codeql-pack.lock.yml b/scripts/generate_modules/queries/codeql-pack.lock.yml index ab9a39f9c1..a45ea8f438 100644 --- a/scripts/generate_modules/queries/codeql-pack.lock.yml +++ b/scripts/generate_modules/queries/codeql-pack.lock.yml @@ -2,23 +2,23 @@ lockVersion: 1.0.0 dependencies: codeql/cpp-all: - version: 2.1.1 + version: 4.0.3 codeql/dataflow: - version: 1.1.6 + version: 2.0.3 codeql/mad: - version: 1.0.12 + version: 1.0.19 codeql/rangeanalysis: - version: 1.0.12 + version: 1.0.19 codeql/ssa: - version: 1.0.12 + version: 1.0.19 codeql/tutorial: - version: 1.0.12 + version: 1.0.19 codeql/typeflow: - version: 1.0.12 + version: 1.0.19 codeql/typetracking: - version: 1.0.12 + version: 2.0.3 codeql/util: - version: 1.0.12 + version: 2.0.6 codeql/xml: - version: 1.0.12 + version: 1.0.19 compiled: false diff --git a/scripts/generate_modules/queries/qlpack.yml b/scripts/generate_modules/queries/qlpack.yml index d2c729dfb9..9aabee2562 100644 --- a/scripts/generate_modules/queries/qlpack.yml +++ b/scripts/generate_modules/queries/qlpack.yml @@ -2,4 +2,4 @@ name: codeql/standard-library-extraction-cpp-coding-standards version: 0.0.0 license: MIT dependencies: - codeql/cpp-all: 2.1.1 + codeql/cpp-all: 4.0.3 diff --git a/supported_codeql_configs.json b/supported_codeql_configs.json index 77534bd53d..9b89dd849e 100644 --- a/supported_codeql_configs.json +++ b/supported_codeql_configs.json @@ -1,9 +1,9 @@ { "supported_environment": [ { - "codeql_cli": "2.19.4", - "codeql_standard_library": "codeql-cli/v2.19.4", - "codeql_cli_bundle": "codeql-bundle-v2.19.4" + "codeql_cli": "2.20.7", + "codeql_standard_library": "codeql-cli/v2.20.7", + "codeql_cli_bundle": "codeql-bundle-v2.20.7" } ], "supported_language": [ From 04613cd353c86fa94dacf6ef2a98b668b400b975 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Jun 2025 13:32:53 +0100 Subject: [PATCH 451/628] Add a library for determining constant expressions The `getValue()` provided in the database applies the conversions, which can be unhelpful when trying to write rules the refer to conversions. --- .../cpp/ConstantExpressions.qll | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/ConstantExpressions.qll diff --git a/cpp/common/src/codingstandards/cpp/ConstantExpressions.qll b/cpp/common/src/codingstandards/cpp/ConstantExpressions.qll new file mode 100644 index 0000000000..c75df942db --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/ConstantExpressions.qll @@ -0,0 +1,97 @@ +import cpp + +final private class FinalExpr = Expr; + +/** + * An integer constant expression as defined by the C++17 standard. + */ +class IntegerConstantExpr extends FinalExpr { + IntegerConstantExpr() { + // An integer constant expression is a constant expression that has an + // integral type. + this.isConstant() and + exists(Type unspecifiedType | unspecifiedType = this.getUnspecifiedType() | + unspecifiedType instanceof IntegralType + or + // Unscoped enum type + unspecifiedType instanceof Enum and + not unspecifiedType instanceof ScopedEnum + ) + } + + /** + * Gets the value of this integer constant expression. + * + * This is only defined for expressions that are constant expressions, and + * that have a value that can be represented as a `BigInt`. + */ + QlBuiltins::BigInt getConstantValue() { + if exists(getPreConversionConstantValue()) + then result = getPreConversionConstantValue() + else result = this.getValue().toBigInt() + } + + /** + * Gets the pre-conversion constant value of this integer constant expression, if it is different + * from `getValue()`. + * + * This is required because `Expr.getValue()` returns the _converted constant expression value_ + * for non-literal constant expressions, which is the expression value after conversions have been + * applied, but for validating conversions we need the _pre-conversion constant expression value_. + */ + private QlBuiltins::BigInt getPreConversionConstantValue() { + // Access of a variable that has a constant initializer + result = + this.(VariableAccess) + .getTarget() + .getInitializer() + .getExpr() + .getFullyConverted() + .getValue() + .toBigInt() + or + result = this.(EnumConstantAccess).getTarget().getValue().toBigInt() + or + result = -this.(UnaryMinusExpr).getOperand().getFullyConverted().getValue().toBigInt() + or + result = this.(UnaryPlusExpr).getOperand().getFullyConverted().getValue().toBigInt() + or + result = this.(NotExpr).getOperand().getFullyConverted().getValue().toBigInt().bitNot() + or + exists(BinaryOperation op, QlBuiltins::BigInt left, QlBuiltins::BigInt right | + op = this and + left = op.getLeftOperand().getFullyConverted().getValue().toBigInt() and + right = op.getRightOperand().getFullyConverted().getValue().toBigInt() + | + op instanceof AddExpr and + result = left + right + or + op instanceof SubExpr and + result = left - right + or + op instanceof MulExpr and + result = left * right + or + op instanceof DivExpr and + result = left / right + or + op instanceof RemExpr and + result = left % right + or + op instanceof BitwiseAndExpr and + result = left.bitAnd(right) + or + op instanceof BitwiseOrExpr and + result = left.bitOr(right) + or + op instanceof BitwiseXorExpr and + result = left.bitXor(right) + or + op instanceof RShiftExpr and + result = left.bitShiftRightSigned(right.toInt()) + or + op instanceof LShiftExpr and + result = left.bitShiftLeft(right.toInt()) + ) + } +} From 4be1395529e7eb6fd515f4c5dae02b2f7df2fab0 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Jun 2025 13:38:58 +0100 Subject: [PATCH 452/628] Rule 7.0.6: Use BigInt for constant expressions - Use IntegerConstantExpr to determine both the expressions which are constant, and the BigInt value of those constants (before final conversion). - Implement a BigInt type upper/lower bound to determine whether a constant assignment is valid. --- .../src/codingstandards/cpp/types/Type.qll | 17 ++++++++++++ .../cpp/misra/StandardConversions.qll | 11 ++++++-- .../NumericAssignmentTypeMismatch.ql | 27 +++++++++++-------- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/types/Type.qll b/cpp/common/src/codingstandards/cpp/types/Type.qll index 42d77b8055..9e2a74904b 100644 --- a/cpp/common/src/codingstandards/cpp/types/Type.qll +++ b/cpp/common/src/codingstandards/cpp/types/Type.qll @@ -94,3 +94,20 @@ int getPrecision(IntegralType type) { or type.isExplicitlySigned() and result = type.getSize() * 8 - 1 } + +/** + * Determines the lower and upper bounds of an integral type. + */ +predicate integralTypeBounds(IntegralType integralType, QlBuiltins::BigInt lb, QlBuiltins::BigInt ub) { + exists(QlBuiltins::BigInt limit | limit = 2.toBigInt().pow(8 * integralType.getSize()) | + if integralType instanceof BoolType + then lb = 0.toBigInt() and ub = 1.toBigInt() + else + if integralType.isSigned() + then ( + lb = -(limit / 2.toBigInt()) and ub = (limit / 2.toBigInt()) - 1.toBigInt() + ) else ( + lb = 0.toBigInt() and ub = limit - 1.toBigInt() + ) + ) +} diff --git a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll index 76ee93f2ae..0f96e61204 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll @@ -1,5 +1,6 @@ import cpp import codingstandards.cpp.misra +import codingstandards.cpp.Type /** * A MISRA C++ 2023 type category. @@ -95,9 +96,15 @@ class NumericType extends Type { TypeCategory getTypeCategory() { result = getTypeCategory(realType) } - float getUpperBound() { result = typeUpperBound(realType) } + /** + * Gets the integeral upper bound of the numeric type, if it represents an integer type. + */ + QlBuiltins::BigInt getIntegralUpperBound() { integralTypeBounds(realType, _, result) } - float getLowerBound() { result = typeLowerBound(realType) } + /** + * Gets the integeral lower bound of the numeric type, if it represents an integer type. + */ + QlBuiltins::BigInt getIntegralLowerBound() { integralTypeBounds(realType, result, _) } Type getRealType() { result = realType } } diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index 23409abcb3..60b661911c 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -15,14 +15,13 @@ import cpp import codingstandards.cpp.misra +import codingstandards.cpp.ConstantExpressions import codingstandards.cpp.misra.StandardConversions +import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis -predicate isValidConstantAssignment(Expr source, NumericType targetType) { +predicate isValidConstantAssignment(IntegerConstantExpr source, NumericType targetType) { isAssignment(source, targetType, _) and - // Source is an integer constant expression - source.isConstant() and - source.getType().(NumericType).getTypeCategory() = Integral() and - exists(float val | val = source.getValue().toFloat() | + exists(QlBuiltins::BigInt val | val = source.getConstantValue() | // Bit field assignment: check if the value fits in the bit field exists(BitField bf, int numBits | isAssignedToBitfield(source, bf) and @@ -30,19 +29,25 @@ predicate isValidConstantAssignment(Expr source, NumericType targetType) { if targetType.getSignedness() = Signed() then // Signed bit field: value must be in the range of signed bit field - val >= -2.pow(numBits - 1) and - val < 2.pow(numBits - 1) + val >= -2.toBigInt().pow(numBits - 1) and + val < 2.toBigInt().pow(numBits - 1) else ( // Unsigned bit field: value must be in the range of unsigned bit field - val >= 0 and - val < 2.pow(numBits) + val >= 0.toBigInt() and + val < 2.toBigInt().pow(numBits) ) ) or // Regular assignment: check if the value fits in the target type range not isAssignedToBitfield(source, _) and - targetType.getLowerBound() <= val and - val <= targetType.getUpperBound() + ( + // Integer types: check if the value fits in the target type range + targetType.getIntegralLowerBound() <= val and + val <= targetType.getIntegralUpperBound() + or + // All floating point types can represent all integer values + targetType.getTypeCategory() = FloatingPoint() + ) ) } From e87892e9e35f9ef583fba95a8f846caef55b5208 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Jun 2025 13:41:48 +0100 Subject: [PATCH 453/628] Rule 7.0.6: add tests for cv-qualified types --- .../NumericAssignmentTypeMismatch.expected | 94 +++++ .../test/rules/RULE-7-0-6/test_specified.cpp | 371 ++++++++++++++++++ 2 files changed, 465 insertions(+) create mode 100644 cpp/misra/test/rules/RULE-7-0-6/test_specified.cpp diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index 8f9cbfe24c..23665ed100 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -170,3 +170,97 @@ | test.cpp:854:29:854:31 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | | test.cpp:854:34:854:36 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | | test.cpp:864:28:864:30 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:37:8:37:9 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:38:8:38:9 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | +| test_specified.cpp:41:8:41:9 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'int8_t'. | +| test_specified.cpp:42:8:42:9 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | +| test_specified.cpp:43:9:43:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | +| test_specified.cpp:48:8:48:9 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | +| test_specified.cpp:49:9:49:10 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'uint16_t'. | +| test_specified.cpp:50:9:50:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | +| test_specified.cpp:58:9:58:10 | l7 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test_specified.cpp:59:9:59:10 | l8 | Assignment between incompatible numeric types from 'double' to 'int32_t'. | +| test_specified.cpp:71:7:71:8 | l8 | Assignment between incompatible numeric types from 'double' to 'float'. | +| test_specified.cpp:94:8:94:9 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:95:8:95:9 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | +| test_specified.cpp:96:9:96:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | +| test_specified.cpp:97:8:97:9 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'int8_t'. | +| test_specified.cpp:98:8:98:9 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | +| test_specified.cpp:99:9:99:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | +| test_specified.cpp:102:8:102:9 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | +| test_specified.cpp:103:9:103:10 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'uint16_t'. | +| test_specified.cpp:104:9:104:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | +| test_specified.cpp:105:8:105:9 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | +| test_specified.cpp:106:9:106:10 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'int16_t'. | +| test_specified.cpp:107:9:107:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_specified.cpp:110:9:110:10 | l7 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test_specified.cpp:111:9:111:10 | l8 | Assignment between incompatible numeric types from 'double' to 'int32_t'. | +| test_specified.cpp:112:7:112:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'float'. | +| test_specified.cpp:113:7:113:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'float'. | +| test_specified.cpp:114:7:114:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test_specified.cpp:115:7:115:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'double'. | +| test_specified.cpp:116:7:116:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'double'. | +| test_specified.cpp:117:7:117:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'double'. | +| test_specified.cpp:120:7:120:8 | l8 | Assignment between incompatible numeric types from 'double' to 'float'. | +| test_specified.cpp:143:8:143:9 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:144:8:144:9 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | +| test_specified.cpp:145:9:145:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | +| test_specified.cpp:146:8:146:9 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'int8_t'. | +| test_specified.cpp:147:8:147:9 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | +| test_specified.cpp:148:9:148:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | +| test_specified.cpp:151:8:151:9 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | +| test_specified.cpp:152:9:152:10 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'uint16_t'. | +| test_specified.cpp:153:9:153:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | +| test_specified.cpp:154:8:154:9 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | +| test_specified.cpp:155:9:155:10 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'int16_t'. | +| test_specified.cpp:156:9:156:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_specified.cpp:159:9:159:10 | l7 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test_specified.cpp:160:9:160:10 | l8 | Assignment between incompatible numeric types from 'double' to 'int32_t'. | +| test_specified.cpp:161:7:161:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'float'. | +| test_specified.cpp:162:7:162:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'float'. | +| test_specified.cpp:163:7:163:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test_specified.cpp:164:7:164:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'double'. | +| test_specified.cpp:165:7:165:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'double'. | +| test_specified.cpp:166:7:166:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'double'. | +| test_specified.cpp:169:7:169:8 | l8 | Assignment between incompatible numeric types from 'double' to 'float'. | +| test_specified.cpp:213:8:213:9 | l6 | Assignment between incompatible numeric types from 'const uint16_t &' to 'uint8_t'. | +| test_specified.cpp:214:8:214:10 | l10 | Assignment between incompatible numeric types from 'volatile uint16_t &' to 'uint8_t'. | +| test_specified.cpp:215:8:215:10 | l14 | Assignment between incompatible numeric types from 'const volatile uint16_t &' to 'uint8_t'. | +| test_specified.cpp:218:8:218:9 | l5 | Assignment between incompatible numeric types from 'const uint8_t &' to 'int8_t'. | +| test_specified.cpp:219:8:219:9 | l7 | Assignment between incompatible numeric types from 'const int8_t &' to 'uint8_t'. | +| test_specified.cpp:220:8:220:9 | l9 | Assignment between incompatible numeric types from 'volatile uint8_t &' to 'int8_t'. | +| test_specified.cpp:221:8:221:10 | l11 | Assignment between incompatible numeric types from 'volatile int8_t &' to 'uint8_t'. | +| test_specified.cpp:222:8:222:10 | l13 | Assignment between incompatible numeric types from 'const volatile uint8_t &' to 'int8_t'. | +| test_specified.cpp:223:8:223:10 | l15 | Assignment between incompatible numeric types from 'const volatile int8_t &' to 'uint8_t'. | +| test_specified.cpp:226:9:226:10 | l8 | Assignment between incompatible numeric types from 'const float &' to 'int32_t'. | +| test_specified.cpp:227:9:227:11 | l12 | Assignment between incompatible numeric types from 'volatile float &' to 'int32_t'. | +| test_specified.cpp:228:9:228:11 | l16 | Assignment between incompatible numeric types from 'const volatile float &' to 'int32_t'. | +| test_specified.cpp:229:7:229:8 | l3 | Assignment between incompatible numeric types from 'int8_t' to 'float'. | +| test_specified.cpp:230:7:230:8 | l7 | Assignment between incompatible numeric types from 'const int8_t &' to 'float'. | +| test_specified.cpp:231:7:231:9 | l11 | Assignment between incompatible numeric types from 'volatile int8_t &' to 'float'. | +| test_specified.cpp:232:7:232:9 | l15 | Assignment between incompatible numeric types from 'const volatile int8_t &' to 'float'. | +| test_specified.cpp:245:7:245:8 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'const uint32_t'. | +| test_specified.cpp:246:7:246:8 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'const uint32_t'. | +| test_specified.cpp:247:7:247:8 | l3 | Assignment between incompatible numeric types from 'int8_t' to 'volatile int64_t'. | +| test_specified.cpp:248:7:248:8 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'const volatile uint16_t'. | +| test_specified.cpp:250:7:250:8 | l3 | Assignment between incompatible numeric types from 'int8_t' to 'const volatile uint16_t'. | +| test_specified.cpp:285:8:285:22 | g4 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:287:8:287:19 | s4 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:292:9:292:23 | g5 | Assignment between incompatible numeric types from 'int8_t' to 'uint16_t'. | +| test_specified.cpp:294:9:294:20 | s5 | Assignment between incompatible numeric types from 'int8_t' to 'uint16_t'. | +| test_specified.cpp:308:23:308:25 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test_specified.cpp:308:28:308:32 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test_specified.cpp:308:35:308:38 | 3000 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test_specified.cpp:309:12:309:16 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test_specified.cpp:314:23:314:25 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test_specified.cpp:314:28:314:30 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | +| test_specified.cpp:314:33:314:35 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test_specified.cpp:329:8:329:9 | l2 | Assignment between incompatible numeric types from 'CVColour' to 'uint8_t'. | +| test_specified.cpp:331:8:331:9 | l3 | Assignment between incompatible numeric types from 'CVColour' to 'uint8_t'. | +| test_specified.cpp:342:8:342:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test_specified.cpp:343:8:343:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test_specified.cpp:344:8:344:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test_specified.cpp:351:10:351:11 | l2 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test_specified.cpp:352:10:352:11 | l3 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test_specified.cpp:370:18:370:20 | 300 | Assignment between incompatible numeric types from 'int' to 'const uint8_t'. | +| test_specified.cpp:370:23:370:27 | 70000 | Assignment between incompatible numeric types from 'int' to 'volatile uint16_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test_specified.cpp b/cpp/misra/test/rules/RULE-7-0-6/test_specified.cpp new file mode 100644 index 0000000000..dc58ade311 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/test_specified.cpp @@ -0,0 +1,371 @@ +#include +#include + +// Global variables for testing +std::uint32_t u32; +std::int32_t s32; +std::uint8_t u8; +std::int8_t s8; +std::uint16_t u16; +std::int16_t s16; +std::uint64_t u64; +std::int64_t s64; +float f; +double d; + +// Test cv-qualified types +void test_cv_qualified_const() { + const std::uint8_t l1 = 42; // COMPLIANT + const std::uint16_t l2 = 1000; // COMPLIANT + const std::uint32_t l3 = 50000; // COMPLIANT + const std::int8_t l4 = -5; // COMPLIANT + const std::int16_t l5 = -1000; // COMPLIANT + const std::int32_t l6 = -50000; // COMPLIANT + const float l7 = 3.14f; // COMPLIANT + const double l8 = 2.718; // COMPLIANT + + // Widening of const id-expressions - allowed + // Also allowed because the integer constant expressions are within the range + u16 = l1; // COMPLIANT + u32 = l1; // COMPLIANT + u32 = l2; // COMPLIANT + s16 = l4; // COMPLIANT + s32 = l4; // COMPLIANT + s32 = l5; // COMPLIANT + + // Narrowing of const id-expressions - not allowed + u8 = l2; // NON_COMPLIANT + u8 = l3; // NON_COMPLIANT + // Permitted because the integer constant expression is within the range + u16 = l3; // COMPLIANT + s8 = l5; // NON_COMPLIANT + s8 = l6; // NON_COMPLIANT + s16 = l6; // NON_COMPLIANT + + // Incorrect signedness conversions, and the integer constant + // expressions are not in the range of the target type (as they are all + // negative) + u8 = l4; // NON_COMPLIANT + u16 = l5; // NON_COMPLIANT + u32 = l6; // NON_COMPLIANT + // These are signedness violations, but as they are integer constant + // expressions within range they are allowed + s8 = l1; // COMPLIANT + s16 = l2; // COMPLIANT + s32 = l3; // COMPLIANT + + // Type category errors (int to float) + s32 = l7; // NON_COMPLIANT + s32 = l8; // NON_COMPLIANT + // These are not type category errors, as they are integer constant + // expressions whose value fits within both floating point types, as the range + // is infinite + f = l4; // COMPLIANT + f = l5; // COMPLIANT + f = l6; // COMPLIANT + d = l4; // COMPLIANT + d = l5; // COMPLIANT + d = l6; // COMPLIANT + + // Size violations within same type category with const + f = l8; // NON_COMPLIANT + d = l7; // COMPLIANT +} + +void test_cv_qualified_volatile() { + volatile std::uint8_t l1 = 42; + volatile std::uint16_t l2 = 1000; + volatile std::uint32_t l3 = 50000; + volatile std::int8_t l4 = -5; + volatile std::int16_t l5 = -1000; + volatile std::int32_t l6 = -50000; + volatile float l7 = 3.14f; + volatile double l8 = 2.718; + + // Widening of volatile id-expressions - allowed + u16 = l1; // COMPLIANT + u32 = l1; // COMPLIANT + u32 = l2; // COMPLIANT + s16 = l4; // COMPLIANT + s32 = l4; // COMPLIANT + s32 = l5; // COMPLIANT + + // Narrowing of volatile id-expressions - not allowed + u8 = l2; // NON_COMPLIANT + u8 = l3; // NON_COMPLIANT + u16 = l3; // NON_COMPLIANT + s8 = l5; // NON_COMPLIANT + s8 = l6; // NON_COMPLIANT + s16 = l6; // NON_COMPLIANT + + // Signedness violations with volatile + u8 = l4; // NON_COMPLIANT + u16 = l5; // NON_COMPLIANT + u32 = l6; // NON_COMPLIANT + s8 = l1; // NON_COMPLIANT + s16 = l2; // NON_COMPLIANT + s32 = l3; // NON_COMPLIANT + + // Type category violations with volatile + s32 = l7; // NON_COMPLIANT + s32 = l8; // NON_COMPLIANT + f = l4; // NON_COMPLIANT + f = l5; // NON_COMPLIANT + f = l6; // NON_COMPLIANT + d = l4; // NON_COMPLIANT + d = l5; // NON_COMPLIANT + d = l6; // NON_COMPLIANT + + // Size violations within same type category with volatile + f = l8; // NON_COMPLIANT + d = l7; // COMPLIANT +} + +void test_cv_qualified_const_volatile() { + const volatile std::uint8_t l1 = 42; + const volatile std::uint16_t l2 = 1000; + const volatile std::uint32_t l3 = 50000; + const volatile std::int8_t l4 = -5; + const volatile std::int16_t l5 = -1000; + const volatile std::int32_t l6 = -50000; + const volatile float l7 = 3.14f; + const volatile double l8 = 2.718; + + // Widening of const volatile id-expressions - allowed + u16 = l1; // COMPLIANT + u32 = l1; // COMPLIANT + u32 = l2; // COMPLIANT + s16 = l4; // COMPLIANT + s32 = l4; // COMPLIANT + s32 = l5; // COMPLIANT + + // Narrowing of const volatile id-expressions - not allowed + u8 = l2; // NON_COMPLIANT + u8 = l3; // NON_COMPLIANT + u16 = l3; // NON_COMPLIANT + s8 = l5; // NON_COMPLIANT + s8 = l6; // NON_COMPLIANT + s16 = l6; // NON_COMPLIANT + + // Signedness violations with const volatile + u8 = l4; // NON_COMPLIANT + u16 = l5; // NON_COMPLIANT + u32 = l6; // NON_COMPLIANT + s8 = l1; // NON_COMPLIANT + s16 = l2; // NON_COMPLIANT + s32 = l3; // NON_COMPLIANT + + // Type category violations with const volatile + s32 = l7; // NON_COMPLIANT + s32 = l8; // NON_COMPLIANT + f = l4; // NON_COMPLIANT + f = l5; // NON_COMPLIANT + f = l6; // NON_COMPLIANT + d = l4; // NON_COMPLIANT + d = l5; // NON_COMPLIANT + d = l6; // NON_COMPLIANT + + // Size violations within same type category with const volatile + f = l8; // NON_COMPLIANT + d = l7; // COMPLIANT +} + +// Test cv-qualified references +void test_cv_qualified_references() { + std::uint8_t l1 = 42; + std::uint16_t l2 = 1000; + std::int8_t l3 = -5; + float l4 = 3.14f; + + const std::uint8_t &l5 = l1; + const std::uint16_t &l6 = l2; + const std::int8_t &l7 = l3; + const float &l8 = l4; + + volatile std::uint8_t &l9 = l1; + volatile std::uint16_t &l10 = l2; + volatile std::int8_t &l11 = l3; + volatile float &l12 = l4; + + const volatile std::uint8_t &l13 = l1; + const volatile std::uint16_t &l14 = l2; + const volatile std::int8_t &l15 = l3; + const volatile float &l16 = l4; + + // Widening through cv-qualified references - allowed + u16 = l5; // COMPLIANT + u32 = l5; // COMPLIANT + u32 = l6; // COMPLIANT + s16 = l7; // COMPLIANT + s32 = l7; // COMPLIANT + u16 = l9; // COMPLIANT + u32 = l9; // COMPLIANT + u32 = l10; // COMPLIANT + s16 = l11; // COMPLIANT + s32 = l11; // COMPLIANT + u16 = l13; // COMPLIANT + u32 = l13; // COMPLIANT + u32 = l14; // COMPLIANT + s16 = l15; // COMPLIANT + s32 = l15; // COMPLIANT + + // Narrowing through cv-qualified references - not allowed + u8 = l6; // NON_COMPLIANT + u8 = l10; // NON_COMPLIANT + u8 = l14; // NON_COMPLIANT + + // Signedness violations through cv-qualified references + s8 = l5; // NON_COMPLIANT + u8 = l7; // NON_COMPLIANT + s8 = l9; // NON_COMPLIANT + u8 = l11; // NON_COMPLIANT + s8 = l13; // NON_COMPLIANT + u8 = l15; // NON_COMPLIANT + + // Type category violations through cv-qualified references + s32 = l8; // NON_COMPLIANT + s32 = l12; // NON_COMPLIANT + s32 = l16; // NON_COMPLIANT + f = l3; // NON_COMPLIANT + f = l7; // NON_COMPLIANT + f = l11; // NON_COMPLIANT + f = l15; // NON_COMPLIANT +} + +// Test cv-qualified function parameters +void f15(const std::uint32_t l1) {} +void f16(volatile std::int64_t l1) {} +void f17(const volatile std::uint16_t l1) {} + +void test_cv_qualified_function_parameters() { + const std::uint8_t l1 = 42; + volatile std::uint16_t l2 = 1000; + const volatile std::int8_t l3 = -5; + + f15(l1); // NON_COMPLIANT + f15(l2); // NON_COMPLIANT + f16(l3); // NON_COMPLIANT + f17(l1); // NON_COMPLIANT + f17(l2); // COMPLIANT + f17(l3); // NON_COMPLIANT +} + +// Test cv-qualified static and namespace variables +namespace CVNamespace { +const std::uint8_t g3 = 42; +volatile std::uint16_t g4 = 1000; +const volatile std::int8_t g5 = -5; +} // namespace CVNamespace + +struct CVStruct { + static const std::uint8_t s3; + static volatile std::uint16_t s4; + static const volatile std::int8_t s5; +}; + +const std::uint8_t CVStruct::s3 = 42; +volatile std::uint16_t CVStruct::s4 = 1000; +const volatile std::int8_t CVStruct::s5 = -5; + +void test_cv_qualified_static_and_namespace() { + // Widening of cv-qualified namespace and static variables - allowed + u16 = CVNamespace::g3; // COMPLIANT + u32 = CVNamespace::g3; // COMPLIANT + u32 = CVNamespace::g4; // COMPLIANT + s16 = CVNamespace::g5; // COMPLIANT + s32 = CVNamespace::g5; // COMPLIANT + + u16 = CVStruct::s3; // COMPLIANT + u32 = CVStruct::s3; // COMPLIANT + u32 = CVStruct::s4; // COMPLIANT + s16 = CVStruct::s5; // COMPLIANT + s32 = CVStruct::s5; // COMPLIANT + + // Narrowing of cv-qualified namespace and static variables - not allowed + u8 = CVNamespace::g4; // NON_COMPLIANT + s8 = CVNamespace::g5; // COMPLIANT - constant fits + u8 = CVStruct::s4; // NON_COMPLIANT + s8 = CVStruct::s5; // COMPLIANT - constant fits + + // Signedness violations with cv-qualified namespace and static variables + s8 = CVNamespace::g3; // COMPLIANT - constant expression + u16 = CVNamespace::g5; // NON_COMPLIANT + s8 = CVStruct::s3; // COMPLIANT - constant expression + u16 = CVStruct::s5; // NON_COMPLIANT +} + +// Test cv-qualified bitfields +struct CVBitfieldStruct { + const std::uint32_t m11 : 8; + volatile std::uint32_t m12 : 16; + const volatile std::int32_t m13 : 12; +}; + +void test_cv_qualified_bitfields() { + CVBitfieldStruct l1{100, 30000, -500}; // COMPLIANT + + // CV-qualified bitfields follow same rules as regular bitfields + CVBitfieldStruct l2{300, 70000, 3000}; // NON_COMPLIANT + l2.m12 = 70000; // NON_COMPLIANT + + CVBitfieldStruct l3{u8, u16, s16}; // COMPLIANT + l1.m12 = u16; // COMPLIANT + + CVBitfieldStruct l4{u16, u32, s32}; // NON_COMPLIANT +} + +// Test cv-qualified enums +enum CVColour : std::uint16_t { cv_red, cv_green, cv_blue }; + +void test_cv_qualified_enums() { + const CVColour l1 = cv_red; + volatile CVColour l2 = cv_green; + const volatile CVColour l3 = cv_blue; + + u8 = cv_red; // COMPLIANT + u32 = cv_red; // COMPLIANT + u8 = l1; // COMPLIANT - constant fits in uint8_t + u32 = l1; // COMPLIANT + u8 = l2; // NON_COMPLIANT + u32 = l2; // COMPLIANT + u8 = l3; // NON_COMPLIANT + u32 = l3; // COMPLIANT +} + +// Test cv-qualified expressions with operators +void test_cv_qualified_expressions() { + const std::uint8_t l1 = 10; + volatile std::uint8_t l2 = 20; + const volatile std::uint8_t l3 = 30; + + // Expressions with cv-qualified operands still follow expression rules + u8 = l1 + l2; // NON_COMPLIANT + u8 = l1 + l3; // NON_COMPLIANT + u8 = l2 + l3; // NON_COMPLIANT + s32 = l1 + l2; // COMPLIANT + s32 = l1 + l3; // COMPLIANT + s32 = l2 + l3; // COMPLIANT + + // Parenthesized cv-qualified expressions are not id-expressions + u32 = (l1); // COMPLIANT - constant expression fits + u32 = (l2); // NON_COMPLIANT + u32 = (l3); // NON_COMPLIANT +} + +// Test cv-qualified aggregate initialization +struct CVAggregate { + const std::uint8_t m1; + volatile std::uint16_t m2; + const volatile std::int32_t m3; +}; + +void test_cv_qualified_aggregate_initialization() { + const std::uint8_t l1 = 42; + volatile std::uint16_t l2 = 1000; + const volatile std::int8_t l3 = -5; + + // CV-qualified aggregate members follow same rules + CVAggregate l4{10, 100, -50}; // COMPLIANT + CVAggregate l5{l1, l2, l3}; // COMPLIANT + CVAggregate l6{300, 70000, l3}; // NON_COMPLIANT +} \ No newline at end of file From 916fb3dc58cced90b34778d2854aa82c805914b8 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Jun 2025 21:11:26 +0100 Subject: [PATCH 454/628] Rule 7.0.6: Support pointer to member cases - Support assignment to pointer to members - Support pointer-to-member function calls --- .../cpp/misra/StandardConversions.qll | 24 +++- .../NumericAssignmentTypeMismatch.expected | 35 +++++ .../rules/RULE-7-0-6/test_member_pointers.cpp | 128 ++++++++++++++++++ 3 files changed, 186 insertions(+), 1 deletion(-) create mode 100644 cpp/misra/test/rules/RULE-7-0-6/test_member_pointers.cpp diff --git a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll index 0f96e61204..d5dbbc8862 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll @@ -129,7 +129,13 @@ predicate isAssignment(Expr source, NumericType targetType, string context) { isAssignedToBitfield(source, bf) and targetType = getBitFieldType(bf) ) - else targetType = assign.getLValue().getType() + else + exists(Type t | t = assign.getLValue().getType() | + // Unwrap PointerToMemberType e.g `l1.*l2 = x;` + if t instanceof PointerToMemberType + then targetType = t.(PointerToMemberType).getBaseType() + else targetType = t + ) ) or // Variable initialization @@ -157,6 +163,22 @@ predicate isAssignment(Expr source, NumericType targetType, string context) { // Handle varargs - use the fully converted type of the argument call.getTarget().getNumberOfParameters() <= i and targetType = source.getFullyConverted().getType() + or + // A standard expression call + targetType = call.(ExprCall).getExpr().getType().(FunctionPointerIshType).getParameterType(i) + or + // An expression call using the pointer to member operator (.* or ->*) + // This special handling is required because we don't have a CodeQL class representing the call + // to a pointer to member function, but the right hand side is extracted as the -1 child of the + // call + targetType = + call.(ExprCall) + .getChild(-1) + .getType() + .(PointerToMemberType) + .getBaseType() + .(RoutineType) + .getParameterType(i) ) or // Return statement diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index 23665ed100..cbc6ff266a 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -170,6 +170,41 @@ | test.cpp:854:29:854:31 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | | test.cpp:854:34:854:36 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | | test.cpp:864:28:864:30 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_member_pointers.cpp:25:12:25:14 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:26:12:26:14 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:27:12:27:14 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:28:12:28:14 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:32:13:32:15 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:33:13:33:15 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:34:13:34:15 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:35:13:35:15 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:42:12:42:14 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:43:12:43:14 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:44:12:44:14 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:45:12:45:14 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:49:13:49:15 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:50:13:50:15 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:51:13:51:15 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:52:13:52:15 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:58:11:58:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test_member_pointers.cpp:60:11:60:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:66:11:66:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:67:11:67:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:82:6:82:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:83:6:83:8 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:84:6:84:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:85:6:85:8 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:90:6:90:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:91:6:91:8 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:92:6:92:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:93:6:93:8 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:97:7:97:9 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test_member_pointers.cpp:100:7:100:9 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:106:41:106:43 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:107:41:107:43 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:125:12:125:14 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int64_t'. | +| test_member_pointers.cpp:126:12:126:14 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int64_t'. | +| test_member_pointers.cpp:127:12:127:14 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int64_t'. | | test_specified.cpp:37:8:37:9 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | | test_specified.cpp:38:8:38:9 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | | test_specified.cpp:41:8:41:9 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'int8_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test_member_pointers.cpp b/cpp/misra/test/rules/RULE-7-0-6/test_member_pointers.cpp new file mode 100644 index 0000000000..d6f3de7eb8 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/test_member_pointers.cpp @@ -0,0 +1,128 @@ +#include + +std::int16_t s16; +std::uint16_t u16; +std::int32_t s32; +std::uint32_t u32; +std::int64_t s64; +std::uint64_t u64; + +struct MemberFunctionPointerTest { + void mf15(std::int32_t l1) {} + void mf15(std::uint32_t l1) {} + void mf16(std::int32_t l1) {} +}; + +void test_pointer_to_member_functions() { + MemberFunctionPointerTest l1; + MemberFunctionPointerTest *l6 = &l1; + + // mf15 is overload independent when used as a member function pointer + void (MemberFunctionPointerTest::*l2)(std::int32_t) = + &MemberFunctionPointerTest::mf15; + (l1.*l2)(s16); // COMPLIANT - widening of id-expression + (l1.*l2)(s32); // COMPLIANT - type match + (l1.*l2)(s64); // NON_COMPLIANT - narrowing + (l1.*l2)(u16); // NON_COMPLIANT - wrong sign + (l1.*l2)(u32); // NON_COMPLIANT - wrong sign + (l1.*l2)(u64); // NON_COMPLIANT - wrong sign and narrowing + + (l6->*l2)(s16); // COMPLIANT - is widening of id-expression + (l6->*l2)(s32); // COMPLIANT - type match + (l6->*l2)(s64); // NON_COMPLIANT - narrowing + (l6->*l2)(u16); // NON_COMPLIANT - wrong sign + (l6->*l2)(u32); // NON_COMPLIANT - wrong sign + (l6->*l2)(u64); // NON_COMPLIANT - wrong sign and narrowing + + // mf16 is overload independent when used as a member function pointer + void (MemberFunctionPointerTest::*l3)(std::int32_t) = + &MemberFunctionPointerTest::mf16; + (l1.*l3)(s16); // COMPLIANT - widening of id-expression + (l1.*l3)(s32); // COMPLIANT - type match + (l1.*l3)(s64); // NON_COMPLIANT - narrowing + (l1.*l3)(u16); // NON_COMPLIANT - wrong sign + (l1.*l3)(u32); // NON_COMPLIANT - wrong sign + (l1.*l3)(u64); // NON_COMPLIANT - wrong sign and narrowing + + (l6->*l3)(s16); // COMPLIANT - widening of id-expression + (l6->*l3)(s32); // COMPLIANT - type match + (l6->*l3)(s64); // NON_COMPLIANT - narrowing + (l6->*l3)(u16); // NON_COMPLIANT - wrong sign + (l6->*l3)(u32); // NON_COMPLIANT - wrong sign + (l6->*l3)(u64); // NON_COMPLIANT - wrong sign and narrowing + + // Direct calls for comparison + + // mf15 is not overload-independent, so it should only be compliant + // where an exact type of an overload is used + l1.mf15(s16); // NON_COMPLIANT - widening not allowed + l1.mf15(s32); // COMPLIANT - exact type match + l1.mf15(u16); // NON_COMPLIANT - widening not allowed + l1.mf15(u32); // COMPLIANT - exact type match + + // A qualified call to mf16 is overload-independent + l1.mf16(s16); // COMPLIANT - widening of id-expression + l1.mf16(s32); // COMPLIANT - exact type match + l1.mf16(u16); // NON_COMPLIANT + l1.mf16(u32); // NON_COMPLIANT +} + +// Test static member function pointers - should be overload-independent +struct StaticMemberFunctionPointerTest { + static void mf19(std::int32_t l1) {} + static void mf19(std::uint32_t l1) {} + static void mf20(std::int32_t l1) {} +}; + +void test_static_member_function_pointers() { + // Static member function pointers - overload-independent + void (*l1)(std::int32_t) = &StaticMemberFunctionPointerTest::mf19; + l1(s16); // COMPLIANT - widening of id-expression + l1(s32); // COMPLIANT - type match + l1(s64); // NON_COMPLIANT - narrowing + l1(u16); // NON_COMPLIANT - wrong sign + l1(u32); // NON_COMPLIANT - wrong sign + l1(u64); // NON_COMPLIANT - wrong sign and narrowing + + void (*l2)(std::int32_t) = &StaticMemberFunctionPointerTest::mf20; + l2(s16); // COMPLIANT - widening of id-expression + l2(s32); // COMPLIANT - type match + l2(s64); // NON_COMPLIANT - narrowing + l2(u16); // NON_COMPLIANT - wrong sign + l2(u32); // NON_COMPLIANT - wrong sign + l2(u64); // NON_COMPLIANT - wrong sign and narrowing + + // Direct calls for comparison - not overload-independent + StaticMemberFunctionPointerTest::mf19( + s16); // NON_COMPLIANT - widening not allowed + StaticMemberFunctionPointerTest::mf19(s32); // COMPLIANT - exact type match + StaticMemberFunctionPointerTest::mf19( + u16); // NON_COMPLIANT - widening not allowed + StaticMemberFunctionPointerTest::mf19(u32); // COMPLIANT - exact type match + + StaticMemberFunctionPointerTest::mf20( + s16); // COMPLIANT - widening of id-expression + StaticMemberFunctionPointerTest::mf20(s32); // COMPLIANT - exact type match + StaticMemberFunctionPointerTest::mf20(u16); // NON_COMPLIANT + StaticMemberFunctionPointerTest::mf20(u32); // NON_COMPLIANT +} + +// Test member data pointers - not function calls, but test assignment to them +struct MemberDataPointerTest { + std::int64_t m1; + std::int64_t m2 : 10; +}; + +void test_member_data_pointers() { + MemberDataPointerTest l1; + + // Member data pointer assignments - follow normal assignment rules + std::int64_t MemberDataPointerTest::*l2 = &MemberDataPointerTest::m1; + + l1.*l2 = s16; // COMPLIANT - widening conversion allowed + l1.*l2 = s32; // COMPLIANT - widening conversion allowed + l1.*l2 = s64; // COMPLIANT + l1.*l2 = u16; // NON_COMPLIANT - signedness violation + l1.*l2 = u32; // NON_COMPLIANT - different signedness/size + l1.*l2 = u64; // NON_COMPLIANT - different signedness +} \ No newline at end of file From e655ed85787c8e301370c9a941f4d7d4f1279cad Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Thu, 19 Jun 2025 14:56:50 -0700 Subject: [PATCH 455/628] Exclude if (f) f() from EXP-16-C --- ...CompareFunctionPointersToConstantValues.ql | 31 ++-------- ...eFunctionPointersToConstantValues.expected | 34 ++++++----- c/cert/test/rules/EXP16-C/test.c | 42 ++++++++++++- .../cpp/exprs/FunctionExprs.qll | 59 +++++++++++++++++++ .../src/codingstandards/cpp/exprs/Guards.qll | 34 +++++++++++ 5 files changed, 158 insertions(+), 42 deletions(-) create mode 100644 cpp/common/src/codingstandards/cpp/exprs/FunctionExprs.qll create mode 100644 cpp/common/src/codingstandards/cpp/exprs/Guards.qll diff --git a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql index bdd4f1b375..e65d58a652 100644 --- a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql +++ b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql @@ -17,33 +17,11 @@ */ import cpp +import semmle.code.cpp.controlflow.IRGuards import codingstandards.c.cert import codingstandards.cpp.types.FunctionType -import semmle.code.cpp.controlflow.IRGuards - -class FunctionExpr extends Expr { - Element function; - string funcName; - - FunctionExpr() { - function = this.(FunctionAccess).getTarget() and - funcName = "Function " + function.(Function).getName() - or - this.(VariableAccess).getUnderlyingType() instanceof FunctionType and - function = this and - funcName = "Function pointer variable " + this.(VariableAccess).getTarget().getName() - or - this.getUnderlyingType() instanceof FunctionType and - not this instanceof FunctionAccess and - not this instanceof VariableAccess and - function = this and - funcName = "Expression with function pointer type" - } - - Element getFunction() { result = function } - - string getFuncName() { result = funcName } -} +import codingstandards.cpp.exprs.FunctionExprs +import codingstandards.cpp.exprs.Guards abstract class EffectivelyComparison extends Element { abstract string getExplanation(); @@ -85,6 +63,7 @@ where not isExcluded(comparison, Expressions2Package::doNotCompareFunctionPointersToConstantValuesQuery()) and funcExpr = comparison.getFunctionExpr() and + not exists(NullFunctionCallGuard nullGuard | nullGuard.getFunctionExpr() = funcExpr) and function = funcExpr.getFunction() and - funcName = funcExpr.getFuncName() + funcName = funcExpr.describe() select comparison, comparison.getExplanation(), function, funcName diff --git a/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.expected b/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.expected index a18f0d32f6..403d211651 100644 --- a/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.expected +++ b/c/cert/test/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.expected @@ -1,16 +1,20 @@ -| test.c:17:7:17:13 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Function f1 | -| test.c:20:7:20:12 | ... > ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Function f1 | -| test.c:29:7:29:13 | ... == ... | $@ compared to constant value. | test.c:29:7:29:8 | g1 | Function pointer variable g1 | -| test.c:32:7:32:16 | ... == ... | $@ compared to constant value. | test.c:32:7:32:8 | g2 | Function pointer variable g2 | -| test.c:35:7:35:15 | ... != ... | $@ compared to constant value. | test.c:35:7:35:8 | g1 | Function pointer variable g1 | -| test.c:38:7:38:8 | f1 | $@ undergoes implicit constant comparison. | test.c:3:5:3:6 | f1 | Function f1 | -| test.c:41:7:41:8 | g1 | $@ undergoes implicit constant comparison. | test.c:41:7:41:8 | g1 | Function pointer variable g1 | -| test.c:68:7:68:27 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Function f1 | -| test.c:71:7:71:18 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Function f1 | -| test.c:74:7:76:14 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Function f1 | -| test.c:83:3:83:9 | ... == ... | $@ compared to constant value. | test.c:83:3:83:4 | l1 | Function pointer variable l1 | -| test.c:84:3:84:12 | ... == ... | $@ compared to constant value. | test.c:84:3:84:4 | l1 | Function pointer variable l1 | -| test.c:91:3:91:4 | g1 | $@ undergoes implicit constant comparison. | test.c:91:3:91:4 | g1 | Function pointer variable g1 | -| test.c:96:7:96:18 | ... == ... | $@ compared to constant value. | test.c:96:9:96:10 | fp | Function pointer variable fp | -| test.c:102:7:102:22 | ... == ... | $@ compared to constant value. | test.c:14:11:14:21 | get_handler | Function get_handler | +| test.c:17:7:17:13 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 | +| test.c:20:7:20:12 | ... > ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 | +| test.c:29:7:29:13 | ... == ... | $@ compared to constant value. | test.c:4:8:4:9 | g1 | Function pointer variable g1 | +| test.c:32:7:32:16 | ... == ... | $@ compared to constant value. | test.c:5:7:5:8 | g2 | Function pointer variable g2 | +| test.c:35:7:35:15 | ... != ... | $@ compared to constant value. | test.c:4:8:4:9 | g1 | Function pointer variable g1 | +| test.c:38:7:38:8 | f1 | $@ undergoes implicit constant comparison. | test.c:3:5:3:6 | f1 | Address of function f1 | +| test.c:41:7:41:8 | g1 | $@ undergoes implicit constant comparison. | test.c:4:8:4:9 | g1 | Function pointer variable g1 | +| test.c:68:7:68:27 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 | +| test.c:71:7:71:18 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 | +| test.c:74:7:76:14 | ... == ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 | +| test.c:83:3:83:9 | ... == ... | $@ compared to constant value. | test.c:82:10:82:11 | l1 | Function pointer variable l1 | +| test.c:84:3:84:12 | ... == ... | $@ compared to constant value. | test.c:82:10:82:11 | l1 | Function pointer variable l1 | +| test.c:91:3:91:4 | g1 | $@ undergoes implicit constant comparison. | test.c:4:8:4:9 | g1 | Function pointer variable g1 | +| test.c:96:7:96:18 | ... == ... | $@ compared to constant value. | test.c:9:9:9:10 | fp | Function pointer variable fp | +| test.c:102:7:102:22 | ... == ... | $@ compared to constant value. | test.c:14:11:14:21 | get_handler | Address of function get_handler | | test.c:105:7:105:24 | ... == ... | $@ compared to constant value. | test.c:105:7:105:17 | call to get_handler | Expression with function pointer type | +| test.c:121:7:121:13 | ... != ... | $@ compared to constant value. | test.c:3:5:3:6 | f1 | Address of function f1 | +| test.c:133:7:133:13 | ... != ... | $@ compared to constant value. | test.c:4:8:4:9 | g1 | Function pointer variable g1 | +| test.c:139:7:139:13 | ... == ... | $@ compared to constant value. | test.c:4:8:4:9 | g1 | Function pointer variable g1 | +| test.c:149:8:149:9 | g1 | $@ undergoes implicit constant comparison. | test.c:4:8:4:9 | g1 | Function pointer variable g1 | diff --git a/c/cert/test/rules/EXP16-C/test.c b/c/cert/test/rules/EXP16-C/test.c index afc1b1b53e..16dfea9bc2 100644 --- a/c/cert/test/rules/EXP16-C/test.c +++ b/c/cert/test/rules/EXP16-C/test.c @@ -94,7 +94,7 @@ void f6(void) { void f7(void) { struct S s; if (s.fp == NULL) // NON-COMPLIANT - return; + f1(); if (s.fp() == NULL) // COMPLIANT return; @@ -110,4 +110,44 @@ void f7(void) { if (get_handler()() == 0) // COMPLIANT return; +} + +void f8(void) { + // Test instances of where the function pointer check is used to guard calls + // to that function. + + // Technically, this function may perhaps be set to NULL by the linker. But + // it is not a variable that should need to be null-checked at runtime. + if (f1 != 0) // NON-COMPLIANT + { + f1(); + } + + // Check guards a call, so it is compliant. + if (g1 != 0) // COMPLIANT + { + g1(); + } + + // Incorrect check, not compliant. + if (g1 != 0) // NON-COMPLIANT + { + f1(); + } + + // Incorrect check, not compliant. + if (g1 == 0) // NON-COMPLIANT + { + g1(); + } + + if (g1) // COMPLIANT + { + g1(); + } + + if (!g1) // NON-COMPLIANT + { + g1(); + } } \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exprs/FunctionExprs.qll b/cpp/common/src/codingstandards/cpp/exprs/FunctionExprs.qll new file mode 100644 index 0000000000..5c46fce075 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exprs/FunctionExprs.qll @@ -0,0 +1,59 @@ +import cpp +import codingstandards.cpp.types.FunctionType + +/** + * A class representing an expression that has a function pointer type. This can be a function + * access, a variable access, or any expression that has a function pointer type. + */ +abstract class FunctionExpr extends Expr { + /** Any element that could represent the function, for example, a variable or an expression. */ + abstract Element getFunction(); + + /** A name or string that describes the function. */ + abstract string describe(); + + /** Get calls of this function */ + abstract Call getACall(); +} + +/** + * A function access is an an expression of function type where we know the function. + */ +class SimpleFunctionAccess extends FunctionExpr, FunctionAccess { + override Element getFunction() { result = this.getTarget() } + + override string describe() { result = "Address of function " + this.getTarget().getName() } + + override FunctionCall getACall() { result.getTarget() = this.getTarget() } +} + +/** + * An access of a variable that has a function pointer type is also a function expression, for which + * we can track certain properties of the function. + */ +class FunctionVariableAccess extends FunctionExpr, VariableAccess { + FunctionVariableAccess() { this.getUnderlyingType() instanceof FunctionType } + + override Element getFunction() { result = this.getTarget() } + + override string describe() { result = "Function pointer variable " + this.getTarget().getName() } + + override ExprCall getACall() { result.getExpr().(VariableAccess).getTarget() = this.getTarget() } +} + +/** + * A function typed expression that is not a function access or a variable access. + */ +class FunctionTypedExpr extends FunctionExpr { + FunctionTypedExpr() { + this.getUnderlyingType() instanceof FunctionType and + not this instanceof FunctionAccess and + not this instanceof VariableAccess + } + + override Element getFunction() { result = this } + + override string describe() { result = "Expression with function pointer type" } + + override ExprCall getACall() { result.getExpr() = this } +} diff --git a/cpp/common/src/codingstandards/cpp/exprs/Guards.qll b/cpp/common/src/codingstandards/cpp/exprs/Guards.qll new file mode 100644 index 0000000000..73a35ccc6b --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exprs/Guards.qll @@ -0,0 +1,34 @@ +import cpp +import codeql.util.Boolean +import semmle.code.cpp.controlflow.Guards +import codingstandards.cpp.exprs.FunctionExprs + +/** + * A guard of the form: `if (funcPtr) funcPtr();`, e.g., a null check on a function before calling + * that function. + * + * Note this does not consider the above to be a null function call guard if `funcPtr` is a + * function name, as that could only be null via unusual linkage steps, and is not expected to be + * an intentional null check. + */ +class NullFunctionCallGuard extends GuardCondition { + FunctionExpr expr; + + NullFunctionCallGuard() { + exists(BasicBlock block, Call guardedCall | + ( + // Handles 'if (funcPtr != NULL)`: + this.ensuresEq(expr, 0, block, false) + or + // Handles `if (funcPtr)` in C where no implicit conversion to bool exists: + expr = this and + expr.getFunction() instanceof Variable and + this.controls(block, true) + ) and + guardedCall = expr.getACall() and + block.contains(guardedCall) + ) + } + + FunctionExpr getFunctionExpr() { result = expr } +} From 2ec2814363fc9ccd72fa72c375539d5d733cb6b2 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Jun 2025 23:15:21 +0100 Subject: [PATCH 456/628] Rule 7.0.6: Support functions with default parameters Overload independence should consider what parameters are default. --- .../NumericAssignmentTypeMismatch.ql | 9 +- .../NumericAssignmentTypeMismatch.expected | 249 +++++++++--------- cpp/misra/test/rules/RULE-7-0-6/test.cpp | 14 +- 3 files changed, 144 insertions(+), 128 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index 60b661911c..718f7c48cf 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -119,6 +119,10 @@ predicate isNonExtensible(Call c) { c.getTarget() instanceof Operator } +int getMinimumNumberOfParameters(Function f) { + result = count(Parameter p | p = f.getAParameter() and not p.hasInitializer() | p) +} + predicate isOverloadIndependent(Call call, Expr arg) { arg = call.getAnArgument() and ( @@ -135,7 +139,10 @@ predicate isOverloadIndependent(Call call, Expr arg) { // so check the templates overloads overload = target.(FunctionTemplateInstantiation).getTemplate().getAnOverload() ) and - overload.getNumberOfParameters() = call.getNumberOfArguments() and + // Check that the overload accepts the number of arguments provided by this call, + // considering parameters with default values may be omitted in the call + overload.getNumberOfParameters() >= call.getNumberOfArguments() and + getMinimumNumberOfParameters(overload) <= call.getNumberOfArguments() and call.getArgument(i) = arg | // Check that the parameter types match diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index cbc6ff266a..4a68c1363f 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -46,130 +46,131 @@ | test.cpp:252:6:252:7 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | | test.cpp:261:6:261:6 | 2 | Assignment between incompatible numeric types from 'int' to 'long'. | | test.cpp:269:14:269:15 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int'. | -| test.cpp:281:6:281:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. | -| test.cpp:303:9:303:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | -| test.cpp:332:23:332:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. | -| test.cpp:342:19:342:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | -| test.cpp:347:10:347:12 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:380:8:380:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. | -| test.cpp:381:8:381:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | -| test.cpp:382:9:382:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | -| test.cpp:393:6:393:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. | -| test.cpp:394:6:394:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. | -| test.cpp:405:8:405:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. | -| test.cpp:406:8:406:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | -| test.cpp:419:9:419:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | -| test.cpp:420:7:420:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. | -| test.cpp:421:7:421:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. | -| test.cpp:432:8:432:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test.cpp:450:7:450:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | -| test.cpp:453:7:453:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | -| test.cpp:573:8:573:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:574:8:574:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:578:8:578:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:579:8:579:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:583:7:583:8 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:584:7:584:8 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:588:8:588:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:589:8:589:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:593:8:593:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:594:8:594:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:598:8:598:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:599:8:599:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:603:8:603:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:604:8:604:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:608:8:608:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:609:8:609:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:613:9:613:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:614:9:614:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:618:9:618:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:619:9:619:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:624:9:624:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:625:9:625:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:629:9:629:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:630:9:630:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:634:8:634:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:635:8:635:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:639:9:639:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:640:9:640:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:644:8:644:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:645:8:645:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:649:9:649:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:650:9:650:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:655:6:655:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:656:6:656:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:661:6:661:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:662:6:662:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:664:10:664:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:665:6:665:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:666:6:666:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:666:10:666:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:671:8:671:9 | l3 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | -| test.cpp:672:8:672:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:673:8:673:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:677:9:677:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:678:9:678:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:682:9:682:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:683:9:683:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:687:9:687:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:688:9:688:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:692:9:692:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:693:9:693:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:697:9:697:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:698:9:698:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:702:9:702:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:703:9:703:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:707:9:707:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:708:9:708:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:712:9:712:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:713:9:713:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:717:10:717:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:718:10:718:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:722:10:722:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:723:10:723:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:728:3:728:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:729:3:729:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:733:3:733:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:734:3:734:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:738:3:738:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:739:3:739:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:751:8:751:12 | 42.0 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | -| test.cpp:766:8:766:10 | 42 | Assignment between incompatible numeric types from 'long' to 'int32_t'. | -| test.cpp:767:8:767:11 | 42 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | -| test.cpp:768:8:768:10 | 42 | Assignment between incompatible numeric types from 'unsigned int' to 'int32_t'. | -| test.cpp:786:22:786:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | -| test.cpp:788:26:788:28 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | -| test.cpp:790:31:790:33 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:792:22:792:24 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | -| test.cpp:795:22:795:24 | 256 | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test.cpp:795:27:795:31 | 65536 | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | -| test.cpp:796:22:796:33 | 2147483648 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | -| test.cpp:808:22:808:24 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | -| test.cpp:808:27:808:29 | 400 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | -| test.cpp:808:32:808:34 | 500 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | -| test.cpp:809:22:809:23 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | -| test.cpp:809:26:809:27 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | -| test.cpp:809:30:809:31 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | -| test.cpp:810:22:810:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | -| test.cpp:810:27:810:29 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | -| test.cpp:810:32:810:34 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | -| test.cpp:815:26:815:28 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | -| test.cpp:815:31:815:33 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | -| test.cpp:815:38:815:40 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | -| test.cpp:815:43:815:45 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | -| test.cpp:816:26:816:27 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | -| test.cpp:816:30:816:31 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | -| test.cpp:817:26:817:27 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | -| test.cpp:817:30:817:31 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | -| test.cpp:833:8:833:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | -| test.cpp:837:7:837:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | -| test.cpp:853:24:853:26 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | -| test.cpp:853:29:853:33 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | -| test.cpp:853:36:853:39 | 5000 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | -| test.cpp:854:24:854:26 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | -| test.cpp:854:29:854:31 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | -| test.cpp:854:34:854:36 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | -| test.cpp:864:28:864:30 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test.cpp:287:6:287:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. | +| test.cpp:292:12:292:14 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test.cpp:311:9:311:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | +| test.cpp:340:23:340:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. | +| test.cpp:350:19:350:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:355:10:355:12 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:388:8:388:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. | +| test.cpp:389:8:389:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:390:9:390:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:401:6:401:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. | +| test.cpp:402:6:402:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. | +| test.cpp:413:8:413:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. | +| test.cpp:414:8:414:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:427:9:427:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:428:7:428:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. | +| test.cpp:429:7:429:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. | +| test.cpp:440:8:440:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:458:7:458:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | +| test.cpp:461:7:461:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | +| test.cpp:581:8:581:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:582:8:582:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:586:8:586:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:587:8:587:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:591:7:591:8 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:592:7:592:8 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:596:8:596:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:597:8:597:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:601:8:601:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:602:8:602:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:606:8:606:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:607:8:607:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:611:8:611:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:612:8:612:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:616:8:616:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:617:8:617:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:621:9:621:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:622:9:622:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:626:9:626:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:627:9:627:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:632:9:632:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:633:9:633:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:637:9:637:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:638:9:638:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:642:8:642:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:643:8:643:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:647:9:647:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:648:9:648:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:652:8:652:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:653:8:653:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:657:9:657:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:658:9:658:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:663:6:663:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:664:6:664:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:669:6:669:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:670:6:670:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:672:10:672:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:673:6:673:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:674:6:674:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:674:10:674:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:679:8:679:9 | l3 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test.cpp:680:8:680:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:681:8:681:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:685:9:685:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:686:9:686:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:690:9:690:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:691:9:691:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:695:9:695:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:696:9:696:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:700:9:700:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:701:9:701:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:705:9:705:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:706:9:706:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:710:9:710:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:711:9:711:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:715:9:715:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:716:9:716:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:720:9:720:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:721:9:721:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:725:10:725:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:726:10:726:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:730:10:730:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:731:10:731:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:736:3:736:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:737:3:737:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:741:3:741:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:742:3:742:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:746:3:746:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:747:3:747:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:759:8:759:12 | 42.0 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test.cpp:774:8:774:10 | 42 | Assignment between incompatible numeric types from 'long' to 'int32_t'. | +| test.cpp:775:8:775:11 | 42 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | +| test.cpp:776:8:776:10 | 42 | Assignment between incompatible numeric types from 'unsigned int' to 'int32_t'. | +| test.cpp:794:22:794:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test.cpp:796:26:796:28 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | +| test.cpp:798:31:798:33 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:800:22:800:24 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test.cpp:803:22:803:24 | 256 | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:803:27:803:31 | 65536 | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | +| test.cpp:804:22:804:33 | 2147483648 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | +| test.cpp:816:22:816:24 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test.cpp:816:27:816:29 | 400 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test.cpp:816:32:816:34 | 500 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test.cpp:817:22:817:23 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | +| test.cpp:817:26:817:27 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | +| test.cpp:817:30:817:31 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | +| test.cpp:818:22:818:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:818:27:818:29 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:818:32:818:34 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:823:26:823:28 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test.cpp:823:31:823:33 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test.cpp:823:38:823:40 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test.cpp:823:43:823:45 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test.cpp:824:26:824:27 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test.cpp:824:30:824:31 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test.cpp:825:26:825:27 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test.cpp:825:30:825:31 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test.cpp:841:8:841:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test.cpp:845:7:845:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | +| test.cpp:861:24:861:26 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test.cpp:861:29:861:33 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test.cpp:861:36:861:39 | 5000 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test.cpp:862:24:862:26 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:862:29:862:31 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | +| test.cpp:862:34:862:36 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test.cpp:872:28:872:30 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | | test_member_pointers.cpp:25:12:25:14 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | | test_member_pointers.cpp:26:12:26:14 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | | test_member_pointers.cpp:27:12:27:14 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index f74ce3050c..0191325fbe 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -270,19 +270,27 @@ void test_variadic_functions() { f5("test", s32); // COMPLIANT - already `int`, no promotion needed } -// Test member function calls - not overload-independent struct A { + // first parameter to f6 with two arguments is overload-independent void f6(std::size_t l1, int l2) {} void f6(std::size_t l1, std::string l2) {} - void f7(); + // Different overload, so does not conflict with f6 above + void f6(std::int8_t l1, std::string l2, int x) {} + // Not overload-independent when called with one parameter + // Overload-independent when called with two parameters + void f7(float l1) {} + void f7(std::int32_t l1, int x = 1) {} + void f8(); }; -void A::f7() { +void A::f8() { f6(u32, "answer"); // NON_COMPLIANT - extensible, could call a global // function instead - e.g. `void f6(std::uint32_t l1, // std::string l2)` this->f6(u32, "answer"); // COMPLIANT this->f6(u32, 42); // COMPLIANT + this->f7(s16); // NON_COMPLIANT - no widening as not overload-independent + this->f7(s16, 2); // COMPLIANT - overload-independent, only one target } void test_member_function_overload_independent() { From e659944358097f49a001ed18b98f0df223ea2152 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Jun 2025 23:23:39 +0100 Subject: [PATCH 457/628] Rule 7.0.6: Ignore deleted overloads --- .../NumericAssignmentTypeMismatch.ql | 3 + .../NumericAssignmentTypeMismatch.expected | 302 ------------------ cpp/misra/test/rules/RULE-7-0-6/test.cpp | 2 + 3 files changed, 5 insertions(+), 302 deletions(-) delete mode 100644 cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index 718f7c48cf..bcab42fd0c 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -143,6 +143,9 @@ predicate isOverloadIndependent(Call call, Expr arg) { // considering parameters with default values may be omitted in the call overload.getNumberOfParameters() >= call.getNumberOfArguments() and getMinimumNumberOfParameters(overload) <= call.getNumberOfArguments() and + // Ignore deleted overloads + not overload.isDeleted() and + // call.getArgument(i) = arg | // Check that the parameter types match diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected deleted file mode 100644 index 4a68c1363f..0000000000 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ /dev/null @@ -1,302 +0,0 @@ -| test.cpp:36:8:36:11 | 300 | Assignment between incompatible numeric types from 'unsigned int' to 'uint8_t'. | -| test.cpp:39:7:39:10 | 0.0 | Assignment between incompatible numeric types from 'float' to 'double'. | -| test.cpp:45:8:45:9 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | -| test.cpp:46:8:46:9 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | -| test.cpp:51:8:51:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | -| test.cpp:52:9:52:11 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'uint16_t'. | -| test.cpp:57:7:57:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | -| test.cpp:58:9:58:9 | f | Assignment between incompatible numeric types from 'float' to 'int32_t'. | -| test.cpp:95:12:95:13 | m1 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | -| test.cpp:96:12:96:13 | m2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint64_t'. | -| test.cpp:97:13:97:14 | m1 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | -| test.cpp:98:13:98:14 | m2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint64_t'. | -| test.cpp:103:9:103:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint32_t'. | -| test.cpp:104:10:104:11 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | -| test.cpp:105:35:105:36 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | -| test.cpp:110:8:110:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test.cpp:111:21:111:27 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | -| test.cpp:134:11:134:11 | 4 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | -| test.cpp:137:11:137:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | -| test.cpp:141:11:141:13 | 256 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | -| test.cpp:143:11:143:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | -| test.cpp:144:11:144:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned char'. | -| test.cpp:148:11:148:13 | 512 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | -| test.cpp:149:11:149:15 | 65535 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | -| test.cpp:150:11:150:15 | 65536 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | -| test.cpp:153:11:153:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | -| test.cpp:157:11:157:15 | 65536 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | -| test.cpp:160:11:160:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | -| test.cpp:164:11:164:16 | 131072 | Assignment between incompatible numeric types from 'int' to 'unsigned int'. | -| test.cpp:168:11:168:13 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'unsigned int'. | -| test.cpp:172:11:172:22 | 4294967296 | Assignment between incompatible numeric types from 'unsigned long' to 'unsigned int'. | -| test.cpp:176:11:176:13 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'unsigned int'. | -| test.cpp:180:11:180:21 | 8589934592 | Assignment between incompatible numeric types from 'long' to 'unsigned long'. | -| test.cpp:193:11:193:12 | 16 | Assignment between incompatible numeric types from 'int32_t' to 'signed char'. | -| test.cpp:194:11:194:13 | - ... | Assignment between incompatible numeric types from 'int' to 'signed char'. | -| test.cpp:196:11:196:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'signed char'. | -| test.cpp:200:11:200:14 | 2048 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | -| test.cpp:201:11:201:15 | - ... | Assignment between incompatible numeric types from 'int' to 'short'. | -| test.cpp:204:11:204:13 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | -| test.cpp:208:12:208:22 | 134217728 | Assignment between incompatible numeric types from 'long long' to 'int'. | -| test.cpp:209:12:209:23 | - ... | Assignment between incompatible numeric types from 'long long' to 'int'. | -| test.cpp:224:8:224:9 | l1 | Assignment between incompatible numeric types from 'Colour' to 'uint8_t'. | -| test.cpp:234:6:234:8 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'int64_t'. | -| test.cpp:237:6:237:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:239:6:239:7 | l1 | Assignment between incompatible numeric types from 'int' to 'int32_t'. | -| test.cpp:252:6:252:7 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | -| test.cpp:261:6:261:6 | 2 | Assignment between incompatible numeric types from 'int' to 'long'. | -| test.cpp:269:14:269:15 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int'. | -| test.cpp:287:6:287:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. | -| test.cpp:292:12:292:14 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | -| test.cpp:311:9:311:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | -| test.cpp:340:23:340:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. | -| test.cpp:350:19:350:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | -| test.cpp:355:10:355:12 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:388:8:388:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. | -| test.cpp:389:8:389:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | -| test.cpp:390:9:390:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | -| test.cpp:401:6:401:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. | -| test.cpp:402:6:402:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. | -| test.cpp:413:8:413:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. | -| test.cpp:414:8:414:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | -| test.cpp:427:9:427:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | -| test.cpp:428:7:428:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. | -| test.cpp:429:7:429:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. | -| test.cpp:440:8:440:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test.cpp:458:7:458:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | -| test.cpp:461:7:461:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | -| test.cpp:581:8:581:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:582:8:582:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:586:8:586:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:587:8:587:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:591:7:591:8 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:592:7:592:8 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:596:8:596:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:597:8:597:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:601:8:601:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:602:8:602:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:606:8:606:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:607:8:607:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:611:8:611:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:612:8:612:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:616:8:616:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:617:8:617:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:621:9:621:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:622:9:622:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:626:9:626:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:627:9:627:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:632:9:632:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:633:9:633:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:637:9:637:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:638:9:638:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:642:8:642:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:643:8:643:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:647:9:647:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:648:9:648:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:652:8:652:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:653:8:653:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:657:9:657:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:658:9:658:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:663:6:663:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:664:6:664:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:669:6:669:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:670:6:670:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:672:10:672:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:673:6:673:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:674:6:674:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:674:10:674:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:679:8:679:9 | l3 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | -| test.cpp:680:8:680:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:681:8:681:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:685:9:685:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:686:9:686:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:690:9:690:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:691:9:691:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:695:9:695:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:696:9:696:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:700:9:700:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:701:9:701:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:705:9:705:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:706:9:706:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:710:9:710:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:711:9:711:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:715:9:715:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:716:9:716:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:720:9:720:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:721:9:721:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:725:10:725:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:726:10:726:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:730:10:730:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:731:10:731:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:736:3:736:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:737:3:737:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:741:3:741:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:742:3:742:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:746:3:746:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:747:3:747:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:759:8:759:12 | 42.0 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | -| test.cpp:774:8:774:10 | 42 | Assignment between incompatible numeric types from 'long' to 'int32_t'. | -| test.cpp:775:8:775:11 | 42 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | -| test.cpp:776:8:776:10 | 42 | Assignment between incompatible numeric types from 'unsigned int' to 'int32_t'. | -| test.cpp:794:22:794:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | -| test.cpp:796:26:796:28 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | -| test.cpp:798:31:798:33 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:800:22:800:24 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | -| test.cpp:803:22:803:24 | 256 | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test.cpp:803:27:803:31 | 65536 | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | -| test.cpp:804:22:804:33 | 2147483648 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | -| test.cpp:816:22:816:24 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | -| test.cpp:816:27:816:29 | 400 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | -| test.cpp:816:32:816:34 | 500 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | -| test.cpp:817:22:817:23 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | -| test.cpp:817:26:817:27 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | -| test.cpp:817:30:817:31 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | -| test.cpp:818:22:818:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | -| test.cpp:818:27:818:29 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | -| test.cpp:818:32:818:34 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | -| test.cpp:823:26:823:28 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | -| test.cpp:823:31:823:33 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | -| test.cpp:823:38:823:40 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | -| test.cpp:823:43:823:45 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | -| test.cpp:824:26:824:27 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | -| test.cpp:824:30:824:31 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | -| test.cpp:825:26:825:27 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | -| test.cpp:825:30:825:31 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | -| test.cpp:841:8:841:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | -| test.cpp:845:7:845:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | -| test.cpp:861:24:861:26 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | -| test.cpp:861:29:861:33 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | -| test.cpp:861:36:861:39 | 5000 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | -| test.cpp:862:24:862:26 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | -| test.cpp:862:29:862:31 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | -| test.cpp:862:34:862:36 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | -| test.cpp:872:28:872:30 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | -| test_member_pointers.cpp:25:12:25:14 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test_member_pointers.cpp:26:12:26:14 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | -| test_member_pointers.cpp:27:12:27:14 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test_member_pointers.cpp:28:12:28:14 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | -| test_member_pointers.cpp:32:13:32:15 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test_member_pointers.cpp:33:13:33:15 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | -| test_member_pointers.cpp:34:13:34:15 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test_member_pointers.cpp:35:13:35:15 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | -| test_member_pointers.cpp:42:12:42:14 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test_member_pointers.cpp:43:12:43:14 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | -| test_member_pointers.cpp:44:12:44:14 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test_member_pointers.cpp:45:12:45:14 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | -| test_member_pointers.cpp:49:13:49:15 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test_member_pointers.cpp:50:13:50:15 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | -| test_member_pointers.cpp:51:13:51:15 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test_member_pointers.cpp:52:13:52:15 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | -| test_member_pointers.cpp:58:11:58:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | -| test_member_pointers.cpp:60:11:60:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | -| test_member_pointers.cpp:66:11:66:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | -| test_member_pointers.cpp:67:11:67:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test_member_pointers.cpp:82:6:82:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test_member_pointers.cpp:83:6:83:8 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | -| test_member_pointers.cpp:84:6:84:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test_member_pointers.cpp:85:6:85:8 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | -| test_member_pointers.cpp:90:6:90:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test_member_pointers.cpp:91:6:91:8 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | -| test_member_pointers.cpp:92:6:92:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test_member_pointers.cpp:93:6:93:8 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | -| test_member_pointers.cpp:97:7:97:9 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | -| test_member_pointers.cpp:100:7:100:9 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | -| test_member_pointers.cpp:106:41:106:43 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | -| test_member_pointers.cpp:107:41:107:43 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test_member_pointers.cpp:125:12:125:14 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int64_t'. | -| test_member_pointers.cpp:126:12:126:14 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int64_t'. | -| test_member_pointers.cpp:127:12:127:14 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int64_t'. | -| test_specified.cpp:37:8:37:9 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | -| test_specified.cpp:38:8:38:9 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | -| test_specified.cpp:41:8:41:9 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'int8_t'. | -| test_specified.cpp:42:8:42:9 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | -| test_specified.cpp:43:9:43:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | -| test_specified.cpp:48:8:48:9 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | -| test_specified.cpp:49:9:49:10 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'uint16_t'. | -| test_specified.cpp:50:9:50:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | -| test_specified.cpp:58:9:58:10 | l7 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | -| test_specified.cpp:59:9:59:10 | l8 | Assignment between incompatible numeric types from 'double' to 'int32_t'. | -| test_specified.cpp:71:7:71:8 | l8 | Assignment between incompatible numeric types from 'double' to 'float'. | -| test_specified.cpp:94:8:94:9 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | -| test_specified.cpp:95:8:95:9 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | -| test_specified.cpp:96:9:96:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | -| test_specified.cpp:97:8:97:9 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'int8_t'. | -| test_specified.cpp:98:8:98:9 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | -| test_specified.cpp:99:9:99:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | -| test_specified.cpp:102:8:102:9 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | -| test_specified.cpp:103:9:103:10 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'uint16_t'. | -| test_specified.cpp:104:9:104:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | -| test_specified.cpp:105:8:105:9 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | -| test_specified.cpp:106:9:106:10 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'int16_t'. | -| test_specified.cpp:107:9:107:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test_specified.cpp:110:9:110:10 | l7 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | -| test_specified.cpp:111:9:111:10 | l8 | Assignment between incompatible numeric types from 'double' to 'int32_t'. | -| test_specified.cpp:112:7:112:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'float'. | -| test_specified.cpp:113:7:113:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'float'. | -| test_specified.cpp:114:7:114:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | -| test_specified.cpp:115:7:115:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'double'. | -| test_specified.cpp:116:7:116:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'double'. | -| test_specified.cpp:117:7:117:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'double'. | -| test_specified.cpp:120:7:120:8 | l8 | Assignment between incompatible numeric types from 'double' to 'float'. | -| test_specified.cpp:143:8:143:9 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | -| test_specified.cpp:144:8:144:9 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | -| test_specified.cpp:145:9:145:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | -| test_specified.cpp:146:8:146:9 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'int8_t'. | -| test_specified.cpp:147:8:147:9 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | -| test_specified.cpp:148:9:148:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | -| test_specified.cpp:151:8:151:9 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | -| test_specified.cpp:152:9:152:10 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'uint16_t'. | -| test_specified.cpp:153:9:153:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | -| test_specified.cpp:154:8:154:9 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | -| test_specified.cpp:155:9:155:10 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'int16_t'. | -| test_specified.cpp:156:9:156:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test_specified.cpp:159:9:159:10 | l7 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | -| test_specified.cpp:160:9:160:10 | l8 | Assignment between incompatible numeric types from 'double' to 'int32_t'. | -| test_specified.cpp:161:7:161:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'float'. | -| test_specified.cpp:162:7:162:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'float'. | -| test_specified.cpp:163:7:163:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | -| test_specified.cpp:164:7:164:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'double'. | -| test_specified.cpp:165:7:165:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'double'. | -| test_specified.cpp:166:7:166:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'double'. | -| test_specified.cpp:169:7:169:8 | l8 | Assignment between incompatible numeric types from 'double' to 'float'. | -| test_specified.cpp:213:8:213:9 | l6 | Assignment between incompatible numeric types from 'const uint16_t &' to 'uint8_t'. | -| test_specified.cpp:214:8:214:10 | l10 | Assignment between incompatible numeric types from 'volatile uint16_t &' to 'uint8_t'. | -| test_specified.cpp:215:8:215:10 | l14 | Assignment between incompatible numeric types from 'const volatile uint16_t &' to 'uint8_t'. | -| test_specified.cpp:218:8:218:9 | l5 | Assignment between incompatible numeric types from 'const uint8_t &' to 'int8_t'. | -| test_specified.cpp:219:8:219:9 | l7 | Assignment between incompatible numeric types from 'const int8_t &' to 'uint8_t'. | -| test_specified.cpp:220:8:220:9 | l9 | Assignment between incompatible numeric types from 'volatile uint8_t &' to 'int8_t'. | -| test_specified.cpp:221:8:221:10 | l11 | Assignment between incompatible numeric types from 'volatile int8_t &' to 'uint8_t'. | -| test_specified.cpp:222:8:222:10 | l13 | Assignment between incompatible numeric types from 'const volatile uint8_t &' to 'int8_t'. | -| test_specified.cpp:223:8:223:10 | l15 | Assignment between incompatible numeric types from 'const volatile int8_t &' to 'uint8_t'. | -| test_specified.cpp:226:9:226:10 | l8 | Assignment between incompatible numeric types from 'const float &' to 'int32_t'. | -| test_specified.cpp:227:9:227:11 | l12 | Assignment between incompatible numeric types from 'volatile float &' to 'int32_t'. | -| test_specified.cpp:228:9:228:11 | l16 | Assignment between incompatible numeric types from 'const volatile float &' to 'int32_t'. | -| test_specified.cpp:229:7:229:8 | l3 | Assignment between incompatible numeric types from 'int8_t' to 'float'. | -| test_specified.cpp:230:7:230:8 | l7 | Assignment between incompatible numeric types from 'const int8_t &' to 'float'. | -| test_specified.cpp:231:7:231:9 | l11 | Assignment between incompatible numeric types from 'volatile int8_t &' to 'float'. | -| test_specified.cpp:232:7:232:9 | l15 | Assignment between incompatible numeric types from 'const volatile int8_t &' to 'float'. | -| test_specified.cpp:245:7:245:8 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'const uint32_t'. | -| test_specified.cpp:246:7:246:8 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'const uint32_t'. | -| test_specified.cpp:247:7:247:8 | l3 | Assignment between incompatible numeric types from 'int8_t' to 'volatile int64_t'. | -| test_specified.cpp:248:7:248:8 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'const volatile uint16_t'. | -| test_specified.cpp:250:7:250:8 | l3 | Assignment between incompatible numeric types from 'int8_t' to 'const volatile uint16_t'. | -| test_specified.cpp:285:8:285:22 | g4 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | -| test_specified.cpp:287:8:287:19 | s4 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | -| test_specified.cpp:292:9:292:23 | g5 | Assignment between incompatible numeric types from 'int8_t' to 'uint16_t'. | -| test_specified.cpp:294:9:294:20 | s5 | Assignment between incompatible numeric types from 'int8_t' to 'uint16_t'. | -| test_specified.cpp:308:23:308:25 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | -| test_specified.cpp:308:28:308:32 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | -| test_specified.cpp:308:35:308:38 | 3000 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | -| test_specified.cpp:309:12:309:16 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | -| test_specified.cpp:314:23:314:25 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | -| test_specified.cpp:314:28:314:30 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | -| test_specified.cpp:314:33:314:35 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | -| test_specified.cpp:329:8:329:9 | l2 | Assignment between incompatible numeric types from 'CVColour' to 'uint8_t'. | -| test_specified.cpp:331:8:331:9 | l3 | Assignment between incompatible numeric types from 'CVColour' to 'uint8_t'. | -| test_specified.cpp:342:8:342:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test_specified.cpp:343:8:343:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test_specified.cpp:344:8:344:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test_specified.cpp:351:10:351:11 | l2 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | -| test_specified.cpp:352:10:352:11 | l3 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | -| test_specified.cpp:370:18:370:20 | 300 | Assignment between incompatible numeric types from 'int' to 'const uint8_t'. | -| test_specified.cpp:370:23:370:27 | 70000 | Assignment between incompatible numeric types from 'int' to 'volatile uint16_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index 0191325fbe..cc477d1f33 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -276,6 +276,8 @@ struct A { void f6(std::size_t l1, std::string l2) {} // Different overload, so does not conflict with f6 above void f6(std::int8_t l1, std::string l2, int x) {} + // Deleted function, ignored for overload independence calculations + void f6(float l1, float l2) = delete; // Not overload-independent when called with one parameter // Overload-independent when called with two parameters void f7(float l1) {} From c0fe44dd335d76c5a790b10a4d588754222b54ca Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Jun 2025 23:31:20 +0100 Subject: [PATCH 458/628] Rule 7.0.6: Refactor overload independent code --- .../NumericAssignmentTypeMismatch.ql | 49 ++++++++++--------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index bcab42fd0c..16931f4330 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -123,34 +123,37 @@ int getMinimumNumberOfParameters(Function f) { result = count(Parameter p | p = f.getAParameter() and not p.hasInitializer() | p) } -predicate isOverloadIndependent(Call call, Expr arg) { - arg = call.getAnArgument() and +/** Get an overload of the function f, excluding deleted overloads. */ +Function getAnOverload(Function f) { ( + result = f.getAnOverload() + or + // Instantiated function templates don't directly participate in overload resolution + // so check the templates overloads + result = f.(FunctionTemplateInstantiation).getTemplate().getAnOverload() + ) and + // Exclude deleted overloads + not result.isDeleted() +} + +predicate isOverloadIndependent(Call call, Expr arg) { + exists(int i | arg = call.getArgument(i) | // Call through function pointer call instanceof ExprCall or isNonExtensible(call) and - forall(Function target, Function overload, int i | - target = call.getTarget() and - ( - overload = target.getAnOverload() - or - // Instantiated function templates don't directly participate in overload resolution - // so check the templates overloads - overload = target.(FunctionTemplateInstantiation).getTemplate().getAnOverload() - ) and - // Check that the overload accepts the number of arguments provided by this call, - // considering parameters with default values may be omitted in the call - overload.getNumberOfParameters() >= call.getNumberOfArguments() and - getMinimumNumberOfParameters(overload) <= call.getNumberOfArguments() and - // Ignore deleted overloads - not overload.isDeleted() and - // - call.getArgument(i) = arg - | - // Check that the parameter types match - overload.getParameter(i).getType().getUnspecifiedType() = - target.getParameter(i).getType().getUnspecifiedType() + exists(Function target | target = call.getTarget() | + forall(Function overload | + overload = getAnOverload(target) and + // Check that the overload accepts the number of arguments provided by this call, + // considering parameters with default values may be omitted in the call + overload.getNumberOfParameters() >= call.getNumberOfArguments() and + getMinimumNumberOfParameters(overload) <= call.getNumberOfArguments() + | + // Check that the parameter types match + overload.getParameter(i).getType().getUnspecifiedType() = + target.getParameter(i).getType().getUnspecifiedType() + ) ) ) } From 06ffbfbcab8307c2af16a7810717b8614c8cae8c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Jun 2025 23:36:26 +0100 Subject: [PATCH 459/628] Rule 7.0.6: Move aggregate tests to new file --- .../NumericAssignmentTypeMismatch.expected | 302 ++++++++++++++++++ cpp/misra/test/rules/RULE-7-0-6/test.cpp | 99 ------ .../test/rules/RULE-7-0-6/test_aggregate.cpp | 111 +++++++ 3 files changed, 413 insertions(+), 99 deletions(-) create mode 100644 cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected create mode 100644 cpp/misra/test/rules/RULE-7-0-6/test_aggregate.cpp diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected new file mode 100644 index 0000000000..c0c9e50ec3 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -0,0 +1,302 @@ +| test.cpp:36:8:36:11 | 300 | Assignment between incompatible numeric types from 'unsigned int' to 'uint8_t'. | +| test.cpp:39:7:39:10 | 0.0 | Assignment between incompatible numeric types from 'float' to 'double'. | +| test.cpp:45:8:45:9 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | +| test.cpp:46:8:46:9 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | +| test.cpp:51:8:51:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test.cpp:52:9:52:11 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'uint16_t'. | +| test.cpp:57:7:57:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test.cpp:58:9:58:9 | f | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test.cpp:95:12:95:13 | m1 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test.cpp:96:12:96:13 | m2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint64_t'. | +| test.cpp:97:13:97:14 | m1 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test.cpp:98:13:98:14 | m2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint64_t'. | +| test.cpp:103:9:103:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint32_t'. | +| test.cpp:104:10:104:11 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test.cpp:105:35:105:36 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test.cpp:110:8:110:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:111:21:111:27 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:134:11:134:11 | 4 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test.cpp:137:11:137:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:141:11:141:13 | 256 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test.cpp:143:11:143:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test.cpp:144:11:144:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned char'. | +| test.cpp:148:11:148:13 | 512 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test.cpp:149:11:149:15 | 65535 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test.cpp:150:11:150:15 | 65536 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test.cpp:153:11:153:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | +| test.cpp:157:11:157:15 | 65536 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test.cpp:160:11:160:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | +| test.cpp:164:11:164:16 | 131072 | Assignment between incompatible numeric types from 'int' to 'unsigned int'. | +| test.cpp:168:11:168:13 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'unsigned int'. | +| test.cpp:172:11:172:22 | 4294967296 | Assignment between incompatible numeric types from 'unsigned long' to 'unsigned int'. | +| test.cpp:176:11:176:13 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'unsigned int'. | +| test.cpp:180:11:180:21 | 8589934592 | Assignment between incompatible numeric types from 'long' to 'unsigned long'. | +| test.cpp:193:11:193:12 | 16 | Assignment between incompatible numeric types from 'int32_t' to 'signed char'. | +| test.cpp:194:11:194:13 | - ... | Assignment between incompatible numeric types from 'int' to 'signed char'. | +| test.cpp:196:11:196:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'signed char'. | +| test.cpp:200:11:200:14 | 2048 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test.cpp:201:11:201:15 | - ... | Assignment between incompatible numeric types from 'int' to 'short'. | +| test.cpp:204:11:204:13 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test.cpp:208:12:208:22 | 134217728 | Assignment between incompatible numeric types from 'long long' to 'int'. | +| test.cpp:209:12:209:23 | - ... | Assignment between incompatible numeric types from 'long long' to 'int'. | +| test.cpp:224:8:224:9 | l1 | Assignment between incompatible numeric types from 'Colour' to 'uint8_t'. | +| test.cpp:234:6:234:8 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'int64_t'. | +| test.cpp:237:6:237:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:239:6:239:7 | l1 | Assignment between incompatible numeric types from 'int' to 'int32_t'. | +| test.cpp:252:6:252:7 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | +| test.cpp:261:6:261:6 | 2 | Assignment between incompatible numeric types from 'int' to 'long'. | +| test.cpp:269:14:269:15 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'int'. | +| test.cpp:289:6:289:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. | +| test.cpp:294:12:294:14 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test.cpp:313:9:313:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | +| test.cpp:342:23:342:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. | +| test.cpp:352:19:352:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:357:10:357:12 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:390:8:390:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. | +| test.cpp:391:8:391:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:392:9:392:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:403:6:403:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. | +| test.cpp:404:6:404:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. | +| test.cpp:415:8:415:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. | +| test.cpp:416:8:416:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:429:9:429:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:430:7:430:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. | +| test.cpp:431:7:431:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. | +| test.cpp:442:8:442:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:460:7:460:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | +| test.cpp:463:7:463:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | +| test.cpp:583:8:583:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:584:8:584:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:588:8:588:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:589:8:589:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:593:7:593:8 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:594:7:594:8 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:598:8:598:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:599:8:599:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:603:8:603:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:604:8:604:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:608:8:608:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:609:8:609:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:613:8:613:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:614:8:614:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:618:8:618:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:619:8:619:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:623:9:623:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:624:9:624:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:628:9:628:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:629:9:629:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:634:9:634:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:635:9:635:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:639:9:639:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:640:9:640:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:644:8:644:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:645:8:645:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:649:9:649:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:650:9:650:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:654:8:654:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:655:8:655:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:659:9:659:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:660:9:660:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:665:6:665:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:666:6:666:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:671:6:671:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:672:6:672:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:674:10:674:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:675:6:675:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:676:6:676:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:676:10:676:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:681:8:681:9 | l3 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test.cpp:682:8:682:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:683:8:683:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:687:9:687:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:688:9:688:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:692:9:692:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:693:9:693:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:697:9:697:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:698:9:698:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:702:9:702:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:703:9:703:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:707:9:707:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:708:9:708:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:712:9:712:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:713:9:713:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:717:9:717:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:718:9:718:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:722:9:722:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:723:9:723:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:727:10:727:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:728:10:728:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:732:10:732:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:733:10:733:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:738:3:738:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:739:3:739:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:743:3:743:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:744:3:744:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:748:3:748:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test.cpp:749:3:749:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:761:8:761:12 | 42.0 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test.cpp:776:8:776:10 | 42 | Assignment between incompatible numeric types from 'long' to 'int32_t'. | +| test.cpp:777:8:777:11 | 42 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | +| test.cpp:778:8:778:10 | 42 | Assignment between incompatible numeric types from 'unsigned int' to 'int32_t'. | +| test_aggregate.cpp:29:22:29:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_aggregate.cpp:31:26:31:28 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | +| test_aggregate.cpp:33:31:33:33 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_aggregate.cpp:35:22:35:24 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test_aggregate.cpp:38:22:38:24 | 256 | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test_aggregate.cpp:38:27:38:31 | 65536 | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | +| test_aggregate.cpp:39:22:39:33 | 2147483648 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | +| test_aggregate.cpp:51:22:51:24 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test_aggregate.cpp:51:27:51:29 | 400 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test_aggregate.cpp:51:32:51:34 | 500 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test_aggregate.cpp:52:22:52:23 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | +| test_aggregate.cpp:52:26:52:27 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | +| test_aggregate.cpp:52:30:52:31 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'unsigned char'. | +| test_aggregate.cpp:53:22:53:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test_aggregate.cpp:53:27:53:29 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test_aggregate.cpp:53:32:53:34 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test_aggregate.cpp:58:26:58:28 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test_aggregate.cpp:58:31:58:33 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test_aggregate.cpp:58:38:58:40 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test_aggregate.cpp:58:43:58:45 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'signed short'. | +| test_aggregate.cpp:59:26:59:27 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test_aggregate.cpp:59:30:59:31 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test_aggregate.cpp:60:26:60:27 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test_aggregate.cpp:60:30:60:31 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'signed short'. | +| test_aggregate.cpp:76:8:76:10 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_aggregate.cpp:80:7:80:9 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | +| test_aggregate.cpp:96:24:96:26 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test_aggregate.cpp:96:29:96:33 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test_aggregate.cpp:96:36:96:39 | 5000 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test_aggregate.cpp:97:24:97:26 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test_aggregate.cpp:97:29:97:31 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | +| test_aggregate.cpp:97:34:97:36 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test_aggregate.cpp:107:28:107:30 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_member_pointers.cpp:25:12:25:14 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:26:12:26:14 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:27:12:27:14 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:28:12:28:14 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:32:13:32:15 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:33:13:33:15 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:34:13:34:15 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:35:13:35:15 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:42:12:42:14 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:43:12:43:14 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:44:12:44:14 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:45:12:45:14 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:49:13:49:15 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:50:13:50:15 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:51:13:51:15 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:52:13:52:15 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:58:11:58:13 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test_member_pointers.cpp:60:11:60:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:66:11:66:13 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:67:11:67:13 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:82:6:82:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:83:6:83:8 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:84:6:84:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:85:6:85:8 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:90:6:90:8 | s64 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_member_pointers.cpp:91:6:91:8 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:92:6:92:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:93:6:93:8 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int32_t'. | +| test_member_pointers.cpp:97:7:97:9 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test_member_pointers.cpp:100:7:100:9 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:106:41:106:43 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int32_t'. | +| test_member_pointers.cpp:107:41:107:43 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_member_pointers.cpp:125:12:125:14 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int64_t'. | +| test_member_pointers.cpp:126:12:126:14 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int64_t'. | +| test_member_pointers.cpp:127:12:127:14 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int64_t'. | +| test_specified.cpp:37:8:37:9 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:38:8:38:9 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | +| test_specified.cpp:41:8:41:9 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'int8_t'. | +| test_specified.cpp:42:8:42:9 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | +| test_specified.cpp:43:9:43:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | +| test_specified.cpp:48:8:48:9 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | +| test_specified.cpp:49:9:49:10 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'uint16_t'. | +| test_specified.cpp:50:9:50:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | +| test_specified.cpp:58:9:58:10 | l7 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test_specified.cpp:59:9:59:10 | l8 | Assignment between incompatible numeric types from 'double' to 'int32_t'. | +| test_specified.cpp:71:7:71:8 | l8 | Assignment between incompatible numeric types from 'double' to 'float'. | +| test_specified.cpp:94:8:94:9 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:95:8:95:9 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | +| test_specified.cpp:96:9:96:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | +| test_specified.cpp:97:8:97:9 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'int8_t'. | +| test_specified.cpp:98:8:98:9 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | +| test_specified.cpp:99:9:99:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | +| test_specified.cpp:102:8:102:9 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | +| test_specified.cpp:103:9:103:10 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'uint16_t'. | +| test_specified.cpp:104:9:104:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | +| test_specified.cpp:105:8:105:9 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | +| test_specified.cpp:106:9:106:10 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'int16_t'. | +| test_specified.cpp:107:9:107:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_specified.cpp:110:9:110:10 | l7 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test_specified.cpp:111:9:111:10 | l8 | Assignment between incompatible numeric types from 'double' to 'int32_t'. | +| test_specified.cpp:112:7:112:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'float'. | +| test_specified.cpp:113:7:113:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'float'. | +| test_specified.cpp:114:7:114:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test_specified.cpp:115:7:115:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'double'. | +| test_specified.cpp:116:7:116:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'double'. | +| test_specified.cpp:117:7:117:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'double'. | +| test_specified.cpp:120:7:120:8 | l8 | Assignment between incompatible numeric types from 'double' to 'float'. | +| test_specified.cpp:143:8:143:9 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:144:8:144:9 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | +| test_specified.cpp:145:9:145:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | +| test_specified.cpp:146:8:146:9 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'int8_t'. | +| test_specified.cpp:147:8:147:9 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | +| test_specified.cpp:148:9:148:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | +| test_specified.cpp:151:8:151:9 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'uint8_t'. | +| test_specified.cpp:152:9:152:10 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'uint16_t'. | +| test_specified.cpp:153:9:153:10 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'uint32_t'. | +| test_specified.cpp:154:8:154:9 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int8_t'. | +| test_specified.cpp:155:9:155:10 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'int16_t'. | +| test_specified.cpp:156:9:156:10 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_specified.cpp:159:9:159:10 | l7 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test_specified.cpp:160:9:160:10 | l8 | Assignment between incompatible numeric types from 'double' to 'int32_t'. | +| test_specified.cpp:161:7:161:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'float'. | +| test_specified.cpp:162:7:162:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'float'. | +| test_specified.cpp:163:7:163:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'float'. | +| test_specified.cpp:164:7:164:8 | l4 | Assignment between incompatible numeric types from 'int8_t' to 'double'. | +| test_specified.cpp:165:7:165:8 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'double'. | +| test_specified.cpp:166:7:166:8 | l6 | Assignment between incompatible numeric types from 'int32_t' to 'double'. | +| test_specified.cpp:169:7:169:8 | l8 | Assignment between incompatible numeric types from 'double' to 'float'. | +| test_specified.cpp:213:8:213:9 | l6 | Assignment between incompatible numeric types from 'const uint16_t &' to 'uint8_t'. | +| test_specified.cpp:214:8:214:10 | l10 | Assignment between incompatible numeric types from 'volatile uint16_t &' to 'uint8_t'. | +| test_specified.cpp:215:8:215:10 | l14 | Assignment between incompatible numeric types from 'const volatile uint16_t &' to 'uint8_t'. | +| test_specified.cpp:218:8:218:9 | l5 | Assignment between incompatible numeric types from 'const uint8_t &' to 'int8_t'. | +| test_specified.cpp:219:8:219:9 | l7 | Assignment between incompatible numeric types from 'const int8_t &' to 'uint8_t'. | +| test_specified.cpp:220:8:220:9 | l9 | Assignment between incompatible numeric types from 'volatile uint8_t &' to 'int8_t'. | +| test_specified.cpp:221:8:221:10 | l11 | Assignment between incompatible numeric types from 'volatile int8_t &' to 'uint8_t'. | +| test_specified.cpp:222:8:222:10 | l13 | Assignment between incompatible numeric types from 'const volatile uint8_t &' to 'int8_t'. | +| test_specified.cpp:223:8:223:10 | l15 | Assignment between incompatible numeric types from 'const volatile int8_t &' to 'uint8_t'. | +| test_specified.cpp:226:9:226:10 | l8 | Assignment between incompatible numeric types from 'const float &' to 'int32_t'. | +| test_specified.cpp:227:9:227:11 | l12 | Assignment between incompatible numeric types from 'volatile float &' to 'int32_t'. | +| test_specified.cpp:228:9:228:11 | l16 | Assignment between incompatible numeric types from 'const volatile float &' to 'int32_t'. | +| test_specified.cpp:229:7:229:8 | l3 | Assignment between incompatible numeric types from 'int8_t' to 'float'. | +| test_specified.cpp:230:7:230:8 | l7 | Assignment between incompatible numeric types from 'const int8_t &' to 'float'. | +| test_specified.cpp:231:7:231:9 | l11 | Assignment between incompatible numeric types from 'volatile int8_t &' to 'float'. | +| test_specified.cpp:232:7:232:9 | l15 | Assignment between incompatible numeric types from 'const volatile int8_t &' to 'float'. | +| test_specified.cpp:245:7:245:8 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'const uint32_t'. | +| test_specified.cpp:246:7:246:8 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'const uint32_t'. | +| test_specified.cpp:247:7:247:8 | l3 | Assignment between incompatible numeric types from 'int8_t' to 'volatile int64_t'. | +| test_specified.cpp:248:7:248:8 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'const volatile uint16_t'. | +| test_specified.cpp:250:7:250:8 | l3 | Assignment between incompatible numeric types from 'int8_t' to 'const volatile uint16_t'. | +| test_specified.cpp:285:8:285:22 | g4 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:287:8:287:19 | s4 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | +| test_specified.cpp:292:9:292:23 | g5 | Assignment between incompatible numeric types from 'int8_t' to 'uint16_t'. | +| test_specified.cpp:294:9:294:20 | s5 | Assignment between incompatible numeric types from 'int8_t' to 'uint16_t'. | +| test_specified.cpp:308:23:308:25 | 300 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | +| test_specified.cpp:308:28:308:32 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test_specified.cpp:308:35:308:38 | 3000 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test_specified.cpp:309:12:309:16 | 70000 | Assignment between incompatible numeric types from 'int' to 'unsigned short'. | +| test_specified.cpp:314:23:314:25 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'unsigned char'. | +| test_specified.cpp:314:28:314:30 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned short'. | +| test_specified.cpp:314:33:314:35 | s32 | Assignment between incompatible numeric types from 'int32_t' to 'short'. | +| test_specified.cpp:329:8:329:9 | l2 | Assignment between incompatible numeric types from 'CVColour' to 'uint8_t'. | +| test_specified.cpp:331:8:331:9 | l3 | Assignment between incompatible numeric types from 'CVColour' to 'uint8_t'. | +| test_specified.cpp:342:8:342:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test_specified.cpp:343:8:343:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test_specified.cpp:344:8:344:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test_specified.cpp:351:10:351:11 | l2 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test_specified.cpp:352:10:352:11 | l3 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test_specified.cpp:370:18:370:20 | 300 | Assignment between incompatible numeric types from 'int' to 'const uint8_t'. | +| test_specified.cpp:370:23:370:27 | 70000 | Assignment between incompatible numeric types from 'int' to 'volatile uint16_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index cc477d1f33..9b7d6dbd02 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -776,103 +776,4 @@ void test_user_defined_operators_constants() { l1 = 42L; // NON_COMPLIANT l1 = 42LL; // NON_COMPLIANT l1 = 42U; // NON_COMPLIANT -} - -// Test aggregate initialization - struct with multiple members -struct SimpleAggregate { - std::uint8_t m1; - std::uint16_t m2; - std::int32_t m3; - float m4; -}; - -void test_aggregate_initialization_basic() { - // Compliant cases - exact types or constants that fit - SimpleAggregate l1{42, 1000, -50, 3.14f}; // COMPLIANT - SimpleAggregate l2{u8, u16, s32, f}; // COMPLIANT - SimpleAggregate l3{255, 65535, 2147483647, 0.0f}; // COMPLIANT - - // Non-compliant cases - type violations - SimpleAggregate l4{u16, u8, s32, // NON_COMPLIANT - narrowing u16 to uint8_t - f}; - SimpleAggregate l5{u8, u32, s32, // NON_COMPLIANT - narrowing u32 to uint16_t - f}; - SimpleAggregate l6{u8, u16, u32, f}; // NON_COMPLIANT - different signedness - SimpleAggregate l7{u8, u16, s32, - s32}; // NON_COMPLIANT - different type category - - // Constants that don't fit - SimpleAggregate l8{256, 65536, // NON_COMPLIANT - constants don't fit - 2147483648LL, // NON_COMPLIANT - constants don't fit - 0.0f}; - - // Widening of id-expressions is allowed - SimpleAggregate l9{u8, u8, s8, f}; // COMPLIANT - widening allowed -} - -// Test aggregate initialization - arrays -void test_aggregate_initialization_arrays() { - // Basic arrays - std::uint8_t l1[3]{10, 20, 30}; // COMPLIANT - std::uint8_t l2[3]{u8, u8, u8}; // COMPLIANT - std::uint8_t l3[3]{300, 400, 500}; // NON_COMPLIANT - constants don't fit - std::uint8_t l4[3]{s8, s8, s8}; // NON_COMPLIANT - signedness mismatch - std::uint8_t l5[3]{u16, u16, u16}; // NON_COMPLIANT - narrowing - - // Multi-dimensional arrays - std::int16_t l6[2][2]{{1, 2}, {3, 4}}; // COMPLIANT - std::int16_t l7[2][2]{{s8, s8}, {s8, s8}}; // COMPLIANT - widening allowed - std::int16_t l8[2][2]{{s32, s32}, {s32, s32}}; // NON_COMPLIANT - narrowing - std::int16_t l9[2][2]{{u8, u8}, // NON_COMPLIANT - signedness mismatch - {u8, u8}}; // NON_COMPLIANT - signedness mismatch -} - -// Test aggregate initialization - nested structs -struct NestedAggregate { - SimpleAggregate m1; - std::uint32_t m2; -}; - -void test_aggregate_initialization_nested() { - // Compliant nested initialization - NestedAggregate l1{{10, 100, -5, 1.0f}, 500}; // COMPLIANT - NestedAggregate l2{{u8, u16, s32, f}, u32}; // COMPLIANT - - // Non-compliant nested initialization - NestedAggregate l3{ - {u16, u8, s32, f}, // NON_COMPLIANT - narrowing in nested struct - u32}; - NestedAggregate l4{ - {u8, u16, s32, f}, - s32}; // NON_COMPLIANT - signedness mismatch in outer member -} - -// Test aggregate initialization - struct with bit-fields -struct BitfieldAggregate { - std::uint32_t m1 : 8; - std::uint32_t m2 : 16; - std::int32_t m3 : 12; -}; - -void test_aggregate_initialization_bitfields() { - // Compliant cases - BitfieldAggregate l1{100, 30000, -500}; // COMPLIANT - BitfieldAggregate l2{u8, u16, s16}; // COMPLIANT - appropriate sizes - - // Non-compliant cases - BitfieldAggregate l3{300, 70000, 5000}; // NON_COMPLIANT - constants don't fit - BitfieldAggregate l4{u16, u32, s32}; // NON_COMPLIANT - narrowing -} - -// Test aggregate initialization with designated initializers (C++20 feature, -// but test for basic cases) -void test_aggregate_initialization_designated() { - // Note: Designated initializers are C++20, but we can test basic aggregate - // init patterns - SimpleAggregate l1{.m1 = 10, .m2 = 100, .m3 = -5, .m4 = 1.0f}; // COMPLIANT - SimpleAggregate l2{.m1 = u8, .m2 = u16, .m3 = s32, .m4 = f}; // COMPLIANT - SimpleAggregate l3{.m1 = u16, // NON_COMPLIANT - type violation - .m2 = u8, - .m3 = s32, - .m4 = f}; } \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-6/test_aggregate.cpp b/cpp/misra/test/rules/RULE-7-0-6/test_aggregate.cpp new file mode 100644 index 0000000000..7e215bc602 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/test_aggregate.cpp @@ -0,0 +1,111 @@ +#include + +std::uint32_t u32; +std::int32_t s32; +std::uint8_t u8; +std::int8_t s8; +std::uint16_t u16; +std::int16_t s16; +std::uint64_t u64; +std::int64_t s64; +float f; +double d; + +// Test aggregate initialization - struct with multiple members +struct SimpleAggregate { + std::uint8_t m1; + std::uint16_t m2; + std::int32_t m3; + float m4; +}; + +void test_aggregate_initialization_basic() { + // Compliant cases - exact types or constants that fit + SimpleAggregate l1{42, 1000, -50, 3.14f}; // COMPLIANT + SimpleAggregate l2{u8, u16, s32, f}; // COMPLIANT + SimpleAggregate l3{255, 65535, 2147483647, 0.0f}; // COMPLIANT + + // Non-compliant cases - type violations + SimpleAggregate l4{u16, u8, s32, // NON_COMPLIANT - narrowing u16 to uint8_t + f}; + SimpleAggregate l5{u8, u32, s32, // NON_COMPLIANT - narrowing u32 to uint16_t + f}; + SimpleAggregate l6{u8, u16, u32, f}; // NON_COMPLIANT - different signedness + SimpleAggregate l7{u8, u16, s32, + s32}; // NON_COMPLIANT - different type category + + // Constants that don't fit + SimpleAggregate l8{256, 65536, // NON_COMPLIANT - constants don't fit + 2147483648LL, // NON_COMPLIANT - constants don't fit + 0.0f}; + + // Widening of id-expressions is allowed + SimpleAggregate l9{u8, u8, s8, f}; // COMPLIANT - widening allowed +} + +// Test aggregate initialization - arrays +void test_aggregate_initialization_arrays() { + // Basic arrays + std::uint8_t l1[3]{10, 20, 30}; // COMPLIANT + std::uint8_t l2[3]{u8, u8, u8}; // COMPLIANT + std::uint8_t l3[3]{300, 400, 500}; // NON_COMPLIANT - constants don't fit + std::uint8_t l4[3]{s8, s8, s8}; // NON_COMPLIANT - signedness mismatch + std::uint8_t l5[3]{u16, u16, u16}; // NON_COMPLIANT - narrowing + + // Multi-dimensional arrays + std::int16_t l6[2][2]{{1, 2}, {3, 4}}; // COMPLIANT + std::int16_t l7[2][2]{{s8, s8}, {s8, s8}}; // COMPLIANT - widening allowed + std::int16_t l8[2][2]{{s32, s32}, {s32, s32}}; // NON_COMPLIANT - narrowing + std::int16_t l9[2][2]{{u8, u8}, // NON_COMPLIANT - signedness mismatch + {u8, u8}}; // NON_COMPLIANT - signedness mismatch +} + +// Test aggregate initialization - nested structs +struct NestedAggregate { + SimpleAggregate m1; + std::uint32_t m2; +}; + +void test_aggregate_initialization_nested() { + // Compliant nested initialization + NestedAggregate l1{{10, 100, -5, 1.0f}, 500}; // COMPLIANT + NestedAggregate l2{{u8, u16, s32, f}, u32}; // COMPLIANT + + // Non-compliant nested initialization + NestedAggregate l3{ + {u16, u8, s32, f}, // NON_COMPLIANT - narrowing in nested struct + u32}; + NestedAggregate l4{ + {u8, u16, s32, f}, + s32}; // NON_COMPLIANT - signedness mismatch in outer member +} + +// Test aggregate initialization - struct with bit-fields +struct BitfieldAggregate { + std::uint32_t m1 : 8; + std::uint32_t m2 : 16; + std::int32_t m3 : 12; +}; + +void test_aggregate_initialization_bitfields() { + // Compliant cases + BitfieldAggregate l1{100, 30000, -500}; // COMPLIANT + BitfieldAggregate l2{u8, u16, s16}; // COMPLIANT - appropriate sizes + + // Non-compliant cases + BitfieldAggregate l3{300, 70000, 5000}; // NON_COMPLIANT - constants don't fit + BitfieldAggregate l4{u16, u32, s32}; // NON_COMPLIANT - narrowing +} + +// Test aggregate initialization with designated initializers (C++20 feature, +// but test for basic cases) +void test_aggregate_initialization_designated() { + // Note: Designated initializers are C++20, but we can test basic aggregate + // init patterns + SimpleAggregate l1{.m1 = 10, .m2 = 100, .m3 = -5, .m4 = 1.0f}; // COMPLIANT + SimpleAggregate l2{.m1 = u8, .m2 = u16, .m3 = s32, .m4 = f}; // COMPLIANT + SimpleAggregate l3{.m1 = u16, // NON_COMPLIANT - type violation + .m2 = u8, + .m3 = s32, + .m4 = f}; +} \ No newline at end of file From fc63db1d69434de645fa3db6c4e330194dd84459 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Jun 2025 23:38:24 +0100 Subject: [PATCH 460/628] Rule 7.0.6: Move operator tests to separate file --- .../NumericAssignmentTypeMismatch.expected | 146 ++++----- cpp/misra/test/rules/RULE-7-0-6/test.cpp | 294 ----------------- .../test/rules/RULE-7-0-6/test_operators.cpp | 295 ++++++++++++++++++ 3 files changed, 368 insertions(+), 367 deletions(-) create mode 100644 cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index c0c9e50ec3..e9ac08e3c4 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -65,79 +65,6 @@ | test.cpp:442:8:442:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | | test.cpp:460:7:460:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | | test.cpp:463:7:463:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | -| test.cpp:583:8:583:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:584:8:584:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:588:8:588:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:589:8:589:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:593:7:593:8 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:594:7:594:8 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:598:8:598:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:599:8:599:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:603:8:603:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:604:8:604:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:608:8:608:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:609:8:609:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:613:8:613:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:614:8:614:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:618:8:618:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:619:8:619:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:623:9:623:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:624:9:624:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:628:9:628:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:629:9:629:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:634:9:634:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:635:9:635:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:639:9:639:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:640:9:640:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:644:8:644:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:645:8:645:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:649:9:649:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:650:9:650:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:654:8:654:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:655:8:655:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:659:9:659:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:660:9:660:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:665:6:665:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:666:6:666:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:671:6:671:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:672:6:672:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:674:10:674:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:675:6:675:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:676:6:676:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:676:10:676:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:681:8:681:9 | l3 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | -| test.cpp:682:8:682:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:683:8:683:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:687:9:687:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:688:9:688:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:692:9:692:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:693:9:693:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:697:9:697:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:698:9:698:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:702:9:702:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:703:9:703:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:707:9:707:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:708:9:708:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:712:9:712:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:713:9:713:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:717:9:717:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:718:9:718:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:722:9:722:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:723:9:723:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:727:10:727:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:728:10:728:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:732:10:732:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:733:10:733:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:738:3:738:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:739:3:739:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:743:3:743:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:744:3:744:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:748:3:748:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test.cpp:749:3:749:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:761:8:761:12 | 42.0 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | -| test.cpp:776:8:776:10 | 42 | Assignment between incompatible numeric types from 'long' to 'int32_t'. | -| test.cpp:777:8:777:11 | 42 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | -| test.cpp:778:8:778:10 | 42 | Assignment between incompatible numeric types from 'unsigned int' to 'int32_t'. | | test_aggregate.cpp:29:22:29:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | | test_aggregate.cpp:31:26:31:28 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | | test_aggregate.cpp:33:31:33:33 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | @@ -206,6 +133,79 @@ | test_member_pointers.cpp:125:12:125:14 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'int64_t'. | | test_member_pointers.cpp:126:12:126:14 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int64_t'. | | test_member_pointers.cpp:127:12:127:14 | u64 | Assignment between incompatible numeric types from 'uint64_t' to 'int64_t'. | +| test_operators.cpp:99:8:99:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:100:8:100:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:104:8:104:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:105:8:105:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:109:7:109:8 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:110:7:110:8 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:114:8:114:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:115:8:115:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:119:8:119:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:120:8:120:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:124:8:124:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:125:8:125:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:129:8:129:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:130:8:130:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:134:8:134:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:135:8:135:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:139:9:139:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:140:9:140:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:144:9:144:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:145:9:145:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:150:9:150:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:151:9:151:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:155:9:155:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:156:9:156:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:160:8:160:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:161:8:161:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:165:9:165:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:166:9:166:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:170:8:170:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:171:8:171:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:175:9:175:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:176:9:176:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:181:6:181:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:182:6:182:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:187:6:187:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:188:6:188:7 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:190:10:190:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:191:6:191:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:192:6:192:7 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:192:10:192:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:197:8:197:9 | l3 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test_operators.cpp:198:8:198:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:199:8:199:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:203:9:203:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:204:9:204:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:208:9:208:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:209:9:209:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:213:9:213:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:214:9:214:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:218:9:218:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:219:9:219:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:223:9:223:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:224:9:224:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:228:9:228:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:229:9:229:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:233:9:233:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:234:9:234:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:238:9:238:10 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:239:9:239:10 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:243:10:243:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:244:10:244:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:248:10:248:11 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:249:10:249:11 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:254:3:254:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:255:3:255:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:259:3:259:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:260:3:260:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:264:3:264:4 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:265:3:265:4 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:277:8:277:12 | 42.0 | Assignment between incompatible numeric types from 'float' to 'int32_t'. | +| test_operators.cpp:292:8:292:10 | 42 | Assignment between incompatible numeric types from 'long' to 'int32_t'. | +| test_operators.cpp:293:8:293:11 | 42 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | +| test_operators.cpp:294:8:294:10 | 42 | Assignment between incompatible numeric types from 'unsigned int' to 'int32_t'. | | test_specified.cpp:37:8:37:9 | l2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | | test_specified.cpp:38:8:38:9 | l3 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | | test_specified.cpp:41:8:41:9 | l5 | Assignment between incompatible numeric types from 'int16_t' to 'int8_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index 9b7d6dbd02..9b8bdc0022 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -482,298 +482,4 @@ void test_compound_assignments() { l2 >>= 1; // COMPLIANT - compound assignment, rule does not apply l4 += l1; // COMPLIANT - compound assignment, rule does not apply l4 -= s32; // COMPLIANT - compound assignment, rule does not apply -} - -// Test user-defined operators - always non-extensible -struct UserDefinedOperators { - UserDefinedOperators(std::int32_t l1) {} - - // Binary operators - UserDefinedOperators operator+(std::int32_t l1) const { - return UserDefinedOperators{0}; - } - UserDefinedOperators operator-(std::int32_t l1) const { - return UserDefinedOperators{0}; - } - UserDefinedOperators operator*(std::int32_t l1) const { - return UserDefinedOperators{0}; - } - UserDefinedOperators operator/(std::int32_t l1) const { - return UserDefinedOperators{0}; - } - UserDefinedOperators operator%(std::int32_t l1) const { - return UserDefinedOperators{0}; - } - UserDefinedOperators operator&(std::int32_t l1) const { - return UserDefinedOperators{0}; - } - UserDefinedOperators operator|(std::int32_t l1) const { - return UserDefinedOperators{0}; - } - UserDefinedOperators operator^(std::int32_t l1) const { - return UserDefinedOperators{0}; - } - UserDefinedOperators operator<<(std::int32_t l1) const { - return UserDefinedOperators{0}; - } - UserDefinedOperators operator>>(std::int32_t l1) const { - return UserDefinedOperators{0}; - } - - // Comparison operators - bool operator==(std::int32_t l1) const { return true; } - bool operator!=(std::int32_t l1) const { return false; } - bool operator<(std::int32_t l1) const { return false; } - bool operator<=(std::int32_t l1) const { return false; } - bool operator>(std::int32_t l1) const { return false; } - bool operator>=(std::int32_t l1) const { return false; } - - // Subscript operator - std::int32_t operator[](std::int32_t l1) const { return 0; } - - // Function call operator - std::int32_t operator()(std::int32_t l1) const { return 0; } - std::int32_t operator()(std::int32_t l1, std::int32_t l2) const { return 0; } - - // Assignment operators - UserDefinedOperators &operator=(std::int32_t l1) { return *this; } - UserDefinedOperators &operator+=(std::int32_t l1) { return *this; } - UserDefinedOperators &operator-=(std::int32_t l1) { return *this; } - UserDefinedOperators &operator*=(std::int32_t l1) { return *this; } - UserDefinedOperators &operator/=(std::int32_t l1) { return *this; } - UserDefinedOperators &operator%=(std::int32_t l1) { return *this; } - UserDefinedOperators &operator&=(std::int32_t l1) { return *this; } - UserDefinedOperators &operator|=(std::int32_t l1) { return *this; } - UserDefinedOperators &operator^=(std::int32_t l1) { return *this; } - UserDefinedOperators &operator<<=(std::int32_t l1) { return *this; } - UserDefinedOperators &operator>>=(std::int32_t l1) { return *this; } - - // Increment/decrement operators - UserDefinedOperators &operator++() { return *this; } - UserDefinedOperators operator++(int) { return UserDefinedOperators{0}; } - UserDefinedOperators &operator--() { return *this; } - UserDefinedOperators operator--(int) { return UserDefinedOperators{0}; } -}; - -// Global user-defined operators -UserDefinedOperators operator+(std::int32_t l1, - const UserDefinedOperators &l2) { - return UserDefinedOperators{0}; -} - -UserDefinedOperators operator-(std::int32_t l1, - const UserDefinedOperators &l2) { - return UserDefinedOperators{0}; -} - -bool operator==(std::int32_t l1, const UserDefinedOperators &l2) { - return true; -} - -void test_user_defined_operators() { - UserDefinedOperators l1{42}; - std::int32_t l2 = 10; - std::int16_t l3 = 5; - std::int64_t l4 = 100; - std::uint32_t l5 = 20; - - // Member operators - non-extensible, exact type match required - l1 + l2; // COMPLIANT - exact type match - l1 + l3; // COMPLIANT - widening conversion is allowed - l1 + l4; // NON_COMPLIANT - different type - l1 + l5; // NON_COMPLIANT - different signedness - - l1 - l2; // COMPLIANT - exact type match - l1 - l3; // COMPLIANT - widening conversion is allowed - l1 - l4; // NON_COMPLIANT - different type - l1 - l5; // NON_COMPLIANT - different signedness - - l1 *l2; // COMPLIANT - exact type match - l1 *l3; // COMPLIANT - widening conversion is allowed - l1 *l4; // NON_COMPLIANT - different type - l1 *l5; // NON_COMPLIANT - different signedness - - l1 / l2; // COMPLIANT - exact type match - l1 / l3; // COMPLIANT - widening conversion is allowed - l1 / l4; // NON_COMPLIANT - different type - l1 / l5; // NON_COMPLIANT - different signedness - - l1 % l2; // COMPLIANT - exact type match - l1 % l3; // COMPLIANT - widening conversion is allowed - l1 % l4; // NON_COMPLIANT - different type - l1 % l5; // NON_COMPLIANT - different signedness - - l1 & l2; // COMPLIANT - exact type match - l1 & l3; // COMPLIANT - widening conversion is allowed - l1 & l4; // NON_COMPLIANT - different type - l1 & l5; // NON_COMPLIANT - different signedness - - l1 | l2; // COMPLIANT - exact type match - l1 | l3; // COMPLIANT - widening conversion is allowed - l1 | l4; // NON_COMPLIANT - different type - l1 | l5; // NON_COMPLIANT - different signedness - - l1 ^ l2; // COMPLIANT - exact type match - l1 ^ l3; // COMPLIANT - widening conversion is allowed - l1 ^ l4; // NON_COMPLIANT - different type - l1 ^ l5; // NON_COMPLIANT - different signedness - - l1 << l2; // COMPLIANT - exact type match - l1 << l3; // COMPLIANT - widening conversion is allowed - l1 << l4; // NON_COMPLIANT - different type - l1 << l5; // NON_COMPLIANT - different signedness - - l1 >> l2; // COMPLIANT - exact type match - l1 >> l3; // COMPLIANT - widening conversion is allowed - l1 >> l4; // NON_COMPLIANT - different type - l1 >> l5; // NON_COMPLIANT - different signedness - - // Comparison operators - l1 == l2; // COMPLIANT - exact type match - l1 == l3; // COMPLIANT - widening conversion is allowed - l1 == l4; // NON_COMPLIANT - different type - l1 == l5; // NON_COMPLIANT - different signedness - - l1 != l2; // COMPLIANT - exact type match - l1 != l3; // COMPLIANT - widening conversion is allowed - l1 != l4; // NON_COMPLIANT - different type - l1 != l5; // NON_COMPLIANT - different signedness - - l1 < l2; // COMPLIANT - exact type match - l1 < l3; // COMPLIANT - widening conversion is allowed - l1 < l4; // NON_COMPLIANT - different type - l1 < l5; // NON_COMPLIANT - different signedness - - l1 <= l2; // COMPLIANT - exact type match - l1 <= l3; // COMPLIANT - widening conversion is allowed - l1 <= l4; // NON_COMPLIANT - different type - l1 <= l5; // NON_COMPLIANT - - l1 > l2; // COMPLIANT - exact type match - l1 > l3; // COMPLIANT - widening conversion is allowed - l1 > l4; // NON_COMPLIANT - l1 > l5; // NON_COMPLIANT - different signedness - - l1 >= l2; // COMPLIANT - exact type match - l1 >= l3; // COMPLIANT - widening conversion is allowed - l1 >= l4; // NON_COMPLIANT - l1 >= l5; // NON_COMPLIANT - different signedness - - // Subscript operator - l1[l2]; // COMPLIANT - exact type match - l1[l3]; // COMPLIANT - widening conversion is allowed - l1[l4]; // NON_COMPLIANT - different type - l1[l5]; // NON_COMPLIANT - different signedness - - // Function call operator - l1(l2); // COMPLIANT - exact type match - l1(l3); // COMPLIANT - widening conversion is allowed - l1(l4); // NON_COMPLIANT - different type - l1(l5); // NON_COMPLIANT - different signedness - l1(l2, l2); // COMPLIANT - both exact type match - l1(l2, l4); // NON_COMPLIANT - second parameter different type - l1(l4, l2); // NON_COMPLIANT - first parameter different type - l1(l4, l5); // NON_COMPLIANT - both parameters different type - - // The presence of a default copy constructor for UserDefinedOperators means - // that assignments through operator= must be exact type matches. - l1 = l2; // COMPLIANT - exact type match - l1 = l3; // NON_COMPLIANT - l1 = l4; // NON_COMPLIANT - l1 = l5; // NON_COMPLIANT - - l1 += l2; // COMPLIANT - exact type match - l1 += l3; // COMPLIANT - widening conversion is allowed - l1 += l4; // NON_COMPLIANT - different type - l1 += l5; // NON_COMPLIANT - different signedness - - l1 -= l2; // COMPLIANT - exact type match - l1 -= l3; // COMPLIANT - widening conversion is allowed - l1 -= l4; // NON_COMPLIANT - different type - l1 -= l5; // NON_COMPLIANT - different signedness - - l1 *= l2; // COMPLIANT - exact type match - l1 *= l3; // COMPLIANT - widening conversion is allowed - l1 *= l4; // NON_COMPLIANT - different type - l1 *= l5; // NON_COMPLIANT - different signedness - - l1 /= l2; // COMPLIANT - exact type match - l1 /= l3; // COMPLIANT - widening conversion is allowed - l1 /= l4; // NON_COMPLIANT - different type - l1 /= l5; // NON_COMPLIANT - different signedness - - l1 %= l2; // COMPLIANT - exact type match - l1 %= l3; // COMPLIANT - widening conversion is allowed - l1 %= l4; // NON_COMPLIANT - different type - l1 %= l5; // NON_COMPLIANT - different signedness - - l1 &= l2; // COMPLIANT - exact type match - l1 &= l3; // COMPLIANT - widening conversion is allowed - l1 &= l4; // NON_COMPLIANT - different type - l1 &= l5; // NON_COMPLIANT - different signedness - - l1 |= l2; // COMPLIANT - exact type match - l1 |= l3; // COMPLIANT - widening conversion is allowed - l1 |= l4; // NON_COMPLIANT - different type - l1 |= l5; // NON_COMPLIANT - different signedness - - l1 ^= l2; // COMPLIANT - exact type match - l1 ^= l3; // COMPLIANT - widening conversion is allowed - l1 ^= l4; // NON_COMPLIANT - different type - l1 ^= l5; // NON_COMPLIANT - different signedness - - l1 <<= l2; // COMPLIANT - exact type match - l1 <<= l3; // COMPLIANT - widening conversion is allowed - l1 <<= l4; // NON_COMPLIANT - different type - l1 <<= l5; // NON_COMPLIANT - different signedness - - l1 >>= l2; // COMPLIANT - exact type match - l1 >>= l3; // COMPLIANT - widening conversion is allowed - l1 >>= l4; // NON_COMPLIANT - different type - l1 >>= l5; // NON_COMPLIANT - different signedness - - // Global operators - l2 + l1; // COMPLIANT - exact type match - l3 + l1; // COMPLIANT - widening conversion is allowed - l4 + l1; // NON_COMPLIANT - different type - l5 + l1; // NON_COMPLIANT - different signedness - - l2 - l1; // COMPLIANT - exact type match - l3 - l1; // COMPLIANT - widening conversion is allowed - l4 - l1; // NON_COMPLIANT - different type - l5 - l1; // NON_COMPLIANT - different signedness - - l2 == l1; // COMPLIANT - exact type match - l3 == l1; // COMPLIANT - widening conversion is allowed - l4 == l1; // NON_COMPLIANT - different type - l5 == l1; // NON_COMPLIANT - different signedness -} - -// Test user-defined operators with constants -void test_user_defined_operators_constants() { - UserDefinedOperators l1{42}; - - // Constants with exact type match - l1 + 42; // COMPLIANT - l1 + 42L; // COMPLIANT - l1 + 42LL; // COMPLIANT - l1 + 42U; // COMPLIANT - l1 + 42.0f; // NON_COMPLIANT - float constant - - l1 == 42; // COMPLIANT - integer constant is int/int32_t - l1 == 42L; // COMPLIANT - long constant - l1 == 42LL; // COMPLIANT - long long constant - l1 == 42U; // COMPLIANT - unsigned constant - - l1[42]; // COMPLIANT - integer constant is int/int32_t - l1[42L]; // COMPLIANT - long constant - l1[42LL]; // COMPLIANT - long long constant - l1[42U]; // COMPLIANT - unsigned constant - - // The presence of a default copy constructor for UserDefinedOperators means - // that assignments through operator= must be exact type matches. - l1 = 42; // COMPLIANT - integer constant is int/int32_t - l1 = 42L; // NON_COMPLIANT - l1 = 42LL; // NON_COMPLIANT - l1 = 42U; // NON_COMPLIANT } \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp b/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp new file mode 100644 index 0000000000..f8823bfa03 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp @@ -0,0 +1,295 @@ +#include + +// Test user-defined operators - always non-extensible +struct UserDefinedOperators { + UserDefinedOperators(std::int32_t l1) {} + + // Binary operators + UserDefinedOperators operator+(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator-(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator*(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator/(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator%(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator&(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator|(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator^(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator<<(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + UserDefinedOperators operator>>(std::int32_t l1) const { + return UserDefinedOperators{0}; + } + + // Comparison operators + bool operator==(std::int32_t l1) const { return true; } + bool operator!=(std::int32_t l1) const { return false; } + bool operator<(std::int32_t l1) const { return false; } + bool operator<=(std::int32_t l1) const { return false; } + bool operator>(std::int32_t l1) const { return false; } + bool operator>=(std::int32_t l1) const { return false; } + + // Subscript operator + std::int32_t operator[](std::int32_t l1) const { return 0; } + + // Function call operator + std::int32_t operator()(std::int32_t l1) const { return 0; } + std::int32_t operator()(std::int32_t l1, std::int32_t l2) const { return 0; } + + // Assignment operators + UserDefinedOperators &operator=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator+=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator-=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator*=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator/=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator%=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator&=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator|=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator^=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator<<=(std::int32_t l1) { return *this; } + UserDefinedOperators &operator>>=(std::int32_t l1) { return *this; } + + // Increment/decrement operators + UserDefinedOperators &operator++() { return *this; } + UserDefinedOperators operator++(int) { return UserDefinedOperators{0}; } + UserDefinedOperators &operator--() { return *this; } + UserDefinedOperators operator--(int) { return UserDefinedOperators{0}; } +}; + +// Global user-defined operators +UserDefinedOperators operator+(std::int32_t l1, + const UserDefinedOperators &l2) { + return UserDefinedOperators{0}; +} + +UserDefinedOperators operator-(std::int32_t l1, + const UserDefinedOperators &l2) { + return UserDefinedOperators{0}; +} + +bool operator==(std::int32_t l1, const UserDefinedOperators &l2) { + return true; +} + +void test_user_defined_operators() { + UserDefinedOperators l1{42}; + std::int32_t l2 = 10; + std::int16_t l3 = 5; + std::int64_t l4 = 100; + std::uint32_t l5 = 20; + + // Member operators - non-extensible, exact type match required + l1 + l2; // COMPLIANT - exact type match + l1 + l3; // COMPLIANT - widening conversion is allowed + l1 + l4; // NON_COMPLIANT - different type + l1 + l5; // NON_COMPLIANT - different signedness + + l1 - l2; // COMPLIANT - exact type match + l1 - l3; // COMPLIANT - widening conversion is allowed + l1 - l4; // NON_COMPLIANT - different type + l1 - l5; // NON_COMPLIANT - different signedness + + l1 *l2; // COMPLIANT - exact type match + l1 *l3; // COMPLIANT - widening conversion is allowed + l1 *l4; // NON_COMPLIANT - different type + l1 *l5; // NON_COMPLIANT - different signedness + + l1 / l2; // COMPLIANT - exact type match + l1 / l3; // COMPLIANT - widening conversion is allowed + l1 / l4; // NON_COMPLIANT - different type + l1 / l5; // NON_COMPLIANT - different signedness + + l1 % l2; // COMPLIANT - exact type match + l1 % l3; // COMPLIANT - widening conversion is allowed + l1 % l4; // NON_COMPLIANT - different type + l1 % l5; // NON_COMPLIANT - different signedness + + l1 & l2; // COMPLIANT - exact type match + l1 & l3; // COMPLIANT - widening conversion is allowed + l1 & l4; // NON_COMPLIANT - different type + l1 & l5; // NON_COMPLIANT - different signedness + + l1 | l2; // COMPLIANT - exact type match + l1 | l3; // COMPLIANT - widening conversion is allowed + l1 | l4; // NON_COMPLIANT - different type + l1 | l5; // NON_COMPLIANT - different signedness + + l1 ^ l2; // COMPLIANT - exact type match + l1 ^ l3; // COMPLIANT - widening conversion is allowed + l1 ^ l4; // NON_COMPLIANT - different type + l1 ^ l5; // NON_COMPLIANT - different signedness + + l1 << l2; // COMPLIANT - exact type match + l1 << l3; // COMPLIANT - widening conversion is allowed + l1 << l4; // NON_COMPLIANT - different type + l1 << l5; // NON_COMPLIANT - different signedness + + l1 >> l2; // COMPLIANT - exact type match + l1 >> l3; // COMPLIANT - widening conversion is allowed + l1 >> l4; // NON_COMPLIANT - different type + l1 >> l5; // NON_COMPLIANT - different signedness + + // Comparison operators + l1 == l2; // COMPLIANT - exact type match + l1 == l3; // COMPLIANT - widening conversion is allowed + l1 == l4; // NON_COMPLIANT - different type + l1 == l5; // NON_COMPLIANT - different signedness + + l1 != l2; // COMPLIANT - exact type match + l1 != l3; // COMPLIANT - widening conversion is allowed + l1 != l4; // NON_COMPLIANT - different type + l1 != l5; // NON_COMPLIANT - different signedness + + l1 < l2; // COMPLIANT - exact type match + l1 < l3; // COMPLIANT - widening conversion is allowed + l1 < l4; // NON_COMPLIANT - different type + l1 < l5; // NON_COMPLIANT - different signedness + + l1 <= l2; // COMPLIANT - exact type match + l1 <= l3; // COMPLIANT - widening conversion is allowed + l1 <= l4; // NON_COMPLIANT - different type + l1 <= l5; // NON_COMPLIANT + + l1 > l2; // COMPLIANT - exact type match + l1 > l3; // COMPLIANT - widening conversion is allowed + l1 > l4; // NON_COMPLIANT + l1 > l5; // NON_COMPLIANT - different signedness + + l1 >= l2; // COMPLIANT - exact type match + l1 >= l3; // COMPLIANT - widening conversion is allowed + l1 >= l4; // NON_COMPLIANT + l1 >= l5; // NON_COMPLIANT - different signedness + + // Subscript operator + l1[l2]; // COMPLIANT - exact type match + l1[l3]; // COMPLIANT - widening conversion is allowed + l1[l4]; // NON_COMPLIANT - different type + l1[l5]; // NON_COMPLIANT - different signedness + + // Function call operator + l1(l2); // COMPLIANT - exact type match + l1(l3); // COMPLIANT - widening conversion is allowed + l1(l4); // NON_COMPLIANT - different type + l1(l5); // NON_COMPLIANT - different signedness + l1(l2, l2); // COMPLIANT - both exact type match + l1(l2, l4); // NON_COMPLIANT - second parameter different type + l1(l4, l2); // NON_COMPLIANT - first parameter different type + l1(l4, l5); // NON_COMPLIANT - both parameters different type + + // The presence of a default copy constructor for UserDefinedOperators means + // that assignments through operator= must be exact type matches. + l1 = l2; // COMPLIANT - exact type match + l1 = l3; // NON_COMPLIANT + l1 = l4; // NON_COMPLIANT + l1 = l5; // NON_COMPLIANT + + l1 += l2; // COMPLIANT - exact type match + l1 += l3; // COMPLIANT - widening conversion is allowed + l1 += l4; // NON_COMPLIANT - different type + l1 += l5; // NON_COMPLIANT - different signedness + + l1 -= l2; // COMPLIANT - exact type match + l1 -= l3; // COMPLIANT - widening conversion is allowed + l1 -= l4; // NON_COMPLIANT - different type + l1 -= l5; // NON_COMPLIANT - different signedness + + l1 *= l2; // COMPLIANT - exact type match + l1 *= l3; // COMPLIANT - widening conversion is allowed + l1 *= l4; // NON_COMPLIANT - different type + l1 *= l5; // NON_COMPLIANT - different signedness + + l1 /= l2; // COMPLIANT - exact type match + l1 /= l3; // COMPLIANT - widening conversion is allowed + l1 /= l4; // NON_COMPLIANT - different type + l1 /= l5; // NON_COMPLIANT - different signedness + + l1 %= l2; // COMPLIANT - exact type match + l1 %= l3; // COMPLIANT - widening conversion is allowed + l1 %= l4; // NON_COMPLIANT - different type + l1 %= l5; // NON_COMPLIANT - different signedness + + l1 &= l2; // COMPLIANT - exact type match + l1 &= l3; // COMPLIANT - widening conversion is allowed + l1 &= l4; // NON_COMPLIANT - different type + l1 &= l5; // NON_COMPLIANT - different signedness + + l1 |= l2; // COMPLIANT - exact type match + l1 |= l3; // COMPLIANT - widening conversion is allowed + l1 |= l4; // NON_COMPLIANT - different type + l1 |= l5; // NON_COMPLIANT - different signedness + + l1 ^= l2; // COMPLIANT - exact type match + l1 ^= l3; // COMPLIANT - widening conversion is allowed + l1 ^= l4; // NON_COMPLIANT - different type + l1 ^= l5; // NON_COMPLIANT - different signedness + + l1 <<= l2; // COMPLIANT - exact type match + l1 <<= l3; // COMPLIANT - widening conversion is allowed + l1 <<= l4; // NON_COMPLIANT - different type + l1 <<= l5; // NON_COMPLIANT - different signedness + + l1 >>= l2; // COMPLIANT - exact type match + l1 >>= l3; // COMPLIANT - widening conversion is allowed + l1 >>= l4; // NON_COMPLIANT - different type + l1 >>= l5; // NON_COMPLIANT - different signedness + + // Global operators + l2 + l1; // COMPLIANT - exact type match + l3 + l1; // COMPLIANT - widening conversion is allowed + l4 + l1; // NON_COMPLIANT - different type + l5 + l1; // NON_COMPLIANT - different signedness + + l2 - l1; // COMPLIANT - exact type match + l3 - l1; // COMPLIANT - widening conversion is allowed + l4 - l1; // NON_COMPLIANT - different type + l5 - l1; // NON_COMPLIANT - different signedness + + l2 == l1; // COMPLIANT - exact type match + l3 == l1; // COMPLIANT - widening conversion is allowed + l4 == l1; // NON_COMPLIANT - different type + l5 == l1; // NON_COMPLIANT - different signedness +} + +// Test user-defined operators with constants +void test_user_defined_operators_constants() { + UserDefinedOperators l1{42}; + + // Constants with exact type match + l1 + 42; // COMPLIANT + l1 + 42L; // COMPLIANT + l1 + 42LL; // COMPLIANT + l1 + 42U; // COMPLIANT + l1 + 42.0f; // NON_COMPLIANT - float constant + + l1 == 42; // COMPLIANT - integer constant is int/int32_t + l1 == 42L; // COMPLIANT - long constant + l1 == 42LL; // COMPLIANT - long long constant + l1 == 42U; // COMPLIANT - unsigned constant + + l1[42]; // COMPLIANT - integer constant is int/int32_t + l1[42L]; // COMPLIANT - long constant + l1[42LL]; // COMPLIANT - long long constant + l1[42U]; // COMPLIANT - unsigned constant + + // The presence of a default copy constructor for UserDefinedOperators means + // that assignments through operator= must be exact type matches. + l1 = 42; // COMPLIANT - integer constant is int/int32_t + l1 = 42L; // NON_COMPLIANT + l1 = 42LL; // NON_COMPLIANT + l1 = 42U; // NON_COMPLIANT +} \ No newline at end of file From f68658a4d2f650c05ef6fb0879278b2ef8f4f9e4 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Jun 2025 23:50:31 +0100 Subject: [PATCH 461/628] Rule 7.0.6: Support constructor field initializers --- .../cpp/misra/StandardConversions.qll | 12 +++ .../NumericAssignmentTypeMismatch.expected | 19 +++++ cpp/misra/test/rules/RULE-7-0-6/test.cpp | 84 +++++++++++++++++++ 3 files changed, 115 insertions(+) diff --git a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll index d5dbbc8862..fe3ddd2344 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll @@ -152,6 +152,18 @@ predicate isAssignment(Expr source, NumericType targetType, string context) { targetType = v.getType() ) or + exists(ConstructorFieldInit fi | + fi.getExpr() = source and + context = "constructor field initialization" + | + // For the MISRA type rules we treat bit fields as a special case + if fi.getTarget() instanceof BitField + then targetType = getBitFieldType(fi.getTarget()) + else + // Regular variable initialization + targetType = fi.getTarget().getType() + ) + or // Passing a function parameter by value exists(Call call, int i | call.getArgument(i) = source and diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index e9ac08e3c4..85ee49754b 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -65,6 +65,25 @@ | test.cpp:442:8:442:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | | test.cpp:460:7:460:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | | test.cpp:463:7:463:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | +| test.cpp:512:12:512:13 | l1 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | +| test.cpp:513:12:513:13 | l1 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | +| test.cpp:515:12:515:13 | l2 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | +| test.cpp:516:12:516:13 | l2 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | +| test.cpp:536:12:536:14 | 300 | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:537:12:537:16 | 70000 | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | +| test.cpp:538:12:538:27 | 4294967296 | Assignment between incompatible numeric types from 'unsigned long long' to 'uint32_t'. | +| test.cpp:539:12:539:14 | 200 | Assignment between incompatible numeric types from 'int' to 'int8_t'. | +| test.cpp:540:12:540:16 | 40000 | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:541:12:541:26 | 4294967296 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | +| test.cpp:542:12:542:14 | 1.0 | Assignment between incompatible numeric types from 'double' to 'float'. | +| test.cpp:543:12:543:15 | 1.0 | Assignment between incompatible numeric types from 'float' to 'double'. | +| test.cpp:548:12:548:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:549:12:549:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | +| test.cpp:550:12:550:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint32_t'. | +| test.cpp:552:12:552:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int16_t'. | +| test.cpp:553:12:553:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int32_t'. | +| test.cpp:554:12:554:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'float'. | +| test.cpp:555:12:555:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'double'. | | test_aggregate.cpp:29:22:29:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | | test_aggregate.cpp:31:26:31:28 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | | test_aggregate.cpp:33:31:33:33 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index 9b8bdc0022..61669f2841 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -482,4 +482,88 @@ void test_compound_assignments() { l2 >>= 1; // COMPLIANT - compound assignment, rule does not apply l4 += l1; // COMPLIANT - compound assignment, rule does not apply l4 -= s32; // COMPLIANT - compound assignment, rule does not apply +} + +// Test constructor field initializers +struct ConstructorTest { + std::uint8_t m1; + std::uint16_t m2; + std::uint32_t m3; + std::int8_t m4; + std::int16_t m5; + std::int32_t m6; + float m7; + double m8; + + // Constructor with various member initializer scenarios + ConstructorTest(std::uint8_t l1, std::uint16_t l2, std::int8_t l3) + : m1(l1), // COMPLIANT - same type + m2(l2), // COMPLIANT - same type + m3(l1), // COMPLIANT - widening of id-expression + m4(l3), // COMPLIANT - same type + m5(l3), // COMPLIANT - widening of id-expression + m6(l3), // COMPLIANT - widening of id-expression + m7(1.0f), // COMPLIANT - same type + m8(1.0) { // COMPLIANT - same type + } + + // Constructor with non-compliant initializers + ConstructorTest(std::uint32_t l1, std::int32_t l2, float l3) + : m1(l1), // NON_COMPLIANT - narrowing + m2(l1), // NON_COMPLIANT - narrowing + m3(l1), // COMPLIANT - same type + m4(l2), // NON_COMPLIANT - narrowing and different signedness + m5(l2), // NON_COMPLIANT - narrowing and different signedness + m6(l2), // COMPLIANT - same type + m7(l3), // COMPLIANT - same type + m8(l3) { // COMPLIANT - allowed to use float to initialize double + } + + // Constructor with constant initializers + ConstructorTest() + : m1(100), // COMPLIANT - constant fits + m2(65535), // COMPLIANT - constant fits + m3(4294967295U), // COMPLIANT - constant fits + m4(127), // COMPLIANT - constant fits + m5(32767), // COMPLIANT - constant fits + m6(2147483647), // COMPLIANT - constant fits + m7(3.14f), // COMPLIANT - same type constant + m8(2.718) { // COMPLIANT - same type constant + } + + // Constructor with non-compliant constant initializers + ConstructorTest(int) + : m1(300), // NON_COMPLIANT - constant too large + m2(70000), // NON_COMPLIANT - constant too large + m3(0x1'0000'0000ULL), // NON_COMPLIANT - constant too large + m4(200), // NON_COMPLIANT - constant too large + m5(40000), // NON_COMPLIANT - constant too large + m6(0x1'0000'0000LL), // NON_COMPLIANT - constant too large + m7(1.0), // NON_COMPLIANT - different size + m8(1.0f) { // NON_COMPLIANT - different size + } + + // Constructor with expression initializers + ConstructorTest(std::uint8_t l1, std::uint8_t l2, std::int8_t l3) + : m1(l1 + l2), // NON_COMPLIANT - expression result is int + m2(l1 + l2), // NON_COMPLIANT - expression result is int + m3(l1 + l2), // NON_COMPLIANT - expression result is int + m4(l3), // COMPLIANT - widening of id-expression + m5(l1), // NON_COMPLIANT - different signedness + m6(l1), // NON_COMPLIANT - different signedness + m7(l1), // NON_COMPLIANT - different type category + m8(l1) { // NON_COMPLIANT - different type category + } +}; + +void test_constructor_field_initializers() { + std::uint8_t l1 = 42; + std::uint16_t l2 = 1000; + std::int8_t l3 = 10; + + ConstructorTest l4(l1, l2, l3); // Test first constructor + ConstructorTest l5(u32, s32, f); // Test second constructor + ConstructorTest l6; // Test third constructor + ConstructorTest l7(0); // Test fourth constructor + ConstructorTest l8(l1, l1, l3); // Test fifth constructor } \ No newline at end of file From 3fdaa98f8f9bb1f8bcd5a20a8f4fdb5c3bbaa5a7 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 20 Jun 2025 00:06:59 +0100 Subject: [PATCH 462/628] Rule 7.0.6: Handle explicit conversions Consider the conversion as the source, not the pre-conversion value. --- .../cpp/misra/StandardConversions.qll | 11 +++- .../NumericAssignmentTypeMismatch.ql | 6 +-- .../NumericAssignmentTypeMismatch.expected | 9 ++-- cpp/misra/test/rules/RULE-7-0-6/test.cpp | 52 +++++++++++++++++++ 4 files changed, 70 insertions(+), 8 deletions(-) diff --git a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll index fe3ddd2344..8c010fa71f 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll @@ -117,6 +117,13 @@ class CanonicalIntegerTypes extends NumericType, IntegralType { } predicate isAssignment(Expr source, NumericType targetType, string context) { + exists(Expr preConversionAssignment | + isPreConversionAssignment(preConversionAssignment, targetType, context) and + preConversionAssignment.getExplicitlyConverted() = source + ) +} + +predicate isPreConversionAssignment(Expr source, NumericType targetType, string context) { // Assignment expression (which excludes compound assignments) exists(AssignExpr assign | assign.getRValue() = source and @@ -261,4 +268,6 @@ CanonicalIntegerTypes getBitFieldType(BitField bf) { /** * Holds if the `source` expression is assigned to a bit field. */ -predicate isAssignedToBitfield(Expr source, BitField bf) { source = bf.getAnAssignedValue() } +predicate isAssignedToBitfield(Expr source, BitField bf) { + source = bf.getAnAssignedValue().getExplicitlyConverted() +} diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index 16931f4330..4ff284fe7e 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -101,7 +101,7 @@ predicate isValidWidening(Expr source, NumericType sourceType, NumericType targe // Same type category and signedness, source size smaller, source is id-expression or has constructor exception ( source instanceof IdExpression or - hasConstructorException(any(Call call | call.getAnArgument() = source)) + hasConstructorException(any(Call call | call.getAnArgument().getExplicitlyConverted() = source)) ) and sourceType.getTypeCategory() = targetType.getTypeCategory() and sourceType.getSignedness() = targetType.getSignedness() and @@ -163,7 +163,7 @@ predicate isOverloadIndependent(Call call, Expr arg) { */ predicate shouldHaveSameType(Expr source) { exists(Call call | - call.getAnArgument() = source and + call.getAnArgument().getExplicitlyConverted() = source and isAssignment(source, _, _) and not hasConstructorException(call) | @@ -172,7 +172,7 @@ predicate shouldHaveSameType(Expr source) { // Passed as a varargs parameter exists(int i | call.getTarget().isVarargs() and - call.getArgument(i) = source and + call.getArgument(i).getExplicitlyConverted() = source and // Argument is greater than the number of parameters call.getTarget().getNumberOfParameters() <= i ) diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index 85ee49754b..870f579d74 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -11,8 +11,8 @@ | test.cpp:97:13:97:14 | m1 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | | test.cpp:98:13:98:14 | m2 | Assignment between incompatible numeric types from 'uint16_t' to 'uint64_t'. | | test.cpp:103:9:103:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint32_t'. | -| test.cpp:104:10:104:11 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | -| test.cpp:105:35:105:36 | u8 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test.cpp:104:9:104:12 | (...) | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test.cpp:105:9:105:37 | static_cast... | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | | test.cpp:110:8:110:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | | test.cpp:111:21:111:27 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | | test.cpp:134:11:134:11 | 4 | Assignment between incompatible numeric types from 'int' to 'unsigned char'. | @@ -84,6 +84,7 @@ | test.cpp:553:12:553:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int32_t'. | | test.cpp:554:12:554:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'float'. | | test.cpp:555:12:555:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'double'. | +| test.cpp:585:9:585:37 | static_cast... | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | | test_aggregate.cpp:29:22:29:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | | test_aggregate.cpp:31:26:31:28 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | | test_aggregate.cpp:33:31:33:33 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | @@ -315,7 +316,7 @@ | test_specified.cpp:342:8:342:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | | test_specified.cpp:343:8:343:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | | test_specified.cpp:344:8:344:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test_specified.cpp:351:10:351:11 | l2 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | -| test_specified.cpp:352:10:352:11 | l3 | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test_specified.cpp:351:9:351:12 | (...) | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | +| test_specified.cpp:352:9:352:12 | (...) | Assignment between incompatible numeric types from 'uint8_t' to 'uint32_t'. | | test_specified.cpp:370:18:370:20 | 300 | Assignment between incompatible numeric types from 'int' to 'const uint8_t'. | | test_specified.cpp:370:23:370:27 | 70000 | Assignment between incompatible numeric types from 'int' to 'volatile uint16_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index 61669f2841..659c268254 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -566,4 +566,56 @@ void test_constructor_field_initializers() { ConstructorTest l6; // Test third constructor ConstructorTest l7(0); // Test fourth constructor ConstructorTest l8(l1, l1, l3); // Test fifth constructor +} + +// Test explicit casts +void test_explicit_casts() { + std::uint8_t l1 = 42; + std::uint16_t l2 = 1000; + std::int8_t l3 = -10; + std::int32_t l4 = -100; + float l5 = 3.14f; + double l6 = 2.718; + + // Explicit cast expressions are treated as expressions, not id-expressions + u8 = static_cast(l2); // COMPLIANT + u16 = static_cast(l1); // COMPLIANT + s8 = static_cast(l4); // COMPLIANT + s32 = static_cast(l3); // COMPLIANT + s32 = static_cast(l3); // NON_COMPLIANT + + // Type category conversions with explicit casts + f = static_cast(l4); // COMPLIANT + s32 = static_cast(l5); // COMPLIANT + + // Size conversions with explicit casts + d = static_cast(l5); // COMPLIANT + l5 = static_cast(l6); // COMPLIANT + + // C-style casts (also expressions) + u8 = (std::uint8_t)l2; // COMPLIANT + s8 = (std::int8_t)l4; // COMPLIANT + f = (float)l4; // COMPLIANT + + // Functional style casts (also expressions) + u8 = std::uint8_t(l2); // COMPLIANT + s8 = std::int8_t(l4); // COMPLIANT + f = float(l4); // COMPLIANT + + // Const_cast (creates expressions) + const std::uint8_t l7 = 100; + u8 = const_cast(l7); // COMPLIANT + + // Reinterpret_cast (creates expressions) + u32 = reinterpret_cast(l4); // COMPLIANT + + // Assignment to variables through explicit casts + std::uint32_t l8; + std::uint16_t l9; + l8 = static_cast(l9); // COMPLIANT + l9 = static_cast(l8); // COMPLIANT + + // Function calls with explicit casts + f1(static_cast(l4)); // COMPLIANT + f2(static_cast(l4)); // COMPLIANT } \ No newline at end of file From 063a5ccff14c05e6ece1dd87bd51d750cf951c85 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 20 Jun 2025 09:10:21 +0100 Subject: [PATCH 463/628] Rule 7.0.6: Improve tests for templates --- .../NumericAssignmentTypeMismatch.expected | 72 +++++++++---------- cpp/misra/test/rules/RULE-7-0-6/test.cpp | 20 ++++-- 2 files changed, 49 insertions(+), 43 deletions(-) diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index 870f579d74..a6473c6df0 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -49,42 +49,42 @@ | test.cpp:289:6:289:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. | | test.cpp:294:12:294:14 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | | test.cpp:313:9:313:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | -| test.cpp:342:23:342:24 | 42 | Assignment between incompatible numeric types from 'int' to 'unsigned long'. | -| test.cpp:352:19:352:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | -| test.cpp:357:10:357:12 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:390:8:390:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. | -| test.cpp:391:8:391:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | -| test.cpp:392:9:392:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | -| test.cpp:403:6:403:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. | -| test.cpp:404:6:404:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. | -| test.cpp:415:8:415:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. | -| test.cpp:416:8:416:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | -| test.cpp:429:9:429:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | -| test.cpp:430:7:430:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. | -| test.cpp:431:7:431:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. | -| test.cpp:442:8:442:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test.cpp:460:7:460:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | -| test.cpp:463:7:463:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | -| test.cpp:512:12:512:13 | l1 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | -| test.cpp:513:12:513:13 | l1 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | -| test.cpp:515:12:515:13 | l2 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | -| test.cpp:516:12:516:13 | l2 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | -| test.cpp:536:12:536:14 | 300 | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test.cpp:537:12:537:16 | 70000 | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | -| test.cpp:538:12:538:27 | 4294967296 | Assignment between incompatible numeric types from 'unsigned long long' to 'uint32_t'. | -| test.cpp:539:12:539:14 | 200 | Assignment between incompatible numeric types from 'int' to 'int8_t'. | -| test.cpp:540:12:540:16 | 40000 | Assignment between incompatible numeric types from 'int' to 'int16_t'. | -| test.cpp:541:12:541:26 | 4294967296 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | -| test.cpp:542:12:542:14 | 1.0 | Assignment between incompatible numeric types from 'double' to 'float'. | -| test.cpp:543:12:543:15 | 1.0 | Assignment between incompatible numeric types from 'float' to 'double'. | -| test.cpp:548:12:548:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test.cpp:549:12:549:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | -| test.cpp:550:12:550:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint32_t'. | -| test.cpp:552:12:552:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int16_t'. | -| test.cpp:553:12:553:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int32_t'. | -| test.cpp:554:12:554:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'float'. | -| test.cpp:555:12:555:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'double'. | -| test.cpp:585:9:585:37 | static_cast... | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test.cpp:346:25:346:27 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned long'. | +| test.cpp:358:19:358:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:363:10:363:12 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:396:8:396:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. | +| test.cpp:397:8:397:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:398:9:398:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:409:6:409:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. | +| test.cpp:410:6:410:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. | +| test.cpp:421:8:421:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. | +| test.cpp:422:8:422:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:435:9:435:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:436:7:436:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. | +| test.cpp:437:7:437:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. | +| test.cpp:448:8:448:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:466:7:466:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | +| test.cpp:469:7:469:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | +| test.cpp:518:12:518:13 | l1 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | +| test.cpp:519:12:519:13 | l1 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | +| test.cpp:521:12:521:13 | l2 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | +| test.cpp:522:12:522:13 | l2 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | +| test.cpp:542:12:542:14 | 300 | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:543:12:543:16 | 70000 | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | +| test.cpp:544:12:544:27 | 4294967296 | Assignment between incompatible numeric types from 'unsigned long long' to 'uint32_t'. | +| test.cpp:545:12:545:14 | 200 | Assignment between incompatible numeric types from 'int' to 'int8_t'. | +| test.cpp:546:12:546:16 | 40000 | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:547:12:547:26 | 4294967296 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | +| test.cpp:548:12:548:14 | 1.0 | Assignment between incompatible numeric types from 'double' to 'float'. | +| test.cpp:549:12:549:15 | 1.0 | Assignment between incompatible numeric types from 'float' to 'double'. | +| test.cpp:554:12:554:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:555:12:555:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | +| test.cpp:556:12:556:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint32_t'. | +| test.cpp:558:12:558:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int16_t'. | +| test.cpp:559:12:559:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int32_t'. | +| test.cpp:560:12:560:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'float'. | +| test.cpp:561:12:561:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'double'. | +| test.cpp:591:9:591:37 | static_cast... | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | | test_aggregate.cpp:29:22:29:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | | test_aggregate.cpp:31:26:31:28 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | | test_aggregate.cpp:33:31:33:33 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index 659c268254..ae7310bc3d 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -326,22 +326,28 @@ void test_constructor_exception() { MyInt l1{s8}; // COMPLIANT } -// Test template functions - not overload-independent template struct D { + // Overload-independent - f10 parameters are always the same type void f10(T l1, int l2) {} void f10(T l1, std::string l2) {} + // Not overload-independent template void f11(S1 l1, int l2) {} template void f11(S2 l1, std::string l2) {} void f11(std::int32_t l1, float f) {} }; void test_template_functions() { - D l1; - l1.f10(42, "X"); // COMPLIANT - l1.f10(42, 1); // COMPLIANT - l1.f11(42, "X"); // NON_COMPLIANT - int not size_t - l1.f11(42, 1); // COMPLIANT - same as specialized type - l1.f11(42, 0.0f); // COMPLIANT - same as specialized type + D l1; + l1.f10(u32, "X"); // COMPLIANT - can widen, because always same type + l1.f10(u32, 1); // COMPLIANT - can widen, because always same type + D l2; + l2.f10(u16, "X"); // COMPLIANT - can widen, because always same type + l2.f10(u16, 1); // COMPLIANT - can widen, because always same type + l1.f11(u32, "X"); // NON_COMPLIANT - not overload-independent + // and not the same type as the parameter + // so cannot widen - must be the same type + l1.f11(s32, 1); // COMPLIANT - same as specialized type + l1.f11(s32, 0.0f); // COMPLIANT - matches parameter type } // Test initialization forms From 96d5c1bfb447ba237949cb989e85bf03470669a9 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 20 Jun 2025 09:22:32 +0100 Subject: [PATCH 464/628] MISRA C++ 2023: Rename StandardConversions library These relate to the built-in type rules. --- .../misra/{StandardConversions.qll => BuiltInTypeRules.qll} | 6 +++++- .../src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) rename cpp/misra/src/codingstandards/cpp/misra/{StandardConversions.qll => BuiltInTypeRules.qll} (98%) diff --git a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll similarity index 98% rename from cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll rename to cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index 8c010fa71f..0116d8c3cc 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/StandardConversions.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -1,3 +1,7 @@ +/** + * A library for utility classes related to the built-in type rules in MISRA C++ 2023 (Section 4.7.0). + */ + import cpp import codingstandards.cpp.misra import codingstandards.cpp.Type @@ -54,7 +58,7 @@ TypeCategory getTypeCategory(BuiltInType t) { } /** - * The signedness of a MISRA C++ 2023 numeric type + * The signedness of a MISRA C++ 2023 numeric type. */ newtype Signedness = Signed() or diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index 4ff284fe7e..3b0f227399 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.cpp.misra import codingstandards.cpp.ConstantExpressions -import codingstandards.cpp.misra.StandardConversions +import codingstandards.cpp.misra.BuiltInTypeRules import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis predicate isValidConstantAssignment(IntegerConstantExpr source, NumericType targetType) { From 7c5fb879f39c1474d49209adb327754036bdfe22 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 20 Jun 2025 09:54:20 +0100 Subject: [PATCH 465/628] Rule 7.0.6: Address performance issues - Extract the determination of ExprCall FunctionTypes - Ensure type matching is inlined --- .../codingstandards/cpp/types/Compatible.qll | 19 +---------- .../src/codingstandards/cpp/types/Type.qll | 18 ++++++++++ .../cpp/misra/BuiltInTypeRules.qll | 34 ++++++++++--------- .../NumericAssignmentTypeMismatch.ql | 2 ++ 4 files changed, 39 insertions(+), 34 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll index c4ee9a22e3..399ba80629 100644 --- a/cpp/common/src/codingstandards/cpp/types/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -1,6 +1,7 @@ import cpp import codeql.util.Boolean import codingstandards.cpp.types.Graph +import codingstandards.cpp.types.Type module TypeNamesMatchConfig implements TypeEquivalenceSig { predicate resolveTypedefs() { @@ -522,24 +523,6 @@ module FunctionDeclarationTypeEquivalence< } } -/** - * Convenience class to reduce the awkwardness of how `RoutineType` and `FunctionPointerIshType` - * don't have a common ancestor. - */ -private class FunctionType extends Type { - FunctionType() { this instanceof RoutineType or this instanceof FunctionPointerIshType } - - Type getReturnType() { - result = this.(RoutineType).getReturnType() or - result = this.(FunctionPointerIshType).getReturnType() - } - - Type getParameterType(int i) { - result = this.(RoutineType).getParameterType(i) or - result = this.(FunctionPointerIshType).getParameterType(i) - } -} - private class LeafType extends Type { LeafType() { not this instanceof DerivedType and diff --git a/cpp/common/src/codingstandards/cpp/types/Type.qll b/cpp/common/src/codingstandards/cpp/types/Type.qll index 9e2a74904b..b1b0b7aba8 100644 --- a/cpp/common/src/codingstandards/cpp/types/Type.qll +++ b/cpp/common/src/codingstandards/cpp/types/Type.qll @@ -111,3 +111,21 @@ predicate integralTypeBounds(IntegralType integralType, QlBuiltins::BigInt lb, Q ) ) } + +/** + * Convenience class to reduce the awkwardness of how `RoutineType` and `FunctionPointerIshType` + * don't have a common ancestor. + */ +class FunctionType extends Type { + FunctionType() { this instanceof RoutineType or this instanceof FunctionPointerIshType } + + Type getReturnType() { + result = this.(RoutineType).getReturnType() or + result = this.(FunctionPointerIshType).getReturnType() + } + + Type getParameterType(int i) { + result = this.(RoutineType).getParameterType(i) or + result = this.(FunctionPointerIshType).getParameterType(i) + } +} diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index 0116d8c3cc..4e892efcf1 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -120,6 +120,19 @@ class CanonicalIntegerTypes extends NumericType, IntegralType { CanonicalIntegerTypes() { this = this.getCanonicalArithmeticType() } } +FunctionType getExprCallFunctionType(ExprCall call) { + // A standard expression call + // Returns a FunctionPointerIshType + result = call.(ExprCall).getExpr().getType() + or + // An expression call using the pointer to member operator (.* or ->*) + // This special handling is required because we don't have a CodeQL class representing the call + // to a pointer to member function, but the right hand side is extracted as the -1 child of the + // call. + // Returns a RoutineType + result = call.(ExprCall).getChild(-1).getType().(PointerToMemberType).getBaseType() +} + predicate isAssignment(Expr source, NumericType targetType, string context) { exists(Expr preConversionAssignment | isPreConversionAssignment(preConversionAssignment, targetType, context) and @@ -181,27 +194,16 @@ predicate isPreConversionAssignment(Expr source, NumericType targetType, string not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and context = "function argument" | + // A regular function call targetType = call.getTarget().getParameter(i).getType() or - // Handle varargs - use the fully converted type of the argument + // A function call where the argument is passed as varargs call.getTarget().getNumberOfParameters() <= i and + // The rule states that the type should match the "adjusted" type of the argument targetType = source.getFullyConverted().getType() or - // A standard expression call - targetType = call.(ExprCall).getExpr().getType().(FunctionPointerIshType).getParameterType(i) - or - // An expression call using the pointer to member operator (.* or ->*) - // This special handling is required because we don't have a CodeQL class representing the call - // to a pointer to member function, but the right hand side is extracted as the -1 child of the - // call - targetType = - call.(ExprCall) - .getChild(-1) - .getType() - .(PointerToMemberType) - .getBaseType() - .(RoutineType) - .getParameterType(i) + // An expression call - get the function type, then the parameter type + targetType = getExprCallFunctionType(call).getParameterType(i) ) or // Return statement diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index 3b0f227399..94f5210c8d 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -51,6 +51,8 @@ predicate isValidConstantAssignment(IntegerConstantExpr source, NumericType targ ) } +bindingset[sourceType, targetType] +pragma[inline_late] predicate isValidTypeMatch(NumericType sourceType, NumericType targetType) { // Same type category, signedness and size sourceType.getTypeCategory() = targetType.getTypeCategory() and From 6ddab35740b224c62ec8a55455368db4bc0db557 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 20 Jun 2025 09:56:58 +0100 Subject: [PATCH 466/628] Create Call library --- cpp/common/src/codingstandards/cpp/Call.qll | 18 ++++++++++++++++++ .../cpp/misra/BuiltInTypeRules.qll | 14 +------------- 2 files changed, 19 insertions(+), 13 deletions(-) create mode 100644 cpp/common/src/codingstandards/cpp/Call.qll diff --git a/cpp/common/src/codingstandards/cpp/Call.qll b/cpp/common/src/codingstandards/cpp/Call.qll new file mode 100644 index 0000000000..706d66e01c --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Call.qll @@ -0,0 +1,18 @@ +import cpp +import codingstandards.cpp.types.Type + +/** + * Gets the `FunctionType` of an expression call. + */ +FunctionType getExprCallFunctionType(ExprCall call) { + // A standard expression call + // Returns a FunctionPointerIshType + result = call.(ExprCall).getExpr().getType() + or + // An expression call using the pointer to member operator (.* or ->*) + // This special handling is required because we don't have a CodeQL class representing the call + // to a pointer to member function, but the right hand side is extracted as the -1 child of the + // call. + // Returns a RoutineType + result = call.(ExprCall).getChild(-1).getType().(PointerToMemberType).getBaseType() +} diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index 4e892efcf1..17a3e257a2 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -4,6 +4,7 @@ import cpp import codingstandards.cpp.misra +import codingstandards.cpp.Call import codingstandards.cpp.Type /** @@ -120,19 +121,6 @@ class CanonicalIntegerTypes extends NumericType, IntegralType { CanonicalIntegerTypes() { this = this.getCanonicalArithmeticType() } } -FunctionType getExprCallFunctionType(ExprCall call) { - // A standard expression call - // Returns a FunctionPointerIshType - result = call.(ExprCall).getExpr().getType() - or - // An expression call using the pointer to member operator (.* or ->*) - // This special handling is required because we don't have a CodeQL class representing the call - // to a pointer to member function, but the right hand side is extracted as the -1 child of the - // call. - // Returns a RoutineType - result = call.(ExprCall).getChild(-1).getType().(PointerToMemberType).getBaseType() -} - predicate isAssignment(Expr source, NumericType targetType, string context) { exists(Expr preConversionAssignment | isPreConversionAssignment(preConversionAssignment, targetType, context) and From 983f2568608d4ce88b8173030bc019f69c51de54 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 25 Jun 2025 09:59:54 +0100 Subject: [PATCH 467/628] Extend ios stubs for C++ --- .../test/includes/standard-library/ios.h | 3 +++ .../test/includes/standard-library/ostream.h | 26 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/cpp/common/test/includes/standard-library/ios.h b/cpp/common/test/includes/standard-library/ios.h index 1a78db28aa..55e7e8db5d 100644 --- a/cpp/common/test/includes/standard-library/ios.h +++ b/cpp/common/test/includes/standard-library/ios.h @@ -67,5 +67,8 @@ template class basic_ios : public std::ios_base { ios_base &hex(ios_base &str); +std::ios_base &boolalpha(std::ios_base &str); +std::ios_base &noboolalpha(std::ios_base &str); + } // namespace std #endif // _GHLIBCPP_IOS \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/ostream.h b/cpp/common/test/includes/standard-library/ostream.h index 9f2c6d9069..23117a93d2 100644 --- a/cpp/common/test/includes/standard-library/ostream.h +++ b/cpp/common/test/includes/standard-library/ostream.h @@ -10,6 +10,18 @@ class basic_ostream : virtual public basic_ios { typedef charT char_type; basic_ostream &operator<<(int n); + basic_ostream &operator<<(bool n); + basic_ostream &operator<<(short n); + basic_ostream &operator<<(unsigned short n); + basic_ostream &operator<<(unsigned int n); + basic_ostream &operator<<(long n); + basic_ostream &operator<<(unsigned long n); + basic_ostream &operator<<(long long n); + basic_ostream &operator<<(unsigned long long n); + basic_ostream &operator<<(float f); + basic_ostream &operator<<(double f); + basic_ostream &operator<<(long double f); + basic_ostream &operator<<(const void *p); basic_ostream &put(char_type c); basic_ostream &write(const char_type *s, streamsize n); @@ -25,6 +37,20 @@ template basic_ostream &operator<<( basic_ostream &, basic_ostream &(*func)(basic_ostream &)); + +template +basic_ostream & +operator<<(basic_ostream &, + std::ios_base &(*func)(std::ios_base &)); +template +basic_ostream &operator<<( + basic_ostream &, + std::basic_ios &(*func)(std::basic_ios &)); + +template +basic_ostream &operator<<(basic_ostream &os, + const void *p); + template basic_ostream &endl(basic_ostream &); From bb9f5a1f0c372d1063f8deca7b6d87de68a445fb Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 25 Jun 2025 10:00:31 +0100 Subject: [PATCH 468/628] RULE-7-11-3 - FunctionPointerConversionContext Detects inappropriate implicit conversions from function type to pointer-to-function type outside of static_cast or assignment contexts. Prevents ambiguous code where function pointer usage in boolean or arithmetic expressions may contradict developer intent. [a] --- .../cpp/misra/BuiltInTypeRules.qll | 4 +- .../FunctionPointerConversionContext.ql | 63 ++++++++++++ .../FunctionPointerConversionContext.expected | 16 +++ .../FunctionPointerConversionContext.qlref | 1 + cpp/misra/test/rules/RULE-7-11-3/test.cpp | 98 +++++++++++++++++++ 5 files changed, 180 insertions(+), 2 deletions(-) create mode 100644 cpp/misra/src/rules/RULE-7-11-3/FunctionPointerConversionContext.ql create mode 100644 cpp/misra/test/rules/RULE-7-11-3/FunctionPointerConversionContext.expected create mode 100644 cpp/misra/test/rules/RULE-7-11-3/FunctionPointerConversionContext.qlref create mode 100644 cpp/misra/test/rules/RULE-7-11-3/test.cpp diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index 17a3e257a2..e728aa7e41 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -121,14 +121,14 @@ class CanonicalIntegerTypes extends NumericType, IntegralType { CanonicalIntegerTypes() { this = this.getCanonicalArithmeticType() } } -predicate isAssignment(Expr source, NumericType targetType, string context) { +predicate isAssignment(Expr source, Type targetType, string context) { exists(Expr preConversionAssignment | isPreConversionAssignment(preConversionAssignment, targetType, context) and preConversionAssignment.getExplicitlyConverted() = source ) } -predicate isPreConversionAssignment(Expr source, NumericType targetType, string context) { +predicate isPreConversionAssignment(Expr source, Type targetType, string context) { // Assignment expression (which excludes compound assignments) exists(AssignExpr assign | assign.getRValue() = source and diff --git a/cpp/misra/src/rules/RULE-7-11-3/FunctionPointerConversionContext.ql b/cpp/misra/src/rules/RULE-7-11-3/FunctionPointerConversionContext.ql new file mode 100644 index 0000000000..7dadbb734d --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-11-3/FunctionPointerConversionContext.ql @@ -0,0 +1,63 @@ +/** + * @id cpp/misra/function-pointer-conversion-context + * @name RULE-7-11-3: A conversion from function type to pointer-to-function type shall only occur in appropriate contexts + * @description Converting a function type to a pointer-to-function type outside of static_cast or + * assignment to a pointer-to-function object creates ambiguous behavior and potential + * unintended effects. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-11-3 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.misra.BuiltInTypeRules +import codingstandards.cpp.Type + +/** + * An `Expr` representing an implicit conversion from a function type to a pointer-to-function type. + * + * Despite the name, these are not `Conversion`s in our model. Instead, they are expressions + * representing functions that have been implicilty converted to function pointers. + */ +abstract class FunctionToFunctionPointerConversion extends Expr { } + +/** + * A `FunctionAccess` that has been implicitly converted to a function pointer type. + */ +class FunctionAccessConversionToFunctionPointer extends FunctionAccess, + FunctionToFunctionPointerConversion +{ + FunctionAccessConversionToFunctionPointer() { + this.getType().getUnspecifiedType() instanceof FunctionPointerIshType + } +} + +/** + * A `Call` to a `ConversionOperator` that converts a lambda to a function pointer type. + */ +class LambdaFunctionPointerConversion extends Call, FunctionToFunctionPointerConversion { + LambdaFunctionPointerConversion() { + this.getTarget().(ConversionOperator).getDestType() instanceof FunctionPointerIshType and + this.getQualifier().getType().getUnspecifiedType() instanceof Closure + } +} + +from FunctionToFunctionPointerConversion f +where + not isExcluded(f, ConversionsPackage::functionPointerConversionContextQuery()) and + // Not converted by an explicit static cast + not exists(Conversion c | + c.getExpr() = f and + not c.isImplicit() and + c.getType().getUnspecifiedType() instanceof FunctionPointerIshType + ) and + // Not a MISRA compliant assignment to a function pointer type + not exists(FunctionPointerIshType targetType | isAssignment(f, targetType, _)) +select f, + "Inappropriate conversion from function type to pointer-to-function type in '" + f.toString() + + "'." diff --git a/cpp/misra/test/rules/RULE-7-11-3/FunctionPointerConversionContext.expected b/cpp/misra/test/rules/RULE-7-11-3/FunctionPointerConversionContext.expected new file mode 100644 index 0000000000..be07c4b103 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-11-3/FunctionPointerConversionContext.expected @@ -0,0 +1,16 @@ +| test.cpp:11:7:11:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:14:7:14:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:18:16:18:16 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:21:14:21:14 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:25:7:25:7 | call to operator void (*)() | Inappropriate conversion from function type to pointer-to-function type in 'call to operator void (*)()'. | +| test.cpp:33:14:33:14 | call to operator void (*)() | Inappropriate conversion from function type to pointer-to-function type in 'call to operator void (*)()'. | +| test.cpp:61:13:61:13 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:64:13:64:13 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:67:7:67:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:71:7:71:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:74:7:74:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:77:7:77:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:83:7:83:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:87:7:87:7 | f | Inappropriate conversion from function type to pointer-to-function type in 'f'. | +| test.cpp:92:7:92:7 | call to operator void (*)() | Inappropriate conversion from function type to pointer-to-function type in 'call to operator void (*)()'. | +| test.cpp:96:7:96:7 | call to operator void (*)() | Inappropriate conversion from function type to pointer-to-function type in 'call to operator void (*)()'. | diff --git a/cpp/misra/test/rules/RULE-7-11-3/FunctionPointerConversionContext.qlref b/cpp/misra/test/rules/RULE-7-11-3/FunctionPointerConversionContext.qlref new file mode 100644 index 0000000000..d05d05586b --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-11-3/FunctionPointerConversionContext.qlref @@ -0,0 +1 @@ +rules/RULE-7-11-3/FunctionPointerConversionContext.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-11-3/test.cpp b/cpp/misra/test/rules/RULE-7-11-3/test.cpp new file mode 100644 index 0000000000..0522a703fc --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-11-3/test.cpp @@ -0,0 +1,98 @@ +#include +#include + +// Test functions +extern int *f(); +void f1(double); +void f1(std::uint32_t); +void simple_function(); + +void test_function_to_pointer_conversion() { + if (f) { // NON_COMPLIANT + } + + if (f == nullptr) { // NON_COMPLIANT + } + + std::cout << std::boolalpha // COMPLIANT - considered assignment + << f; // NON_COMPLIANT - not assignment + + // Non-compliant: Unary plus operator causing pointer decay + auto l1 = +f; // NON_COMPLIANT + + auto lam = []() {}; + // Lambda used in boolean context + if (lam) { // NON_COMPLIANT + } + + // Lambda used in address-of operator + if (&lam) { // COMPLIANT + } + + // Unary plus on lambda + auto l2 = +lam; // NON_COMPLIANT + + // Using address-of operator + if (&f != nullptr) { // COMPLIANT + } + + // Function call + (f)(); // COMPLIANT + lam(); // COMPLIANT + + // static_cast conversion + auto selected = static_cast(f1); // COMPLIANT + + // Assignment to pointer-to-function type + void (*p)() = lam; // COMPLIANT + + // Assignment to pointer-to-function type + int *(*func_ptr)() = f; // COMPLIANT + + // Using address-of operator + void (*simple_ptr)() = &simple_function; // COMPLIANT + + // Direct assignment without conversion + void (*simple_ptr2)() = simple_function; // COMPLIANT +} + +void test_arithmetic_expressions() { + // Function used in arithmetic expression (triggers pointer decay) + auto l3 = f + 0; // NON_COMPLIANT + + // Function used in arithmetic subtraction expression + auto l4 = f - 0; // NON_COMPLIANT + + // Function used in comparison with non-null pointer + if (f > nullptr) { // NON_COMPLIANT + } + + // Function used in relational operators + if (f < nullptr) { // NON_COMPLIANT + } + + if (f <= nullptr) { // NON_COMPLIANT + } + + if (f >= nullptr) { // NON_COMPLIANT + } +} + +void test_logical_expressions() { + // Function used in logical AND expression + if (f && true) { // NON_COMPLIANT + } + + // Function used in logical OR expression + if (f || false) { // NON_COMPLIANT + } + + // Lambda used in logical AND expression + auto lam = []() {}; + if (lam && true) { // NON_COMPLIANT + } + + // Lambda used in logical OR expression + if (lam || false) { // NON_COMPLIANT + } +} \ No newline at end of file From 2e753103a3272c06977a83b2d8de15f88fb7c1eb Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 25 Jun 2025 10:35:02 +0100 Subject: [PATCH 469/628] C++: Improve char_traits stubs --- .../test/includes/standard-library/cwchar | 23 +++++ .../test/includes/standard-library/ios.h | 3 + .../test/includes/standard-library/string | 93 +++++++++++++++++-- 3 files changed, 113 insertions(+), 6 deletions(-) diff --git a/cpp/common/test/includes/standard-library/cwchar b/cpp/common/test/includes/standard-library/cwchar index e69de29bb2..cba1ea7248 100644 --- a/cpp/common/test/includes/standard-library/cwchar +++ b/cpp/common/test/includes/standard-library/cwchar @@ -0,0 +1,23 @@ +#ifndef _GHLIBCPP_CWCHAR +#define _GHLIBCPP_CWCHAR + +#include "stddef.h" + +namespace std { +// Character classification and conversion types +typedef struct { + int __count; + union { + unsigned int __wch; + char __wchb[4]; + } __value; +} mbstate_t; + +typedef unsigned int wint_t; + +// Wide character constants +static const wint_t WEOF = static_cast(-1); + +} // namespace std + +#endif // _GHLIBCPP_CWCHAR \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/ios.h b/cpp/common/test/includes/standard-library/ios.h index 55e7e8db5d..08d32a6c36 100644 --- a/cpp/common/test/includes/standard-library/ios.h +++ b/cpp/common/test/includes/standard-library/ios.h @@ -5,6 +5,9 @@ namespace std { typedef size_t streamsize; typedef int pos_type; +typedef long long streamoff; +typedef pos_type streampos; +typedef pos_type wstreampos; // Bitmask type as specified by [bitmask.types] // Operators omitted as not required for our test cases diff --git a/cpp/common/test/includes/standard-library/string b/cpp/common/test/includes/standard-library/string index a3f22f5e80..cb76a7742d 100644 --- a/cpp/common/test/includes/standard-library/string +++ b/cpp/common/test/includes/standard-library/string @@ -1,12 +1,92 @@ #ifndef _GHLIBCPP_STRING #define _GHLIBCPP_STRING +#include "cwchar" #include "initializer_list" +#include "ios.h" #include "iosfwd.h" #include "iterator.h" #include "stddef.h" namespace std { -template struct char_traits; +template struct char_traits { + typedef charT char_type; + typedef int int_type; + typedef streamoff off_type; + typedef streampos pos_type; + typedef mbstate_t state_type; + + static void assign(char_type &c1, const char_type &c2); + static bool eq(const char_type &c1, const char_type &c2); + static bool lt(const char_type &c1, const char_type &c2); + + static int compare(const char_type *s1, const char_type *s2, size_t n); + static size_t length(const char_type *s); + static const char_type *find(const char_type *s, size_t n, + const char_type &a); + static char_type *move(char_type *s1, const char_type *s2, size_t n); + static char_type *copy(char_type *s1, const char_type *s2, size_t n); + static char_type *assign(char_type *s, size_t n, char_type a); + + static int_type not_eof(const int_type &c); + static char_type to_char_type(const int_type &c); + static int_type to_int_type(const char_type &c); + static bool eq_int_type(const int_type &c1, const int_type &c2); + static int_type eof(); +}; + +// Specialization for char +template <> struct char_traits { + typedef char char_type; + typedef int int_type; + typedef streamoff off_type; + typedef streampos pos_type; + typedef mbstate_t state_type; + + static void assign(char_type &c1, const char_type &c2); + static bool eq(const char_type &c1, const char_type &c2); + static bool lt(const char_type &c1, const char_type &c2); + + static int compare(const char_type *s1, const char_type *s2, size_t n); + static size_t length(const char_type *s); + static const char_type *find(const char_type *s, size_t n, + const char_type &a); + static char_type *move(char_type *s1, const char_type *s2, size_t n); + static char_type *copy(char_type *s1, const char_type *s2, size_t n); + static char_type *assign(char_type *s, size_t n, char_type a); + + static int_type not_eof(const int_type &c); + static char_type to_char_type(const int_type &c); + static int_type to_int_type(const char_type &c); + static bool eq_int_type(const int_type &c1, const int_type &c2); + static int_type eof(); +}; + +// Specialization for wchar_t +template <> struct char_traits { + typedef wchar_t char_type; + typedef wint_t int_type; + typedef streamoff off_type; + typedef wstreampos pos_type; + typedef mbstate_t state_type; + + static void assign(char_type &c1, const char_type &c2); + static bool eq(const char_type &c1, const char_type &c2); + static bool lt(const char_type &c1, const char_type &c2); + + static int compare(const char_type *s1, const char_type *s2, size_t n); + static size_t length(const char_type *s); + static const char_type *find(const char_type *s, size_t n, + const char_type &a); + static char_type *move(char_type *s1, const char_type *s2, size_t n); + static char_type *copy(char_type *s1, const char_type *s2, size_t n); + static char_type *assign(char_type *s, size_t n, char_type a); + + static int_type not_eof(const int_type &c); + static char_type to_char_type(const int_type &c); + static int_type to_int_type(const char_type &c); + static bool eq_int_type(const int_type &c1, const int_type &c2); + static int_type eof(); +}; template class allocator { public: @@ -114,14 +194,15 @@ public: basic_string &replace(size_type pos, size_type n1, size_type n2, charT c); basic_string &replace(__const_iterator i1, __const_iterator i2, const basic_string &str); - basic_string &replace(__const_iterator i1, __const_iterator i2, const charT *s, - size_type n); - basic_string &replace(__const_iterator i1, __const_iterator i2, const charT *s); + basic_string &replace(__const_iterator i1, __const_iterator i2, + const charT *s, size_type n); + basic_string &replace(__const_iterator i1, __const_iterator i2, + const charT *s); basic_string &replace(__const_iterator i1, __const_iterator i2, size_type n, charT c); template - basic_string &replace(__const_iterator i1, __const_iterator i2, InputIterator j1, - InputIterator j2); + basic_string &replace(__const_iterator i1, __const_iterator i2, + InputIterator j1, InputIterator j2); basic_string &replace(__const_iterator, __const_iterator, initializer_list); From 4bf8d51d5f16d5502d3d818d118eed506adffbed Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 14:50:00 +0100 Subject: [PATCH 470/628] Improve C++ stubs for locales --- .../test/includes/standard-library/clocale | 5 +- .../test/includes/standard-library/locale | 25 ++++++++ .../test/includes/standard-library/locale.h | 59 +++++++++---------- 3 files changed, 58 insertions(+), 31 deletions(-) create mode 100644 cpp/common/test/includes/standard-library/locale diff --git a/cpp/common/test/includes/standard-library/clocale b/cpp/common/test/includes/standard-library/clocale index 430c36daa0..8ec16234b8 100644 --- a/cpp/common/test/includes/standard-library/clocale +++ b/cpp/common/test/includes/standard-library/clocale @@ -1,4 +1,5 @@ -#pragma once +#ifndef _GHLIBCPP_CLOCALE +#define _GHLIBCPP_CLOCALE #define NULL 0 #define LC_ALL 0 @@ -15,3 +16,5 @@ using ::lconv; using ::localeconv; using ::setlocale; } // namespace std + +#endif // _GHLIBCPP_CLOCALE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/locale b/cpp/common/test/includes/standard-library/locale new file mode 100644 index 0000000000..4d19e3dbaa --- /dev/null +++ b/cpp/common/test/includes/standard-library/locale @@ -0,0 +1,25 @@ + +#ifndef _GHLIBCPP_LOCALE +#define _GHLIBCPP_LOCALE + +namespace std { + +class locale {}; + +template bool isspace(charT c, const locale &loc); +template bool isprint(charT c, const locale &loc); +template bool iscntrl(charT c, const locale &loc); +template bool isupper(charT c, const locale &loc); +template bool islower(charT c, const locale &loc); +template bool isalpha(charT c, const locale &loc); +template bool isdigit(charT c, const locale &loc); +template bool ispunct(charT c, const locale &loc); +template bool isxdigit(charT c, const locale &loc); +template bool isalnum(charT c, const locale &loc); +template bool isgraph(charT c, const locale &loc); +template bool isblank(charT c, const locale &loc); +template charT toupper(charT c, const locale &loc); +template charT tolower(charT c, const locale &loc); +} // namespace std + +#endif // _GHLIBCPP_LOCALE \ No newline at end of file diff --git a/cpp/common/test/includes/standard-library/locale.h b/cpp/common/test/includes/standard-library/locale.h index 19a8905531..2501c9c5d5 100644 --- a/cpp/common/test/includes/standard-library/locale.h +++ b/cpp/common/test/includes/standard-library/locale.h @@ -1,38 +1,37 @@ -#ifndef _GHLIBCPP_LOCALE -#define _GHLIBCPP_LOCALE +#ifndef _GHLIBCPP_LOCALE_H +#define _GHLIBCPP_LOCALE_H -#define LC_ALL 6 +#define LC_ALL 6 struct lconv { - char *decimal_point; - char *thousands_sep; - char *grouping; + char *decimal_point; + char *thousands_sep; + char *grouping; - char *int_curr_symbol; - char *currency_symbol; - char *mon_decimal_point; - char *mon_thousands_sep; - char *mon_grouping; - char *positive_sign; - char *negative_sign; - char int_frac_digits; - char frac_digits; - char p_cs_precedes; - char p_sep_by_space; - char n_cs_precedes; - char n_sep_by_space; - char p_sign_posn; - char n_sign_posn; - char int_p_cs_precedes; - char int_p_sep_by_space; - char int_n_cs_precedes; - char int_n_sep_by_space; - char int_p_sign_posn; - char int_n_sign_posn; + char *int_curr_symbol; + char *currency_symbol; + char *mon_decimal_point; + char *mon_thousands_sep; + char *mon_grouping; + char *positive_sign; + char *negative_sign; + char int_frac_digits; + char frac_digits; + char p_cs_precedes; + char p_sep_by_space; + char n_cs_precedes; + char n_sep_by_space; + char p_sign_posn; + char n_sign_posn; + char int_p_cs_precedes; + char int_p_sep_by_space; + char int_n_cs_precedes; + char int_n_sep_by_space; + char int_p_sign_posn; + char int_n_sign_posn; }; - -char *setlocale (int, const char *); +char *setlocale(int, const char *); struct lconv *localeconv(void); -#endif // _GHLIBCPP_LOCALE \ No newline at end of file +#endif // _GHLIBCPP_LOCALE_H \ No newline at end of file From 4d5e35f1d3281ac31de87067c21ecd18d2ee0cf1 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 6 Jun 2025 17:24:47 +0100 Subject: [PATCH 471/628] Extend C++ stubs for locale --- .../test/includes/standard-library/locale | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/cpp/common/test/includes/standard-library/locale b/cpp/common/test/includes/standard-library/locale index 4d19e3dbaa..755c5f6ee1 100644 --- a/cpp/common/test/includes/standard-library/locale +++ b/cpp/common/test/includes/standard-library/locale @@ -2,9 +2,45 @@ #ifndef _GHLIBCPP_LOCALE #define _GHLIBCPP_LOCALE +#include + namespace std { -class locale {}; +class locale { +public: + class facet; + class id; + typedef int category; + + static const category none = 0, collate = 0x010, ctype = 0x020, + monetary = 0x040, numeric = 0x080, time = 0x100, + messages = 0x200, + all = collate | ctype | monetary | numeric | time | + messages; + + locale() noexcept; + locale(const locale &other) noexcept; + explicit locale(const char *std_name); + explicit locale(const string &std_name); + locale(const locale &other, const char *std_name, category); + locale(const locale &other, const string &std_name, category); + template locale(const locale &other, Facet *f); + locale(const locale &other, const locale &one, category); + ~locale(); + const locale &operator=(const locale &other) noexcept; + template locale combine(const locale &other) const; + + basic_string name() const; + + bool operator==(const locale &other) const; + bool operator!=(const locale &other) const; + template + bool operator()(const basic_string &s1, + const basic_string &s2) const; + + static locale global(const locale &); + static const locale &classic(); +}; template bool isspace(charT c, const locale &loc); template bool isprint(charT c, const locale &loc); From f2b5410bf2e9edad2c2643b1d861845e580b2d32 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 25 Jun 2025 10:41:21 +0100 Subject: [PATCH 472/628] C++: Add optional stubs --- .../test/includes/standard-library/optional | 165 ++++++++++++++++++ 1 file changed, 165 insertions(+) create mode 100644 cpp/common/test/includes/standard-library/optional diff --git a/cpp/common/test/includes/standard-library/optional b/cpp/common/test/includes/standard-library/optional new file mode 100644 index 0000000000..8b129a36cb --- /dev/null +++ b/cpp/common/test/includes/standard-library/optional @@ -0,0 +1,165 @@ +#ifndef _GHLIBCPP_OPTIONAL +#define _GHLIBCPP_OPTIONAL + +#include "initializer_list" +#include "stddef.h" + +namespace std { + +// Forward declarations and helper types +struct in_place_t { + explicit in_place_t() = default; +}; +constexpr in_place_t in_place{}; + +// Type trait helper +template struct decay { + typedef T type; +}; + +// nullopt_t type and nullopt constant +struct nullopt_t { + explicit constexpr nullopt_t(int) {} +}; +constexpr nullopt_t nullopt{0}; + +// bad_optional_access exception +class bad_optional_access {}; + +// optional template class +template class optional { +public: + typedef T value_type; + + // Constructors + constexpr optional() noexcept; + constexpr optional(nullopt_t) noexcept; + constexpr optional(const optional &other); + constexpr optional(optional &&other) noexcept; + template constexpr explicit optional(const optional &other); + template constexpr explicit optional(optional &&other); + template + constexpr explicit optional(in_place_t, Args &&...args); + template + constexpr explicit optional(in_place_t, initializer_list ilist, + Args &&...args); + template constexpr explicit optional(U &&value); + + // Destructor + ~optional(); + + // Assignment operators + optional &operator=(nullopt_t) noexcept; + constexpr optional &operator=(const optional &other); + constexpr optional &operator=(optional &&other) noexcept; + template optional &operator=(U &&value); + template optional &operator=(const optional &other); + template optional &operator=(optional &&other); + + // Observers + constexpr const T *operator->() const; + constexpr T *operator->(); + constexpr const T &operator*() const &; + constexpr T &operator*() &; + constexpr const T &&operator*() const &&; + constexpr T &&operator*() &&; + constexpr explicit operator bool() const noexcept; + constexpr bool has_value() const noexcept; + constexpr const T &value() const &; + constexpr T &value() &; + constexpr const T &&value() const &&; + constexpr T &&value() &&; + template constexpr T value_or(U &&default_value) const &; + template constexpr T value_or(U &&default_value) &&; + + // Modifiers + void swap(optional &other) noexcept; + void reset() noexcept; + template T &emplace(Args &&...args); + template + T &emplace(initializer_list ilist, Args &&...args); +}; + +// Deduction guides +template optional(T) -> optional; + +// Comparison operators +template +constexpr bool operator==(const optional &lhs, const optional &rhs); +template +constexpr bool operator!=(const optional &lhs, const optional &rhs); +template +constexpr bool operator<(const optional &lhs, const optional &rhs); +template +constexpr bool operator<=(const optional &lhs, const optional &rhs); +template +constexpr bool operator>(const optional &lhs, const optional &rhs); +template +constexpr bool operator>=(const optional &lhs, const optional &rhs); + +// Comparison with nullopt +template +constexpr bool operator==(const optional &opt, nullopt_t) noexcept; +template +constexpr bool operator==(nullopt_t, const optional &opt) noexcept; +template +constexpr bool operator!=(const optional &opt, nullopt_t) noexcept; +template +constexpr bool operator!=(nullopt_t, const optional &opt) noexcept; +template +constexpr bool operator<(const optional &opt, nullopt_t) noexcept; +template +constexpr bool operator<(nullopt_t, const optional &opt) noexcept; +template +constexpr bool operator<=(const optional &opt, nullopt_t) noexcept; +template +constexpr bool operator<=(nullopt_t, const optional &opt) noexcept; +template +constexpr bool operator>(const optional &opt, nullopt_t) noexcept; +template +constexpr bool operator>(nullopt_t, const optional &opt) noexcept; +template +constexpr bool operator>=(const optional &opt, nullopt_t) noexcept; +template +constexpr bool operator>=(nullopt_t, const optional &opt) noexcept; + +// Comparison with T +template +constexpr bool operator==(const optional &opt, const U &value); +template +constexpr bool operator==(const T &value, const optional &opt); +template +constexpr bool operator!=(const optional &opt, const U &value); +template +constexpr bool operator!=(const T &value, const optional &opt); +template +constexpr bool operator<(const optional &opt, const U &value); +template +constexpr bool operator<(const T &value, const optional &opt); +template +constexpr bool operator<=(const optional &opt, const U &value); +template +constexpr bool operator<=(const T &value, const optional &opt); +template +constexpr bool operator>(const optional &opt, const U &value); +template +constexpr bool operator>(const T &value, const optional &opt); +template +constexpr bool operator>=(const optional &opt, const U &value); +template +constexpr bool operator>=(const T &value, const optional &opt); + +// Specialized algorithms +template void swap(optional &lhs, optional &rhs) noexcept; + +// Factory functions +template +constexpr optional::type> make_optional(T &&value); +template +constexpr optional make_optional(Args &&...args); +template +constexpr optional make_optional(initializer_list ilist, Args &&...args); + +} // namespace std + +#endif // _GHLIBCPP_OPTIONAL \ No newline at end of file From 74946cf7f0d46f66606a71d3436c987e73308889 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 25 Jun 2025 19:47:22 +0100 Subject: [PATCH 473/628] Rule 7.0.3: NoCharacterNumericalValue.ql Adds a query that identifies when a numerical value of a character has been used. Also fixes a character type category bug, exposed getBuiltinType and provide a CharacterType class. --- .../cpp/misra/BuiltInTypeRules.qll | 49 +++++-- .../RULE-7-0-3/NoCharacterNumericalValue.ql | 61 ++++++++ .../NoCharacterNumericalValue.expected | 27 ++++ .../NoCharacterNumericalValue.qlref | 1 + cpp/misra/test/rules/RULE-7-0-3/test.cpp | 131 ++++++++++++++++++ 5 files changed, 256 insertions(+), 13 deletions(-) create mode 100644 cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql create mode 100644 cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.expected create mode 100644 cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.qlref create mode 100644 cpp/misra/test/rules/RULE-7-0-3/test.cpp diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index e728aa7e41..0ce4bfd42c 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -23,7 +23,7 @@ newtype TypeCategory = */ TypeCategory getTypeCategory(BuiltInType t) { ( - t instanceof CharType or + t instanceof PlainCharType or t instanceof WideCharType or t instanceof Char16Type or t instanceof Char32Type or @@ -58,6 +58,25 @@ TypeCategory getTypeCategory(BuiltInType t) { result = Other() } +/** + * Gets the built-in type of a type, if it is a built-in type. + * + * This function will strip specifiers and typedefs to get the underlying built-in type. + */ +BuiltInType getBuiltInType(Type t) { + // Get the built-in type of a type, if it is a built-in type + result = t + or + // Strip specifiers and typedefs to get the built-in type + result = getBuiltInType(t.getUnspecifiedType()) + or + // For reference types, get the base type and then the built-in type + result = getBuiltInType(t.(ReferenceType).getBaseType()) + or + // For enum types, get the explicit underlying type and then the built-in type + result = getBuiltInType(t.(Enum).getExplicitUnderlyingType()) +} + /** * The signedness of a MISRA C++ 2023 numeric type. */ @@ -65,6 +84,19 @@ newtype Signedness = Signed() or Unsigned() +class CharacterType extends Type { + // The actual character type, which is either a plain char or a wide char + BuiltInType realType; + + CharacterType() { + // A type whose type category is character + getTypeCategory(realType) = Character() and + realType = getBuiltInType(this) + } + + Type getRealType() { result = realType } +} + /** * A MISRA C++ 2023 numeric type is a type that represents a number, either an integral or a floating-point. * @@ -78,18 +110,9 @@ class NumericType extends Type { Type realType; NumericType() { - // A type which is either an integral or a floating-point type category - getTypeCategory(this) = [Integral().(TypeCategory), FloatingPoint()] and - realType = this - or - // Any type which, after stripping specifiers and typedefs, is a numeric type - realType = this.getUnspecifiedType().(NumericType).getRealType() - or - // Any reference type where the base type is a numeric type - realType = this.(ReferenceType).getBaseType().(NumericType).getRealType() - or - // Any Enum type with an explicit underlying type that is a numeric type - realType = this.(Enum).getExplicitUnderlyingType().(NumericType).getRealType() + // A type whose type category is either integral or a floating-point + getTypeCategory(realType) = [Integral().(TypeCategory), FloatingPoint()] and + realType = getBuiltInType(this) } Signedness getSignedness() { diff --git a/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql b/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql new file mode 100644 index 0000000000..c4d294a0b8 --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql @@ -0,0 +1,61 @@ +/** + * @id cpp/misra/no-character-numerical-value + * @name RULE-7-0-3: The numerical value of a character shall not be used + * @description Using the numerical value of a character type may lead to inconsistent behavior due + * to encoding dependencies and should be avoided in favor of safer C++ Standard + * Library functions. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-0-3 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra.BuiltInTypeRules + +from Conversion c, Expr expr, Type sourceType, Type targetType +where + expr = c.getExpr() and + sourceType = expr.getType() and + targetType = c.getType() and + ( + // Conversion from character type to non-character type + sourceType instanceof CharacterType and + not targetType instanceof CharacterType + or + // Conversion from non-character type to character type + not sourceType instanceof CharacterType and + targetType instanceof CharacterType + // or + // // Conversion between different character types + // getTypeCategory(sourceType) instanceof Character and + // getTypeCategory(targetType) instanceof Character and + // not sourceType = targetType + ) and + // Exclude conversions where both operands have the same character type in equality operations + not exists(EqualityOperation eq, CharacterType leftType, CharacterType rightType | + eq.getAnOperand() = expr and + leftType = eq.getLeftOperand().getType() and + rightType = eq.getRightOperand().getType() and + leftType.getRealType() = rightType.getRealType() + ) and + // Exclude unevaluated operands + not ( + expr.getParent*() instanceof SizeofExprOperator or + expr.getParent*() instanceof SizeofTypeOperator or + expr.getParent*() instanceof TypeidOperator or + expr.getParent*() = any(Decltype dt).getExpr() or + expr.getParent*() instanceof StaticAssert + ) and + // Exclude optional comparisons that don't involve conversion + not exists(FunctionCall fc | + fc.getTarget().hasName("operator==") and + fc.getAnArgument() = expr and + fc.getQualifier().getType().hasName("optional") + ) +select expr, + "Conversion of character type '" + sourceType.getName() + "' to '" + targetType.getName() + + "' uses numerical value of character." diff --git a/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.expected b/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.expected new file mode 100644 index 0000000000..0b6088d34e --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.expected @@ -0,0 +1,27 @@ +| test.cpp:17:13:17:14 | 10 | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:18:13:18:14 | 65 | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:19:13:19:13 | 0 | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:24:20:24:22 | 97 | Conversion of character type 'char' to 'int8_t' uses numerical value of character. | +| test.cpp:25:21:25:24 | 13 | Conversion of character type 'char' to 'uint8_t' uses numerical value of character. | +| test.cpp:26:12:26:14 | 98 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:43:13:43:14 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:43:13:43:20 | ... - ... | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:43:18:43:20 | 48 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:44:13:44:14 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:44:13:44:18 | ... + ... | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:45:13:45:14 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:45:13:45:18 | ... * ... | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:51:7:51:8 | l1 | Conversion of character type 'char' to 'bool' uses numerical value of character. | +| test.cpp:51:13:51:14 | l2 | Conversion of character type 'char' to 'bool' uses numerical value of character. | +| test.cpp:53:7:53:8 | l1 | Conversion of character type 'char' to 'bool' uses numerical value of character. | +| test.cpp:55:8:55:9 | l2 | Conversion of character type 'char' to 'bool' uses numerical value of character. | +| test.cpp:73:39:73:41 | 97 | Conversion of character type 'char' to 'int_type' uses numerical value of character. | +| test.cpp:89:8:89:9 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:89:14:89:16 | 48 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:89:23:89:24 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:89:29:89:31 | 57 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:102:25:102:26 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:117:15:117:16 | l2 | Conversion of character type 'int_type' to 'char' uses numerical value of character. | +| test.cpp:123:31:123:32 | 65 | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:124:29:124:31 | 65 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:130:6:130:7 | l2 | Conversion of character type 'char' to 'int' uses numerical value of character. | diff --git a/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.qlref b/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.qlref new file mode 100644 index 0000000000..b1254bda14 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.qlref @@ -0,0 +1 @@ +rules/RULE-7-0-3/NoCharacterNumericalValue.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-3/test.cpp b/cpp/misra/test/rules/RULE-7-0-3/test.cpp new file mode 100644 index 0000000000..205712b1ff --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-3/test.cpp @@ -0,0 +1,131 @@ +#include +#include +#include +#include +#include +#include +#include + +void test_character_literal_assignment() { + char l1 = 'a'; // COMPLIANT + char l2 = '\r'; // COMPLIANT + char l3 = '\n'; // COMPLIANT + char l4 = '\0'; // COMPLIANT +} + +void test_implicit_conversion_from_int() { + char l1 = 10; // NON_COMPLIANT + char l2 = 65; // NON_COMPLIANT + char l3 = 0; // NON_COMPLIANT +} + +void test_implicit_conversion_to_int() { + char l1 = 'a'; + std::int8_t l2 = 'a'; // NON_COMPLIANT + std::uint8_t l3 = '\r'; // NON_COMPLIANT + int l4 = 'b'; // NON_COMPLIANT +} + +void test_signed_char_assignment() { + signed char l1 = 11; // COMPLIANT + signed char l2 = 65; // COMPLIANT +} + +void test_conversion_between_character_types() { + char l1 = L'A'; // COMPLIANT + wchar_t l2 = 'B'; // COMPLIANT + char16_t l3 = 'C'; // COMPLIANT + char32_t l4 = 'D'; // COMPLIANT +} + +void test_arithmetic_operations() { + char l1 = 'a'; + char l2 = l1 - '0'; // NON_COMPLIANT + char l3 = l1 + 1; // NON_COMPLIANT + char l4 = l1 * 2; // NON_COMPLIANT +} + +void test_boolean_conversion() { + char l1 = 'a'; + char l2 = '\0'; + if (l1 && l2) { // NON_COMPLIANT + } + if (l1) { // NON_COMPLIANT + } + if (!l2) { // NON_COMPLIANT + } +} + +void test_same_type_comparison() { + char l1 = 'a'; + if (l1 != 'q') { // COMPLIANT + } + if (l1 == 'b') { // COMPLIANT + } +} + +void test_char_traits_usage() { + using CT = std::char_traits; + char l1 = 'a'; + if (CT::eq(l1, 'q')) { // COMPLIANT + } + auto l2 = CT::to_int_type('a'); // COMPLIANT + auto l3 = static_cast('a'); // NON_COMPLIANT +} + +void test_optional_comparison() { + std::optional l1; + if (l1 == 'r') { // COMPLIANT + } +} + +void test_unevaluated_operand() { + decltype('s' + 't') l1; // COMPLIANT + static_assert(sizeof('x') > 0); // COMPLIANT +} + +void test_range_check_non_compliant() { + char l1 = 'a'; + if ((l1 >= '0') && (l1 <= '9')) { // NON_COMPLIANT + } +} + +void test_range_check_compliant() { + using CT = std::char_traits; + char l1 = 'a'; + if (!CT::lt(l1, '0') && !CT::lt('9', l1)) { // COMPLIANT + } +} + +void test_isdigit_non_compliant() { + char l1 = 'a'; + if (0 == std::isdigit(l1)) { // NON_COMPLIANT + } +} + +void test_isdigit_compliant() { + char l1 = 'a'; + if (std::isdigit(l1, std::locale{})) { // COMPLIANT + } +} + +void test_stream_conversion() { + std::istream &l1 = std::cin; + auto l2 = l1.get(); + using CT = std::char_traits; + if (CT::not_eof(l2)) { + char l3 = l2; // NON_COMPLIANT + char l4 = CT::to_char_type(l2); // COMPLIANT + } +} + +void test_explicit_cast() { + char l1 = static_cast(65); // NON_COMPLIANT + int l2 = static_cast('A'); // NON_COMPLIANT +} + +void test_function_parameter_conversion() { + auto f1 = [](int l1) {}; + char l2 = 'x'; + f1(l2); // NON_COMPLIANT +} \ No newline at end of file From a2d7ee33ccf5d9eee4fe0bf25d93b624c330e907 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 26 Jun 2025 20:41:27 +0100 Subject: [PATCH 474/628] RULE-7-0-5 - NoSignednessChangeFromPromotion Detects integral promotions and arithmetic conversions that change the signedness or type category of operands, preventing unexpected behavior from implicit type conversions. [a] --- .../NoSignednessChangeFromPromotion.ql | 88 +++++++++++ .../NoSignednessChangeFromPromotion.expected | 47 ++++++ .../NoSignednessChangeFromPromotion.qlref | 1 + cpp/misra/test/rules/RULE-7-0-5/test.cpp | 146 ++++++++++++++++++ 4 files changed, 282 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql create mode 100644 cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected create mode 100644 cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.qlref create mode 100644 cpp/misra/test/rules/RULE-7-0-5/test.cpp diff --git a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql new file mode 100644 index 0000000000..f9a4fb6f5c --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql @@ -0,0 +1,88 @@ +/** + * @id cpp/misra/no-signedness-change-from-promotion + * @name RULE-7-0-5: Integral promotion and the usual arithmetic conversions shall not change the signedness or the type + * @description Integral promotion and usual arithmetic conversions that change operand signedness + * or type category may cause unexpected behavior or undefined behavior when operations + * overflow. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-0-5 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.misra.BuiltInTypeRules + +/** + * A `Conversion` that is relevant for the rule. + */ +abstract class RelevantConversion extends Conversion { + NumericType fromType; + NumericType toType; + + RelevantConversion() { + fromType = this.getExpr().getType().getUnspecifiedType() and + toType = this.getType().getUnspecifiedType() and + this.isImplicit() + } + + Type getFromType() { result = fromType } + + Type getToType() { result = toType } +} + +class UsualArithmeticConversion extends RelevantConversion { + UsualArithmeticConversion() { + ( + exists(BinaryOperation op | op.getAnOperand().getFullyConverted() = this) or + exists(UnaryOperation uao | uao.getOperand().getFullyConverted() = this) or + exists(AssignArithmeticOperation ao | ao.getAnOperand().getFullyConverted() = this) + ) + } +} + +class IntegerPromotion extends RelevantConversion { + IntegerPromotion() { + // Only consider cases where the integer promotion is the last conversion applied + exists(Expr e | e.getFullyConverted() = this) and + // Integer promotion occurs where the from type is smaller than int + fromType.getRealSize() < any(IntType i).(NumericType).getRealSize() and + // To type is bigger than or equal to int + toType.getRealSize() >= any(IntType i).(NumericType).getRealSize() and + fromType.getTypeCategory() = Integral() and + toType.getTypeCategory() = Integral() + } +} + +from Expr e, RelevantConversion c, NumericType fromType, NumericType toType, string changeType +where + not isExcluded(e, ConversionsPackage::noSignednessChangeFromPromotionQuery()) and + c = e.getConversion() and + fromType = c.getFromType() and + toType = c.getToType() and + ( + fromType.getSignedness() != toType.getSignedness() and changeType = "signedness" + or + fromType.getTypeCategory() != toType.getTypeCategory() and changeType = "type category" + ) and + // Ignore crement operations + not exists(CrementOperation cop | cop.getAnOperand() = e) and + // Exception 1: allow safe constant conversions + not ( + e.getValue().toInt() >= 0 and + fromType.(IntegralType).isSigned() and + toType.(IntegralType).isUnsigned() + ) and + // Exception 2: allow safe conversions from integral to floating-point types + not ( + e.isConstant() and + fromType.getTypeCategory() = Integral() and + toType.getTypeCategory() = FloatingPoint() + ) +select e, + "Conversion from '" + fromType.getName() + "' to '" + toType.getName() + "' changes " + changeType + + "." diff --git a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected new file mode 100644 index 0000000000..0a2df74048 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected @@ -0,0 +1,47 @@ +| test.cpp:24:5:24:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:24:10:24:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:25:5:25:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:25:10:25:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:26:5:26:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:26:10:26:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:27:5:27:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:27:10:27:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:28:5:28:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:28:10:28:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:29:5:29:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:29:10:29:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:30:5:30:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:30:10:30:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:31:5:31:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:31:10:31:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:45:11:45:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:46:11:46:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:47:11:47:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:48:11:48:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:49:11:49:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:50:11:50:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:51:11:51:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:52:11:52:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:64:5:64:6 | l1 | Conversion from 'signed int' to 'unsigned int' changes signedness. | +| test.cpp:65:5:65:6 | l1 | Conversion from 'signed int' to 'unsigned int' changes signedness. | +| test.cpp:66:5:66:6 | l1 | Conversion from 'signed int' to 'unsigned int' changes signedness. | +| test.cpp:67:5:67:6 | l1 | Conversion from 'signed int' to 'unsigned int' changes signedness. | +| test.cpp:68:5:68:6 | l1 | Conversion from 'signed int' to 'unsigned int' changes signedness. | +| test.cpp:69:5:69:6 | l1 | Conversion from 'signed int' to 'unsigned int' changes signedness. | +| test.cpp:71:5:71:6 | l3 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:71:10:71:11 | l4 | Conversion from 'unsigned short' to 'int' changes signedness. | +| test.cpp:72:5:72:6 | l3 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:72:10:72:11 | l4 | Conversion from 'unsigned short' to 'int' changes signedness. | +| test.cpp:82:10:82:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:82:15:82:16 | l4 | Conversion from 'unsigned short' to 'int' changes signedness. | +| test.cpp:89:5:89:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:90:5:90:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:100:6:100:7 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:102:6:102:7 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:104:6:104:7 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | +| test.cpp:143:11:143:12 | l2 | Conversion from 'unsigned int' to 'float' changes signedness. | +| test.cpp:143:11:143:12 | l2 | Conversion from 'unsigned int' to 'float' changes type category. | +| test.cpp:144:11:144:12 | l2 | Conversion from 'unsigned int' to 'float' changes signedness. | +| test.cpp:144:11:144:12 | l2 | Conversion from 'unsigned int' to 'float' changes type category. | +| test.cpp:145:11:145:12 | l2 | Conversion from 'unsigned int' to 'float' changes signedness. | +| test.cpp:145:11:145:12 | l2 | Conversion from 'unsigned int' to 'float' changes type category. | diff --git a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.qlref b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.qlref new file mode 100644 index 0000000000..ae020269b9 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.qlref @@ -0,0 +1 @@ +rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-5/test.cpp b/cpp/misra/test/rules/RULE-7-0-5/test.cpp new file mode 100644 index 0000000000..f851f2ac5c --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-5/test.cpp @@ -0,0 +1,146 @@ +#include + +// Global variables for testing +std::uint8_t g1 = 5; +std::uint8_t g2 = 10; +std::uint16_t g3 = 100; +std::uint32_t g4 = 1000; +std::int8_t g5 = -5; +std::int32_t g6 = -1000; +float g7 = 3.14f; + +constexpr std::int32_t f1(std::int32_t i) { + return i * i; +} + +void test_binary_arithmetic_operations() { + std::uint8_t l1 = 5; + std::uint8_t l2 = 10; + std::uint16_t l3 = 100; + std::uint32_t l4 = 1000; + std::int8_t l5 = -5; + std::int32_t l6 = -1000; + + l1 + l2; // NON_COMPLIANT - u8 + u8 -> signed int + l1 * l2; // NON_COMPLIANT - u8 * u8 -> signed int + l1 - l2; // NON_COMPLIANT - u8 - u8 -> signed int + l1 / l2; // NON_COMPLIANT - u8 / u8 -> signed int + l1 % l2; // NON_COMPLIANT - u8 % u8 -> signed int + l1 & l2; // NON_COMPLIANT - u8 & u8 -> signed int + l1 | l2; // NON_COMPLIANT - u8 | u8 -> signed int + l1 ^ l2; // NON_COMPLIANT - u8 ^ u8 -> signed int + + static_cast(l1) + l2; // COMPLIANT - l2 -> unsigned int + l1 + static_cast(l2); // COMPLIANT - l1 -> unsigned int + + l6 * l5; // COMPLIANT - l5 -> signed int + l4 / l1; // COMPLIANT - l1 -> unsigned int +} + +void test_assignment_operations() { + std::uint8_t l1 = 5; + std::uint8_t l2 = 10; + std::uint32_t l3 = 1000; + + l1 += l2; // NON_COMPLIANT - same as l1 + l2 + l1 -= l2; // NON_COMPLIANT - same as l1 - l2 + l1 *= l2; // NON_COMPLIANT - same as l1 * l2 + l1 /= l2; // NON_COMPLIANT - same as l1 / l2 + l1 %= l2; // NON_COMPLIANT - same as l1 % l2 + l1 &= l2; // NON_COMPLIANT - same as l1 & l2 + l1 |= l2; // NON_COMPLIANT - same as l1 | l2 + l1 ^= l2; // NON_COMPLIANT - same as l1 ^ l2 + + l1 += static_cast(l2); // COMPLIANT - l1 -> unsigned int + l1 += l3; // COMPLIANT - l1 -> unsigned int +} + +void test_comparison_operations() { + std::int32_t l1 = -1000; + std::uint32_t l2 = 1000; + std::uint8_t l3 = 5; + std::uint16_t l4 = 100; + + l1 > l2; // NON_COMPLIANT - l1 -> unsigned int + l1 < l2; // NON_COMPLIANT - l1 -> unsigned int + l1 >= l2; // NON_COMPLIANT - l1 -> unsigned int + l1 <= l2; // NON_COMPLIANT - l1 -> unsigned int + l1 == l2; // NON_COMPLIANT - l1 -> unsigned int + l1 != l2; // NON_COMPLIANT - l1 -> unsigned int + + l3 > l4; // NON_COMPLIANT - l3 and l4 -> signed int + l3 < l4; // NON_COMPLIANT - l3 and l4 -> signed int +} + +void test_conditional_operator() { + bool l1 = true; + std::uint8_t l2 = 5; + std::uint8_t l3 = 10; + std::uint16_t l4 = 100; + + l1 ? l2 : l3; // COMPLIANT - no conversion + l1 ? l2 : l4; // NON_COMPLIANT - l2 and l4 -> signed int +} + +void test_shift_operations() { + std::uint8_t l1 = 5; + std::uint32_t l2 = 1000; + + l1 << 2; // NON_COMPLIANT - l1 -> signed int + l1 >> 1; // NON_COMPLIANT - l1 -> signed int + l2 << 2; // COMPLIANT + l2 >> 1; // COMPLIANT +} + +void test_unary_operations() { + std::uint8_t l1 = 5; + std::uint32_t l2 = 1000; + std::int8_t l3 = -5; + + ~l1; // NON_COMPLIANT - l1 -> signed int + ~l2; // COMPLIANT + -l1; // NON_COMPLIANT - l1 -> signed int + -l3; // COMPLIANT - l3 is signed + +l1; // NON_COMPLIANT - l1 -> signed int +} + +void test_increment_decrement() { + std::uint8_t l1 = 5; + std::uint16_t l2 = 100; + + l1++; // COMPLIANT - rule does not apply + ++l1; // COMPLIANT - rule does not apply + l1--; // COMPLIANT - rule does not apply + --l1; // COMPLIANT - rule does not apply + l2++; // COMPLIANT - rule does not apply + ++l2; // COMPLIANT - rule does not apply +} + +void test_array_subscript() { + int l1[10]; + std::uint8_t l2 = 5; + + l1[l2]; // COMPLIANT - rule does not apply +} + +void test_exception_compile_time_constants() { + std::uint32_t l1 = 1000; + float l2 = 3.14f; + std::int32_t l3 = 5; + + l1 - 1; // COMPLIANT - exception #1 + l1 + 42; // COMPLIANT - exception #1 + l2 += 1; // COMPLIANT - exception #2 + l2 += 0x10001; // COMPLIANT - exception #2 + l3 + f1(10); // COMPLIANT - exception #1 + l2 + f1(10); // COMPLIANT - exception #2 +} + +void test_floating_point_conversions() { + float l1; + std::uint32_t l2; + + l1 += l2; // NON_COMPLIANT - l2 -> floating + l1 *= l2; // NON_COMPLIANT - l2 -> floating + l1 /= l2; // NON_COMPLIANT - l2 -> floating +} \ No newline at end of file From c25057d70fdfc7e8ade419aca8cd85ecfbdef098 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 27 Jun 2025 11:47:59 +0100 Subject: [PATCH 475/628] Add sizeOfInt() predicate For determining the size of int on the given platform. --- cpp/common/src/codingstandards/cpp/types/Type.qll | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cpp/common/src/codingstandards/cpp/types/Type.qll b/cpp/common/src/codingstandards/cpp/types/Type.qll index b1b0b7aba8..dba3af7a4a 100644 --- a/cpp/common/src/codingstandards/cpp/types/Type.qll +++ b/cpp/common/src/codingstandards/cpp/types/Type.qll @@ -112,6 +112,19 @@ predicate integralTypeBounds(IntegralType integralType, QlBuiltins::BigInt lb, Q ) } +/** + * The size of the smallest `int` type in the database in bytes. + */ +int sizeOfInt() { + // The size of int is implementation-defined + result = + min(int size | + size = any(IntType i | i.isSigned()).getCanonicalArithmeticType().getSize() + | + size + ) +} + /** * Convenience class to reduce the awkwardness of how `RoutineType` and `FunctionPointerIshType` * don't have a common ancestor. From 3a8dab1de3f64f3ea74a07d9dfb103f79a01ace3 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 27 Jun 2025 11:50:20 +0100 Subject: [PATCH 476/628] Rule 7.0.5: Refactor to enable non-Conversions Not all integer promotions or usual arithmetic conversions are actually Conversions in our model. --- .../NoSignednessChangeFromPromotion.ql | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql index f9a4fb6f5c..cc56e93dd1 100644 --- a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql +++ b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql @@ -17,25 +17,37 @@ import cpp import codingstandards.cpp.misra import codingstandards.cpp.misra.BuiltInTypeRules +abstract class RelevantConversion extends Expr { + abstract Type getFromType(); + + abstract Type getToType(); + + abstract Expr getConvertedExpr(); + + abstract string getKindOfConversion(); +} + /** * A `Conversion` that is relevant for the rule. */ -abstract class RelevantConversion extends Conversion { +abstract class RelevantRealConversion extends RelevantConversion, Conversion { NumericType fromType; NumericType toType; - RelevantConversion() { - fromType = this.getExpr().getType().getUnspecifiedType() and - toType = this.getType().getUnspecifiedType() and + RelevantRealConversion() { + fromType = this.getExpr().getType() and + toType = this.getType() and this.isImplicit() } - Type getFromType() { result = fromType } + override Type getFromType() { result = fromType } + + override Type getToType() { result = toType } - Type getToType() { result = toType } + override Expr getConvertedExpr() { result = this.getExpr() } } -class UsualArithmeticConversion extends RelevantConversion { +class UsualArithmeticConversion extends RelevantRealConversion { UsualArithmeticConversion() { ( exists(BinaryOperation op | op.getAnOperand().getFullyConverted() = this) or @@ -43,9 +55,11 @@ class UsualArithmeticConversion extends RelevantConversion { exists(AssignArithmeticOperation ao | ao.getAnOperand().getFullyConverted() = this) ) } + + override string getKindOfConversion() { result = "Usual arithmetic conversion" } } -class IntegerPromotion extends RelevantConversion { +class IntegerPromotion extends RelevantRealConversion { IntegerPromotion() { // Only consider cases where the integer promotion is the last conversion applied exists(Expr e | e.getFullyConverted() = this) and @@ -61,7 +75,7 @@ class IntegerPromotion extends RelevantConversion { from Expr e, RelevantConversion c, NumericType fromType, NumericType toType, string changeType where not isExcluded(e, ConversionsPackage::noSignednessChangeFromPromotionQuery()) and - c = e.getConversion() and + c.getConvertedExpr() = e and fromType = c.getFromType() and toType = c.getToType() and ( @@ -84,5 +98,5 @@ where toType.getTypeCategory() = FloatingPoint() ) select e, - "Conversion from '" + fromType.getName() + "' to '" + toType.getName() + "' changes " + changeType - + "." + c.getKindOfConversion() + " from '" + fromType.getName() + "' to '" + toType.getName() + + "' changes " + changeType + "." From 3cf9eacdf44c1caf31522f8396385e8f345dd7ac Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 27 Jun 2025 12:07:15 +0100 Subject: [PATCH 477/628] Improve detection of integer promotions and usual arithmetic conversions --- .../NoSignednessChangeFromPromotion.ql | 32 ++++++- .../NoSignednessChangeFromPromotion.expected | 94 +++++++++---------- 2 files changed, 74 insertions(+), 52 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql index cc56e93dd1..f35c18bae4 100644 --- a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql +++ b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql @@ -50,9 +50,22 @@ abstract class RelevantRealConversion extends RelevantConversion, Conversion { class UsualArithmeticConversion extends RelevantRealConversion { UsualArithmeticConversion() { ( - exists(BinaryOperation op | op.getAnOperand().getFullyConverted() = this) or - exists(UnaryOperation uao | uao.getOperand().getFullyConverted() = this) or - exists(AssignArithmeticOperation ao | ao.getAnOperand().getFullyConverted() = this) + // Most binary operations from and to numeric types participate in usual arithmetic conversions + exists(BinaryOperation op | + // Shifts do not participate in usual arithmetic conversions + not op instanceof LShiftExpr and + not op instanceof RShiftExpr and + op.getAnOperand().getFullyConverted() = this + ) + or + // Most binary assignment operations from and to numeric types participate in usual arithmetic + // conversions + exists(AssignOperation ao | + // Shifts do not participate in usual arithmetic conversions + not ao instanceof AssignLShiftExpr and + not ao instanceof AssignRShiftExpr and + ao.getRValue().getFullyConverted() = this + ) ) } @@ -61,15 +74,24 @@ class UsualArithmeticConversion extends RelevantRealConversion { class IntegerPromotion extends RelevantRealConversion { IntegerPromotion() { + // Exclude integer promotions combined with usual arithmetic conversions, which are handled separately + not this instanceof UsualArithmeticConversion and // Only consider cases where the integer promotion is the last conversion applied exists(Expr e | e.getFullyConverted() = this) and // Integer promotion occurs where the from type is smaller than int - fromType.getRealSize() < any(IntType i).(NumericType).getRealSize() and + fromType.getRealSize() < sizeOfInt() and // To type is bigger than or equal to int - toType.getRealSize() >= any(IntType i).(NumericType).getRealSize() and + toType.getRealSize() >= sizeOfInt() and + // An integer promotion is a conversion from an integral type to an integral type + // + // This deliberately excludes integer promotions from `bool` and unscoped enums which do not + // have a fixed underlying type, because neither of these are considered integral types in the + // MISRA C++ rules. fromType.getTypeCategory() = Integral() and toType.getTypeCategory() = Integral() } + + override string getKindOfConversion() { result = "Integer promotion" } } from Expr e, RelevantConversion c, NumericType fromType, NumericType toType, string changeType diff --git a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected index 0a2df74048..5fbabb2052 100644 --- a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected +++ b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected @@ -1,47 +1,47 @@ -| test.cpp:24:5:24:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:24:10:24:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:25:5:25:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:25:10:25:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:26:5:26:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:26:10:26:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:27:5:27:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:27:10:27:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:28:5:28:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:28:10:28:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:29:5:29:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:29:10:29:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:30:5:30:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:30:10:30:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:31:5:31:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:31:10:31:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:45:11:45:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:46:11:46:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:47:11:47:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:48:11:48:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:49:11:49:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:50:11:50:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:51:11:51:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:52:11:52:12 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:64:5:64:6 | l1 | Conversion from 'signed int' to 'unsigned int' changes signedness. | -| test.cpp:65:5:65:6 | l1 | Conversion from 'signed int' to 'unsigned int' changes signedness. | -| test.cpp:66:5:66:6 | l1 | Conversion from 'signed int' to 'unsigned int' changes signedness. | -| test.cpp:67:5:67:6 | l1 | Conversion from 'signed int' to 'unsigned int' changes signedness. | -| test.cpp:68:5:68:6 | l1 | Conversion from 'signed int' to 'unsigned int' changes signedness. | -| test.cpp:69:5:69:6 | l1 | Conversion from 'signed int' to 'unsigned int' changes signedness. | -| test.cpp:71:5:71:6 | l3 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:71:10:71:11 | l4 | Conversion from 'unsigned short' to 'int' changes signedness. | -| test.cpp:72:5:72:6 | l3 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:72:10:72:11 | l4 | Conversion from 'unsigned short' to 'int' changes signedness. | -| test.cpp:82:10:82:11 | l2 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:82:15:82:16 | l4 | Conversion from 'unsigned short' to 'int' changes signedness. | -| test.cpp:89:5:89:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:90:5:90:6 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:100:6:100:7 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:102:6:102:7 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:104:6:104:7 | l1 | Conversion from 'unsigned char' to 'int' changes signedness. | -| test.cpp:143:11:143:12 | l2 | Conversion from 'unsigned int' to 'float' changes signedness. | -| test.cpp:143:11:143:12 | l2 | Conversion from 'unsigned int' to 'float' changes type category. | -| test.cpp:144:11:144:12 | l2 | Conversion from 'unsigned int' to 'float' changes signedness. | -| test.cpp:144:11:144:12 | l2 | Conversion from 'unsigned int' to 'float' changes type category. | -| test.cpp:145:11:145:12 | l2 | Conversion from 'unsigned int' to 'float' changes signedness. | -| test.cpp:145:11:145:12 | l2 | Conversion from 'unsigned int' to 'float' changes type category. | +| test.cpp:24:5:24:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:24:10:24:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:25:5:25:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:25:10:25:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:26:5:26:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:26:10:26:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:27:5:27:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:27:10:27:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:28:5:28:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:28:10:28:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:29:5:29:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:29:10:29:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:30:5:30:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:30:10:30:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:31:5:31:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:31:10:31:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:45:11:45:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:46:11:46:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:47:11:47:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:48:11:48:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:49:11:49:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:50:11:50:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:51:11:51:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:52:11:52:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:64:5:64:6 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:65:5:65:6 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:66:5:66:6 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:67:5:67:6 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:68:5:68:6 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:69:5:69:6 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:71:5:71:6 | l3 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:71:10:71:11 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:72:5:72:6 | l3 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:72:10:72:11 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:82:10:82:11 | l2 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:82:15:82:16 | l4 | Integer promotion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:89:5:89:6 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:90:5:90:6 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:100:6:100:7 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:102:6:102:7 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:104:6:104:7 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:143:11:143:12 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | +| test.cpp:143:11:143:12 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | +| test.cpp:144:11:144:12 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | +| test.cpp:144:11:144:12 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | +| test.cpp:145:11:145:12 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | +| test.cpp:145:11:145:12 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | From f50baa9166523b6c39fc5c5c3e8831ecc6a2db30 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 27 Jun 2025 12:08:12 +0100 Subject: [PATCH 478/628] Format test case --- .../NoSignednessChangeFromPromotion.expected | 94 ++++---- cpp/misra/test/rules/RULE-7-0-5/test.cpp | 208 +++++++++--------- 2 files changed, 150 insertions(+), 152 deletions(-) diff --git a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected index 5fbabb2052..ede74bd18d 100644 --- a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected +++ b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected @@ -1,47 +1,47 @@ -| test.cpp:24:5:24:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:24:10:24:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:25:5:25:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:25:10:25:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:26:5:26:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:26:10:26:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:27:5:27:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:27:10:27:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:28:5:28:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:28:10:28:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:29:5:29:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:29:10:29:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:30:5:30:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:30:10:30:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:31:5:31:6 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:31:10:31:11 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:45:11:45:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:46:11:46:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:47:11:47:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:48:11:48:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:49:11:49:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:50:11:50:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:51:11:51:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:52:11:52:12 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:64:5:64:6 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | -| test.cpp:65:5:65:6 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | -| test.cpp:66:5:66:6 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | -| test.cpp:67:5:67:6 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | -| test.cpp:68:5:68:6 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | -| test.cpp:69:5:69:6 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | -| test.cpp:71:5:71:6 | l3 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:71:10:71:11 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | -| test.cpp:72:5:72:6 | l3 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:72:10:72:11 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | -| test.cpp:82:10:82:11 | l2 | Integer promotion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:82:15:82:16 | l4 | Integer promotion from 'uint16_t' to 'int' changes signedness. | -| test.cpp:89:5:89:6 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:90:5:90:6 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:100:6:100:7 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:102:6:102:7 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:104:6:104:7 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:143:11:143:12 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | -| test.cpp:143:11:143:12 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | -| test.cpp:144:11:144:12 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | -| test.cpp:144:11:144:12 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | -| test.cpp:145:11:145:12 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | -| test.cpp:145:11:145:12 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | +| test.cpp:22:3:22:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:22:8:22:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:23:3:23:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:23:7:23:8 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:24:3:24:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:24:8:24:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:25:3:25:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:25:8:25:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:26:3:26:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:26:8:26:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:27:3:27:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:27:8:27:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:28:3:28:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:28:8:28:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:29:3:29:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:29:8:29:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:43:9:43:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:44:9:44:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:45:9:45:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:46:9:46:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:47:9:47:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:48:9:48:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:49:9:49:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:50:9:50:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:62:3:62:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:63:3:63:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:64:3:64:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:65:3:65:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:66:3:66:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:67:3:67:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:69:3:69:4 | l3 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:69:8:69:9 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:70:3:70:4 | l3 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:70:8:70:9 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:80:8:80:9 | l2 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:80:13:80:14 | l4 | Integer promotion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:87:3:87:4 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:88:3:88:4 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:98:4:98:5 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:100:4:100:5 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:102:4:102:5 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:141:9:141:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | +| test.cpp:141:9:141:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | +| test.cpp:142:9:142:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | +| test.cpp:142:9:142:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | +| test.cpp:143:9:143:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | +| test.cpp:143:9:143:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | diff --git a/cpp/misra/test/rules/RULE-7-0-5/test.cpp b/cpp/misra/test/rules/RULE-7-0-5/test.cpp index f851f2ac5c..272b699a67 100644 --- a/cpp/misra/test/rules/RULE-7-0-5/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-5/test.cpp @@ -9,138 +9,136 @@ std::int8_t g5 = -5; std::int32_t g6 = -1000; float g7 = 3.14f; -constexpr std::int32_t f1(std::int32_t i) { - return i * i; -} +constexpr std::int32_t f1(std::int32_t i) { return i * i; } void test_binary_arithmetic_operations() { - std::uint8_t l1 = 5; - std::uint8_t l2 = 10; - std::uint16_t l3 = 100; - std::uint32_t l4 = 1000; - std::int8_t l5 = -5; - std::int32_t l6 = -1000; - - l1 + l2; // NON_COMPLIANT - u8 + u8 -> signed int - l1 * l2; // NON_COMPLIANT - u8 * u8 -> signed int - l1 - l2; // NON_COMPLIANT - u8 - u8 -> signed int - l1 / l2; // NON_COMPLIANT - u8 / u8 -> signed int - l1 % l2; // NON_COMPLIANT - u8 % u8 -> signed int - l1 & l2; // NON_COMPLIANT - u8 & u8 -> signed int - l1 | l2; // NON_COMPLIANT - u8 | u8 -> signed int - l1 ^ l2; // NON_COMPLIANT - u8 ^ u8 -> signed int - - static_cast(l1) + l2; // COMPLIANT - l2 -> unsigned int - l1 + static_cast(l2); // COMPLIANT - l1 -> unsigned int - - l6 * l5; // COMPLIANT - l5 -> signed int - l4 / l1; // COMPLIANT - l1 -> unsigned int + std::uint8_t l1 = 5; + std::uint8_t l2 = 10; + std::uint16_t l3 = 100; + std::uint32_t l4 = 1000; + std::int8_t l5 = -5; + std::int32_t l6 = -1000; + + l1 + l2; // NON_COMPLIANT - u8 + u8 -> signed int + l1 *l2; // NON_COMPLIANT - u8 * u8 -> signed int + l1 - l2; // NON_COMPLIANT - u8 - u8 -> signed int + l1 / l2; // NON_COMPLIANT - u8 / u8 -> signed int + l1 % l2; // NON_COMPLIANT - u8 % u8 -> signed int + l1 & l2; // NON_COMPLIANT - u8 & u8 -> signed int + l1 | l2; // NON_COMPLIANT - u8 | u8 -> signed int + l1 ^ l2; // NON_COMPLIANT - u8 ^ u8 -> signed int + + static_cast(l1) + l2; // COMPLIANT - l2 -> unsigned int + l1 + static_cast(l2); // COMPLIANT - l1 -> unsigned int + + l6 *l5; // COMPLIANT - l5 -> signed int + l4 / l1; // COMPLIANT - l1 -> unsigned int } void test_assignment_operations() { - std::uint8_t l1 = 5; - std::uint8_t l2 = 10; - std::uint32_t l3 = 1000; - - l1 += l2; // NON_COMPLIANT - same as l1 + l2 - l1 -= l2; // NON_COMPLIANT - same as l1 - l2 - l1 *= l2; // NON_COMPLIANT - same as l1 * l2 - l1 /= l2; // NON_COMPLIANT - same as l1 / l2 - l1 %= l2; // NON_COMPLIANT - same as l1 % l2 - l1 &= l2; // NON_COMPLIANT - same as l1 & l2 - l1 |= l2; // NON_COMPLIANT - same as l1 | l2 - l1 ^= l2; // NON_COMPLIANT - same as l1 ^ l2 - - l1 += static_cast(l2); // COMPLIANT - l1 -> unsigned int - l1 += l3; // COMPLIANT - l1 -> unsigned int + std::uint8_t l1 = 5; + std::uint8_t l2 = 10; + std::uint32_t l3 = 1000; + + l1 += l2; // NON_COMPLIANT - same as l1 + l2 + l1 -= l2; // NON_COMPLIANT - same as l1 - l2 + l1 *= l2; // NON_COMPLIANT - same as l1 * l2 + l1 /= l2; // NON_COMPLIANT - same as l1 / l2 + l1 %= l2; // NON_COMPLIANT - same as l1 % l2 + l1 &= l2; // NON_COMPLIANT - same as l1 & l2 + l1 |= l2; // NON_COMPLIANT - same as l1 | l2 + l1 ^= l2; // NON_COMPLIANT - same as l1 ^ l2 + + l1 += static_cast(l2); // COMPLIANT - l1 -> unsigned int + l1 += l3; // COMPLIANT - l1 -> unsigned int } void test_comparison_operations() { - std::int32_t l1 = -1000; - std::uint32_t l2 = 1000; - std::uint8_t l3 = 5; - std::uint16_t l4 = 100; - - l1 > l2; // NON_COMPLIANT - l1 -> unsigned int - l1 < l2; // NON_COMPLIANT - l1 -> unsigned int - l1 >= l2; // NON_COMPLIANT - l1 -> unsigned int - l1 <= l2; // NON_COMPLIANT - l1 -> unsigned int - l1 == l2; // NON_COMPLIANT - l1 -> unsigned int - l1 != l2; // NON_COMPLIANT - l1 -> unsigned int - - l3 > l4; // NON_COMPLIANT - l3 and l4 -> signed int - l3 < l4; // NON_COMPLIANT - l3 and l4 -> signed int + std::int32_t l1 = -1000; + std::uint32_t l2 = 1000; + std::uint8_t l3 = 5; + std::uint16_t l4 = 100; + + l1 > l2; // NON_COMPLIANT - l1 -> unsigned int + l1 < l2; // NON_COMPLIANT - l1 -> unsigned int + l1 >= l2; // NON_COMPLIANT - l1 -> unsigned int + l1 <= l2; // NON_COMPLIANT - l1 -> unsigned int + l1 == l2; // NON_COMPLIANT - l1 -> unsigned int + l1 != l2; // NON_COMPLIANT - l1 -> unsigned int + + l3 > l4; // NON_COMPLIANT - l3 and l4 -> signed int + l3 < l4; // NON_COMPLIANT - l3 and l4 -> signed int } void test_conditional_operator() { - bool l1 = true; - std::uint8_t l2 = 5; - std::uint8_t l3 = 10; - std::uint16_t l4 = 100; - - l1 ? l2 : l3; // COMPLIANT - no conversion - l1 ? l2 : l4; // NON_COMPLIANT - l2 and l4 -> signed int + bool l1 = true; + std::uint8_t l2 = 5; + std::uint8_t l3 = 10; + std::uint16_t l4 = 100; + + l1 ? l2 : l3; // COMPLIANT - no conversion + l1 ? l2 : l4; // NON_COMPLIANT - l2 and l4 -> signed int } void test_shift_operations() { - std::uint8_t l1 = 5; - std::uint32_t l2 = 1000; - - l1 << 2; // NON_COMPLIANT - l1 -> signed int - l1 >> 1; // NON_COMPLIANT - l1 -> signed int - l2 << 2; // COMPLIANT - l2 >> 1; // COMPLIANT + std::uint8_t l1 = 5; + std::uint32_t l2 = 1000; + + l1 << 2; // NON_COMPLIANT - l1 -> signed int + l1 >> 1; // NON_COMPLIANT - l1 -> signed int + l2 << 2; // COMPLIANT + l2 >> 1; // COMPLIANT } void test_unary_operations() { - std::uint8_t l1 = 5; - std::uint32_t l2 = 1000; - std::int8_t l3 = -5; - - ~l1; // NON_COMPLIANT - l1 -> signed int - ~l2; // COMPLIANT - -l1; // NON_COMPLIANT - l1 -> signed int - -l3; // COMPLIANT - l3 is signed - +l1; // NON_COMPLIANT - l1 -> signed int + std::uint8_t l1 = 5; + std::uint32_t l2 = 1000; + std::int8_t l3 = -5; + + ~l1; // NON_COMPLIANT - l1 -> signed int + ~l2; // COMPLIANT + -l1; // NON_COMPLIANT - l1 -> signed int + -l3; // COMPLIANT - l3 is signed + +l1; // NON_COMPLIANT - l1 -> signed int } void test_increment_decrement() { - std::uint8_t l1 = 5; - std::uint16_t l2 = 100; - - l1++; // COMPLIANT - rule does not apply - ++l1; // COMPLIANT - rule does not apply - l1--; // COMPLIANT - rule does not apply - --l1; // COMPLIANT - rule does not apply - l2++; // COMPLIANT - rule does not apply - ++l2; // COMPLIANT - rule does not apply + std::uint8_t l1 = 5; + std::uint16_t l2 = 100; + + l1++; // COMPLIANT - rule does not apply + ++l1; // COMPLIANT - rule does not apply + l1--; // COMPLIANT - rule does not apply + --l1; // COMPLIANT - rule does not apply + l2++; // COMPLIANT - rule does not apply + ++l2; // COMPLIANT - rule does not apply } void test_array_subscript() { - int l1[10]; - std::uint8_t l2 = 5; - - l1[l2]; // COMPLIANT - rule does not apply + int l1[10]; + std::uint8_t l2 = 5; + + l1[l2]; // COMPLIANT - rule does not apply } void test_exception_compile_time_constants() { - std::uint32_t l1 = 1000; - float l2 = 3.14f; - std::int32_t l3 = 5; - - l1 - 1; // COMPLIANT - exception #1 - l1 + 42; // COMPLIANT - exception #1 - l2 += 1; // COMPLIANT - exception #2 - l2 += 0x10001; // COMPLIANT - exception #2 - l3 + f1(10); // COMPLIANT - exception #1 - l2 + f1(10); // COMPLIANT - exception #2 + std::uint32_t l1 = 1000; + float l2 = 3.14f; + std::int32_t l3 = 5; + + l1 - 1; // COMPLIANT - exception #1 + l1 + 42; // COMPLIANT - exception #1 + l2 += 1; // COMPLIANT - exception #2 + l2 += 0x10001; // COMPLIANT - exception #2 + l3 + f1(10); // COMPLIANT - exception #1 + l2 + f1(10); // COMPLIANT - exception #2 } void test_floating_point_conversions() { - float l1; - std::uint32_t l2; - - l1 += l2; // NON_COMPLIANT - l2 -> floating - l1 *= l2; // NON_COMPLIANT - l2 -> floating - l1 /= l2; // NON_COMPLIANT - l2 -> floating + float l1; + std::uint32_t l2; + + l1 += l2; // NON_COMPLIANT - l2 -> floating + l1 *= l2; // NON_COMPLIANT - l2 -> floating + l1 /= l2; // NON_COMPLIANT - l2 -> floating } \ No newline at end of file From a7ce6f5b476201dedf27b7bd643db62a02818080 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 27 Jun 2025 12:16:13 +0100 Subject: [PATCH 479/628] Rule 7.0.5: Expand test cases - More shift testing - Mixed signed/unsigned --- .../NoSignednessChangeFromPromotion.expected | 66 ++++++++++------ cpp/misra/test/rules/RULE-7-0-5/test.cpp | 78 ++++++++++++++++--- 2 files changed, 111 insertions(+), 33 deletions(-) diff --git a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected index ede74bd18d..b97aa3ee2a 100644 --- a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected +++ b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected @@ -22,26 +22,46 @@ | test.cpp:48:9:48:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:49:9:49:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:50:9:50:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:62:3:62:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | -| test.cpp:63:3:63:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | -| test.cpp:64:3:64:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | -| test.cpp:65:3:65:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | -| test.cpp:66:3:66:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | -| test.cpp:67:3:67:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | -| test.cpp:69:3:69:4 | l3 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:69:8:69:9 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | -| test.cpp:70:3:70:4 | l3 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:70:8:70:9 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | -| test.cpp:80:8:80:9 | l2 | Integer promotion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:80:13:80:14 | l4 | Integer promotion from 'uint16_t' to 'int' changes signedness. | -| test.cpp:87:3:87:4 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:88:3:88:4 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:98:4:98:5 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:100:4:100:5 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:102:4:102:5 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:141:9:141:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | -| test.cpp:141:9:141:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | -| test.cpp:142:9:142:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | -| test.cpp:142:9:142:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | -| test.cpp:143:9:143:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | -| test.cpp:143:9:143:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | +| test.cpp:62:3:62:4 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:63:3:63:4 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:64:3:64:4 | l2 | Integer promotion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:65:3:65:4 | l2 | Integer promotion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:68:9:68:10 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:69:9:69:10 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:79:10:79:11 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:80:10:80:11 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:91:3:91:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:92:3:92:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:93:3:93:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:94:3:94:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:95:3:95:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:96:3:96:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | +| test.cpp:98:3:98:4 | l3 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:98:8:98:9 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:99:3:99:4 | l3 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:99:8:99:9 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:109:8:109:9 | l2 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:109:13:109:14 | l4 | Integer promotion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:117:4:117:5 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:119:4:119:5 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:121:4:121:5 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:164:8:164:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:165:8:165:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:166:7:166:8 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:167:8:167:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:168:8:168:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:169:8:169:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:170:8:170:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:171:8:171:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:173:8:173:9 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:174:8:174:9 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:175:7:175:8 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:177:8:177:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:178:8:178:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:179:9:179:10 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:199:9:199:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | +| test.cpp:199:9:199:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | +| test.cpp:200:9:200:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | +| test.cpp:200:9:200:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | +| test.cpp:201:9:201:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | +| test.cpp:201:9:201:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | diff --git a/cpp/misra/test/rules/RULE-7-0-5/test.cpp b/cpp/misra/test/rules/RULE-7-0-5/test.cpp index 272b699a67..af2150e9ae 100644 --- a/cpp/misra/test/rules/RULE-7-0-5/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-5/test.cpp @@ -53,6 +53,35 @@ void test_assignment_operations() { l1 += l3; // COMPLIANT - l1 -> unsigned int } +void test_shift_operations() { + std::uint8_t l1 = 5; + std::uint16_t l2 = 100; + std::uint32_t l3 = 1000; + std::int16_t l4; + + l1 << 2; // NON_COMPLIANT - l1 -> signed int + l1 >> 1; // NON_COMPLIANT - l1 -> signed int + l2 << 2; // NON_COMPLIANT - l2 -> signed int + l2 >> 1; // NON_COMPLIANT - l2 -> signed int + l3 << 2; // COMPLIANT + l3 >> 1; // COMPLIANT + l3 << l1; // NON_COMPLIANT - l1 -> signed int + l3 >> l1; // NON_COMPLIANT - l1 -> signed int + l3 << l4; // COMPLIANT + l3 >> l4; // COMPLIANT + + l1 <<= 2; // NON_COMPLIANT - l1 -> signed int + l1 >>= 1; // NON_COMPLIANT - l1 -> signed int + l2 <<= 2; // NON_COMPLIANT - l2 -> signed int + l2 >>= 1; // NON_COMPLIANT - l2 -> signed int + l3 <<= 2; // COMPLIANT + l3 >>= 1; // COMPLIANT + l3 <<= l1; // NON_COMPLIANT - l1 -> signed int + l3 >>= l1; // NON_COMPLIANT - l1 -> signed int + l3 <<= l4; // COMPLIANT + l3 >>= l4; // COMPLIANT +} + void test_comparison_operations() { std::int32_t l1 = -1000; std::uint32_t l2 = 1000; @@ -80,16 +109,6 @@ void test_conditional_operator() { l1 ? l2 : l4; // NON_COMPLIANT - l2 and l4 -> signed int } -void test_shift_operations() { - std::uint8_t l1 = 5; - std::uint32_t l2 = 1000; - - l1 << 2; // NON_COMPLIANT - l1 -> signed int - l1 >> 1; // NON_COMPLIANT - l1 -> signed int - l2 << 2; // COMPLIANT - l2 >> 1; // COMPLIANT -} - void test_unary_operations() { std::uint8_t l1 = 5; std::uint32_t l2 = 1000; @@ -121,6 +140,45 @@ void test_array_subscript() { l1[l2]; // COMPLIANT - rule does not apply } +void test_logical_operators() { + std::uint8_t l1 = 5; + std::uint8_t l2 = 10; + std::uint16_t l3 = 100; + std::int8_t l4 = -5; + bool l5 = true; + + l1 &&l2; // COMPLIANT - rule does not apply to logical operators + l1 || l2; // COMPLIANT - rule does not apply to logical operators + l1 &&l3; // COMPLIANT - rule does not apply to logical operators + l4 &&l1; // COMPLIANT - rule does not apply to logical operators + l5 &&l1; // COMPLIANT - rule does not apply to logical operators + l1 &&l5; // COMPLIANT - rule does not apply to logical operators +} + +void test_mixed_signed_unsigned_arithmetic() { + std::int8_t l1 = -5; + std::uint8_t l2 = 10; + std::int16_t l3 = -100; + std::uint16_t l4 = 200; + + l1 + l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 - l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 *l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 / l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 % l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 & l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 | l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 ^ l2; // NON_COMPLIANT - l1 and l2 -> signed int + + l3 + l4; // NON_COMPLIANT - l3 and l4 -> signed int + l3 - l4; // NON_COMPLIANT - l3 and l4 -> signed int + l3 *l4; // NON_COMPLIANT - l3 and l4 -> signed int + + l1 < l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 > l2; // NON_COMPLIANT - l1 and l2 -> signed int + l3 == l4; // NON_COMPLIANT - l3 and l4 -> signed int +} + void test_exception_compile_time_constants() { std::uint32_t l1 = 1000; float l2 = 3.14f; From 9aed463df7f38cce841938e280fc9d07b854c636 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 27 Jun 2025 12:17:57 +0100 Subject: [PATCH 480/628] Ruley 7.0.5: Support lvalue conversions on assign operations AssignOperations do not include a Conversion in the database for lvalues, so create new classes to capture those cases. --- .../NoSignednessChangeFromPromotion.ql | 91 +++++++++++++++++++ .../NoSignednessChangeFromPromotion.expected | 12 +++ 2 files changed, 103 insertions(+) diff --git a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql index f35c18bae4..8fe555fcbe 100644 --- a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql +++ b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql @@ -94,6 +94,97 @@ class IntegerPromotion extends RelevantRealConversion { override string getKindOfConversion() { result = "Integer promotion" } } +class ImpliedUsualArithmeticConversion extends RelevantConversion { + NumericType fromType; + NumericType toType; + + ImpliedUsualArithmeticConversion() { + // The lvalue of an assignment operation does not have a `Conversion` in our model, but + // it is still subject to usual arithmetic conversions (excepting shifts). + // + // rvalues are handled separately in the `UsualArithmeticConversion` class. + exists(AssignOperation aop | + not aop instanceof AssignLShiftExpr and + not aop instanceof AssignRShiftExpr and + // lvalue subject to usual arithmetic conversions + aop.getLValue() = this and + // From type is the type of the lvalue, which should be a numeric type under the MISRA rule + fromType = this.getType() and + // Under usual arithmetic conversions, the converted types of both arguments will be the same, + // so even though we don't have an explicit conversion, we can still deduce that the target + // type will be the same as the converted type of the rvalue. + toType = aop.getRValue().getFullyConverted().getType() and + // Only consider cases where the conversion is not a no-op, for consistency with the `Conversion` class + not fromType.getRealType() = toType.getRealType() + ) + } + + override Type getFromType() { result = fromType } + + override Type getToType() { result = toType } + + override Expr getConvertedExpr() { result = this } + + override string getKindOfConversion() { result = "Usual arithmetic conversion" } +} + +class ImpliedIntegerPromotion extends RelevantConversion { + NumericType fromType; + + ImpliedIntegerPromotion() { + ( + exists(AssignLShiftExpr aop | aop.getLValue() = this) or + exists(AssignRShiftExpr aop | aop.getLValue() = this) + ) and + // Only consider integer promotions from MISRA C++ "numeric types" as per the rule + fromType = this.getType() and + fromType.getTypeCategory() = Integral() and + // If the size is less than int, then it is an implied integer promotion + fromType.getRealSize() < sizeOfInt() + } + + override Type getFromType() { result = fromType } + + override IntegralType getToType() { + // Only report the canonical type - e.g. `int` not `signed int` + result = result.getCanonicalArithmeticType() and + if result instanceof Char16Type or result instanceof Char32Type or result instanceof Wchar_t + then + // Smallest type that can hold the value of the `fromType` + result = + min(NumericType candidateType | + ( + candidateType instanceof IntType or + candidateType instanceof LongType or + candidateType instanceof LongLongType + ) and + fromType.getIntegralUpperBound() <= candidateType.getIntegralUpperBound() + | + candidateType order by candidateType.getIntegralUpperBound() + ) + else ( + // The result is always `int` or `unsigned int` + result instanceof IntType and + if + // If the `fromType` is signed, the result must be signed + fromType.getSignedness() = Signed() + or + // If the `fromType` is unsigned, but the result can fit into the signed int type, then the + // result must be signed as well. + fromType.getIntegralUpperBound() <= + any(IntType t | t.isSigned()).(NumericType).getIntegralUpperBound() + then result.isSigned() + else + // Otherwise an unsigned type is returned + result.isUnsigned() + ) + } + + override Expr getConvertedExpr() { result = this } + + override string getKindOfConversion() { result = "Integer promotion" } +} + from Expr e, RelevantConversion c, NumericType fromType, NumericType toType, string changeType where not isExcluded(e, ConversionsPackage::noSignednessChangeFromPromotionQuery()) and diff --git a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected index b97aa3ee2a..1bde6e9a14 100644 --- a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected +++ b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected @@ -14,13 +14,21 @@ | test.cpp:28:8:28:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:29:3:29:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:29:8:29:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:43:3:43:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:43:9:43:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:44:3:44:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:44:9:44:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:45:3:45:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:45:9:45:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:46:3:46:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:46:9:46:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:47:3:47:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:47:9:47:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:48:3:48:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:48:9:48:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:49:3:49:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:49:9:49:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:50:3:50:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:50:9:50:10 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:62:3:62:4 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | | test.cpp:63:3:63:4 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | @@ -28,6 +36,10 @@ | test.cpp:65:3:65:4 | l2 | Integer promotion from 'uint16_t' to 'int' changes signedness. | | test.cpp:68:9:68:10 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | | test.cpp:69:9:69:10 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:73:3:73:4 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:74:3:74:4 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:75:3:75:4 | l2 | Integer promotion from 'uint16_t' to 'int' changes signedness. | +| test.cpp:76:3:76:4 | l2 | Integer promotion from 'uint16_t' to 'int' changes signedness. | | test.cpp:79:10:79:11 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | | test.cpp:80:10:80:11 | l1 | Integer promotion from 'uint8_t' to 'int' changes signedness. | | test.cpp:91:3:91:4 | l1 | Usual arithmetic conversion from 'int32_t' to 'unsigned int' changes signedness. | From aac2dc21194f656b24a09f3d9e6522ee3ad45517 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 27 Jun 2025 12:20:36 +0100 Subject: [PATCH 481/628] Refactor to use NumericType --- .../NoSignednessChangeFromPromotion.ql | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql index 8fe555fcbe..30d75e3dee 100644 --- a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql +++ b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql @@ -18,9 +18,9 @@ import codingstandards.cpp.misra import codingstandards.cpp.misra.BuiltInTypeRules abstract class RelevantConversion extends Expr { - abstract Type getFromType(); + abstract NumericType getFromType(); - abstract Type getToType(); + abstract NumericType getToType(); abstract Expr getConvertedExpr(); @@ -40,9 +40,9 @@ abstract class RelevantRealConversion extends RelevantConversion, Conversion { this.isImplicit() } - override Type getFromType() { result = fromType } + override NumericType getFromType() { result = fromType } - override Type getToType() { result = toType } + override NumericType getToType() { result = toType } override Expr getConvertedExpr() { result = this.getExpr() } } @@ -119,9 +119,9 @@ class ImpliedUsualArithmeticConversion extends RelevantConversion { ) } - override Type getFromType() { result = fromType } + override NumericType getFromType() { result = fromType } - override Type getToType() { result = toType } + override NumericType getToType() { result = toType } override Expr getConvertedExpr() { result = this } @@ -143,11 +143,11 @@ class ImpliedIntegerPromotion extends RelevantConversion { fromType.getRealSize() < sizeOfInt() } - override Type getFromType() { result = fromType } + override NumericType getFromType() { result = fromType } - override IntegralType getToType() { + override NumericType getToType() { // Only report the canonical type - e.g. `int` not `signed int` - result = result.getCanonicalArithmeticType() and + result = result.(IntegralType).getCanonicalArithmeticType() and if result instanceof Char16Type or result instanceof Char32Type or result instanceof Wchar_t then // Smallest type that can hold the value of the `fromType` @@ -163,8 +163,6 @@ class ImpliedIntegerPromotion extends RelevantConversion { candidateType order by candidateType.getIntegralUpperBound() ) else ( - // The result is always `int` or `unsigned int` - result instanceof IntType and if // If the `fromType` is signed, the result must be signed fromType.getSignedness() = Signed() @@ -173,10 +171,12 @@ class ImpliedIntegerPromotion extends RelevantConversion { // result must be signed as well. fromType.getIntegralUpperBound() <= any(IntType t | t.isSigned()).(NumericType).getIntegralUpperBound() - then result.isSigned() + then + // `int` is returned + result.(IntType).isSigned() else - // Otherwise an unsigned type is returned - result.isUnsigned() + // Otherwise `unsigned int` is returned + result.(IntType).isUnsigned() ) } From 92c7dac28d7dfa21bdee67132b4c8fde935db87c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 27 Jun 2025 13:17:08 +0100 Subject: [PATCH 482/628] Rule 7.0.5: Add pointer tests (should be ignored) --- cpp/misra/test/rules/RULE-7-0-5/test.cpp | 37 ++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/cpp/misra/test/rules/RULE-7-0-5/test.cpp b/cpp/misra/test/rules/RULE-7-0-5/test.cpp index af2150e9ae..e6f853ff95 100644 --- a/cpp/misra/test/rules/RULE-7-0-5/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-5/test.cpp @@ -199,4 +199,41 @@ void test_floating_point_conversions() { l1 += l2; // NON_COMPLIANT - l2 -> floating l1 *= l2; // NON_COMPLIANT - l2 -> floating l1 /= l2; // NON_COMPLIANT - l2 -> floating +} + +void test_pointer_arithmetic() { + int l1[10]; + std::uint8_t l2 = 5; + std::uint16_t l3 = 2; + std::int8_t l4 = 3; + std::int32_t l5 = 1; + int *l6 = l1; + + l1 + l2; // COMPLIANT - rule does not apply to pointer arithmetic + l1 + l3; // COMPLIANT - rule does not apply to pointer arithmetic + l1 + l4; // COMPLIANT - rule does not apply to pointer arithmetic + l1 + l5; // COMPLIANT - rule does not apply to pointer arithmetic + l6 + l2; // COMPLIANT - rule does not apply to pointer arithmetic + l6 + l3; // COMPLIANT - rule does not apply to pointer arithmetic + + l1 - l2; // COMPLIANT - rule does not apply to pointer arithmetic + l6 - l3; // COMPLIANT - rule does not apply to pointer arithmetic + + l6 - l1; // COMPLIANT - rule does not apply to pointer arithmetic +} + +void test_pointer_assignment_arithmetic() { + int l1[10]; + std::uint8_t l2 = 5; + std::uint16_t l3 = 2; + std::int8_t l4 = 3; + int *l5 = l1; + + l5 += l2; // COMPLIANT - rule does not apply to pointer arithmetic + l5 += l3; // COMPLIANT - rule does not apply to pointer arithmetic + l5 += l4; // COMPLIANT - rule does not apply to pointer arithmetic + + l5 -= l2; // COMPLIANT - rule does not apply to pointer arithmetic + l5 -= l3; // COMPLIANT - rule does not apply to pointer arithmetic + l5 -= l4; // COMPLIANT - rule does not apply to pointer arithmetic } \ No newline at end of file From 4be88a3754d2cc90ffa67aba90bd2805b6be0a2c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 27 Jun 2025 14:01:22 +0100 Subject: [PATCH 483/628] Rule 7.0.5: Add failing test case --- cpp/misra/test/rules/RULE-7-0-5/test.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/cpp/misra/test/rules/RULE-7-0-5/test.cpp b/cpp/misra/test/rules/RULE-7-0-5/test.cpp index e6f853ff95..9ee2c9bf6e 100644 --- a/cpp/misra/test/rules/RULE-7-0-5/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-5/test.cpp @@ -236,4 +236,24 @@ void test_pointer_assignment_arithmetic() { l5 -= l2; // COMPLIANT - rule does not apply to pointer arithmetic l5 -= l3; // COMPLIANT - rule does not apply to pointer arithmetic l5 -= l4; // COMPLIANT - rule does not apply to pointer arithmetic -} \ No newline at end of file +} + +#define A 100LL // intmax_t +#define B 200LL // intmax_t +#define C 300ULL // uintmax_t +#define D 400ULL // uintmax_t + +#if A + B > 250 // COMPLIANT - both intmax_t, no conversion +; +#elif C + D < 800 // COMPLIANT - both uintmax_t, no conversion +; +#endif + +#define SIGNED_MAX 9223372036854775807LL // intmax_t +#define UNSIGNED_VAL 1ULL // uintmax_t + +#if SIGNED_MAX + UNSIGNED_VAL > 0 // NON_COMPLIANT[FALSE_NEGATIVE] +// intmax_t + uintmax_t → both converted to uintmax_t +// This changes SIGNED_MAX from signed to unsigned +; +#endif From f1502d6193706ac87675a23ea7a909c25bf670bf Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 1 Jul 2025 14:07:46 +0100 Subject: [PATCH 484/628] Rule 7.0.5: Add test cases for enum conversions --- .../NoSignednessChangeFromPromotion.expected | 31 ++++++++ cpp/misra/test/rules/RULE-7-0-5/test.cpp | 71 +++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected index 1bde6e9a14..a9f1f37c63 100644 --- a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected +++ b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected @@ -77,3 +77,34 @@ | test.cpp:200:9:200:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | | test.cpp:201:9:201:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes signedness. | | test.cpp:201:9:201:10 | l2 | Usual arithmetic conversion from 'uint32_t' to 'float' changes type category. | +| test.cpp:270:3:270:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:270:8:270:9 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:271:3:271:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:271:7:271:8 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:272:3:272:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:272:8:272:9 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:273:3:273:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:273:8:273:9 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:274:3:274:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:274:8:274:9 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:275:3:275:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:275:8:275:9 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:278:3:278:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:278:8:278:9 | l7 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:279:3:279:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:279:7:279:8 | l7 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:280:3:280:4 | l7 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:280:8:280:9 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:286:4:286:5 | l3 | Integer promotion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:287:4:287:5 | l3 | Integer promotion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:288:4:288:5 | l3 | Integer promotion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:294:3:294:31 | static_cast... | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:295:7:296:46 | static_cast... | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:299:3:299:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:299:8:299:9 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:300:3:300:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:300:9:300:10 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:301:3:301:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:301:9:301:10 | l7 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:304:3:304:4 | l3 | Integer promotion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:305:3:305:4 | l3 | Integer promotion from 'UnscopedEnumExplicit' to 'int' changes signedness. | diff --git a/cpp/misra/test/rules/RULE-7-0-5/test.cpp b/cpp/misra/test/rules/RULE-7-0-5/test.cpp index 9ee2c9bf6e..6e36d80d68 100644 --- a/cpp/misra/test/rules/RULE-7-0-5/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-5/test.cpp @@ -238,6 +238,77 @@ void test_pointer_assignment_arithmetic() { l5 -= l4; // COMPLIANT - rule does not apply to pointer arithmetic } +// Enum types for testing +enum UnscopedEnum { VALUE1, VALUE2, VALUE3 }; +enum class ScopedEnum { VALUE1, VALUE2, VALUE3 }; +enum UnscopedEnumExplicit : std::uint8_t { + EXPLICIT_VALUE1 = 1, + EXPLICIT_VALUE2 = 2 +}; +enum class ScopedEnumExplicit : std::uint8_t { + EXPLICIT_VALUE1 = 1, + EXPLICIT_VALUE2 = 2 +}; + +void test_enum_types() { + UnscopedEnum l1 = VALUE1; + UnscopedEnum l2 = VALUE2; + UnscopedEnumExplicit l3 = EXPLICIT_VALUE1; + UnscopedEnumExplicit l4 = EXPLICIT_VALUE2; + ScopedEnum l5 = ScopedEnum::VALUE1; + ScopedEnumExplicit l6 = ScopedEnumExplicit::EXPLICIT_VALUE1; + std::uint8_t l7 = 5; + std::uint32_t l8 = 10; + + // Unscoped enum without explicit underlying type - not considered numeric + // type + l1 + l2; // COMPLIANT - rule does not apply + l1 *l2; // COMPLIANT - rule does not apply + l1 & l2; // COMPLIANT - rule does not apply + + // Unscoped enum with explicit underlying type - considered numeric type + l3 + l4; // NON_COMPLIANT - uint8_t + uint8_t -> signed int + l3 *l4; // NON_COMPLIANT - uint8_t * uint8_t -> signed int + l3 & l4; // NON_COMPLIANT - uint8_t & uint8_t -> signed int + l3 - l4; // NON_COMPLIANT - uint8_t - uint8_t -> signed int + l3 | l4; // NON_COMPLIANT - uint8_t | uint8_t -> signed int + l3 ^ l4; // NON_COMPLIANT - uint8_t ^ uint8_t -> signed int + + // Mixed enum and integer arithmetic + l3 + l7; // NON_COMPLIANT - uint8_t + uint8_t -> signed int + l3 *l7; // NON_COMPLIANT - uint8_t * uint8_t -> signed int + l7 - l3; // NON_COMPLIANT - uint8_t - uint8_t -> signed int + + l3 + l8; // COMPLIANT - uint8_t -> signed int (matches l8) + l8 *l3; // COMPLIANT - uint8_t -> signed int (matches l8) + + // Unary operations on enum with explicit underlying type + ~l3; // NON_COMPLIANT - uint8_t -> signed int + -l3; // NON_COMPLIANT - uint8_t -> signed int + +l3; // NON_COMPLIANT - uint8_t -> signed int + + // Scoped enums - not considered numeric type regardless of underlying type + static_cast(l5) + + static_cast(ScopedEnum::VALUE2); // COMPLIANT - rule does not apply + // to explicit casts + static_cast(l6) + // NON_COMPLIANT + static_cast( // NON_COMPLIANT + ScopedEnumExplicit::EXPLICIT_VALUE2); + + // Comparison operations with enum + l3 > l4; // NON_COMPLIANT - uint8_t > uint8_t -> signed int + l3 == l4; // NON_COMPLIANT - uint8_t == uint8_t -> signed int + l3 != l7; // NON_COMPLIANT - uint8_t != uint8_t -> signed int + + // Shift operations with enum + l3 << 1; // NON_COMPLIANT - uint8_t -> signed int + l3 >> 1; // NON_COMPLIANT - uint8_t -> signed int + + // Conditional operator with enum + true ? l3 : l4; // COMPLIANT - same types, no conversion + true ? l3 : l8; // COMPLIANT - same underlying types, no conversion +} + #define A 100LL // intmax_t #define B 200LL // intmax_t #define C 300ULL // uintmax_t From 89485d528411eb39e1a465aa762df45736814616 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 1 Jul 2025 14:25:08 +0100 Subject: [PATCH 485/628] Conversions: Swap some queries around Rule 7.0.4 is now in the Conversions package. Rules 8.x in the Conversions package are now moved to Conversions2. This is to avoid having too many complex queries in one package, and because 7.0.4 is more closely related to the other 7.x rules. --- .../cpp/exclusions/cpp/Conversions.qll | 121 +++------------ rule_packages/cpp/Conversions.json | 144 ++++++++++++++++++ rules.csv | 14 +- 3 files changed, 169 insertions(+), 110 deletions(-) create mode 100644 rule_packages/cpp/Conversions.json diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions.qll index f151565d11..393f0cbdf5 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions.qll @@ -7,15 +7,10 @@ newtype ConversionsQuery = TNoConversionFromBoolQuery() or TNoImplicitBoolConversionQuery() or TNoCharacterNumericalValueQuery() or + TInappropriateBitwiseOrShiftOperandsQuery() or TNoSignednessChangeFromPromotionQuery() or TNumericAssignmentTypeMismatchQuery() or - TFunctionPointerConversionContextQuery() or - TVirtualBaseClassCastToDerivedQuery() or - TNoCStyleOrFunctionalCastsQuery() or - TIntToPointerCastProhibitedQuery() or - TNoPointerToIntegralCastQuery() or - TPointerToIntegralCastQuery() or - TNoStandaloneTypeCastExpressionQuery() + TFunctionPointerConversionContextQuery() predicate isConversionsQueryMetadata(Query query, string queryId, string ruleId, string category) { query = @@ -45,6 +40,15 @@ predicate isConversionsQueryMetadata(Query query, string queryId, string ruleId, ruleId = "RULE-7-0-3" and category = "required" or + query = + // `Query` instance for the `inappropriateBitwiseOrShiftOperands` query + ConversionsPackage::inappropriateBitwiseOrShiftOperandsQuery() and + queryId = + // `@id` for the `inappropriateBitwiseOrShiftOperands` query + "cpp/misra/inappropriate-bitwise-or-shift-operands" and + ruleId = "RULE-7-0-4" and + category = "required" + or query = // `Query` instance for the `noSignednessChangeFromPromotion` query ConversionsPackage::noSignednessChangeFromPromotionQuery() and @@ -71,60 +75,6 @@ predicate isConversionsQueryMetadata(Query query, string queryId, string ruleId, "cpp/misra/function-pointer-conversion-context" and ruleId = "RULE-7-11-3" and category = "required" - or - query = - // `Query` instance for the `virtualBaseClassCastToDerived` query - ConversionsPackage::virtualBaseClassCastToDerivedQuery() and - queryId = - // `@id` for the `virtualBaseClassCastToDerived` query - "cpp/misra/virtual-base-class-cast-to-derived" and - ruleId = "RULE-8-2-1" and - category = "required" - or - query = - // `Query` instance for the `noCStyleOrFunctionalCasts` query - ConversionsPackage::noCStyleOrFunctionalCastsQuery() and - queryId = - // `@id` for the `noCStyleOrFunctionalCasts` query - "cpp/misra/no-c-style-or-functional-casts" and - ruleId = "RULE-8-2-2" and - category = "required" - or - query = - // `Query` instance for the `intToPointerCastProhibited` query - ConversionsPackage::intToPointerCastProhibitedQuery() and - queryId = - // `@id` for the `intToPointerCastProhibited` query - "cpp/misra/int-to-pointer-cast-prohibited" and - ruleId = "RULE-8-2-6" and - category = "required" - or - query = - // `Query` instance for the `noPointerToIntegralCast` query - ConversionsPackage::noPointerToIntegralCastQuery() and - queryId = - // `@id` for the `noPointerToIntegralCast` query - "cpp/misra/no-pointer-to-integral-cast" and - ruleId = "RULE-8-2-7" and - category = "advisory" - or - query = - // `Query` instance for the `pointerToIntegralCast` query - ConversionsPackage::pointerToIntegralCastQuery() and - queryId = - // `@id` for the `pointerToIntegralCast` query - "cpp/misra/pointer-to-integral-cast" and - ruleId = "RULE-8-2-8" and - category = "required" - or - query = - // `Query` instance for the `noStandaloneTypeCastExpression` query - ConversionsPackage::noStandaloneTypeCastExpressionQuery() and - queryId = - // `@id` for the `noStandaloneTypeCastExpression` query - "cpp/misra/no-standalone-type-cast-expression" and - ruleId = "RULE-9-2-1" and - category = "required" } module ConversionsPackage { @@ -149,6 +99,13 @@ module ConversionsPackage { TQueryCPP(TConversionsPackageQuery(TNoCharacterNumericalValueQuery())) } + Query inappropriateBitwiseOrShiftOperandsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `inappropriateBitwiseOrShiftOperands` query + TQueryCPP(TConversionsPackageQuery(TInappropriateBitwiseOrShiftOperandsQuery())) + } + Query noSignednessChangeFromPromotionQuery() { //autogenerate `Query` type result = @@ -169,46 +126,4 @@ module ConversionsPackage { // `Query` type for `functionPointerConversionContext` query TQueryCPP(TConversionsPackageQuery(TFunctionPointerConversionContextQuery())) } - - Query virtualBaseClassCastToDerivedQuery() { - //autogenerate `Query` type - result = - // `Query` type for `virtualBaseClassCastToDerived` query - TQueryCPP(TConversionsPackageQuery(TVirtualBaseClassCastToDerivedQuery())) - } - - Query noCStyleOrFunctionalCastsQuery() { - //autogenerate `Query` type - result = - // `Query` type for `noCStyleOrFunctionalCasts` query - TQueryCPP(TConversionsPackageQuery(TNoCStyleOrFunctionalCastsQuery())) - } - - Query intToPointerCastProhibitedQuery() { - //autogenerate `Query` type - result = - // `Query` type for `intToPointerCastProhibited` query - TQueryCPP(TConversionsPackageQuery(TIntToPointerCastProhibitedQuery())) - } - - Query noPointerToIntegralCastQuery() { - //autogenerate `Query` type - result = - // `Query` type for `noPointerToIntegralCast` query - TQueryCPP(TConversionsPackageQuery(TNoPointerToIntegralCastQuery())) - } - - Query pointerToIntegralCastQuery() { - //autogenerate `Query` type - result = - // `Query` type for `pointerToIntegralCast` query - TQueryCPP(TConversionsPackageQuery(TPointerToIntegralCastQuery())) - } - - Query noStandaloneTypeCastExpressionQuery() { - //autogenerate `Query` type - result = - // `Query` type for `noStandaloneTypeCastExpression` query - TQueryCPP(TConversionsPackageQuery(TNoStandaloneTypeCastExpressionQuery())) - } } diff --git a/rule_packages/cpp/Conversions.json b/rule_packages/cpp/Conversions.json new file mode 100644 index 0000000000..9835110e27 --- /dev/null +++ b/rule_packages/cpp/Conversions.json @@ -0,0 +1,144 @@ +{ + "MISRA-C++-2023": { + "RULE-7-0-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Converting a bool type (implicitly or explicitly) to another type can lead to unintended behavior and code obfuscation, particularly when using bitwise operators instead of logical operators.", + "kind": "problem", + "name": "There shall be no conversion from type bool", + "precision": "very-high", + "severity": "error", + "short_name": "NoConversionFromBool", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "There shall be no conversion from type bool" + }, + "RULE-7-0-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Implicit and contextual conversions to bool from fundamental types, unscoped enums, or pointers may lead to unintended behavior, except for specific cases like pointer checks and explicit operator bool conversions.", + "kind": "problem", + "name": "There shall be no conversion to type bool", + "precision": "very-high", + "severity": "error", + "short_name": "NoImplicitBoolConversion", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "There shall be no conversion to type bool" + }, + "RULE-7-0-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using the numerical value of a character type may lead to inconsistent behavior due to encoding dependencies and should be avoided in favor of safer C++ Standard Library functions.", + "kind": "problem", + "name": "The numerical value of a character shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "NoCharacterNumericalValue", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The numerical value of a character shall not be used" + }, + "RULE-7-0-4": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Bitwise and shift operators should only be applied to operands of appropriate types and values to avoid implementation-defined or undefined behavior.", + "kind": "problem", + "name": "The operands of bitwise operators and shift operators shall be appropriate", + "precision": "very-high", + "severity": "error", + "short_name": "InappropriateBitwiseOrShiftOperands", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "The operands of bitwise operators and shift operators shall be appropriate" + }, + "RULE-7-0-5": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Integral promotion and usual arithmetic conversions that change operand signedness or type category may cause unexpected behavior or undefined behavior when operations overflow.", + "kind": "problem", + "name": "Integral promotion and the usual arithmetic conversions shall not change the signedness or the type", + "precision": "very-high", + "severity": "error", + "short_name": "NoSignednessChangeFromPromotion", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Integral promotion and the usual arithmetic conversions shall not change the signedness or the type category of an operand" + }, + "RULE-7-0-6": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Assignment between numeric types with different sizes, signedness, or type categories can lead to unexpected information loss, undefined behavior, or silent overload resolution changes.", + "kind": "problem", + "name": "Assignment between numeric types shall be appropriate", + "precision": "high", + "severity": "error", + "short_name": "NumericAssignmentTypeMismatch", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "Assignment between numeric types shall be appropriate" + }, + "RULE-7-11-3": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Converting a function type to a pointer-to-function type outside of static_cast or assignment to a pointer-to-function object creates ambiguous behavior and potential unintended effects.", + "kind": "problem", + "name": "A conversion from function type to pointer-to-function type shall only occur in appropriate contexts", + "precision": "very-high", + "severity": "error", + "short_name": "FunctionPointerConversionContext", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "A conversion from function type to pointer-to-function type shall only occur in appropriate contexts" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index 68049625e6..3cb64a0bac 100644 --- a/rules.csv +++ b/rules.csv @@ -873,7 +873,7 @@ cpp,MISRA-C++-2023,RULE-6-9-2,Yes,Advisory,Decidable,Single Translation Unit,The cpp,MISRA-C++-2023,RULE-7-0-1,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion from type bool,,Conversions,Easy, cpp,MISRA-C++-2023,RULE-7-0-2,Yes,Required,Decidable,Single Translation Unit,There shall be no conversion to type bool,,Conversions,Easy, cpp,MISRA-C++-2023,RULE-7-0-3,Yes,Required,Decidable,Single Translation Unit,The numerical value of a character shall not be used,M5-0-11,Conversions,Medium, -cpp,MISRA-C++-2023,RULE-7-0-4,Yes,Required,Decidable,Single Translation Unit,The operands of bitwise operators and shift operators shall be appropriate,RULE-10-1,Preconditions,Medium, +cpp,MISRA-C++-2023,RULE-7-0-4,Yes,Required,Decidable,Single Translation Unit,The operands of bitwise operators and shift operators shall be appropriate,RULE-10-1,Conversions,Medium, cpp,MISRA-C++-2023,RULE-7-0-5,Yes,Required,Decidable,Single Translation Unit,Integral promotion and the usual arithmetic conversions shall not change the signedness or the type category of an operand,"M5-0-4,M5-0-9,INT31-C",Conversions,Medium, cpp,MISRA-C++-2023,RULE-7-0-6,Yes,Required,Decidable,Single Translation Unit,Assignment between numeric types shall be appropriate,,Conversions,Hard, cpp,MISRA-C++-2023,RULE-7-11-1,Yes,Required,Decidable,Single Translation Unit,nullptr shall be the only form of the null-pointer-constant,A4-10-1,ImportMisra23,Import, @@ -882,14 +882,14 @@ cpp,MISRA-C++-2023,RULE-7-11-3,Yes,Required,Decidable,Single Translation Unit,A cpp,MISRA-C++-2023,RULE-8-0-1,Yes,Advisory,Decidable,Single Translation Unit,Parentheses should be used to make the meaning of an expression appropriately explicit,M5-0-2,Expressions2,Medium, cpp,MISRA-C++-2023,RULE-8-1-1,Yes,Required,Decidable,Single Translation Unit,A non-transient lambda shall not implicitly capture this,,Expressions2,Easy, cpp,MISRA-C++-2023,RULE-8-1-2,Yes,Advisory,Decidable,Single Translation Unit,Variables should be captured explicitly in a non-transient lambda,A5-1-2,Expressions2,Easy, -cpp,MISRA-C++-2023,RULE-8-2-1,Yes,Required,Decidable,Single Translation Unit,A virtual base class shall only be cast to a derived class by means of dynamic_cast,,Conversions,Easy, -cpp,MISRA-C++-2023,RULE-8-2-2,Yes,Required,Decidable,Single Translation Unit,C-style casts and functional notation casts shall not be used,A5-2-2,Conversions,Easy, +cpp,MISRA-C++-2023,RULE-8-2-1,Yes,Required,Decidable,Single Translation Unit,A virtual base class shall only be cast to a derived class by means of dynamic_cast,,Conversions2,Easy, +cpp,MISRA-C++-2023,RULE-8-2-2,Yes,Required,Decidable,Single Translation Unit,C-style casts and functional notation casts shall not be used,A5-2-2,Conversions2,Easy, cpp,MISRA-C++-2023,RULE-8-2-3,Yes,Required,Decidable,Single Translation Unit,A cast shall not remove any const or volatile qualification from the type accessed via a pointer or by reference,A5-2-3,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-8-2-4,Yes,Required,Decidable,Single Translation Unit,Casts shall not be performed between a pointer to function and any other type,M5-2-6,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-8-2-5,Yes,Required,Decidable,Single Translation Unit,reinterpret_cast shall not be used,A5-2-4,ImportMisra23,Import, -cpp,MISRA-C++-2023,RULE-8-2-6,Yes,Required,Decidable,Single Translation Unit,"An object with integral, enumerated, or pointer to void type shall not be cast to a pointer type","RULE-11-6, INT36-C",Conversions,Easy, -cpp,MISRA-C++-2023,RULE-8-2-7,Yes,Advisory,Decidable,Single Translation Unit,A cast should not convert a pointer type to an integral type,"RULE-11-6, INT36-C",Conversions,Easy, -cpp,MISRA-C++-2023,RULE-8-2-8,Yes,Required,Decidable,Single Translation Unit,An object pointer type shall not be cast to an integral type other than std::uintptr_t or std::intptr_t,"RULE-11-6, INT36-C",Conversions,Easy, +cpp,MISRA-C++-2023,RULE-8-2-6,Yes,Required,Decidable,Single Translation Unit,"An object with integral, enumerated, or pointer to void type shall not be cast to a pointer type","RULE-11-6, INT36-C",Conversions2,Easy, +cpp,MISRA-C++-2023,RULE-8-2-7,Yes,Advisory,Decidable,Single Translation Unit,A cast should not convert a pointer type to an integral type,"RULE-11-6, INT36-C",Conversions2,Easy, +cpp,MISRA-C++-2023,RULE-8-2-8,Yes,Required,Decidable,Single Translation Unit,An object pointer type shall not be cast to an integral type other than std::uintptr_t or std::intptr_t,"RULE-11-6, INT36-C",Conversions2,Easy, cpp,MISRA-C++-2023,RULE-8-2-9,Yes,Required,Decidable,Single Translation Unit,The operand to typeid shall not be an expression of polymorphic class type,,Preconditions,Easy, cpp,MISRA-C++-2023,RULE-8-2-10,Yes,Required,Undecidable,System,"Functions shall not call themselves, either directly or indirectly",A7-5-2,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-8-2-11,Yes,Required,Decidable,Single Translation Unit,An argument passed via ellipsis shall have an appropriate type,,Preconditions,Easy, @@ -903,7 +903,7 @@ cpp,MISRA-C++-2023,RULE-8-18-1,Yes,Mandatory,Undecidable,System,An object or sub cpp,MISRA-C++-2023,RULE-8-18-2,Yes,Advisory,Decidable,Single Translation Unit,The result of an assignment operator should not be used,RULE-13-4,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-8-19-1,Yes,Advisory,Decidable,Single Translation Unit,The comma operator should not be used,M5-18-1,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-8-20-1,Yes,Advisory,Decidable,Single Translation Unit,An unsigned arithmetic operation with constant operands should not wrap,INT30-C,ImportMisra23,Import, -cpp,MISRA-C++-2023,RULE-9-2-1,Yes,Required,Decidable,Single Translation Unit,An explicit type conversion shall not be an expression statement,DCL53-CPP,Conversions,Easy, +cpp,MISRA-C++-2023,RULE-9-2-1,Yes,Required,Decidable,Single Translation Unit,An explicit type conversion shall not be an expression statement,DCL53-CPP,Conversions2,Easy, cpp,MISRA-C++-2023,RULE-9-3-1,Yes,Required,Decidable,Single Translation Unit,The body of an iteration-statement or a selection-statement shall be a compound-statement,RULE-15-6,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-9-4-1,Yes,Required,Decidable,Single Translation Unit,All if ... else if constructs shall be terminated with an else statement,RULE-15-7,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-9-4-2,Yes,Required,Decidable,Single Translation Unit,The structure of a switch statement shall be appropriate,"RULE-16-1, RULE-16-2,RULE-16-3,RULE-16-4,RULE-16-5,RULE-16-6,RULE-16-7",Statements,Medium, From 6845cdc76431de06772c55af5804b9d3b3e67fa8 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 4 Jul 2025 11:23:10 +0100 Subject: [PATCH 486/628] RULE-7-0-4 - InappropriateBitwiseOrShiftOperands Detects inappropriate operands for bitwise and shift operators that violate type requirements. Identifies signed operands in bitwise operations and improper shift operand types that may cause undefined behavior. [a] --- .../InappropriateBitwiseOrShiftOperands.ql | 124 ++++++++++++++++++ ...appropriateBitwiseOrShiftOperands.expected | 25 ++++ .../InappropriateBitwiseOrShiftOperands.qlref | 1 + cpp/misra/test/rules/RULE-7-0-4/test.cpp | 121 +++++++++++++++++ 4 files changed, 271 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql create mode 100644 cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected create mode 100644 cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.qlref create mode 100644 cpp/misra/test/rules/RULE-7-0-4/test.cpp diff --git a/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql new file mode 100644 index 0000000000..45f8e51936 --- /dev/null +++ b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql @@ -0,0 +1,124 @@ +/** + * @id cpp/misra/inappropriate-bitwise-or-shift-operands + * @name RULE-7-0-4: The operands of bitwise operators and shift operators shall be appropriate + * @description Bitwise and shift operators should only be applied to operands of appropriate types + * and values to avoid implementation-defined or undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-7-0-4 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.misra.BuiltInTypeRules + +predicate isSignedType(NumericType t) { t.getSignedness() = Signed() } + +predicate isUnsignedType(NumericType t) { t.getSignedness() = Unsigned() } + +predicate isConstantExpression(Expr e) { + e instanceof Literal or + e.isConstant() +} + +predicate isValidShiftConstantRange(Expr right, Type leftType) { + exists(int value | + value = right.getValue().toInt() and + value >= 0 and + value < leftType.getSize() * 8 + ) +} + +predicate isSignedConstantLeftShiftException(LShiftExpr shift) { + exists(Expr left, Expr right, NumericType leftType, int leftVal, int rightVal, int maxBit | + left = shift.getLeftOperand() and + right = shift.getRightOperand() and + leftType = left.getType() and + isConstantExpression(left) and + isConstantExpression(right) and + isSignedType(leftType) and + isValidShiftConstantRange(right, leftType) and + leftVal = left.getValue().toInt() and + rightVal = right.getValue().toInt() and + leftVal >= 0 and + maxBit = leftType.getSize() * 8 - 1 and + // Check that no set bit is shifted into or beyond the sign bit + leftVal * 2.pow(rightVal) < 2.pow(maxBit) + ) +} + +class BinaryShiftOperation extends BinaryOperation { + BinaryShiftOperation() { + this instanceof LShiftExpr or + this instanceof RShiftExpr + } +} + +class AssignShiftOperation extends AssignOperation { + AssignShiftOperation() { + this instanceof AssignLShiftExpr or + this instanceof AssignRShiftExpr + } +} + +from Expr x, string message +where + not isExcluded(x, ConversionsPackage::inappropriateBitwiseOrShiftOperandsQuery()) and + ( + // Binary bitwise operators (excluding shift operations) - both operands must be unsigned + exists(BinaryBitwiseOperation op | + not op instanceof BinaryShiftOperation and + op = x and + not ( + isUnsignedType(op.getLeftOperand().getExplicitlyConverted().getType()) and + isUnsignedType(op.getRightOperand().getExplicitlyConverted().getType()) + ) and + message = + "Binary bitwise operator '" + op.getOperator() + "' requires both operands to be unsigned." + ) + or + // Compound assignment bitwise operators - both operands must be unsigned + exists(AssignBitwiseOperation op | + not op instanceof AssignShiftOperation and + op = x and + not ( + isUnsignedType(op.getLValue().getExplicitlyConverted().getType()) and + isUnsignedType(op.getRValue().getExplicitlyConverted().getType()) + ) and + message = + "Compound assignment bitwise operator '" + op.getOperator() + + "' requires both operands to be unsigned." + ) + or + // Bit complement operator - operand must be unsigned + exists(ComplementExpr comp | + comp = x and + not isUnsignedType(comp.getOperand().getExplicitlyConverted().getType()) and + message = "Bit complement operator '~' requires unsigned operand." + ) + or + // Shift operators - left operand must be unsigned + exists(BinaryShiftOperation shift | + shift = x and + not isUnsignedType(shift.getLeftOperand().getExplicitlyConverted().getType()) and + not isSignedConstantLeftShiftException(shift) and + message = "Shift operator '" + shift.getOperator() + "' requires unsigned left operand." + ) + or + // Shift operators - right operand must be unsigned or constant in valid range + exists(BinaryShiftOperation shift, Expr right | + shift = x and + shift = x and + right = shift.getRightOperand() and + not isUnsignedType(right.getExplicitlyConverted().getType()) and + not isValidShiftConstantRange(right, shift.getLeftOperand().getExplicitlyConverted().getType()) and + message = + "Shift operator '" + shift.getOperator() + + "' requires unsigned right operand or constant in valid range." + ) + ) +select x, message diff --git a/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected new file mode 100644 index 0000000000..fbc22131af --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected @@ -0,0 +1,25 @@ +| test.cpp:14:3:14:13 | ... & ... | Binary bitwise operator '&' requires both operands to be unsigned. | +| test.cpp:15:3:15:13 | ... \| ... | Binary bitwise operator '\|' requires both operands to be unsigned. | +| test.cpp:16:3:16:13 | ... ^ ... | Binary bitwise operator '^' requires both operands to be unsigned. | +| test.cpp:18:3:18:13 | ... & ... | Binary bitwise operator '&' requires both operands to be unsigned. | +| test.cpp:19:3:19:13 | ... \| ... | Binary bitwise operator '\|' requires both operands to be unsigned. | +| test.cpp:30:3:30:15 | ... &= ... | Compound assignment bitwise operator '&=' requires both operands to be unsigned. | +| test.cpp:31:3:31:15 | ... \|= ... | Compound assignment bitwise operator '\|=' requires both operands to be unsigned. | +| test.cpp:32:3:32:15 | ... ^= ... | Compound assignment bitwise operator '^=' requires both operands to be unsigned. | +| test.cpp:42:3:42:6 | ~ ... | Bit complement operator '~' requires unsigned operand. | +| test.cpp:54:3:54:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:55:3:55:11 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:63:3:63:18 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:74:3:74:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. | +| test.cpp:75:3:75:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. | +| test.cpp:85:3:85:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. | +| test.cpp:86:3:86:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. | +| test.cpp:87:3:87:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. | +| test.cpp:97:3:97:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:98:3:98:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:99:3:99:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:100:3:100:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:104:3:104:11 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:106:3:106:17 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:112:3:112:10 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:120:3:120:11 | ... >> ... | Shift operator '>>' requires unsigned left operand. | diff --git a/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.qlref b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.qlref new file mode 100644 index 0000000000..df3c14d752 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.qlref @@ -0,0 +1 @@ +rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-7-0-4/test.cpp b/cpp/misra/test/rules/RULE-7-0-4/test.cpp new file mode 100644 index 0000000000..314c105415 --- /dev/null +++ b/cpp/misra/test/rules/RULE-7-0-4/test.cpp @@ -0,0 +1,121 @@ +#include +#include + +void test_binary_bitwise_operators_unsigned_operands() { + std::uint32_t u32a = 0x12345678U; + std::uint32_t u32b = 0x87654321U; + std::int32_t s32a = 0x12345678; + std::int32_t s32b = 0x87654321; + + u32a & u32b; // COMPLIANT + u32a | u32b; // COMPLIANT + u32a ^ u32b; // COMPLIANT + + s32a & s32b; // NON_COMPLIANT + s32a | s32b; // NON_COMPLIANT + s32a ^ s32b; // NON_COMPLIANT + + s32a & u32b; // NON_COMPLIANT + u32a | s32b; // NON_COMPLIANT +} + +void test_compound_assignment_bitwise_operators() { + std::uint32_t u32 = 0x12345678U; + std::int32_t s32 = 0x12345678; + + u32 &= 0xFFFFU; // COMPLIANT + u32 |= 0x1000U; // COMPLIANT + u32 ^= 0x5555U; // COMPLIANT + + s32 &= 0xFFFF; // NON_COMPLIANT + s32 |= 0x1000; // NON_COMPLIANT + s32 ^= 0x5555; // NON_COMPLIANT +} + +void test_bit_complement_operator() { + std::uint32_t u32 = 0x12345678U; + std::uint8_t u8 = 0x55U; + std::int32_t s32 = 0x12345678; + + ~u32; // COMPLIANT + ~u8; // COMPLIANT + ~s32; // NON_COMPLIANT +} + +void test_shift_operators_left_operand_type() { + std::uint32_t u32 = 0x12345678U; + std::uint8_t u8 = 2U; + std::int32_t s32 = 0x12345678; + + 1U << u8; // COMPLIANT + 1U << 31; // COMPLIANT + u32 << 2U; // COMPLIANT + + 1 << u8; // NON_COMPLIANT + s32 << 2U; // NON_COMPLIANT +} + +void test_shift_operators_with_promotion() { + std::uint8_t u8 = 1U; + std::uint16_t u16 = 2U; + + static_cast(u8 + u16) << 2U; // COMPLIANT + (u8 + u16) << 2U; // NON_COMPLIANT +} + +void test_shift_operators_right_operand_unsigned() { + std::uint32_t u32 = 0x12345678U; + std::uint8_t u8 = 2U; + std::int8_t s8 = 2; + + u32 << u8; // COMPLIANT + u32 >> u8; // COMPLIANT + + u32 << s8; // NON_COMPLIANT + u32 >> s8; // NON_COMPLIANT +} + +void test_shift_operators_right_operand_constant_range() { + std::uint32_t u32 = 0x12345678U; + + u32 << 0; // COMPLIANT + u32 << 31; // COMPLIANT + u32 >> 15; // COMPLIANT + + u32 << 32; // NON_COMPLIANT + u32 << 64; // NON_COMPLIANT + u32 >> 32; // NON_COMPLIANT +} + +void test_exception_signed_constant_left_operand() { + // Exception cases for signed constant expressions + 1 << 30; // COMPLIANT + 2 << 29; // COMPLIANT + 4 << 28; // COMPLIANT + 8 << 27; // COMPLIANT + + 1 << 31; // NON_COMPLIANT + 2 << 30; // NON_COMPLIANT + 4 << 29; // NON_COMPLIANT + 8 << 28; // NON_COMPLIANT + + 1LL << 31; // COMPLIANT - 64 bit type + 1LL << 62; // COMPLIANT - 64 bit type + 1LL << 63; // NON_COMPLIANT - 64 bit type + + 0x40000000 << 1; // NON_COMPLIANT +} + +void test_exception_non_constant_signed_operand() { + std::int32_t s32 = 1; + + s32 << 2; // NON_COMPLIANT +} + +void test_right_shift_signed_operands() { + std::uint32_t u32 = 0x80000000U; + std::int32_t s32 = -1; + + u32 >> 1U; // COMPLIANT + s32 >> 1U; // NON_COMPLIANT +} \ No newline at end of file From db5870420f1611e71e37b5a770c2f706ee9a6ab8 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 4 Jul 2025 12:13:05 +0100 Subject: [PATCH 487/628] Test large and negative constants, use BigInt --- .../InappropriateBitwiseOrShiftOperands.ql | 12 ++++++----- ...appropriateBitwiseOrShiftOperands.expected | 21 ++++++++++++------- cpp/misra/test/rules/RULE-7-0-4/test.cpp | 21 +++++++++++++++---- 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql index 45f8e51936..5c24d9fa25 100644 --- a/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql +++ b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql @@ -34,7 +34,10 @@ predicate isValidShiftConstantRange(Expr right, Type leftType) { } predicate isSignedConstantLeftShiftException(LShiftExpr shift) { - exists(Expr left, Expr right, NumericType leftType, int leftVal, int rightVal, int maxBit | + exists( + Expr left, Expr right, NumericType leftType, QlBuiltins::BigInt leftVal, int rightVal, + int maxBit + | left = shift.getLeftOperand() and right = shift.getRightOperand() and leftType = left.getType() and @@ -42,12 +45,12 @@ predicate isSignedConstantLeftShiftException(LShiftExpr shift) { isConstantExpression(right) and isSignedType(leftType) and isValidShiftConstantRange(right, leftType) and - leftVal = left.getValue().toInt() and + leftVal = left.getValue().toBigInt() and rightVal = right.getValue().toInt() and - leftVal >= 0 and + leftVal >= 0.toBigInt() and maxBit = leftType.getSize() * 8 - 1 and // Check that no set bit is shifted into or beyond the sign bit - leftVal * 2.pow(rightVal) < 2.pow(maxBit) + leftVal * 2.toBigInt().pow(rightVal) < 2.toBigInt().pow(maxBit) ) } @@ -111,7 +114,6 @@ where or // Shift operators - right operand must be unsigned or constant in valid range exists(BinaryShiftOperation shift, Expr right | - shift = x and shift = x and right = shift.getRightOperand() and not isUnsignedType(right.getExplicitlyConverted().getType()) and diff --git a/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected index fbc22131af..74d010b948 100644 --- a/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected +++ b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected @@ -15,11 +15,16 @@ | test.cpp:85:3:85:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. | | test.cpp:86:3:86:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. | | test.cpp:87:3:87:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. | -| test.cpp:97:3:97:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:98:3:98:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:99:3:99:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:100:3:100:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:104:3:104:11 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:106:3:106:17 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:112:3:112:10 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:120:3:120:11 | ... >> ... | Shift operator '>>' requires unsigned left operand. | +| test.cpp:93:3:93:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. | +| test.cpp:94:3:94:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. | +| test.cpp:95:3:95:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. | +| test.cpp:96:3:96:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. | +| test.cpp:106:3:106:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:107:3:107:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:108:3:108:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:109:3:109:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:113:3:113:11 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:117:3:117:30 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:119:3:119:17 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:125:3:125:10 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:133:3:133:11 | ... >> ... | Shift operator '>>' requires unsigned left operand. | diff --git a/cpp/misra/test/rules/RULE-7-0-4/test.cpp b/cpp/misra/test/rules/RULE-7-0-4/test.cpp index 314c105415..b67a7b44e1 100644 --- a/cpp/misra/test/rules/RULE-7-0-4/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-4/test.cpp @@ -87,7 +87,16 @@ void test_shift_operators_right_operand_constant_range() { u32 >> 32; // NON_COMPLIANT } -void test_exception_signed_constant_left_operand() { +void test_shift_operators_negative_right_operand() { + std::uint32_t u32 = 0x12345678U; + + u32 << -1; // NON_COMPLIANT + u32 << -5; // NON_COMPLIANT + u32 >> -1; // NON_COMPLIANT + u32 >> -3; // NON_COMPLIANT +} + +void test_exception_signed_constant_left_operand_exception() { // Exception cases for signed constant expressions 1 << 30; // COMPLIANT 2 << 29; // COMPLIANT @@ -99,9 +108,13 @@ void test_exception_signed_constant_left_operand() { 4 << 29; // NON_COMPLIANT 8 << 28; // NON_COMPLIANT - 1LL << 31; // COMPLIANT - 64 bit type - 1LL << 62; // COMPLIANT - 64 bit type - 1LL << 63; // NON_COMPLIANT - 64 bit type + 1LL << 31; // COMPLIANT - 64 bit type + 1LL << 62; // COMPLIANT - 64 bit type + 1LL << 63; // NON_COMPLIANT - 64 bit type + 0x1000'0000'0000'0000LL << 2; // COMPLIANT + 0x2000'0000'0000'0000LL << 1; // COMPLIANT + + 0x4000'0000'0000'0000LL << 1; // NON_COMPLIANT 0x40000000 << 1; // NON_COMPLIANT } From 3d2616aedad1ccec0873ecda7a6c62bfbb821626 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 7 Jul 2025 14:10:22 +0100 Subject: [PATCH 488/628] Rule 7.0.4: Add support for shift-assignment operators --- .../InappropriateBitwiseOrShiftOperands.ql | 18 +++++++++ ...appropriateBitwiseOrShiftOperands.expected | 31 +++++++++++----- cpp/misra/test/rules/RULE-7-0-4/test.cpp | 37 +++++++++++++++++++ 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql index 5c24d9fa25..b256beaf71 100644 --- a/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql +++ b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql @@ -112,6 +112,13 @@ where message = "Shift operator '" + shift.getOperator() + "' requires unsigned left operand." ) or + // Compound assignment shift operators - left operand must be unsigned + exists(AssignShiftOperation shift | + shift = x and + not isUnsignedType(shift.getLValue().getExplicitlyConverted().getType()) and + message = "Shift operator '" + shift.getOperator() + "' requires unsigned left operand." + ) + or // Shift operators - right operand must be unsigned or constant in valid range exists(BinaryShiftOperation shift, Expr right | shift = x and @@ -122,5 +129,16 @@ where "Shift operator '" + shift.getOperator() + "' requires unsigned right operand or constant in valid range." ) + or + // Compound assignment shift operators - right operand must be unsigned or constant in valid range + exists(AssignShiftOperation shift, Expr right | + shift = x and + right = shift.getRValue() and + not isUnsignedType(right.getExplicitlyConverted().getType()) and + not isValidShiftConstantRange(right, shift.getLValue().getExplicitlyConverted().getType()) and + message = + "Shift operator '" + shift.getOperator() + + "' requires unsigned right operand or constant in valid range." + ) ) select x, message diff --git a/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected index 74d010b948..0c9144d018 100644 --- a/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected +++ b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected @@ -19,12 +19,25 @@ | test.cpp:94:3:94:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. | | test.cpp:95:3:95:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. | | test.cpp:96:3:96:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. | -| test.cpp:106:3:106:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:107:3:107:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:108:3:108:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:109:3:109:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:113:3:113:11 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:117:3:117:30 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:119:3:119:17 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:125:3:125:10 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:133:3:133:11 | ... >> ... | Shift operator '>>' requires unsigned left operand. | +| test.cpp:115:3:115:12 | ... <<= ... | Shift operator '<<=' requires unsigned left operand. | +| test.cpp:116:3:116:12 | ... >>= ... | Shift operator '>>=' requires unsigned left operand. | +| test.cpp:117:3:117:11 | ... <<= ... | Shift operator '<<=' requires unsigned left operand. | +| test.cpp:118:3:118:11 | ... >>= ... | Shift operator '>>=' requires unsigned left operand. | +| test.cpp:121:3:121:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. | +| test.cpp:122:3:122:12 | ... >>= ... | Shift operator '>>=' requires unsigned right operand or constant in valid range. | +| test.cpp:125:3:125:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. | +| test.cpp:126:3:126:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. | +| test.cpp:127:3:127:12 | ... >>= ... | Shift operator '>>=' requires unsigned right operand or constant in valid range. | +| test.cpp:130:3:130:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. | +| test.cpp:131:3:131:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. | +| test.cpp:132:3:132:12 | ... >>= ... | Shift operator '>>=' requires unsigned right operand or constant in valid range. | +| test.cpp:133:3:133:12 | ... >>= ... | Shift operator '>>=' requires unsigned right operand or constant in valid range. | +| test.cpp:143:3:143:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:144:3:144:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:145:3:145:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:146:3:146:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:150:3:150:11 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:154:3:154:30 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:156:3:156:17 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:162:3:162:10 | ... << ... | Shift operator '<<' requires unsigned left operand. | +| test.cpp:170:3:170:11 | ... >> ... | Shift operator '>>' requires unsigned left operand. | diff --git a/cpp/misra/test/rules/RULE-7-0-4/test.cpp b/cpp/misra/test/rules/RULE-7-0-4/test.cpp index b67a7b44e1..1735d59e58 100644 --- a/cpp/misra/test/rules/RULE-7-0-4/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-4/test.cpp @@ -96,6 +96,43 @@ void test_shift_operators_negative_right_operand() { u32 >> -3; // NON_COMPLIANT } +void test_compound_assignment_shift_operators() { + std::uint32_t u32 = 0x12345678U; + std::uint8_t u8 = 2U; + std::int32_t s32 = 0x12345678; + std::int8_t s8 = 2; + + // Unsigned left operand with unsigned right operand + u32 <<= u8; // COMPLIANT + u32 >>= u8; // COMPLIANT + + // Unsigned left operand with constant right operand in valid range + u32 <<= 0; // COMPLIANT + u32 <<= 31; // COMPLIANT + u32 >>= 15; // COMPLIANT + + // Signed left operand + s32 <<= u8; // NON_COMPLIANT + s32 >>= u8; // NON_COMPLIANT + s32 <<= 2; // NON_COMPLIANT + s32 >>= 2; // NON_COMPLIANT + + // Unsigned left operand with signed right operand + u32 <<= s8; // NON_COMPLIANT + u32 >>= s8; // NON_COMPLIANT + + // Right operand out of range + u32 <<= 32; // NON_COMPLIANT + u32 <<= 64; // NON_COMPLIANT + u32 >>= 32; // NON_COMPLIANT + + // Negative right operand + u32 <<= -1; // NON_COMPLIANT + u32 <<= -5; // NON_COMPLIANT + u32 >>= -1; // NON_COMPLIANT + u32 >>= -3; // NON_COMPLIANT +} + void test_exception_signed_constant_left_operand_exception() { // Exception cases for signed constant expressions 1 << 30; // COMPLIANT From 05cfc2b03e32ea368baeda7e4d589e179143d96a Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 7 Jul 2025 14:16:44 +0100 Subject: [PATCH 489/628] Rule 7.0.5: Add an implementation_scope Preprocessor directives are not currently supported. --- rule_packages/cpp/Conversions.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rule_packages/cpp/Conversions.json b/rule_packages/cpp/Conversions.json index 9835110e27..441b5aa85f 100644 --- a/rule_packages/cpp/Conversions.json +++ b/rule_packages/cpp/Conversions.json @@ -95,7 +95,10 @@ "short_name": "NoSignednessChangeFromPromotion", "tags": [ "scope/single-translation-unit" - ] + ], + "implementation_scope": { + "description": "Arithmetic conversions in preprocessor directives are not supported." + } } ], "title": "Integral promotion and the usual arithmetic conversions shall not change the signedness or the type category of an operand" From 6791c0ccfc953c5e3810b55208a730a73dc5b3f8 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 7 Jul 2025 14:51:00 +0100 Subject: [PATCH 490/628] VariableWidthType: return type test results accepted --- .../VariableWidthIntegerTypesUsed.expected | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.expected b/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.expected index 7609c76101..eab4694e7c 100644 --- a/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.expected +++ b/cpp/common/test/rules/variablewidthintegertypesused/VariableWidthIntegerTypesUsed.expected @@ -37,3 +37,16 @@ | test.cpp:70:17:70:18 | l2 | Variable 'l2' has variable-width type. | | test.cpp:71:26:71:28 | ul2 | Variable 'ul2' has variable-width type. | | test.cpp:72:24:72:26 | sl2 | Variable 'sl2' has variable-width type. | +| test.cpp:93:15:93:39 | test_unsigned_char_return | Function 'test_unsigned_char_return' has variable-width return type. | +| test.cpp:96:13:96:35 | test_signed_char_return | Function 'test_signed_char_return' has variable-width return type. | +| test.cpp:99:5:99:19 | test_int_return | Function 'test_int_return' has variable-width return type. | +| test.cpp:102:14:102:37 | test_unsigned_int_return | Function 'test_unsigned_int_return' has variable-width return type. | +| test.cpp:105:10:105:29 | test_unsigned_return | Function 'test_unsigned_return' has variable-width return type. | +| test.cpp:108:12:108:33 | test_signed_int_return | Function 'test_signed_int_return' has variable-width return type. | +| test.cpp:111:8:111:25 | test_signed_return | Function 'test_signed_return' has variable-width return type. | +| test.cpp:114:7:114:23 | test_short_return | Function 'test_short_return' has variable-width return type. | +| test.cpp:117:16:117:41 | test_unsigned_short_return | Function 'test_unsigned_short_return' has variable-width return type. | +| test.cpp:120:14:120:37 | test_signed_short_return | Function 'test_signed_short_return' has variable-width return type. | +| test.cpp:123:6:123:21 | test_long_return | Function 'test_long_return' has variable-width return type. | +| test.cpp:126:15:126:39 | test_unsigned_long_return | Function 'test_unsigned_long_return' has variable-width return type. | +| test.cpp:129:13:129:35 | test_signed_long_return | Function 'test_signed_long_return' has variable-width return type. | From a2de81073f6076f16c98d0e5ee11e615b12acbf4 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 7 Jul 2025 15:03:10 +0100 Subject: [PATCH 491/628] Remove unneeded #pragma --- cpp/common/test/includes/standard-library/cwchar | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/common/test/includes/standard-library/cwchar b/cpp/common/test/includes/standard-library/cwchar index a3e70b8d2b..835edec21d 100644 --- a/cpp/common/test/includes/standard-library/cwchar +++ b/cpp/common/test/includes/standard-library/cwchar @@ -1,4 +1,3 @@ -#pragma once #ifndef _GHLIBCPP_CWCHAR #define _GHLIBCPP_CWCHAR #include "wchar.h" From 516ef7451f27c2eb6237634859f444432afadc6f Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 7 Jul 2025 15:03:25 +0100 Subject: [PATCH 492/628] Rule 23.11.1: Address review comments - Simplify query - Improve documentation --- .../rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql b/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql index 65faa9cfd8..6b45d6c5f1 100644 --- a/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql +++ b/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql @@ -24,9 +24,8 @@ where smartPtrClass.hasQualifiedName("std", "shared_ptr") or smartPtrClass.hasQualifiedName("std", "unique_ptr") ) and - call.getNumberOfArguments() >= 1 and - exists(Type argType | - argType = call.getArgument(0).getType().getUnspecifiedType() and - argType instanceof PointerType - ) + // The rule only applies to constructors that take a raw pointer as the first argument + // This includes the (*p, deleter) and (*p, deleter, alloc) constructors + // and excludes e.g. the move or aliasing constructors. + call.getArgument(0).getType().getUnspecifiedType() instanceof PointerType select call, "Use of raw pointer constructor for 'std::" + smartPtrClass.getSimpleName() + "'." From 215a96c7eaf4f76f7bf6130e8e36f9a9bb3a5b95 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 7 Jul 2025 15:21:58 +0100 Subject: [PATCH 493/628] Rule 21.10.1: Support other uses of va_list --- .../RULE-21-10-1/NoVariadicFunctionMacros.ql | 20 ++++++++++++------- .../NoVariadicFunctionMacros.expected | 1 + cpp/misra/test/rules/RULE-21-10-1/test.cpp | 6 ++++++ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql b/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql index fbe82d45c6..f56232ae7b 100644 --- a/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql +++ b/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql @@ -14,6 +14,7 @@ import cpp import codingstandards.cpp.misra +import codingstandards.cpp.types.Uses class VaListType extends Type { VaListType() { @@ -27,15 +28,24 @@ from Element element, string message where not isExcluded(element, BannedAPIsPackage::noVariadicFunctionMacrosQuery()) and ( - element.(Variable).getType() instanceof VaListType and + element = getATypeUse(any(VaListType vlt)) and ( if element instanceof Parameter then message = "Declaration of parameter '" + element.(Parameter).getName() + "' of type 'va_list'." else - message = - "Declaration of variable '" + element.(Variable).getName() + "' of type 'va_list'." + if element instanceof Variable + then + message = + "Declaration of variable '" + element.(Variable).getName() + "' of type 'va_list'." + else + if element instanceof TypedefType + then + message = + "Declaration of typedef '" + element.(TypedefType).getName() + + "' aliasing 'va_list' type." + else message = "Use of 'va_list' type in an unsupported context." ) or element instanceof BuiltInVarArgsStart and @@ -49,9 +59,5 @@ where or element instanceof BuiltInVarArgCopy and message = "Call to 'va_copy'." - or - element.(TypedefType).getBaseType() instanceof VaListType and - message = - "Declaration of typedef '" + element.(TypedefType).getName() + "' aliasing 'va_list' type." ) select element, message diff --git a/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected index bb52ced03a..c57dec9792 100644 --- a/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected +++ b/cpp/misra/test/rules/RULE-21-10-1/NoVariadicFunctionMacros.expected @@ -26,3 +26,4 @@ | test.cpp:56:17:56:25 | SOME_TYPE | Declaration of typedef 'SOME_TYPE' aliasing 'va_list' type. | | test.cpp:58:17:58:18 | l1 | Declaration of variable 'l1' of type 'va_list'. | | test.cpp:59:13:59:14 | l2 | Declaration of variable 'l2' of type 'va_list'. | +| test.cpp:65:12:65:13 | l1 | Declaration of variable 'l1' of type 'va_list'. | diff --git a/cpp/misra/test/rules/RULE-21-10-1/test.cpp b/cpp/misra/test/rules/RULE-21-10-1/test.cpp index 1ff0793e05..14d25c59b7 100644 --- a/cpp/misra/test/rules/RULE-21-10-1/test.cpp +++ b/cpp/misra/test/rules/RULE-21-10-1/test.cpp @@ -57,4 +57,10 @@ typedef va_list SOME_TYPE; // NON_COMPLIANT void test_va_list_alias() { va_list_alias l1; // NON_COMPLIANT SOME_TYPE l2; // NON_COMPLIANT +} + +// Note: use of va_list as a return type, or a cast, is not legal + +void test_va_list() { + va_list *l1; // NON_COMPLIANT - pointer to va_list } \ No newline at end of file From d0c65bdfaa487e00fd0fed05f1976d5abea3c700 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 7 Jul 2025 15:35:47 +0100 Subject: [PATCH 494/628] Rule 21.10.2: Detect more complex type use of jmp_buf --- .../src/rules/RULE-21-10-2/NoCsetjmpHeader.ql | 17 ++++++++++++----- .../rules/RULE-21-10-2/NoCsetjmpHeader.expected | 1 + cpp/misra/test/rules/RULE-21-10-2/test.cpp | 4 +++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql b/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql index 4cfc7770a1..e3a432adc6 100644 --- a/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql +++ b/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql @@ -16,13 +16,14 @@ import cpp import codingstandards.cpp.misra import codingstandards.cpp.BannedFunctions +import codingstandards.cpp.types.Uses class CSetJmpHeader extends Include { CSetJmpHeader() { this.getIncludeText().regexpMatch("[<\\\"](csetjmp|setjmp.h)[>\\\"]") } } -class JmpBufVariable extends Variable { - JmpBufVariable() { this.getType().(UserType).hasGlobalOrStdName("jmp_buf") } +class JmpBufType extends UserType { + JmpBufType() { this.hasGlobalOrStdName("jmp_buf") } } class LongjmpFunction extends Function { @@ -39,9 +40,15 @@ where ( message = "Use of banned header " + element.(CSetJmpHeader).getIncludeText() + "." or - message = - "Declaration of variable '" + element.(JmpBufVariable).getName() + - "' with banned type 'jmp_buf'." + ( + element = getATypeUse(any(JmpBufType jbt)) and + if element instanceof Variable + then + message = + "Declaration of variable '" + element.(Variable).getName() + + "' with banned type 'jmp_buf'." + else message = "Use of banned type 'jmp_buf'." + ) or message = element.(BannedFunctions::Use).getAction() + " banned function '" + diff --git a/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected b/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected index 6ac8e41484..4572446b0e 100644 --- a/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected +++ b/cpp/misra/test/rules/RULE-21-10-2/NoCsetjmpHeader.expected @@ -12,3 +12,4 @@ | test.cpp:21:5:21:16 | call to longjmp | Call to banned function 'longjmp'. | | test.cpp:26:11:26:12 | l1 | Declaration of variable 'l1' with banned type 'jmp_buf'. | | test.cpp:27:16:27:17 | l2 | Declaration of variable 'l2' with banned type 'jmp_buf'. | +| test.cpp:40:38:40:39 | l1 | Declaration of variable 'l1' with banned type 'jmp_buf'. | diff --git a/cpp/misra/test/rules/RULE-21-10-2/test.cpp b/cpp/misra/test/rules/RULE-21-10-2/test.cpp index 8fbed19530..68b4792da1 100644 --- a/cpp/misra/test/rules/RULE-21-10-2/test.cpp +++ b/cpp/misra/test/rules/RULE-21-10-2/test.cpp @@ -35,4 +35,6 @@ void test_compliant_alternative() { } catch (const std::runtime_error &) { // COMPLIANT // Handle error properly } -} \ No newline at end of file +} + +void test_jmp_buf_usage() { jmp_buf *l1; } // NON_COMPLIANT - pointer to jmp_buf \ No newline at end of file From 6856e110e3c3fc8011f7a39f32c56369afc2a758 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 7 Jul 2025 15:39:46 +0100 Subject: [PATCH 495/628] BannedAPIs: Add tags --- .../AvoidProgramTerminatingFunctions.ql | 2 + .../RULE-21-10-1/NoVariadicFunctionMacros.ql | 2 + .../src/rules/RULE-21-10-2/NoCsetjmpHeader.ql | 2 + .../UnsafeStringHandlingFunctions.ql | 2 + .../rules/RULE-21-2-3/BannedSystemFunction.ql | 3 ++ .../UseSmartPtrFactoryFunctions.ql | 2 + .../CharacterHandlingFunctionRestrictions.ql | 2 + .../NoMemoryFunctionsFromCString.ql | 2 + .../LocaleGlobalFunctionNotAllowed.ql | 3 ++ .../AvoidStandardIntegerTypeNames.ql | 2 + rule_packages/cpp/BannedAPIs.json | 42 ++++++++++++++----- 11 files changed, 54 insertions(+), 10 deletions(-) diff --git a/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql index adafebd44c..7d507bc4d1 100644 --- a/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql +++ b/cpp/misra/src/rules/RULE-18-5-2/AvoidProgramTerminatingFunctions.ql @@ -9,6 +9,8 @@ * @problem.severity error * @tags external/misra/id/rule-18-5-2 * scope/single-translation-unit + * maintainability + * correctness * external/misra/enforcement/decidable * external/misra/obligation/advisory */ diff --git a/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql b/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql index f56232ae7b..37dfa2422b 100644 --- a/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql +++ b/cpp/misra/src/rules/RULE-21-10-1/NoVariadicFunctionMacros.ql @@ -8,6 +8,8 @@ * @problem.severity error * @tags external/misra/id/rule-21-10-1 * scope/single-translation-unit + * correctness + * maintainability * external/misra/enforcement/decidable * external/misra/obligation/required */ diff --git a/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql b/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql index e3a432adc6..85607a5c8b 100644 --- a/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql +++ b/cpp/misra/src/rules/RULE-21-10-2/NoCsetjmpHeader.ql @@ -9,6 +9,8 @@ * @problem.severity error * @tags external/misra/id/rule-21-10-2 * scope/single-translation-unit + * correctness + * maintainability * external/misra/enforcement/decidable * external/misra/obligation/required */ diff --git a/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql b/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql index ff888c9c22..c654ac4771 100644 --- a/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql +++ b/cpp/misra/src/rules/RULE-21-2-2/UnsafeStringHandlingFunctions.ql @@ -8,6 +8,8 @@ * @problem.severity error * @tags external/misra/id/rule-21-2-2 * scope/single-translation-unit + * correctness + * maintainability * external/misra/enforcement/decidable * external/misra/obligation/required */ diff --git a/cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql b/cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql index b8cf0788f8..95900e605b 100644 --- a/cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql +++ b/cpp/misra/src/rules/RULE-21-2-3/BannedSystemFunction.ql @@ -8,6 +8,9 @@ * @problem.severity error * @tags external/misra/id/rule-21-2-3 * scope/single-translation-unit + * correctness + * maintainability + * security * external/misra/enforcement/decidable * external/misra/obligation/required */ diff --git a/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql b/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql index 6b45d6c5f1..9f2cf6f038 100644 --- a/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql +++ b/cpp/misra/src/rules/RULE-23-11-1/UseSmartPtrFactoryFunctions.ql @@ -9,6 +9,8 @@ * @problem.severity error * @tags external/misra/id/rule-23-11-1 * scope/single-translation-unit + * correctness + * maintainability * external/misra/enforcement/decidable * external/misra/obligation/advisory */ diff --git a/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql b/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql index d3dba3c347..a50b535d1a 100644 --- a/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql +++ b/cpp/misra/src/rules/RULE-24-5-1/CharacterHandlingFunctionRestrictions.ql @@ -9,6 +9,8 @@ * @problem.severity error * @tags external/misra/id/rule-24-5-1 * scope/single-translation-unit + * correctness + * maintainability * external/misra/enforcement/decidable * external/misra/obligation/required */ diff --git a/cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql b/cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql index 17bca5c0eb..3352b99455 100644 --- a/cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql +++ b/cpp/misra/src/rules/RULE-24-5-2/NoMemoryFunctionsFromCString.ql @@ -9,6 +9,8 @@ * @problem.severity error * @tags external/misra/id/rule-24-5-2 * scope/single-translation-unit + * correctness + * maintainability * external/misra/enforcement/decidable * external/misra/obligation/required */ diff --git a/cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql b/cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql index 5072da9789..2040f998ca 100644 --- a/cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql +++ b/cpp/misra/src/rules/RULE-25-5-1/LocaleGlobalFunctionNotAllowed.ql @@ -8,6 +8,9 @@ * @problem.severity error * @tags external/misra/id/rule-25-5-1 * scope/single-translation-unit + * correctness + * maintainability + * concurrency * external/misra/enforcement/decidable * external/misra/obligation/required */ diff --git a/cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql b/cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql index ef02deb899..ff1d6f1d98 100644 --- a/cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql +++ b/cpp/misra/src/rules/RULE-6-9-2/AvoidStandardIntegerTypeNames.ql @@ -8,6 +8,8 @@ * @problem.severity error * @tags external/misra/id/rule-6-9-2 * scope/single-translation-unit + * correctness + * maintainability * external/misra/enforcement/decidable * external/misra/obligation/advisory */ diff --git a/rule_packages/cpp/BannedAPIs.json b/rule_packages/cpp/BannedAPIs.json index 313b513315..3bb456fdd4 100644 --- a/rule_packages/cpp/BannedAPIs.json +++ b/rule_packages/cpp/BannedAPIs.json @@ -14,7 +14,9 @@ "severity": "error", "short_name": "AvoidProgramTerminatingFunctions", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "maintainability", + "correctness" ] } ], @@ -34,7 +36,9 @@ "severity": "error", "short_name": "NoVariadicFunctionMacros", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "correctness", + "maintainability" ] } ], @@ -54,7 +58,9 @@ "severity": "error", "short_name": "NoCsetjmpHeader", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "correctness", + "maintainability" ] } ], @@ -74,7 +80,9 @@ "severity": "error", "short_name": "UnsafeStringHandlingFunctions", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "correctness", + "maintainability" ] } ], @@ -94,7 +102,10 @@ "severity": "error", "short_name": "BannedSystemFunction", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "correctness", + "maintainability", + "security" ] } ], @@ -114,7 +125,9 @@ "severity": "error", "short_name": "UseSmartPtrFactoryFunctions", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "correctness", + "maintainability" ] } ], @@ -134,7 +147,9 @@ "severity": "error", "short_name": "CharacterHandlingFunctionRestrictions", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "correctness", + "maintainability" ] } ], @@ -154,7 +169,9 @@ "severity": "error", "short_name": "NoMemoryFunctionsFromCString", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "correctness", + "maintainability" ] } ], @@ -174,7 +191,10 @@ "severity": "error", "short_name": "LocaleGlobalFunctionNotAllowed", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "correctness", + "maintainability", + "concurrency" ] } ], @@ -195,7 +215,9 @@ "short_name": "AvoidStandardIntegerTypeNames", "shared_implementation_short_name": "VariableWidthIntegerTypesUsed", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "correctness", + "maintainability" ] } ], From 68355b0106b8349db717c0bd2a7c7b1963424b6f Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Tue, 8 Jul 2025 22:02:53 +0200 Subject: [PATCH 496/628] Make dataflow imports private in libraries and remove unused imports --- .../VariableLengthArraySizeNotInValidRange.ql | 1 + .../DoNotRelyOnIndeterminateValuesOfErrno.ql | 1 + .../DetectAndHandleStandardLibraryErrors.ql | 1 + .../ResetStringsOnFgetsOrFgetwsFailure.ql | 1 + ...riableLengthArraySizeNotInValidRange.expected | 4 ++-- ...oNotRelyOnIndeterminateValuesOfErrno.expected | 8 ++++---- ...DetectAndHandleStandardLibraryErrors.expected | 2 +- .../ResetStringsOnFgetsOrFgetwsFailure.expected | 6 +++--- c/common/src/codingstandards/c/OutOfBounds.qll | 2 +- c/common/src/codingstandards/c/Signal.qll | 2 +- .../InvalidOperationOnUnlockedMutex.ql | 1 - ...fShallBeComparedWithUnmodifiedReturnValues.ql | 1 + ...BeComparedWithUnmodifiedReturnValues.expected | 16 ++++++++-------- .../InOutParametersDeclaredAsTNotModified.ql | 1 + ...nOutParametersDeclaredAsTNotModified.expected | 4 ++-- .../rules/CTR53-CPP/UseValidIteratorRanges.ql | 1 + .../DoNotUseAnAdditiveOperatorOnAnIterator.ql | 1 + .../CTR53-CPP/UseValidIteratorRanges.expected | 12 ++++++------ ...NotUseAnAdditiveOperatorOnAnIterator.expected | 14 +++++++------- .../src/codingstandards/cpp/AccessPath.qll | 2 +- .../src/codingstandards/cpp/Allocations.qll | 2 +- .../src/codingstandards/cpp/Concurrency.qll | 1 - .../src/codingstandards/cpp/ConstHelpers.qll | 2 +- cpp/common/src/codingstandards/cpp/Expr.qll | 1 + .../codingstandards/cpp/FgetsErrorManagement.qll | 2 +- cpp/common/src/codingstandards/cpp/Iterators.qll | 8 +++++--- cpp/common/src/codingstandards/cpp/Overflow.qll | 2 +- .../src/codingstandards/cpp/ReadErrorsAndEOF.qll | 2 +- .../src/codingstandards/cpp/SideEffect.qll | 2 +- .../src/codingstandards/cpp/SmartPointers.qll | 2 +- .../cpp/concurrency/LockingOperation.qll | 2 +- .../InvalidatedEnvStringPointersWarn.qll | 1 - ...redicateFunctionObjectsShouldNotBeMutable.qll | 1 + .../cpp/standardlibrary/FileStreams.qll | 4 ++-- 34 files changed, 61 insertions(+), 52 deletions(-) diff --git a/c/cert/src/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.ql b/c/cert/src/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.ql index 85fc7b9022..1356777e5f 100644 --- a/c/cert/src/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.ql +++ b/c/cert/src/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.ql @@ -20,6 +20,7 @@ import cpp import codingstandards.c.cert import codingstandards.cpp.Overflow +import semmle.code.cpp.dataflow.TaintTracking /** * Gets the maximum size (in bytes) a variable-length array diff --git a/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql b/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql index c7dfd58c6b..146d0cb30f 100644 --- a/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql +++ b/c/cert/src/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.ql @@ -20,6 +20,7 @@ import codingstandards.c.cert import codingstandards.c.Errno import codingstandards.c.Signal import semmle.code.cpp.controlflow.Guards +import semmle.code.cpp.dataflow.DataFlow /** * A check on `signal` call return value diff --git a/c/cert/src/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.ql b/c/cert/src/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.ql index 01e7b83d13..5e473b226e 100644 --- a/c/cert/src/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.ql +++ b/c/cert/src/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.ql @@ -20,6 +20,7 @@ import cpp import codingstandards.c.cert import semmle.code.cpp.commons.NULL import codingstandards.cpp.ReadErrorsAndEOF +import semmle.code.cpp.dataflow.DataFlow ComparisonOperation getAValidComparison(string spec) { spec = "=0" and result.(EqualityOperation).getAnOperand().getValue() = "0" diff --git a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql index b54436c835..9b0882ac66 100644 --- a/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql +++ b/c/cert/src/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.ql @@ -21,6 +21,7 @@ import cpp import codingstandards.cpp.FgetsErrorManagement import codingstandards.cpp.Dereferenced import codingstandards.c.cert +import semmle.code.cpp.dataflow.DataFlow /* * Models calls to `memcpy` `strcpy` `strncpy` and their wrappers diff --git a/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected b/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected index 0b400c5256..1617571bbe 100644 --- a/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected +++ b/c/cert/test/rules/ARR32-C/VariableLengthArraySizeNotInValidRange.expected @@ -1,5 +1,5 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:109,11-19) -WARNING: module 'TaintTracking' has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:92,5-18) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:110,11-19) +WARNING: module 'TaintTracking' has been deprecated and may be removed in future (VariableLengthArraySizeNotInValidRange.ql:93,5-18) | test.c:14:8:14:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | | test.c:15:8:15:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | | test.c:16:8:16:8 | VLA declaration | Variable-length array dimension size may be in an invalid range. | diff --git a/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected b/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected index 1f313cb90d..b79a17ca35 100644 --- a/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected +++ b/c/cert/test/rules/ERR32-C/DoNotRelyOnIndeterminateValuesOfErrno.expected @@ -1,7 +1,7 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:55,7-15) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:55,27-35) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:56,9-17) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:59,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:56,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:56,27-35) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:57,9-17) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotRelyOnIndeterminateValuesOfErrno.ql:60,9-17) | test.c:12:5:12:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:10:21:10:26 | call to signal | call to signal | | test.c:30:5:30:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:26:21:26:26 | call to signal | call to signal | | test.c:49:5:49:10 | call to perror | `errno` has indeterminate value after this $@. | test.c:45:21:45:26 | call to signal | call to signal | diff --git a/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected b/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected index b13f34522c..f4006c013e 100644 --- a/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected +++ b/c/cert/test/rules/ERR33-C/DetectAndHandleStandardLibraryErrors.expected @@ -1,4 +1,4 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleStandardLibraryErrors.ql:458,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DetectAndHandleStandardLibraryErrors.ql:459,5-13) | test.c:18:3:18:11 | call to setlocale | Missing error detection for the call to function `setlocale`. | | test.c:24:23:24:31 | call to setlocale | Missing error detection for the call to function `setlocale`. | | test.c:29:22:29:27 | call to calloc | Missing error detection for the call to function `calloc`. | diff --git a/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected b/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected index 7d3cbe355b..52cb85e5c4 100644 --- a/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected +++ b/c/cert/test/rules/FIO40-C/ResetStringsOnFgetsOrFgetwsFailure.expected @@ -1,6 +1,6 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:47,11-19) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:47,31-39) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:48,13-21) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:48,11-19) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:48,31-39) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (ResetStringsOnFgetsOrFgetwsFailure.ql:49,13-21) | test.c:20:10:20:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:15:7:15:11 | call to fgets | call to fgets | | test.c:57:10:57:12 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:52:7:52:11 | call to fgets | call to fgets | | test.c:66:18:66:20 | buf | The buffer is not reset before being referenced following a failed $@. | test.c:61:7:61:11 | call to fgets | call to fgets | diff --git a/c/common/src/codingstandards/c/OutOfBounds.qll b/c/common/src/codingstandards/c/OutOfBounds.qll index bb7d1bd124..1f1680f56c 100644 --- a/c/common/src/codingstandards/c/OutOfBounds.qll +++ b/c/common/src/codingstandards/c/OutOfBounds.qll @@ -11,7 +11,7 @@ import codingstandards.cpp.Allocations import codingstandards.cpp.Overflow import codingstandards.cpp.PossiblyUnsafeStringOperation import codingstandards.cpp.SimpleRangeAnalysisCustomizations -import semmle.code.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.valuenumbering.GlobalValueNumbering module OOB { diff --git a/c/common/src/codingstandards/c/Signal.qll b/c/common/src/codingstandards/c/Signal.qll index 95b27e2898..2a570b654f 100644 --- a/c/common/src/codingstandards/c/Signal.qll +++ b/c/common/src/codingstandards/c/Signal.qll @@ -1,5 +1,5 @@ import cpp -import semmle.code.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow /** * A signal corresponding to a computational exception diff --git a/c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql b/c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql index 252b4a7d9f..d85183a831 100644 --- a/c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql +++ b/c/misra/src/rules/RULE-22-17/InvalidOperationOnUnlockedMutex.ql @@ -18,7 +18,6 @@ import codingstandards.c.misra import codingstandards.c.SubObjects import codingstandards.cpp.Concurrency import codingstandards.cpp.dominance.BehavioralSet -import semmle.code.cpp.dataflow.new.DataFlow::DataFlow as NewDF /* A call to mtx_unlock() or cnd_wait() or cnd_timedwait(), which require a locked mutex */ class RequiresLockOperation extends FunctionCall { diff --git a/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql b/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql index a29ee7c898..1da495ca28 100644 --- a/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql +++ b/c/misra/src/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.ql @@ -15,6 +15,7 @@ import cpp import codingstandards.c.misra import codingstandards.cpp.ReadErrorsAndEOF +import semmle.code.cpp.dataflow.DataFlow /** * The getchar() return value propagates directly to a check against EOF macro diff --git a/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected index 83a10a46fb..210a3a9218 100644 --- a/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected +++ b/c/misra/test/rules/RULE-22-7/EofShallBeComparedWithUnmodifiedReturnValues.expected @@ -1,10 +1,10 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:23,28-36) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:24,22-30) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:28,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:37,23-31) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:42,17-25) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:51,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:59,20-28) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:59,46-54) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:24,28-36) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:25,22-30) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:29,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:38,23-31) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:43,17-25) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:52,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:60,20-28) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (EofShallBeComparedWithUnmodifiedReturnValues.ql:60,46-54) | test.c:6:7:6:20 | ... != ... | The check is not reliable as the type of the return value of $@ is converted. | test.c:5:14:5:20 | call to getchar | call to getchar | | test.c:13:7:13:15 | ... != ... | The check is not reliable as the type of the return value of $@ is converted. | test.c:12:14:12:20 | call to getchar | call to getchar | diff --git a/cpp/autosar/src/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.ql b/cpp/autosar/src/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.ql index 1509ee968a..3b30eb676a 100644 --- a/cpp/autosar/src/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.ql +++ b/cpp/autosar/src/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.ql @@ -21,6 +21,7 @@ import codingstandards.cpp.autosar import codingstandards.cpp.FunctionParameter import codingstandards.cpp.ConstHelpers import codingstandards.cpp.Operator +import semmle.code.cpp.dataflow.DataFlow /** * Non-const T& `Parameter`s to `Function`s diff --git a/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected b/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected index bafa98112f..25fe77d9a5 100644 --- a/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected +++ b/cpp/autosar/test/rules/A8-4-9/InOutParametersDeclaredAsTNotModified.expected @@ -1,5 +1,5 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (InOutParametersDeclaredAsTNotModified.ql:49,7-15) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (InOutParametersDeclaredAsTNotModified.ql:63,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (InOutParametersDeclaredAsTNotModified.ql:50,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (InOutParametersDeclaredAsTNotModified.ql:64,7-15) | test.cpp:4:13:4:13 | i | In-out parameter i that is not written to. | | test.cpp:7:22:7:24 | str | In-out parameter str that is not read from. | | test.cpp:18:14:18:14 | i | In-out parameter i that is not read from. | diff --git a/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.ql b/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.ql index 3702cbcd6e..1512a7fd99 100644 --- a/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.ql +++ b/cpp/cert/src/rules/CTR53-CPP/UseValidIteratorRanges.ql @@ -19,6 +19,7 @@ import cpp import codingstandards.cpp.cert import codingstandards.cpp.Iterators +import semmle.code.cpp.dataflow.DataFlow predicate startEndArgumentsDoNotPointToTheSameContainer( IteratorRangeFunctionCall fc, Expr arg, string reason diff --git a/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.ql b/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.ql index 3f2de63246..c6ea2c4518 100644 --- a/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.ql +++ b/cpp/cert/src/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.ql @@ -20,6 +20,7 @@ import cpp import codingstandards.cpp.cert import codingstandards.cpp.Iterators import semmle.code.cpp.controlflow.Dominance +import semmle.code.cpp.dataflow.DataFlow /** * Models a call to an iterator's `operator+` diff --git a/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected b/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected index 1953314c2f..d25d23185a 100644 --- a/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected +++ b/cpp/cert/test/rules/CTR53-CPP/UseValidIteratorRanges.expected @@ -1,9 +1,9 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:28,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:28,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:29,7-15) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:35,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:35,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:36,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:29,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:29,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:30,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:36,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:36,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (UseValidIteratorRanges.ql:37,7-15) | test.cpp:7:3:7:15 | call to for_each | The $@ of iterator range function does not point to the end of an iterator. | test.cpp:7:28:7:32 | call to begin | argument | | test.cpp:7:3:7:15 | call to for_each | The $@ of iterator range function does not point to the start of an iterator. | test.cpp:7:19:7:21 | call to end | argument | | test.cpp:8:3:8:15 | call to for_each | The $@ of iterator range function does not point to the end of an iterator. | test.cpp:8:30:8:34 | call to begin | argument | diff --git a/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected b/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected index 48da16d208..db3b7358d8 100644 --- a/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected +++ b/cpp/cert/test/rules/CTR55-CPP/DoNotUseAnAdditiveOperatorOnAnIterator.expected @@ -1,12 +1,12 @@ -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:43,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:43,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:43,51-59) WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:44,5-13) WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:44,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:44,52-60) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:79,5-13) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:79,25-33) -WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:80,7-15) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:44,51-59) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:45,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:45,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:45,52-60) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:80,5-13) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:80,25-33) +WARNING: module 'DataFlow' has been deprecated and may be removed in future (DoNotUseAnAdditiveOperatorOnAnIterator.ql:81,7-15) | test.cpp:8:7:8:7 | i | Increment of iterator may overflow since its bounds are not checked. | | test.cpp:9:9:9:9 | i | Increment of iterator may overflow since its bounds are not checked. | | test.cpp:10:9:10:9 | i | Increment of iterator may overflow since its bounds are not checked. | diff --git a/cpp/common/src/codingstandards/cpp/AccessPath.qll b/cpp/common/src/codingstandards/cpp/AccessPath.qll index ff7601ed4b..3af462e1ec 100644 --- a/cpp/common/src/codingstandards/cpp/AccessPath.qll +++ b/cpp/common/src/codingstandards/cpp/AccessPath.qll @@ -1,5 +1,5 @@ import cpp -import semmle.code.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow newtype TFieldQualifier = ExplicitQualifier(VariableAccess v) or diff --git a/cpp/common/src/codingstandards/cpp/Allocations.qll b/cpp/common/src/codingstandards/cpp/Allocations.qll index db47b0b028..decdfe9fc4 100644 --- a/cpp/common/src/codingstandards/cpp/Allocations.qll +++ b/cpp/common/src/codingstandards/cpp/Allocations.qll @@ -7,7 +7,7 @@ import cpp import semmle.code.cpp.controlflow.SSA -import semmle.code.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow /** * Holds if `alloc` is a use of `malloc` or `new`. `kind` is diff --git a/cpp/common/src/codingstandards/cpp/Concurrency.qll b/cpp/common/src/codingstandards/cpp/Concurrency.qll index 0e2afb8ece..3f7e5c1af9 100644 --- a/cpp/common/src/codingstandards/cpp/Concurrency.qll +++ b/cpp/common/src/codingstandards/cpp/Concurrency.qll @@ -1,5 +1,4 @@ import cpp -import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.concurrency.Atomic import codingstandards.cpp.concurrency.CConditionOperation import codingstandards.cpp.concurrency.ControlFlow diff --git a/cpp/common/src/codingstandards/cpp/ConstHelpers.qll b/cpp/common/src/codingstandards/cpp/ConstHelpers.qll index a7457dc845..a3d12fd127 100644 --- a/cpp/common/src/codingstandards/cpp/ConstHelpers.qll +++ b/cpp/common/src/codingstandards/cpp/ConstHelpers.qll @@ -4,7 +4,7 @@ import cpp import codingstandards.cpp.SideEffect -import semmle.code.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.FunctionParameter /** A variable that can be modified (both the pointer and object pointed to if pointer type) */ diff --git a/cpp/common/src/codingstandards/cpp/Expr.qll b/cpp/common/src/codingstandards/cpp/Expr.qll index 0b650ae41b..54ba86c5b7 100644 --- a/cpp/common/src/codingstandards/cpp/Expr.qll +++ b/cpp/common/src/codingstandards/cpp/Expr.qll @@ -1,4 +1,5 @@ import cpp +private import semmle.code.cpp.dataflow.DataFlow private import semmle.code.cpp.valuenumbering.GlobalValueNumbering import codingstandards.cpp.AccessPath diff --git a/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll b/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll index 4f99b02e2e..026fd93045 100644 --- a/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll +++ b/cpp/common/src/codingstandards/cpp/FgetsErrorManagement.qll @@ -4,7 +4,7 @@ */ import cpp -import semmle.code.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow import semmle.code.cpp.controlflow.Guards /* diff --git a/cpp/common/src/codingstandards/cpp/Iterators.qll b/cpp/common/src/codingstandards/cpp/Iterators.qll index 76751aa87b..c8c217aea4 100644 --- a/cpp/common/src/codingstandards/cpp/Iterators.qll +++ b/cpp/common/src/codingstandards/cpp/Iterators.qll @@ -3,8 +3,8 @@ */ import cpp -import semmle.code.cpp.dataflow.DataFlow -import semmle.code.cpp.dataflow.TaintTracking +private import semmle.code.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.TaintTracking import codingstandards.cpp.StdNamespace import codingstandards.cpp.rules.containeraccesswithoutrangecheck.ContainerAccessWithoutRangeCheck as ContainerAccessWithoutRangeCheck import semmle.code.cpp.controlflow.Guards @@ -16,7 +16,9 @@ abstract class ContainerAccess extends VariableAccess { } pragma[noinline, nomagic] -predicate localTaint(DataFlow::Node n1, DataFlow::Node n2) { TaintTracking::localTaint(n1, n2) } +private predicate localTaint(DataFlow::Node n1, DataFlow::Node n2) { + TaintTracking::localTaint(n1, n2) +} // define this as anything with dataflow FROM the vector class ContainerPointerOrReferenceAccess extends ContainerAccess { diff --git a/cpp/common/src/codingstandards/cpp/Overflow.qll b/cpp/common/src/codingstandards/cpp/Overflow.qll index 28a5c0d9db..b81147d6bf 100644 --- a/cpp/common/src/codingstandards/cpp/Overflow.qll +++ b/cpp/common/src/codingstandards/cpp/Overflow.qll @@ -6,7 +6,7 @@ import cpp import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis import SimpleRangeAnalysisCustomizations import semmle.code.cpp.controlflow.Guards -import semmle.code.cpp.dataflow.TaintTracking +private import semmle.code.cpp.dataflow.TaintTracking import semmle.code.cpp.valuenumbering.GlobalValueNumbering import codingstandards.cpp.Expr import codingstandards.cpp.UndefinedBehavior diff --git a/cpp/common/src/codingstandards/cpp/ReadErrorsAndEOF.qll b/cpp/common/src/codingstandards/cpp/ReadErrorsAndEOF.qll index c3c433d20d..94e7f89796 100644 --- a/cpp/common/src/codingstandards/cpp/ReadErrorsAndEOF.qll +++ b/cpp/common/src/codingstandards/cpp/ReadErrorsAndEOF.qll @@ -1,5 +1,5 @@ import cpp -import semmle.code.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.standardlibrary.FileAccess /** diff --git a/cpp/common/src/codingstandards/cpp/SideEffect.qll b/cpp/common/src/codingstandards/cpp/SideEffect.qll index d83647ce76..883004e513 100644 --- a/cpp/common/src/codingstandards/cpp/SideEffect.qll +++ b/cpp/common/src/codingstandards/cpp/SideEffect.qll @@ -1,7 +1,7 @@ /** A module to reason about side effects. */ import cpp -import semmle.code.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow private import exceptions.ExceptionFlow private import codingstandards.cpp.Expr private import codingstandards.cpp.Variable diff --git a/cpp/common/src/codingstandards/cpp/SmartPointers.qll b/cpp/common/src/codingstandards/cpp/SmartPointers.qll index 0f01d886be..a643b0bc2b 100644 --- a/cpp/common/src/codingstandards/cpp/SmartPointers.qll +++ b/cpp/common/src/codingstandards/cpp/SmartPointers.qll @@ -1,5 +1,5 @@ import cpp -import semmle.code.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.DataFlow // Local cached version of localExprFlow to avoid bad magic cached diff --git a/cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll b/cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll index 95404b114a..0aab11a269 100644 --- a/cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll +++ b/cpp/common/src/codingstandards/cpp/concurrency/LockingOperation.qll @@ -1,5 +1,5 @@ import cpp -import semmle.code.cpp.dataflow.TaintTracking +private import semmle.code.cpp.dataflow.TaintTracking abstract class LockingOperation extends FunctionCall { /** diff --git a/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.qll b/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.qll index 8bc1b0c920..759bc08deb 100644 --- a/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.qll +++ b/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointerswarn/InvalidatedEnvStringPointersWarn.qll @@ -6,7 +6,6 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions -import semmle.code.cpp.dataflow.DataFlow import codingstandards.cpp.rules.invalidatedenvstringpointers.InvalidatedEnvStringPointers as EnvString abstract class InvalidatedEnvStringPointersWarnSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/rules/predicatefunctionobjectsshouldnotbemutable/PredicateFunctionObjectsShouldNotBeMutable.qll b/cpp/common/src/codingstandards/cpp/rules/predicatefunctionobjectsshouldnotbemutable/PredicateFunctionObjectsShouldNotBeMutable.qll index bf47c1f649..ba2f6ed82a 100644 --- a/cpp/common/src/codingstandards/cpp/rules/predicatefunctionobjectsshouldnotbemutable/PredicateFunctionObjectsShouldNotBeMutable.qll +++ b/cpp/common/src/codingstandards/cpp/rules/predicatefunctionobjectsshouldnotbemutable/PredicateFunctionObjectsShouldNotBeMutable.qll @@ -9,6 +9,7 @@ import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions import codingstandards.cpp.SideEffect import codingstandards.cpp.sideeffect.DefaultEffects +import semmle.code.cpp.dataflow.DataFlow abstract class PredicateFunctionObjectsShouldNotBeMutableSharedQuery extends Query { } diff --git a/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll b/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll index 709e80dc1a..99eec1f5e0 100644 --- a/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll +++ b/cpp/common/src/codingstandards/cpp/standardlibrary/FileStreams.qll @@ -10,8 +10,8 @@ */ import cpp -import semmle.code.cpp.dataflow.DataFlow -import semmle.code.cpp.dataflow.TaintTracking +private import semmle.code.cpp.dataflow.DataFlow +private import semmle.code.cpp.dataflow.TaintTracking private import codingstandards.cpp.Operator /** From 9fa5cb207fd9a5c21fc45727402dc7d1b41ddc2c Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 10 Jul 2025 14:25:31 -0700 Subject: [PATCH 497/628] Add more test cases - 1. Assigning a char to another char - 1-1. Assigning a char to a char variable - 1-2. Assigning a char to a char member - 1-3. Assigning a char to a char through a pointer - 2. Passing a char argument to a char parameter - 2-1. Passing char argument to a char parameter of a regular function - 2-2. Passing char argument to a char parameter through a template - 2-3. Passing a char argument to a char parameter through a template --- cpp/autosar/test/rules/M5-0-12/test.cpp | 363 +++++++++++++++++++++++- 1 file changed, 353 insertions(+), 10 deletions(-) diff --git a/cpp/autosar/test/rules/M5-0-12/test.cpp b/cpp/autosar/test/rules/M5-0-12/test.cpp index 453c37bf1e..355c9cbc4f 100644 --- a/cpp/autosar/test/rules/M5-0-12/test.cpp +++ b/cpp/autosar/test/rules/M5-0-12/test.cpp @@ -1,16 +1,359 @@ #include -void f1() { - unsigned char a1 = 'c'; // NON_COMPLIANT - unsigned char a2 = 10; - signed char a3 = 'c'; // NON_COMPLIANT - signed char a4 = 10; +template class C1 { +public: + C1() : x(y) {} - std::int8_t a5 = 'c'; // NON_COMPLIANT - std::int8_t a6 = 10; +private: + unsigned char x; +}; - std::uint8_t a7 = 'c'; // NON_COMPLIANT - std::uint8_t a8 = 10; +template class C2 { +public: + C2() : x(y) {} - char a9 = 'c'; +private: + signed char x; +}; + +template class C3 { +public: + C3() : x(y) {} + +private: + unsigned char x; +}; + +template class C4 { +public: + C4() : x(y) {} + +private: + signed char x; +}; + +/* Twin templates for std::uint8_t and std::int8_t */ +template class C9 { +public: + C9() : x(y) {} + +private: + std::uint8_t x; +}; + +template class C10 { +public: + C10() : x(y) {} + +private: + std::int8_t x; +}; + +template class C11 { +public: + C11() : x(y) {} + +private: + std::uint8_t x; +}; + +template class C12 { +public: + C12() : x(y) {} + +private: + std::int8_t x; +}; + +void f1(unsigned char x) {} +void f2(signed char x) {} +void f3(unsigned char x) {} +void f4(signed char x) {} + +/* Twin functions for std::uint8_t and std::int8_t */ +void f9(std::uint8_t x) {} +void f10(std::int8_t x) {} +void f11(std::uint8_t x) {} +void f12(std::int8_t x) {} + +template void f5(T x) { unsigned char y = x; } +template void f6(T x) { signed char y = x; } +template void f7(T x) { signed char y = x; } +template void f8(T x) { signed char y = x; } + +/* Twin template functions for std::uint8_t and std::int8_t */ +template void f13(T x) { std::uint8_t y = x; } +template void f14(T x) { std::int8_t y = x; } +template void f15(T x) { std::int8_t y = x; } +template void f16(T x) { std::int8_t y = x; } + +template class C5 { +public: + C5(T y) : x(y) {} + +private: + unsigned char x; +}; + +template class C6 { +public: + C6(T y) : x(y) {} + +private: + signed char x; +}; + +template class C7 { +public: + C7(T y) : x(y) {} + +private: + signed char x; +}; + +template class C8 { +public: + C8(T y) : x(y) {} + +private: + signed char x; +}; + +/* Twin template classes for std::uint8_t and std::int8_t */ +template class C13 { +public: + C13(T y) : x(y) {} + +private: + std::uint8_t x; +}; + +template class C14 { +public: + C14(T y) : x(y) {} + +private: + std::int8_t x; +}; + +template class C15 { +public: + C15(T y) : x(y) {} + +private: + std::int8_t x; +}; + +template class C16 { +public: + C16(T y) : x(y) {} + +private: + std::int8_t x; +}; + +int main() { + + /* ========== 1. Assigning a char to another char ========== */ + + /* ===== 1-1. Assigning a char to a char variable ===== */ + + unsigned char x1 = 1; + unsigned char y1 = + x1; // COMPLIANT: unsigned char assigned to an unsigned char + + signed char x2 = 1; + signed char y2 = x2; // COMPLIANT: signed char assigned to a signed char + + char x3 = 'x'; + unsigned char y3 = x3; // NON-COMPLIANT: plain char assigned to a unsigned char + + char x4 = 'x'; + signed char y4 = x4; // NON-COMPLIANT: plain char assigned to a signed char + + /* Twin cases with std::uint8_t and std::int8_t */ + std::uint8_t x5 = 1; + std::uint8_t y5 = + x5; // COMPLIANT: std::uint8_t assigned to a std::uint8_t + + std::int8_t x6 = 1; + std::int8_t y6 = x6; // COMPLIANT: std::int8_t assigned to a std::int8_t + + char x7 = 'x'; + std::uint8_t y7 = x7; // NON-COMPLIANT: plain char assigned to a std::uint8_t + + char x8 = 'x'; + std::int8_t y8 = x8; // NON-COMPLIANT: plain char assigned to a std::int8_t + + /* ===== 1-2. Assigning a char to a char member ===== */ + + C1 c1; // COMPLIANT: unsigned char arg passed to an unsigned + // char member through a template + + C2 c2; // COMPLIANT: signed char arg passed to a signed char + // member through a template + + C3 c3; // NON-COMPLIANT: plain char arg passed to a unsigned char + // member through a template + + C4 c4; // NON-COMPLIANT: plain char arg passed to a signed char + // member through a template + + /* Twin cases with std::uint8_t and std::int8_t */ + C9 c9; // COMPLIANT: std::uint8_t arg passed to a std::uint8_t + // member through a template + + C10 c10; // COMPLIANT: std::int8_t arg passed to a std::int8_t + // member through a template + + C11 c11; // NON-COMPLIANT: plain char arg passed to a std::uint8_t + // member through a template + + C12 c12; // NON-COMPLIANT: plain char arg passed to a std::int8_t + // member through a template + + /* ========== 1-3. Assigning a char to a char through a pointer ========== */ + + unsigned char x9 = 1; + unsigned char *y9 = &x9; + signed char z1 = + *y9; // COMPLIANT: unsigned char assigned to a *&unsigned char + + unsigned char x10 = 1; + unsigned char *y10 = &x10; + signed char z2 = *y10; // COMPLIANT: signed char assigned to an *&signed char + + char x11 = 1; + char *y11 = &x11; + unsigned char z3 = + *y11; // NON-COMPLIANT: plain char assigned to an *&unsigned char + + char x12 = 1; + char *y12 = &x12; + signed char z4 = + *y12; // NON-COMPLIANT: plain char assigned to an *&signed char + + /* Twin cases with std::uint8_t and std::int8_t */ + std::uint8_t x13 = 1; + std::uint8_t *y13 = &x13; + std::int8_t z5 = + *y13; // COMPLIANT: std::uint8_t assigned to a *&std::uint8_t + + std::uint8_t x14 = 1; + std::uint8_t *y14 = &x14; + std::int8_t z6 = *y14; // COMPLIANT: std::int8_t assigned to an *&std::int8_t + + char x15 = 1; + char *y15 = &x15; + std::uint8_t z7 = + *y15; // NON-COMPLIANT: plain char assigned to an *&std::uint8_t + + char x16 = 1; + char *y16 = &x16; + std::int8_t z8 = + *y16; // NON-COMPLIANT: plain char assigned to an *&std::int8_t + + /* ========== 2. Passing a char argument to a char parameter ========== */ + + /* ===== 2-1. Passing char argument to a char parameter of a regular function + * ===== */ + + unsigned char a1 = 1; + f1(a1); // COMPLIANT: unsigned char arg passed to an unsigned char parameter + + signed char a2 = 1; + f2(a2); // COMPLIANT: signed char arg passed to a signed char parameter + + char a3 = 'a'; + f3(a3); // NON-COMPLIANT: plain char arg passed to a unsigned char parameter + + char a4 = 'a'; + f4(a4); // NON-COMPLIANT: plain char arg passed to a signed char parameter + + /* Twin cases with std::uint8_t and std::int8_t */ + std::uint8_t a5 = 1; + f9(a5); // COMPLIANT: std::uint8_t arg passed to a std::uint8_t parameter + + std::int8_t a6 = 1; + f10(a6); // COMPLIANT: std::int8_t arg passed to a std::int8_t parameter + + char a7 = 'a'; + f11(a7); // NON-COMPLIANT: plain char arg passed to a std::uint8_t parameter + + char a8 = 'a'; + f12(a8); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter + + /* ===== 2-2. Passing char argument to a char parameter through a template + * ===== */ + + unsigned char a9 = 'a'; + f5(a9); // COMPLIANT: unsigned char arg passed to an unsigned char parameter + // through a template + + signed char a10 = 'a'; + f6(a10); // COMPLIANT: signed char arg passed to a signed char parameter + // through a template + + char a11 = 'a'; + f7(a11); // NON-COMPLIANT: plain char arg passed to a unsigned char parameter + // through a template + + char a12 = 'a'; + f8(a12); // COMPLIANT: plain char arg passed to a signed char parameter through + // a template + + /* Twin cases with std::uint8_t and std::int8_t */ + std::uint8_t a13 = 'a'; + f13(a13); // COMPLIANT: std::uint8_t arg passed to a std::uint8_t parameter + // through a template + + std::int8_t a14 = 'a'; + f14(a14); // COMPLIANT: std::int8_t arg passed to a std::int8_t parameter + // through a template + + char a15 = 'a'; + f15(a15); // NON-COMPLIANT: plain char arg passed to a std::uint8_t parameter + // through a template + + char a16 = 'a'; + f16(a16); // COMPLIANT: plain char arg passed to a std::int8_t parameter through + // a template + + /* ========== 2-3. Passing a char argument to a char parameter through a + * template ========== */ + + unsigned char a17 = 1; + C5 c5( + a17); // COMPLIANT: unsigned char arg passed to an unsigned char parameter + // of a constructor through a template + + signed char a18 = 1; + C6 c6(a18); // COMPLIANT: signed char arg passed to an signed + // char parameter of a constructor through a template + + char a19 = 'a'; + C7 c7(a19); // NON-COMPLIANT: plain char arg passed to an unsigned char + // parameter of a constructor through a template + + char a20 = 'a'; + C8 c8(a20); // NON-COMPLIANT: plain char arg passed to an signed char + // parameter of a constructor through a template + + /* Twin cases with std::uint8_t and std::int8_t */ + std::uint8_t a21 = 1; + C13 c13( + a21); // COMPLIANT: std::uint8_t arg passed to a std::uint8_t parameter + // of a constructor through a template + + std::int8_t a22 = 1; + C14 c14(a22); // COMPLIANT: std::int8_t arg passed to a std::int8_t + // parameter of a constructor through a template + + char a23 = 'a'; + C15 c15(a23); // NON-COMPLIANT: plain char arg passed to a std::uint8_t + // parameter of a constructor through a template + + char a24 = 'a'; + C16 c16(a24); // NON-COMPLIANT: plain char arg passed to a std::int8_t + // parameter of a constructor through a template } \ No newline at end of file From fb544876bb2ce448934362c7ce5ce495803a807c Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 10 Jul 2025 14:39:44 -0700 Subject: [PATCH 498/628] Renumber definitions and objects, and fix wrong labels --- cpp/autosar/test/rules/M5-0-12/test.cpp | 70 ++++++++++++------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/cpp/autosar/test/rules/M5-0-12/test.cpp b/cpp/autosar/test/rules/M5-0-12/test.cpp index 355c9cbc4f..57530dae16 100644 --- a/cpp/autosar/test/rules/M5-0-12/test.cpp +++ b/cpp/autosar/test/rules/M5-0-12/test.cpp @@ -33,33 +33,33 @@ template class C4 { }; /* Twin templates for std::uint8_t and std::int8_t */ -template class C9 { +template class C5 { public: - C9() : x(y) {} + C5() : x(y) {} private: std::uint8_t x; }; -template class C10 { +template class C6 { public: - C10() : x(y) {} + C6() : x(y) {} private: std::int8_t x; }; -template class C11 { +template class C7 { public: - C11() : x(y) {} + C7() : x(y) {} private: std::uint8_t x; }; -template class C12 { +template class C8 { public: - C12() : x(y) {} + C8() : x(y) {} private: std::int8_t x; @@ -87,33 +87,33 @@ template void f14(T x) { std::int8_t y = x; } template void f15(T x) { std::int8_t y = x; } template void f16(T x) { std::int8_t y = x; } -template class C5 { +template class C9 { public: - C5(T y) : x(y) {} + C9(T y) : x(y) {} private: unsigned char x; }; -template class C6 { +template class C10 { public: - C6(T y) : x(y) {} + C10(T y) : x(y) {} private: signed char x; }; -template class C7 { +template class C11 { public: - C7(T y) : x(y) {} + C11(T y) : x(y) {} private: signed char x; }; -template class C8 { +template class C12 { public: - C8(T y) : x(y) {} + C12(T y) : x(y) {} private: signed char x; @@ -200,27 +200,27 @@ int main() { // member through a template /* Twin cases with std::uint8_t and std::int8_t */ - C9 c9; // COMPLIANT: std::uint8_t arg passed to a std::uint8_t + C5 c5; // COMPLIANT: std::uint8_t arg passed to a std::uint8_t // member through a template - C10 c10; // COMPLIANT: std::int8_t arg passed to a std::int8_t + C6 c6; // COMPLIANT: std::int8_t arg passed to a std::int8_t // member through a template - C11 c11; // NON-COMPLIANT: plain char arg passed to a std::uint8_t + C7 c7; // NON-COMPLIANT: plain char arg passed to a std::uint8_t // member through a template - C12 c12; // NON-COMPLIANT: plain char arg passed to a std::int8_t + C8 c8; // NON-COMPLIANT: plain char arg passed to a std::int8_t // member through a template /* ========== 1-3. Assigning a char to a char through a pointer ========== */ unsigned char x9 = 1; unsigned char *y9 = &x9; - signed char z1 = + unsigned char z1 = *y9; // COMPLIANT: unsigned char assigned to a *&unsigned char - unsigned char x10 = 1; - unsigned char *y10 = &x10; + signed char x10 = 1; + signed char *y10 = &x10; signed char z2 = *y10; // COMPLIANT: signed char assigned to an *&signed char char x11 = 1; @@ -236,11 +236,11 @@ int main() { /* Twin cases with std::uint8_t and std::int8_t */ std::uint8_t x13 = 1; std::uint8_t *y13 = &x13; - std::int8_t z5 = + std::uint8_t z5 = *y13; // COMPLIANT: std::uint8_t assigned to a *&std::uint8_t - std::uint8_t x14 = 1; - std::uint8_t *y14 = &x14; + std::int8_t x14 = 1; + std::int8_t *y14 = &x14; std::int8_t z6 = *y14; // COMPLIANT: std::int8_t assigned to an *&std::int8_t char x15 = 1; @@ -295,11 +295,11 @@ int main() { // through a template char a11 = 'a'; - f7(a11); // NON-COMPLIANT: plain char arg passed to a unsigned char parameter + f7(a11); // NON-COMPLIANT: plain char arg passed to a signed char parameter // through a template char a12 = 'a'; - f8(a12); // COMPLIANT: plain char arg passed to a signed char parameter through + f8(a12); // NON-COMPLIANT: plain char arg passed to a signed char parameter through // a template /* Twin cases with std::uint8_t and std::int8_t */ @@ -312,31 +312,31 @@ int main() { // through a template char a15 = 'a'; - f15(a15); // NON-COMPLIANT: plain char arg passed to a std::uint8_t parameter + f15(a15); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter // through a template char a16 = 'a'; - f16(a16); // COMPLIANT: plain char arg passed to a std::int8_t parameter through + f16(a16); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter through // a template /* ========== 2-3. Passing a char argument to a char parameter through a * template ========== */ unsigned char a17 = 1; - C5 c5( + C9 c9( a17); // COMPLIANT: unsigned char arg passed to an unsigned char parameter // of a constructor through a template signed char a18 = 1; - C6 c6(a18); // COMPLIANT: signed char arg passed to an signed + C10 c10(a18); // COMPLIANT: signed char arg passed to an signed // char parameter of a constructor through a template char a19 = 'a'; - C7 c7(a19); // NON-COMPLIANT: plain char arg passed to an unsigned char + C11 c11(a19); // NON-COMPLIANT: plain char arg passed to a signed char // parameter of a constructor through a template char a20 = 'a'; - C8 c8(a20); // NON-COMPLIANT: plain char arg passed to an signed char + C12 c12(a20); // NON-COMPLIANT: plain char arg passed to an signed char // parameter of a constructor through a template /* Twin cases with std::uint8_t and std::int8_t */ @@ -350,7 +350,7 @@ int main() { // parameter of a constructor through a template char a23 = 'a'; - C15 c15(a23); // NON-COMPLIANT: plain char arg passed to a std::uint8_t + C15 c15(a23); // NON-COMPLIANT: plain char arg passed to a std::int8_t // parameter of a constructor through a template char a24 = 'a'; From 808b5fd13a620c6401af427b676d871861f9b6a5 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 10 Jul 2025 14:56:37 -0700 Subject: [PATCH 499/628] Fix cases 1. Change signed char / int8_t case to their opposites. 2. Assign a numeral to the unsigned char / signed char than a character. --- cpp/autosar/test/rules/M5-0-12/test.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cpp/autosar/test/rules/M5-0-12/test.cpp b/cpp/autosar/test/rules/M5-0-12/test.cpp index 57530dae16..99cb995854 100644 --- a/cpp/autosar/test/rules/M5-0-12/test.cpp +++ b/cpp/autosar/test/rules/M5-0-12/test.cpp @@ -78,13 +78,13 @@ void f12(std::int8_t x) {} template void f5(T x) { unsigned char y = x; } template void f6(T x) { signed char y = x; } -template void f7(T x) { signed char y = x; } +template void f7(T x) { unsigned char y = x; } template void f8(T x) { signed char y = x; } /* Twin template functions for std::uint8_t and std::int8_t */ template void f13(T x) { std::uint8_t y = x; } template void f14(T x) { std::int8_t y = x; } -template void f15(T x) { std::int8_t y = x; } +template void f15(T x) { std::uint8_t y = x; } template void f16(T x) { std::int8_t y = x; } template class C9 { @@ -286,16 +286,16 @@ int main() { /* ===== 2-2. Passing char argument to a char parameter through a template * ===== */ - unsigned char a9 = 'a'; + unsigned char a9 = 1; f5(a9); // COMPLIANT: unsigned char arg passed to an unsigned char parameter // through a template - signed char a10 = 'a'; + signed char a10 = 1; f6(a10); // COMPLIANT: signed char arg passed to a signed char parameter // through a template char a11 = 'a'; - f7(a11); // NON-COMPLIANT: plain char arg passed to a signed char parameter + f7(a11); // NON-COMPLIANT: plain char arg passed to an unsigned char parameter // through a template char a12 = 'a'; @@ -303,16 +303,16 @@ int main() { // a template /* Twin cases with std::uint8_t and std::int8_t */ - std::uint8_t a13 = 'a'; + std::uint8_t a13 = 1; f13(a13); // COMPLIANT: std::uint8_t arg passed to a std::uint8_t parameter // through a template - std::int8_t a14 = 'a'; + std::int8_t a14 = 1; f14(a14); // COMPLIANT: std::int8_t arg passed to a std::int8_t parameter // through a template char a15 = 'a'; - f15(a15); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter + f15(a15); // NON-COMPLIANT: plain char arg passed to a std::uint8_t parameter // through a template char a16 = 'a'; From da92563a2f0d915e6523d79d08ba44a5cd546d40 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Fri, 11 Jul 2025 00:19:47 +0200 Subject: [PATCH 500/628] Fix misspelling of asynchronous in SIG30-C --- .../CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql | 8 ++++---- ...allOnlyAsyncSafeFunctionsWithinSignalHandlers.expected | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql b/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql index 4cc0f9e32c..e5dc33f817 100644 --- a/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql +++ b/c/cert/src/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql @@ -37,7 +37,7 @@ class AsyncSafeVariableAccess extends VariableAccess { abstract class AsyncSafeFunction extends Function { } /** - * C standard library ayncronous-safe functions + * C standard library asynchronous-safe functions */ class CAsyncSafeFunction extends AsyncSafeFunction { //tion, or the signal function with the first argument equal to the signal number corresponding to the signal that caused the invocation of the handler @@ -45,7 +45,7 @@ class CAsyncSafeFunction extends AsyncSafeFunction { } /** - * POSIX defined ayncronous-safe functions + * POSIX defined asynchronous-safe functions */ class PosixAsyncSafeFunction extends AsyncSafeFunction { PosixAsyncSafeFunction() { @@ -73,7 +73,7 @@ class PosixAsyncSafeFunction extends AsyncSafeFunction { } /** - * Application defined ayncronous-safe functions + * Application defined asynchronous-safe functions */ class ApplicationAsyncSafeFunction extends AsyncSafeFunction { pragma[nomagic] @@ -122,5 +122,5 @@ where or fc instanceof AsyncUnsafeRaiseCall ) -select fc, "Asyncronous-unsafe function calls within a $@ can lead to undefined behavior.", +select fc, "Asynchronous-unsafe function calls within a $@ can lead to undefined behavior.", handler.getRegistration(), "signal handler" diff --git a/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected b/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected index 4898448814..ce13ee69a7 100644 --- a/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected +++ b/c/cert/test/rules/SIG30-C/CallOnlyAsyncSafeFunctionsWithinSignalHandlers.expected @@ -1,7 +1,7 @@ WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:110,11-19) WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:110,31-39) WARNING: module 'DataFlow' has been deprecated and may be removed in future (CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql:111,9-17) -| test.c:10:3:10:18 | call to log_local_unsafe | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:16:7:16:12 | call to signal | signal handler | -| test.c:11:3:11:6 | call to free | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:16:7:16:12 | call to signal | signal handler | -| test.c:46:3:46:9 | call to longjmp | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:50:7:50:12 | call to signal | signal handler | -| test.c:76:7:76:11 | call to raise | Asyncronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:91:7:91:12 | call to signal | signal handler | +| test.c:10:3:10:18 | call to log_local_unsafe | Asynchronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:16:7:16:12 | call to signal | signal handler | +| test.c:11:3:11:6 | call to free | Asynchronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:16:7:16:12 | call to signal | signal handler | +| test.c:46:3:46:9 | call to longjmp | Asynchronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:50:7:50:12 | call to signal | signal handler | +| test.c:76:7:76:11 | call to raise | Asynchronous-unsafe function calls within a $@ can lead to undefined behavior. | test.c:91:7:91:12 | call to signal | signal handler | From 56258d17d63e8017e58bf5d93626297416677756 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Fri, 11 Jul 2025 15:31:16 +0200 Subject: [PATCH 501/628] Add change note --- change_notes/2025-07-11-typo-in-alert-message..md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 change_notes/2025-07-11-typo-in-alert-message..md diff --git a/change_notes/2025-07-11-typo-in-alert-message..md b/change_notes/2025-07-11-typo-in-alert-message..md new file mode 100644 index 0000000000..077f2efb66 --- /dev/null +++ b/change_notes/2025-07-11-typo-in-alert-message..md @@ -0,0 +1,2 @@ +- `SIG30-C`: `CallOnlyAsyncSafeFunctionsWithinSignalHandlers.ql` + - Fixed a misspelling of "asynchronous" in the alert message. From 80029970d8bf7f242cb4de49e8b0a3c3bbbf9c6e Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 11 Jul 2025 16:43:26 -0700 Subject: [PATCH 502/628] Add a working draft of the query --- ...eUsedForTheStorageAndUseOfNumericValues.ql | 207 ++++++++++++++++-- 1 file changed, 189 insertions(+), 18 deletions(-) diff --git a/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql b/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql index 3b6e436c56..7ffc47e50f 100644 --- a/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql +++ b/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql @@ -16,23 +16,194 @@ import cpp import codingstandards.cpp.autosar -from Variable v, Expr aexp +newtype TTemplatedElement = + TClassTemplate(TemplateClass c) or + TFunctionTemplate(TemplateFunction f) or + TVariableTemplate(TemplateVariable v) + +class TemplatedElement extends TTemplatedElement { + TemplateClass asTemplateClass() { this = TClassTemplate(result) } + + TemplateFunction asTemplateFunction() { this = TFunctionTemplate(result) } + + TemplateVariable asTemplateVariable() { this = TVariableTemplate(result) } + + string toString() { + result = this.asTemplateClass().toString() or + result = this.asTemplateFunction().toString() or + result = this.asTemplateVariable().toString() + } + + Location getLocation() { + result = this.asTemplateClass().getLocation() or + result = this.asTemplateFunction().getLocation() or + result = this.asTemplateVariable().getLocation() + } + + string getName() { + result = this.asTemplateClass().getName() or + result = this.asTemplateFunction().getName() or + result = this.asTemplateVariable().getName() + } +} + +newtype TTemplateInstantiation = + TClassTemplateInstantiation(ClassTemplateInstantiation c) or + TFunctionTemplateInstantiation(FunctionTemplateInstantiation f) or + TVariableTemplateInstantiation(VariableTemplateInstantiation v) + +class TemplateInstantiation extends TTemplateInstantiation { + ClassTemplateInstantiation asClassTemplateInstantiation() { + this = TClassTemplateInstantiation(result) + } + + FunctionTemplateInstantiation asFunctionTemplateInstantiation() { + this = TFunctionTemplateInstantiation(result) + } + + VariableTemplateInstantiation asVariableTemplateInstantiation() { + this = TVariableTemplateInstantiation(result) + } + + string toString() { + result = this.asClassTemplateInstantiation().toString() or + result = this.asFunctionTemplateInstantiation().toString() or + result = this.asVariableTemplateInstantiation().toString() + } + + Location getLocation() { + result = this.asClassTemplateInstantiation().getLocation() or + result = this.asFunctionTemplateInstantiation().getLocation() or + result = this.asVariableTemplateInstantiation().getLocation() + } + + Element asElement() { + result = this.asClassTemplateInstantiation() or + result = this.asFunctionTemplateInstantiation() or + result = this.asVariableTemplateInstantiation() + } + + TemplatedElement getTemplate() { + result.asTemplateClass() = this.asClassTemplateInstantiation().getTemplate() or + result.asTemplateFunction() = this.asFunctionTemplateInstantiation().getTemplate() or + result.asTemplateVariable() = this.asVariableTemplateInstantiation().getTemplate() + } + + /** + * Gets a use of an instantiation of this template. i.e. + * 1. For a class template, it's where the instantiated type is used by the name. + * 2. For a function template, it's where the instantiated function is called. + * 3. For a variable template, it's where the instantiated variable is initialized. + */ + Element getAUse() { + result = this.asClassTemplateInstantiation().getATypeNameUse() or + result = this.asFunctionTemplateInstantiation().getACallToThisFunction() or + result = this.asVariableTemplateInstantiation() + } +} + +class ImplicitConversionFromPlainCharType extends Conversion { + ImplicitConversionFromPlainCharType() { + this.isImplicit() and + this.getExpr().getUnspecifiedType() instanceof PlainCharType and + ( + this.getUnspecifiedType() instanceof SignedCharType or + this.getUnspecifiedType() instanceof UnsignedCharType + ) + } +} + +newtype TImplicitConversionElement = + TImplicitConversionOutsideTemplate(ImplicitConversionFromPlainCharType implicitConversion) { + not exists(TemplateInstantiation instantiation | + implicitConversion.isFromTemplateInstantiation(instantiation.asElement()) + ) + } or + TInstantiationOfImplicitConversionTemplate( + TemplateInstantiation templateInstantiation, + ImplicitConversionFromPlainCharType implicitConversion + ) { + implicitConversion.getEnclosingElement+() = templateInstantiation.asElement() + } + +class ImplicitConversionLocation extends TImplicitConversionElement { + ImplicitConversionFromPlainCharType asImplicitConversionOutsideTemplate() { + this = TImplicitConversionOutsideTemplate(result) + } + + TemplateInstantiation asInstantiationOfImplicitConversionTemplate( + ImplicitConversionFromPlainCharType implicitConversion + ) { + this = TInstantiationOfImplicitConversionTemplate(result, implicitConversion) + } + + predicate isImplicitConversionOutsideTemplate() { + exists(this.asImplicitConversionOutsideTemplate()) + } + + predicate isInstantiationOfImplicitConversionTemplate() { + exists( + TemplateInstantiation templateInstantiation, + ImplicitConversionFromPlainCharType implicitConversion + | + templateInstantiation = this.asInstantiationOfImplicitConversionTemplate(implicitConversion) + ) + } + + ImplicitConversionFromPlainCharType getImplicitConversion() { + result = this.asImplicitConversionOutsideTemplate() or + exists(TemplateInstantiation templateInstantiation | + this = TInstantiationOfImplicitConversionTemplate(templateInstantiation, result) + ) + } + + string toString() { + result = this.asImplicitConversionOutsideTemplate().toString() or + exists(ImplicitConversionFromPlainCharType implicitConversion | + result = this.asInstantiationOfImplicitConversionTemplate(implicitConversion).toString() + ) + } + + Location getLocation() { + result = this.asImplicitConversionOutsideTemplate().getLocation() or + exists(ImplicitConversionFromPlainCharType implicitConversion | + result = this.asInstantiationOfImplicitConversionTemplate(implicitConversion).getLocation() + ) + } + + Element asElement() { + result = this.asImplicitConversionOutsideTemplate() or + exists(ImplicitConversionFromPlainCharType implicitConversion | + result = this.asInstantiationOfImplicitConversionTemplate(implicitConversion).getAUse() + ) + } +} + +string getMessageTemplate(ImplicitConversionLocation implicitConversionLocation) { + exists(ImplicitConversionFromPlainCharType implicitConversion | + implicitConversion = implicitConversionLocation.getImplicitConversion() + | + implicitConversionLocation.isImplicitConversionOutsideTemplate() and + result = + "Implicit conversion of plain char $@ to " + implicitConversion.getType().getName() + "." + or + implicitConversionLocation.isInstantiationOfImplicitConversionTemplate() and + result = + "Implicit conversion of plain char $@ to " + implicitConversion.getType().getName() + + " from instantiating template '" + + implicitConversionLocation + .asInstantiationOfImplicitConversionTemplate(implicitConversion) + .getTemplate() + .getName() + "'." + ) +} + +from + ImplicitConversionLocation implicitConversionLocation, + ImplicitConversionFromPlainCharType implicitConversion where - not isExcluded(v, + not isExcluded(implicitConversionLocation.asElement(), StringsPackage::signedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValuesQuery()) and - // We find cases where it is an explicitly signed char type with an assignment - // to a non-numeric type. NOTE: This rule addresses cases where the char type - // is used character data only, the rule does not explicitly cover this. - // Please see M5-0-11 for explicit handling of this case. Get types that are - // char, except for ones that are 'plain', meaning the sign is explicit. - ( - v.getUnspecifiedType() instanceof SignedCharType or - v.getUnspecifiedType() instanceof UnsignedCharType - ) and - // Identify places where these explicitly signed types are being assigned to a - // non-numeric type. - aexp = v.getAnAssignedValue() and - aexp.getUnspecifiedType() instanceof CharType -select aexp, - "Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type", - v, v.getName() + implicitConversion = implicitConversionLocation.getImplicitConversion() +select implicitConversionLocation.asElement(), getMessageTemplate(implicitConversionLocation), + implicitConversion.getExpr(), "expression" From 2ed4443c02d8e1b31cf2058d8321e61d99573a92 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 14 Jul 2025 10:01:00 -0400 Subject: [PATCH 503/628] Deduplicate the test cases and update the expected results. --- ...orTheStorageAndUseOfNumericValues.expected | 28 +++- cpp/autosar/test/rules/M5-0-12/test.cpp | 121 +++++------------- 2 files changed, 54 insertions(+), 95 deletions(-) diff --git a/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected b/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected index 1be5b7b9fc..cafd6c64b2 100644 --- a/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected +++ b/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected @@ -1,4 +1,24 @@ -| test.cpp:4:22:4:24 | 99 | Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type | test.cpp:4:17:4:18 | a1 | a1 | -| test.cpp:6:20:6:22 | 99 | Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type | test.cpp:6:15:6:16 | a3 | a3 | -| test.cpp:9:20:9:22 | 99 | Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type | test.cpp:9:15:9:16 | a5 | a5 | -| test.cpp:12:21:12:23 | 99 | Assignment of an non-integer type to variable $@ which is a variable with an explicitly signed char type | test.cpp:12:16:12:17 | a7 | a7 | +| test.cpp:106:7:106:8 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:106:7:106:8 | x3 | expression | +| test.cpp:109:20:109:21 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:109:20:109:21 | x4 | expression | +| test.cpp:119:21:119:22 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:119:21:119:22 | x7 | expression | +| test.cpp:122:20:122:21 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:122:20:122:21 | x8 | expression | +| test.cpp:132:17:132:18 | definition of c3 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'C1'. | test.cpp:5:12:5:12 | 120 | expression | +| test.cpp:135:17:135:18 | definition of c4 | Implicit conversion of plain char $@ to signed char from instantiating template 'C2'. | test.cpp:13:12:13:12 | 120 | expression | +| test.cpp:145:15:145:16 | definition of c7 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'C5'. | test.cpp:22:12:22:12 | 1 | expression | +| test.cpp:148:15:148:16 | definition of c8 | Implicit conversion of plain char $@ to int8_t from instantiating template 'C6'. | test.cpp:30:12:30:12 | 1 | expression | +| test.cpp:165:7:165:10 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:165:7:165:10 | * ... | expression | +| test.cpp:170:7:170:10 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:170:7:170:10 | * ... | expression | +| test.cpp:185:7:185:10 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:185:7:185:10 | * ... | expression | +| test.cpp:190:7:190:10 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:190:7:190:10 | * ... | expression | +| test.cpp:204:6:204:7 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:204:6:204:7 | a3 | expression | +| test.cpp:207:6:207:7 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:207:6:207:7 | a4 | expression | +| test.cpp:217:7:217:8 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:217:7:217:8 | a7 | expression | +| test.cpp:220:7:220:8 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:220:7:220:8 | a8 | expression | +| test.cpp:234:3:234:4 | call to f7 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'f7'. | test.cpp:49:56:49:56 | x | expression | +| test.cpp:238:3:238:4 | call to f8 | Implicit conversion of plain char $@ to signed char from instantiating template 'f8'. | test.cpp:50:54:50:54 | x | expression | +| test.cpp:251:3:251:5 | call to f15 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'f15'. | test.cpp:55:56:55:56 | x | expression | +| test.cpp:255:3:255:5 | call to f16 | Implicit conversion of plain char $@ to int8_t from instantiating template 'f16'. | test.cpp:56:55:56:55 | x | expression | +| test.cpp:272:12:272:14 | definition of c11 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'C9'. | test.cpp:60:15:60:15 | y | expression | +| test.cpp:277:13:277:15 | definition of c12 | Implicit conversion of plain char $@ to signed char from instantiating template 'C10'. | test.cpp:68:16:68:16 | y | expression | +| test.cpp:292:13:292:15 | definition of c15 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'C13'. | test.cpp:77:16:77:16 | y | expression | +| test.cpp:296:13:296:15 | definition of c16 | Implicit conversion of plain char $@ to int8_t from instantiating template 'C14'. | test.cpp:85:16:85:16 | y | expression | diff --git a/cpp/autosar/test/rules/M5-0-12/test.cpp b/cpp/autosar/test/rules/M5-0-12/test.cpp index 99cb995854..91106b8211 100644 --- a/cpp/autosar/test/rules/M5-0-12/test.cpp +++ b/cpp/autosar/test/rules/M5-0-12/test.cpp @@ -16,22 +16,6 @@ template class C2 { signed char x; }; -template class C3 { -public: - C3() : x(y) {} - -private: - unsigned char x; -}; - -template class C4 { -public: - C4() : x(y) {} - -private: - signed char x; -}; - /* Twin templates for std::uint8_t and std::int8_t */ template class C5 { public: @@ -49,22 +33,6 @@ template class C6 { std::int8_t x; }; -template class C7 { -public: - C7() : x(y) {} - -private: - std::uint8_t x; -}; - -template class C8 { -public: - C8() : x(y) {} - -private: - std::int8_t x; -}; - void f1(unsigned char x) {} void f2(signed char x) {} void f3(unsigned char x) {} @@ -103,22 +71,6 @@ template class C10 { signed char x; }; -template class C11 { -public: - C11(T y) : x(y) {} - -private: - signed char x; -}; - -template class C12 { -public: - C12(T y) : x(y) {} - -private: - signed char x; -}; - /* Twin template classes for std::uint8_t and std::int8_t */ template class C13 { public: @@ -136,22 +88,6 @@ template class C14 { std::int8_t x; }; -template class C15 { -public: - C15(T y) : x(y) {} - -private: - std::int8_t x; -}; - -template class C16 { -public: - C16(T y) : x(y) {} - -private: - std::int8_t x; -}; - int main() { /* ========== 1. Assigning a char to another char ========== */ @@ -166,15 +102,15 @@ int main() { signed char y2 = x2; // COMPLIANT: signed char assigned to a signed char char x3 = 'x'; - unsigned char y3 = x3; // NON-COMPLIANT: plain char assigned to a unsigned char + unsigned char y3 = + x3; // NON-COMPLIANT: plain char assigned to a unsigned char char x4 = 'x'; signed char y4 = x4; // NON-COMPLIANT: plain char assigned to a signed char /* Twin cases with std::uint8_t and std::int8_t */ std::uint8_t x5 = 1; - std::uint8_t y5 = - x5; // COMPLIANT: std::uint8_t assigned to a std::uint8_t + std::uint8_t y5 = x5; // COMPLIANT: std::uint8_t assigned to a std::uint8_t std::int8_t x6 = 1; std::int8_t y6 = x6; // COMPLIANT: std::int8_t assigned to a std::int8_t @@ -193,24 +129,24 @@ int main() { C2 c2; // COMPLIANT: signed char arg passed to a signed char // member through a template - C3 c3; // NON-COMPLIANT: plain char arg passed to a unsigned char + C1 c3; // NON-COMPLIANT: plain char arg passed to a unsigned char // member through a template - C4 c4; // NON-COMPLIANT: plain char arg passed to a signed char + C2 c4; // NON-COMPLIANT: plain char arg passed to a signed char // member through a template /* Twin cases with std::uint8_t and std::int8_t */ - C5 c5; // COMPLIANT: std::uint8_t arg passed to a std::uint8_t - // member through a template + C5 c5; // COMPLIANT: std::uint8_t arg passed to a + // std::uint8_t member through a template C6 c6; // COMPLIANT: std::int8_t arg passed to a std::int8_t - // member through a template + // member through a template - C7 c7; // NON-COMPLIANT: plain char arg passed to a std::uint8_t - // member through a template + C5 c7; // NON-COMPLIANT: plain char arg passed to a + // std::uint8_t member through a template - C8 c8; // NON-COMPLIANT: plain char arg passed to a std::int8_t - // member through a template + C6 c8; // NON-COMPLIANT: plain char arg passed to a std::int8_t + // member through a template /* ========== 1-3. Assigning a char to a char through a pointer ========== */ @@ -299,8 +235,8 @@ int main() { // through a template char a12 = 'a'; - f8(a12); // NON-COMPLIANT: plain char arg passed to a signed char parameter through - // a template + f8(a12); // NON-COMPLIANT: plain char arg passed to a signed char parameter + // through a template /* Twin cases with std::uint8_t and std::int8_t */ std::uint8_t a13 = 1; @@ -316,8 +252,8 @@ int main() { // through a template char a16 = 'a'; - f16(a16); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter through - // a template + f16(a16); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter + // through a template /* ========== 2-3. Passing a char argument to a char parameter through a * template ========== */ @@ -328,16 +264,18 @@ int main() { // of a constructor through a template signed char a18 = 1; - C10 c10(a18); // COMPLIANT: signed char arg passed to an signed - // char parameter of a constructor through a template + C10 c10( + a18); // COMPLIANT: signed char arg passed to an signed + // char parameter of a constructor through a template char a19 = 'a'; - C11 c11(a19); // NON-COMPLIANT: plain char arg passed to a signed char - // parameter of a constructor through a template + C9 c11( + a19); // NON-COMPLIANT: plain char arg passed to a unsigned signed char + // parameter of a constructor through a template char a20 = 'a'; - C12 c12(a20); // NON-COMPLIANT: plain char arg passed to an signed char - // parameter of a constructor through a template + C10 c12(a20); // NON-COMPLIANT: plain char arg passed to an signed char + // parameter of a constructor through a template /* Twin cases with std::uint8_t and std::int8_t */ std::uint8_t a21 = 1; @@ -346,14 +284,15 @@ int main() { // of a constructor through a template std::int8_t a22 = 1; - C14 c14(a22); // COMPLIANT: std::int8_t arg passed to a std::int8_t - // parameter of a constructor through a template + C14 c14( + a22); // COMPLIANT: std::int8_t arg passed to a std::int8_t + // parameter of a constructor through a template char a23 = 'a'; - C15 c15(a23); // NON-COMPLIANT: plain char arg passed to a std::int8_t + C13 c15(a23); // NON-COMPLIANT: plain char arg passed to a std::uint8_t // parameter of a constructor through a template char a24 = 'a'; - C16 c16(a24); // NON-COMPLIANT: plain char arg passed to a std::int8_t + C14 c16(a24); // NON-COMPLIANT: plain char arg passed to a std::int8_t // parameter of a constructor through a template -} \ No newline at end of file +} From 11a277f4289d3be792c3c74c34966f703873b2f8 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 14 Jul 2025 10:23:11 -0400 Subject: [PATCH 504/628] Deduplicate more test cases and fix expected results --- ...orTheStorageAndUseOfNumericValues.expected | 48 +++++++++---------- cpp/autosar/test/rules/M5-0-12/test.cpp | 24 ++++------ 2 files changed, 32 insertions(+), 40 deletions(-) diff --git a/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected b/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected index cafd6c64b2..d5dc9af7e8 100644 --- a/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected +++ b/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected @@ -1,24 +1,24 @@ -| test.cpp:106:7:106:8 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:106:7:106:8 | x3 | expression | -| test.cpp:109:20:109:21 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:109:20:109:21 | x4 | expression | -| test.cpp:119:21:119:22 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:119:21:119:22 | x7 | expression | -| test.cpp:122:20:122:21 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:122:20:122:21 | x8 | expression | -| test.cpp:132:17:132:18 | definition of c3 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'C1'. | test.cpp:5:12:5:12 | 120 | expression | -| test.cpp:135:17:135:18 | definition of c4 | Implicit conversion of plain char $@ to signed char from instantiating template 'C2'. | test.cpp:13:12:13:12 | 120 | expression | -| test.cpp:145:15:145:16 | definition of c7 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'C5'. | test.cpp:22:12:22:12 | 1 | expression | -| test.cpp:148:15:148:16 | definition of c8 | Implicit conversion of plain char $@ to int8_t from instantiating template 'C6'. | test.cpp:30:12:30:12 | 1 | expression | -| test.cpp:165:7:165:10 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:165:7:165:10 | * ... | expression | -| test.cpp:170:7:170:10 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:170:7:170:10 | * ... | expression | -| test.cpp:185:7:185:10 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:185:7:185:10 | * ... | expression | -| test.cpp:190:7:190:10 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:190:7:190:10 | * ... | expression | -| test.cpp:204:6:204:7 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:204:6:204:7 | a3 | expression | -| test.cpp:207:6:207:7 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:207:6:207:7 | a4 | expression | -| test.cpp:217:7:217:8 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:217:7:217:8 | a7 | expression | -| test.cpp:220:7:220:8 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:220:7:220:8 | a8 | expression | -| test.cpp:234:3:234:4 | call to f7 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'f7'. | test.cpp:49:56:49:56 | x | expression | -| test.cpp:238:3:238:4 | call to f8 | Implicit conversion of plain char $@ to signed char from instantiating template 'f8'. | test.cpp:50:54:50:54 | x | expression | -| test.cpp:251:3:251:5 | call to f15 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'f15'. | test.cpp:55:56:55:56 | x | expression | -| test.cpp:255:3:255:5 | call to f16 | Implicit conversion of plain char $@ to int8_t from instantiating template 'f16'. | test.cpp:56:55:56:55 | x | expression | -| test.cpp:272:12:272:14 | definition of c11 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'C9'. | test.cpp:60:15:60:15 | y | expression | -| test.cpp:277:13:277:15 | definition of c12 | Implicit conversion of plain char $@ to signed char from instantiating template 'C10'. | test.cpp:68:16:68:16 | y | expression | -| test.cpp:292:13:292:15 | definition of c15 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'C13'. | test.cpp:77:16:77:16 | y | expression | -| test.cpp:296:13:296:15 | definition of c16 | Implicit conversion of plain char $@ to int8_t from instantiating template 'C14'. | test.cpp:85:16:85:16 | y | expression | +| test.cpp:98:7:98:8 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:98:7:98:8 | x3 | expression | +| test.cpp:101:20:101:21 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:101:20:101:21 | x4 | expression | +| test.cpp:111:21:111:22 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:111:21:111:22 | x7 | expression | +| test.cpp:114:20:114:21 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:114:20:114:21 | x8 | expression | +| test.cpp:124:17:124:18 | definition of c3 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'C1'. | test.cpp:5:12:5:12 | 120 | expression | +| test.cpp:127:17:127:18 | definition of c4 | Implicit conversion of plain char $@ to signed char from instantiating template 'C2'. | test.cpp:13:12:13:12 | 120 | expression | +| test.cpp:137:15:137:16 | definition of c7 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'C5'. | test.cpp:22:12:22:12 | 1 | expression | +| test.cpp:140:15:140:16 | definition of c8 | Implicit conversion of plain char $@ to int8_t from instantiating template 'C6'. | test.cpp:30:12:30:12 | 1 | expression | +| test.cpp:157:7:157:10 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:157:7:157:10 | * ... | expression | +| test.cpp:162:7:162:10 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:162:7:162:10 | * ... | expression | +| test.cpp:177:7:177:10 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:177:7:177:10 | * ... | expression | +| test.cpp:182:7:182:10 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:182:7:182:10 | * ... | expression | +| test.cpp:196:6:196:7 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:196:6:196:7 | a3 | expression | +| test.cpp:199:6:199:7 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:199:6:199:7 | a4 | expression | +| test.cpp:209:6:209:7 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:209:6:209:7 | a7 | expression | +| test.cpp:212:7:212:8 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:212:7:212:8 | a8 | expression | +| test.cpp:226:3:226:4 | call to f5 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'f5'. | test.cpp:43:56:43:56 | x | expression | +| test.cpp:230:3:230:4 | call to f6 | Implicit conversion of plain char $@ to signed char from instantiating template 'f6'. | test.cpp:44:54:44:54 | x | expression | +| test.cpp:243:3:243:5 | call to f13 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'f13'. | test.cpp:47:56:47:56 | x | expression | +| test.cpp:247:3:247:5 | call to f14 | Implicit conversion of plain char $@ to int8_t from instantiating template 'f14'. | test.cpp:48:55:48:55 | x | expression | +| test.cpp:264:12:264:14 | definition of c11 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'C9'. | test.cpp:52:15:52:15 | y | expression | +| test.cpp:269:13:269:15 | definition of c12 | Implicit conversion of plain char $@ to signed char from instantiating template 'C10'. | test.cpp:60:16:60:16 | y | expression | +| test.cpp:284:13:284:15 | definition of c15 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'C13'. | test.cpp:69:16:69:16 | y | expression | +| test.cpp:288:13:288:15 | definition of c16 | Implicit conversion of plain char $@ to int8_t from instantiating template 'C14'. | test.cpp:77:16:77:16 | y | expression | diff --git a/cpp/autosar/test/rules/M5-0-12/test.cpp b/cpp/autosar/test/rules/M5-0-12/test.cpp index 91106b8211..9687743402 100644 --- a/cpp/autosar/test/rules/M5-0-12/test.cpp +++ b/cpp/autosar/test/rules/M5-0-12/test.cpp @@ -35,25 +35,17 @@ template class C6 { void f1(unsigned char x) {} void f2(signed char x) {} -void f3(unsigned char x) {} -void f4(signed char x) {} /* Twin functions for std::uint8_t and std::int8_t */ void f9(std::uint8_t x) {} void f10(std::int8_t x) {} -void f11(std::uint8_t x) {} -void f12(std::int8_t x) {} template void f5(T x) { unsigned char y = x; } template void f6(T x) { signed char y = x; } -template void f7(T x) { unsigned char y = x; } -template void f8(T x) { signed char y = x; } /* Twin template functions for std::uint8_t and std::int8_t */ template void f13(T x) { std::uint8_t y = x; } template void f14(T x) { std::int8_t y = x; } -template void f15(T x) { std::uint8_t y = x; } -template void f16(T x) { std::int8_t y = x; } template class C9 { public: @@ -201,10 +193,10 @@ int main() { f2(a2); // COMPLIANT: signed char arg passed to a signed char parameter char a3 = 'a'; - f3(a3); // NON-COMPLIANT: plain char arg passed to a unsigned char parameter + f1(a3); // NON-COMPLIANT: plain char arg passed to a unsigned char parameter char a4 = 'a'; - f4(a4); // NON-COMPLIANT: plain char arg passed to a signed char parameter + f2(a4); // NON-COMPLIANT: plain char arg passed to a signed char parameter /* Twin cases with std::uint8_t and std::int8_t */ std::uint8_t a5 = 1; @@ -214,10 +206,10 @@ int main() { f10(a6); // COMPLIANT: std::int8_t arg passed to a std::int8_t parameter char a7 = 'a'; - f11(a7); // NON-COMPLIANT: plain char arg passed to a std::uint8_t parameter + f9(a7); // NON-COMPLIANT: plain char arg passed to a std::uint8_t parameter char a8 = 'a'; - f12(a8); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter + f10(a8); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter /* ===== 2-2. Passing char argument to a char parameter through a template * ===== */ @@ -231,11 +223,11 @@ int main() { // through a template char a11 = 'a'; - f7(a11); // NON-COMPLIANT: plain char arg passed to an unsigned char parameter + f5(a11); // NON-COMPLIANT: plain char arg passed to an unsigned char parameter // through a template char a12 = 'a'; - f8(a12); // NON-COMPLIANT: plain char arg passed to a signed char parameter + f6(a12); // NON-COMPLIANT: plain char arg passed to a signed char parameter // through a template /* Twin cases with std::uint8_t and std::int8_t */ @@ -248,11 +240,11 @@ int main() { // through a template char a15 = 'a'; - f15(a15); // NON-COMPLIANT: plain char arg passed to a std::uint8_t parameter + f13(a15); // NON-COMPLIANT: plain char arg passed to a std::uint8_t parameter // through a template char a16 = 'a'; - f16(a16); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter + f14(a16); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter // through a template /* ========== 2-3. Passing a char argument to a char parameter through a From 10c3a2c08ab66c1a5749195367b7426b9ba7e44d Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 14 Jul 2025 10:59:06 -0400 Subject: [PATCH 505/628] Minor label editing --- cpp/autosar/test/rules/M5-0-12/test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/autosar/test/rules/M5-0-12/test.cpp b/cpp/autosar/test/rules/M5-0-12/test.cpp index 9687743402..0fe008436c 100644 --- a/cpp/autosar/test/rules/M5-0-12/test.cpp +++ b/cpp/autosar/test/rules/M5-0-12/test.cpp @@ -121,7 +121,7 @@ int main() { C2 c2; // COMPLIANT: signed char arg passed to a signed char // member through a template - C1 c3; // NON-COMPLIANT: plain char arg passed to a unsigned char + C1 c3; // NON-COMPLIANT: plain char arg passed to an unsigned char // member through a template C2 c4; // NON-COMPLIANT: plain char arg passed to a signed char @@ -145,7 +145,7 @@ int main() { unsigned char x9 = 1; unsigned char *y9 = &x9; unsigned char z1 = - *y9; // COMPLIANT: unsigned char assigned to a *&unsigned char + *y9; // COMPLIANT: unsigned char assigned to an *&unsigned char signed char x10 = 1; signed char *y10 = &x10; @@ -193,7 +193,7 @@ int main() { f2(a2); // COMPLIANT: signed char arg passed to a signed char parameter char a3 = 'a'; - f1(a3); // NON-COMPLIANT: plain char arg passed to a unsigned char parameter + f1(a3); // NON-COMPLIANT: plain char arg passed to an unsigned char parameter char a4 = 'a'; f2(a4); // NON-COMPLIANT: plain char arg passed to a signed char parameter @@ -262,7 +262,7 @@ int main() { char a19 = 'a'; C9 c11( - a19); // NON-COMPLIANT: plain char arg passed to a unsigned signed char + a19); // NON-COMPLIANT: plain char arg passed to an unsigned signed char // parameter of a constructor through a template char a20 = 'a'; From 20a30ccc108c6a781b28b917e9edb729ef94b892 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 14 Jul 2025 10:59:21 -0400 Subject: [PATCH 506/628] Attach docstrings to query elements --- ...eUsedForTheStorageAndUseOfNumericValues.ql | 61 ++++++++++++++++--- 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql b/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql index 7ffc47e50f..b81cf2dc64 100644 --- a/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql +++ b/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql @@ -16,17 +16,21 @@ import cpp import codingstandards.cpp.autosar -newtype TTemplatedElement = - TClassTemplate(TemplateClass c) or - TFunctionTemplate(TemplateFunction f) or - TVariableTemplate(TemplateVariable v) +newtype TTemplateElement = + TTemplateClass(TemplateClass c) or + TTemplateFunction(TemplateFunction f) or + TTemplateVariable(TemplateVariable v) -class TemplatedElement extends TTemplatedElement { - TemplateClass asTemplateClass() { this = TClassTemplate(result) } +/** + * A templated element. These are either templated classes, templated functions, + * or templated variables. + */ +class TemplateElement extends TTemplateElement { + TemplateClass asTemplateClass() { this = TTemplateClass(result) } - TemplateFunction asTemplateFunction() { this = TFunctionTemplate(result) } + TemplateFunction asTemplateFunction() { this = TTemplateFunction(result) } - TemplateVariable asTemplateVariable() { this = TVariableTemplate(result) } + TemplateVariable asTemplateVariable() { this = TTemplateVariable(result) } string toString() { result = this.asTemplateClass().toString() or @@ -52,6 +56,10 @@ newtype TTemplateInstantiation = TFunctionTemplateInstantiation(FunctionTemplateInstantiation f) or TVariableTemplateInstantiation(VariableTemplateInstantiation v) +/** + * An instantiation of a templated element, either a templated class, templated + * function, or templated variable. + */ class TemplateInstantiation extends TTemplateInstantiation { ClassTemplateInstantiation asClassTemplateInstantiation() { this = TClassTemplateInstantiation(result) @@ -83,7 +91,11 @@ class TemplateInstantiation extends TTemplateInstantiation { result = this.asVariableTemplateInstantiation() } - TemplatedElement getTemplate() { + /** + * Gets the template this instantiation is from, depending on the kind of the element + * this instantiation is for. + */ + TemplateElement getTemplate() { result.asTemplateClass() = this.asClassTemplateInstantiation().getTemplate() or result.asTemplateFunction() = this.asFunctionTemplateInstantiation().getTemplate() or result.asTemplateVariable() = this.asVariableTemplateInstantiation().getTemplate() @@ -102,6 +114,13 @@ class TemplateInstantiation extends TTemplateInstantiation { } } +/** + * An implicit conversion from a plain char type to an explicitly signed or unsigned char + * type. `std::uint8_t` and `std::int8_t` are also considered as these char types. + * + * Note that this class only includes implicit conversions and does not include explicit + * type conversions, i.e. casts. + */ class ImplicitConversionFromPlainCharType extends Conversion { ImplicitConversionFromPlainCharType() { this.isImplicit() and @@ -126,6 +145,16 @@ newtype TImplicitConversionElement = implicitConversion.getEnclosingElement+() = templateInstantiation.asElement() } +/** + * The locations where the implicit conversion from a plain char to an explicitly signed / unsigned + * char is taking place on a high level. It splits case on whether the conversion is caused by + * instantiating a template: + * + * - For conversions not due to template usage (i.e. outside a templated element), this refers to + * the same element as the one associated with the conversion. + * - For conversions due to template usage, this refers to the element that uses the instantiation + * of a template where an implicit char conversion happens. + */ class ImplicitConversionLocation extends TImplicitConversionElement { ImplicitConversionFromPlainCharType asImplicitConversionOutsideTemplate() { this = TImplicitConversionOutsideTemplate(result) @@ -137,10 +166,17 @@ class ImplicitConversionLocation extends TImplicitConversionElement { this = TInstantiationOfImplicitConversionTemplate(result, implicitConversion) } + /** + * Holds if this is a location of a conversion happening outside of a template. + */ predicate isImplicitConversionOutsideTemplate() { exists(this.asImplicitConversionOutsideTemplate()) } + /** + * Holds if this is a location of a conversion happening due to instantiating a + * template. + */ predicate isInstantiationOfImplicitConversionTemplate() { exists( TemplateInstantiation templateInstantiation, @@ -150,6 +186,13 @@ class ImplicitConversionLocation extends TImplicitConversionElement { ) } + /** + * Gets the implicit conversion that this location is associated with. + * - In cases of conversions not involving a template, this is the same as the + * location associated with the conversion. + * - In cases of conversions due to using a template, this is the conversion that + * happens in the instantiated template. + */ ImplicitConversionFromPlainCharType getImplicitConversion() { result = this.asImplicitConversionOutsideTemplate() or exists(TemplateInstantiation templateInstantiation | From f3cee16926b6b78f14da4680e8c5b10a052f0fed Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 14 Jul 2025 11:13:11 -0400 Subject: [PATCH 507/628] Add cases of template variable instantiation --- ...orTheStorageAndUseOfNumericValues.expected | 52 ++++++++++--------- cpp/autosar/test/rules/M5-0-12/test.cpp | 23 ++++++++ 2 files changed, 51 insertions(+), 24 deletions(-) diff --git a/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected b/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected index d5dc9af7e8..d0aeaebd41 100644 --- a/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected +++ b/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected @@ -1,24 +1,28 @@ -| test.cpp:98:7:98:8 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:98:7:98:8 | x3 | expression | -| test.cpp:101:20:101:21 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:101:20:101:21 | x4 | expression | -| test.cpp:111:21:111:22 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:111:21:111:22 | x7 | expression | -| test.cpp:114:20:114:21 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:114:20:114:21 | x8 | expression | -| test.cpp:124:17:124:18 | definition of c3 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'C1'. | test.cpp:5:12:5:12 | 120 | expression | -| test.cpp:127:17:127:18 | definition of c4 | Implicit conversion of plain char $@ to signed char from instantiating template 'C2'. | test.cpp:13:12:13:12 | 120 | expression | -| test.cpp:137:15:137:16 | definition of c7 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'C5'. | test.cpp:22:12:22:12 | 1 | expression | -| test.cpp:140:15:140:16 | definition of c8 | Implicit conversion of plain char $@ to int8_t from instantiating template 'C6'. | test.cpp:30:12:30:12 | 1 | expression | -| test.cpp:157:7:157:10 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:157:7:157:10 | * ... | expression | -| test.cpp:162:7:162:10 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:162:7:162:10 | * ... | expression | -| test.cpp:177:7:177:10 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:177:7:177:10 | * ... | expression | -| test.cpp:182:7:182:10 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:182:7:182:10 | * ... | expression | -| test.cpp:196:6:196:7 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:196:6:196:7 | a3 | expression | -| test.cpp:199:6:199:7 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:199:6:199:7 | a4 | expression | -| test.cpp:209:6:209:7 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:209:6:209:7 | a7 | expression | -| test.cpp:212:7:212:8 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:212:7:212:8 | a8 | expression | -| test.cpp:226:3:226:4 | call to f5 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'f5'. | test.cpp:43:56:43:56 | x | expression | -| test.cpp:230:3:230:4 | call to f6 | Implicit conversion of plain char $@ to signed char from instantiating template 'f6'. | test.cpp:44:54:44:54 | x | expression | -| test.cpp:243:3:243:5 | call to f13 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'f13'. | test.cpp:47:56:47:56 | x | expression | -| test.cpp:247:3:247:5 | call to f14 | Implicit conversion of plain char $@ to int8_t from instantiating template 'f14'. | test.cpp:48:55:48:55 | x | expression | -| test.cpp:264:12:264:14 | definition of c11 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'C9'. | test.cpp:52:15:52:15 | y | expression | -| test.cpp:269:13:269:15 | definition of c12 | Implicit conversion of plain char $@ to signed char from instantiating template 'C10'. | test.cpp:60:16:60:16 | y | expression | -| test.cpp:284:13:284:15 | definition of c15 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'C13'. | test.cpp:69:16:69:16 | y | expression | -| test.cpp:288:13:288:15 | definition of c16 | Implicit conversion of plain char $@ to int8_t from instantiating template 'C14'. | test.cpp:77:16:77:16 | y | expression | +| test.cpp:93:7:93:9 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:93:7:93:9 | 118 | expression | +| test.cpp:94:21:94:23 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:94:21:94:23 | 118 | expression | +| test.cpp:102:7:102:9 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:102:7:102:9 | 118 | expression | +| test.cpp:103:21:103:23 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:103:21:103:23 | 118 | expression | +| test.cpp:121:7:121:8 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:121:7:121:8 | x3 | expression | +| test.cpp:124:20:124:21 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:124:20:124:21 | x4 | expression | +| test.cpp:134:21:134:22 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:134:21:134:22 | x7 | expression | +| test.cpp:137:20:137:21 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:137:20:137:21 | x8 | expression | +| test.cpp:147:17:147:18 | definition of c3 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'C1'. | test.cpp:5:12:5:12 | 120 | expression | +| test.cpp:150:17:150:18 | definition of c4 | Implicit conversion of plain char $@ to signed char from instantiating template 'C2'. | test.cpp:13:12:13:12 | 120 | expression | +| test.cpp:160:15:160:16 | definition of c7 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'C5'. | test.cpp:22:12:22:12 | 1 | expression | +| test.cpp:163:15:163:16 | definition of c8 | Implicit conversion of plain char $@ to int8_t from instantiating template 'C6'. | test.cpp:30:12:30:12 | 1 | expression | +| test.cpp:180:7:180:10 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:180:7:180:10 | * ... | expression | +| test.cpp:185:7:185:10 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:185:7:185:10 | * ... | expression | +| test.cpp:200:7:200:10 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:200:7:200:10 | * ... | expression | +| test.cpp:205:7:205:10 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:205:7:205:10 | * ... | expression | +| test.cpp:219:6:219:7 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:219:6:219:7 | a3 | expression | +| test.cpp:222:6:222:7 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:222:6:222:7 | a4 | expression | +| test.cpp:232:6:232:7 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:232:6:232:7 | a7 | expression | +| test.cpp:235:7:235:8 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:235:7:235:8 | a8 | expression | +| test.cpp:249:3:249:4 | call to f5 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'f5'. | test.cpp:43:56:43:56 | x | expression | +| test.cpp:253:3:253:4 | call to f6 | Implicit conversion of plain char $@ to signed char from instantiating template 'f6'. | test.cpp:44:54:44:54 | x | expression | +| test.cpp:266:3:266:5 | call to f13 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'f13'. | test.cpp:47:56:47:56 | x | expression | +| test.cpp:270:3:270:5 | call to f14 | Implicit conversion of plain char $@ to int8_t from instantiating template 'f14'. | test.cpp:48:55:48:55 | x | expression | +| test.cpp:287:12:287:14 | definition of c11 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'C9'. | test.cpp:52:15:52:15 | y | expression | +| test.cpp:292:13:292:15 | definition of c12 | Implicit conversion of plain char $@ to signed char from instantiating template 'C10'. | test.cpp:60:16:60:16 | y | expression | +| test.cpp:307:13:307:15 | definition of c15 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'C13'. | test.cpp:69:16:69:16 | y | expression | +| test.cpp:311:13:311:15 | definition of c16 | Implicit conversion of plain char $@ to int8_t from instantiating template 'C14'. | test.cpp:77:16:77:16 | y | expression | diff --git a/cpp/autosar/test/rules/M5-0-12/test.cpp b/cpp/autosar/test/rules/M5-0-12/test.cpp index 0fe008436c..037c57da13 100644 --- a/cpp/autosar/test/rules/M5-0-12/test.cpp +++ b/cpp/autosar/test/rules/M5-0-12/test.cpp @@ -80,6 +80,29 @@ template class C14 { std::int8_t x; }; +template T v1; +template T v2; + +void instantiateTemplateVariables() { + v1 = + 1; // COMPLIANT: unsigned char assigned to an unsigned char + v2 = 1; // COMPLIANT: signed char assigned to a signed char + v2 = 'v'; // COMPLIANT: signed char assigned to a signed char + + v1 = + 'v'; // NON-COMPLIANT: plain char assigned to an unsigned char + v2 = 'v'; // NON-COMPLIANT: plain char assigned to a signed char + + /* Twin cases with std::uint8_t and std::int8_t */ + v1 = 1; // COMPLIANT: std::uint8_t assigned to a std::uint8_t + v2 = 1; // COMPLIANT: std::int8_t assigned to a std::int8_t + v2 = 'v'; // COMPLIANT: signed char assigned to a signed char + + v1 = + 'v'; // NON-COMPLIANT: plain char assigned to a std::uint8_t + v2 = 'v'; // NON-COMPLIANT: plain char assigned to a std::int8_t +} + int main() { /* ========== 1. Assigning a char to another char ========== */ From bb2ad888ad067ff3b75dad57a5516d92ca04830b Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 14 Jul 2025 11:18:29 -0400 Subject: [PATCH 508/628] Surround type name with single quotes in alert message --- ...eUsedForTheStorageAndUseOfNumericValues.ql | 6 +- ...orTheStorageAndUseOfNumericValues.expected | 56 +++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql b/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql index b81cf2dc64..e6852d7d39 100644 --- a/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql +++ b/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql @@ -228,12 +228,12 @@ string getMessageTemplate(ImplicitConversionLocation implicitConversionLocation) | implicitConversionLocation.isImplicitConversionOutsideTemplate() and result = - "Implicit conversion of plain char $@ to " + implicitConversion.getType().getName() + "." + "Implicit conversion of plain char $@ to '" + implicitConversion.getType().getName() + "'." or implicitConversionLocation.isInstantiationOfImplicitConversionTemplate() and result = - "Implicit conversion of plain char $@ to " + implicitConversion.getType().getName() + - " from instantiating template '" + + "Implicit conversion of plain char $@ to '" + implicitConversion.getType().getName() + + "' from instantiating template '" + implicitConversionLocation .asInstantiationOfImplicitConversionTemplate(implicitConversion) .getTemplate() diff --git a/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected b/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected index d0aeaebd41..ad1f57935e 100644 --- a/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected +++ b/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected @@ -1,28 +1,28 @@ -| test.cpp:93:7:93:9 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:93:7:93:9 | 118 | expression | -| test.cpp:94:21:94:23 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:94:21:94:23 | 118 | expression | -| test.cpp:102:7:102:9 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:102:7:102:9 | 118 | expression | -| test.cpp:103:21:103:23 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:103:21:103:23 | 118 | expression | -| test.cpp:121:7:121:8 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:121:7:121:8 | x3 | expression | -| test.cpp:124:20:124:21 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:124:20:124:21 | x4 | expression | -| test.cpp:134:21:134:22 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:134:21:134:22 | x7 | expression | -| test.cpp:137:20:137:21 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:137:20:137:21 | x8 | expression | -| test.cpp:147:17:147:18 | definition of c3 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'C1'. | test.cpp:5:12:5:12 | 120 | expression | -| test.cpp:150:17:150:18 | definition of c4 | Implicit conversion of plain char $@ to signed char from instantiating template 'C2'. | test.cpp:13:12:13:12 | 120 | expression | -| test.cpp:160:15:160:16 | definition of c7 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'C5'. | test.cpp:22:12:22:12 | 1 | expression | -| test.cpp:163:15:163:16 | definition of c8 | Implicit conversion of plain char $@ to int8_t from instantiating template 'C6'. | test.cpp:30:12:30:12 | 1 | expression | -| test.cpp:180:7:180:10 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:180:7:180:10 | * ... | expression | -| test.cpp:185:7:185:10 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:185:7:185:10 | * ... | expression | -| test.cpp:200:7:200:10 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:200:7:200:10 | * ... | expression | -| test.cpp:205:7:205:10 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:205:7:205:10 | * ... | expression | -| test.cpp:219:6:219:7 | (unsigned char)... | Implicit conversion of plain char $@ to unsigned char. | test.cpp:219:6:219:7 | a3 | expression | -| test.cpp:222:6:222:7 | (signed char)... | Implicit conversion of plain char $@ to signed char. | test.cpp:222:6:222:7 | a4 | expression | -| test.cpp:232:6:232:7 | (uint8_t)... | Implicit conversion of plain char $@ to uint8_t. | test.cpp:232:6:232:7 | a7 | expression | -| test.cpp:235:7:235:8 | (int8_t)... | Implicit conversion of plain char $@ to int8_t. | test.cpp:235:7:235:8 | a8 | expression | -| test.cpp:249:3:249:4 | call to f5 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'f5'. | test.cpp:43:56:43:56 | x | expression | -| test.cpp:253:3:253:4 | call to f6 | Implicit conversion of plain char $@ to signed char from instantiating template 'f6'. | test.cpp:44:54:44:54 | x | expression | -| test.cpp:266:3:266:5 | call to f13 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'f13'. | test.cpp:47:56:47:56 | x | expression | -| test.cpp:270:3:270:5 | call to f14 | Implicit conversion of plain char $@ to int8_t from instantiating template 'f14'. | test.cpp:48:55:48:55 | x | expression | -| test.cpp:287:12:287:14 | definition of c11 | Implicit conversion of plain char $@ to unsigned char from instantiating template 'C9'. | test.cpp:52:15:52:15 | y | expression | -| test.cpp:292:13:292:15 | definition of c12 | Implicit conversion of plain char $@ to signed char from instantiating template 'C10'. | test.cpp:60:16:60:16 | y | expression | -| test.cpp:307:13:307:15 | definition of c15 | Implicit conversion of plain char $@ to uint8_t from instantiating template 'C13'. | test.cpp:69:16:69:16 | y | expression | -| test.cpp:311:13:311:15 | definition of c16 | Implicit conversion of plain char $@ to int8_t from instantiating template 'C14'. | test.cpp:77:16:77:16 | y | expression | +| test.cpp:93:7:93:9 | (unsigned char)... | Implicit conversion of plain char $@ to 'unsigned char'. | test.cpp:93:7:93:9 | 118 | expression | +| test.cpp:94:21:94:23 | (signed char)... | Implicit conversion of plain char $@ to 'signed char'. | test.cpp:94:21:94:23 | 118 | expression | +| test.cpp:102:7:102:9 | (unsigned char)... | Implicit conversion of plain char $@ to 'unsigned char'. | test.cpp:102:7:102:9 | 118 | expression | +| test.cpp:103:21:103:23 | (signed char)... | Implicit conversion of plain char $@ to 'signed char'. | test.cpp:103:21:103:23 | 118 | expression | +| test.cpp:121:7:121:8 | (unsigned char)... | Implicit conversion of plain char $@ to 'unsigned char'. | test.cpp:121:7:121:8 | x3 | expression | +| test.cpp:124:20:124:21 | (signed char)... | Implicit conversion of plain char $@ to 'signed char'. | test.cpp:124:20:124:21 | x4 | expression | +| test.cpp:134:21:134:22 | (uint8_t)... | Implicit conversion of plain char $@ to 'uint8_t'. | test.cpp:134:21:134:22 | x7 | expression | +| test.cpp:137:20:137:21 | (int8_t)... | Implicit conversion of plain char $@ to 'int8_t'. | test.cpp:137:20:137:21 | x8 | expression | +| test.cpp:147:17:147:18 | definition of c3 | Implicit conversion of plain char $@ to 'unsigned char' from instantiating template 'C1'. | test.cpp:5:12:5:12 | 120 | expression | +| test.cpp:150:17:150:18 | definition of c4 | Implicit conversion of plain char $@ to 'signed char' from instantiating template 'C2'. | test.cpp:13:12:13:12 | 120 | expression | +| test.cpp:160:15:160:16 | definition of c7 | Implicit conversion of plain char $@ to 'uint8_t' from instantiating template 'C5'. | test.cpp:22:12:22:12 | 1 | expression | +| test.cpp:163:15:163:16 | definition of c8 | Implicit conversion of plain char $@ to 'int8_t' from instantiating template 'C6'. | test.cpp:30:12:30:12 | 1 | expression | +| test.cpp:180:7:180:10 | (unsigned char)... | Implicit conversion of plain char $@ to 'unsigned char'. | test.cpp:180:7:180:10 | * ... | expression | +| test.cpp:185:7:185:10 | (signed char)... | Implicit conversion of plain char $@ to 'signed char'. | test.cpp:185:7:185:10 | * ... | expression | +| test.cpp:200:7:200:10 | (uint8_t)... | Implicit conversion of plain char $@ to 'uint8_t'. | test.cpp:200:7:200:10 | * ... | expression | +| test.cpp:205:7:205:10 | (int8_t)... | Implicit conversion of plain char $@ to 'int8_t'. | test.cpp:205:7:205:10 | * ... | expression | +| test.cpp:219:6:219:7 | (unsigned char)... | Implicit conversion of plain char $@ to 'unsigned char'. | test.cpp:219:6:219:7 | a3 | expression | +| test.cpp:222:6:222:7 | (signed char)... | Implicit conversion of plain char $@ to 'signed char'. | test.cpp:222:6:222:7 | a4 | expression | +| test.cpp:232:6:232:7 | (uint8_t)... | Implicit conversion of plain char $@ to 'uint8_t'. | test.cpp:232:6:232:7 | a7 | expression | +| test.cpp:235:7:235:8 | (int8_t)... | Implicit conversion of plain char $@ to 'int8_t'. | test.cpp:235:7:235:8 | a8 | expression | +| test.cpp:249:3:249:4 | call to f5 | Implicit conversion of plain char $@ to 'unsigned char' from instantiating template 'f5'. | test.cpp:43:56:43:56 | x | expression | +| test.cpp:253:3:253:4 | call to f6 | Implicit conversion of plain char $@ to 'signed char' from instantiating template 'f6'. | test.cpp:44:54:44:54 | x | expression | +| test.cpp:266:3:266:5 | call to f13 | Implicit conversion of plain char $@ to 'uint8_t' from instantiating template 'f13'. | test.cpp:47:56:47:56 | x | expression | +| test.cpp:270:3:270:5 | call to f14 | Implicit conversion of plain char $@ to 'int8_t' from instantiating template 'f14'. | test.cpp:48:55:48:55 | x | expression | +| test.cpp:287:12:287:14 | definition of c11 | Implicit conversion of plain char $@ to 'unsigned char' from instantiating template 'C9'. | test.cpp:52:15:52:15 | y | expression | +| test.cpp:292:13:292:15 | definition of c12 | Implicit conversion of plain char $@ to 'signed char' from instantiating template 'C10'. | test.cpp:60:16:60:16 | y | expression | +| test.cpp:307:13:307:15 | definition of c15 | Implicit conversion of plain char $@ to 'uint8_t' from instantiating template 'C13'. | test.cpp:69:16:69:16 | y | expression | +| test.cpp:311:13:311:15 | definition of c16 | Implicit conversion of plain char $@ to 'int8_t' from instantiating template 'C14'. | test.cpp:77:16:77:16 | y | expression | From a474ded139a11efb51548d2fd45ef8310f7f050e Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 14 Jul 2025 12:12:13 -0400 Subject: [PATCH 509/628] Minor editing of label --- cpp/autosar/test/rules/M5-0-12/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/autosar/test/rules/M5-0-12/test.cpp b/cpp/autosar/test/rules/M5-0-12/test.cpp index 037c57da13..3e9a21ae17 100644 --- a/cpp/autosar/test/rules/M5-0-12/test.cpp +++ b/cpp/autosar/test/rules/M5-0-12/test.cpp @@ -87,7 +87,7 @@ void instantiateTemplateVariables() { v1 = 1; // COMPLIANT: unsigned char assigned to an unsigned char v2 = 1; // COMPLIANT: signed char assigned to a signed char - v2 = 'v'; // COMPLIANT: signed char assigned to a signed char + v2 = 'v'; // COMPLIANT: plain char assigned to a plain char v1 = 'v'; // NON-COMPLIANT: plain char assigned to an unsigned char @@ -96,7 +96,7 @@ void instantiateTemplateVariables() { /* Twin cases with std::uint8_t and std::int8_t */ v1 = 1; // COMPLIANT: std::uint8_t assigned to a std::uint8_t v2 = 1; // COMPLIANT: std::int8_t assigned to a std::int8_t - v2 = 'v'; // COMPLIANT: signed char assigned to a signed char + v2 = 'v'; // COMPLIANT: plain char assigned to a plain char v1 = 'v'; // NON-COMPLIANT: plain char assigned to a std::uint8_t From 2991f6f8ab337f63127f5d5a60e4812068d86315 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 15 Jul 2025 12:21:30 -0400 Subject: [PATCH 510/628] Remove handling of template cases --- ...eUsedForTheStorageAndUseOfNumericValues.ql | 245 +----------------- 1 file changed, 13 insertions(+), 232 deletions(-) diff --git a/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql b/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql index e6852d7d39..bc3563559b 100644 --- a/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql +++ b/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql @@ -16,237 +16,18 @@ import cpp import codingstandards.cpp.autosar -newtype TTemplateElement = - TTemplateClass(TemplateClass c) or - TTemplateFunction(TemplateFunction f) or - TTemplateVariable(TemplateVariable v) - -/** - * A templated element. These are either templated classes, templated functions, - * or templated variables. - */ -class TemplateElement extends TTemplateElement { - TemplateClass asTemplateClass() { this = TTemplateClass(result) } - - TemplateFunction asTemplateFunction() { this = TTemplateFunction(result) } - - TemplateVariable asTemplateVariable() { this = TTemplateVariable(result) } - - string toString() { - result = this.asTemplateClass().toString() or - result = this.asTemplateFunction().toString() or - result = this.asTemplateVariable().toString() - } - - Location getLocation() { - result = this.asTemplateClass().getLocation() or - result = this.asTemplateFunction().getLocation() or - result = this.asTemplateVariable().getLocation() - } - - string getName() { - result = this.asTemplateClass().getName() or - result = this.asTemplateFunction().getName() or - result = this.asTemplateVariable().getName() - } -} - -newtype TTemplateInstantiation = - TClassTemplateInstantiation(ClassTemplateInstantiation c) or - TFunctionTemplateInstantiation(FunctionTemplateInstantiation f) or - TVariableTemplateInstantiation(VariableTemplateInstantiation v) - -/** - * An instantiation of a templated element, either a templated class, templated - * function, or templated variable. - */ -class TemplateInstantiation extends TTemplateInstantiation { - ClassTemplateInstantiation asClassTemplateInstantiation() { - this = TClassTemplateInstantiation(result) - } - - FunctionTemplateInstantiation asFunctionTemplateInstantiation() { - this = TFunctionTemplateInstantiation(result) - } - - VariableTemplateInstantiation asVariableTemplateInstantiation() { - this = TVariableTemplateInstantiation(result) - } - - string toString() { - result = this.asClassTemplateInstantiation().toString() or - result = this.asFunctionTemplateInstantiation().toString() or - result = this.asVariableTemplateInstantiation().toString() - } - - Location getLocation() { - result = this.asClassTemplateInstantiation().getLocation() or - result = this.asFunctionTemplateInstantiation().getLocation() or - result = this.asVariableTemplateInstantiation().getLocation() - } - - Element asElement() { - result = this.asClassTemplateInstantiation() or - result = this.asFunctionTemplateInstantiation() or - result = this.asVariableTemplateInstantiation() - } - - /** - * Gets the template this instantiation is from, depending on the kind of the element - * this instantiation is for. - */ - TemplateElement getTemplate() { - result.asTemplateClass() = this.asClassTemplateInstantiation().getTemplate() or - result.asTemplateFunction() = this.asFunctionTemplateInstantiation().getTemplate() or - result.asTemplateVariable() = this.asVariableTemplateInstantiation().getTemplate() - } - - /** - * Gets a use of an instantiation of this template. i.e. - * 1. For a class template, it's where the instantiated type is used by the name. - * 2. For a function template, it's where the instantiated function is called. - * 3. For a variable template, it's where the instantiated variable is initialized. - */ - Element getAUse() { - result = this.asClassTemplateInstantiation().getATypeNameUse() or - result = this.asFunctionTemplateInstantiation().getACallToThisFunction() or - result = this.asVariableTemplateInstantiation() - } -} - -/** - * An implicit conversion from a plain char type to an explicitly signed or unsigned char - * type. `std::uint8_t` and `std::int8_t` are also considered as these char types. - * - * Note that this class only includes implicit conversions and does not include explicit - * type conversions, i.e. casts. - */ -class ImplicitConversionFromPlainCharType extends Conversion { - ImplicitConversionFromPlainCharType() { - this.isImplicit() and - this.getExpr().getUnspecifiedType() instanceof PlainCharType and - ( - this.getUnspecifiedType() instanceof SignedCharType or - this.getUnspecifiedType() instanceof UnsignedCharType - ) - } -} - -newtype TImplicitConversionElement = - TImplicitConversionOutsideTemplate(ImplicitConversionFromPlainCharType implicitConversion) { - not exists(TemplateInstantiation instantiation | - implicitConversion.isFromTemplateInstantiation(instantiation.asElement()) - ) - } or - TInstantiationOfImplicitConversionTemplate( - TemplateInstantiation templateInstantiation, - ImplicitConversionFromPlainCharType implicitConversion - ) { - implicitConversion.getEnclosingElement+() = templateInstantiation.asElement() - } - -/** - * The locations where the implicit conversion from a plain char to an explicitly signed / unsigned - * char is taking place on a high level. It splits case on whether the conversion is caused by - * instantiating a template: - * - * - For conversions not due to template usage (i.e. outside a templated element), this refers to - * the same element as the one associated with the conversion. - * - For conversions due to template usage, this refers to the element that uses the instantiation - * of a template where an implicit char conversion happens. - */ -class ImplicitConversionLocation extends TImplicitConversionElement { - ImplicitConversionFromPlainCharType asImplicitConversionOutsideTemplate() { - this = TImplicitConversionOutsideTemplate(result) - } - - TemplateInstantiation asInstantiationOfImplicitConversionTemplate( - ImplicitConversionFromPlainCharType implicitConversion - ) { - this = TInstantiationOfImplicitConversionTemplate(result, implicitConversion) - } - - /** - * Holds if this is a location of a conversion happening outside of a template. - */ - predicate isImplicitConversionOutsideTemplate() { - exists(this.asImplicitConversionOutsideTemplate()) - } - - /** - * Holds if this is a location of a conversion happening due to instantiating a - * template. - */ - predicate isInstantiationOfImplicitConversionTemplate() { - exists( - TemplateInstantiation templateInstantiation, - ImplicitConversionFromPlainCharType implicitConversion - | - templateInstantiation = this.asInstantiationOfImplicitConversionTemplate(implicitConversion) - ) - } - - /** - * Gets the implicit conversion that this location is associated with. - * - In cases of conversions not involving a template, this is the same as the - * location associated with the conversion. - * - In cases of conversions due to using a template, this is the conversion that - * happens in the instantiated template. - */ - ImplicitConversionFromPlainCharType getImplicitConversion() { - result = this.asImplicitConversionOutsideTemplate() or - exists(TemplateInstantiation templateInstantiation | - this = TInstantiationOfImplicitConversionTemplate(templateInstantiation, result) - ) - } - - string toString() { - result = this.asImplicitConversionOutsideTemplate().toString() or - exists(ImplicitConversionFromPlainCharType implicitConversion | - result = this.asInstantiationOfImplicitConversionTemplate(implicitConversion).toString() - ) - } - - Location getLocation() { - result = this.asImplicitConversionOutsideTemplate().getLocation() or - exists(ImplicitConversionFromPlainCharType implicitConversion | - result = this.asInstantiationOfImplicitConversionTemplate(implicitConversion).getLocation() - ) - } - - Element asElement() { - result = this.asImplicitConversionOutsideTemplate() or - exists(ImplicitConversionFromPlainCharType implicitConversion | - result = this.asInstantiationOfImplicitConversionTemplate(implicitConversion).getAUse() - ) - } -} - -string getMessageTemplate(ImplicitConversionLocation implicitConversionLocation) { - exists(ImplicitConversionFromPlainCharType implicitConversion | - implicitConversion = implicitConversionLocation.getImplicitConversion() - | - implicitConversionLocation.isImplicitConversionOutsideTemplate() and - result = - "Implicit conversion of plain char $@ to '" + implicitConversion.getType().getName() + "'." - or - implicitConversionLocation.isInstantiationOfImplicitConversionTemplate() and - result = - "Implicit conversion of plain char $@ to '" + implicitConversion.getType().getName() + - "' from instantiating template '" + - implicitConversionLocation - .asInstantiationOfImplicitConversionTemplate(implicitConversion) - .getTemplate() - .getName() + "'." - ) -} - -from - ImplicitConversionLocation implicitConversionLocation, - ImplicitConversionFromPlainCharType implicitConversion +from Conversion c where - not isExcluded(implicitConversionLocation.asElement(), + not isExcluded(c, StringsPackage::signedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValuesQuery()) and - implicitConversion = implicitConversionLocation.getImplicitConversion() -select implicitConversionLocation.asElement(), getMessageTemplate(implicitConversionLocation), - implicitConversion.getExpr(), "expression" + /* 1. Focus on implicit conversions only (explicit conversions are acceptable). */ + c.isImplicit() and + /* 2. The target type is explicitly signed or unsigned char. */ + ( + c.getUnspecifiedType() instanceof SignedCharType or + c.getUnspecifiedType() instanceof UnsignedCharType + ) and + /* 3. Check if the source expression is a plain char type, i.e. not explicitly signed / unsigned. */ + c.getExpr().getUnspecifiedType() instanceof PlainCharType +select c, "Implicit conversion of plain char type to $@ with an explicitly signed char type", c, + c.getUnspecifiedType().getName() From 8dbaa1baa2735f1c2724cd58f743df50cfcbbc43 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 15 Jul 2025 12:50:14 -0400 Subject: [PATCH 511/628] Remove templates from the coverage of the query Templates are tricky issue; we'd like to address this in a different PR. --- ...eUsedForTheStorageAndUseOfNumericValues.ql | 5 +- ...orTheStorageAndUseOfNumericValues.expected | 44 ++-- cpp/autosar/test/rules/M5-0-12/test.cpp | 193 +++--------------- 3 files changed, 44 insertions(+), 198 deletions(-) diff --git a/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql b/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql index bc3563559b..8e48c05ada 100644 --- a/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql +++ b/cpp/autosar/src/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.ql @@ -29,5 +29,6 @@ where ) and /* 3. Check if the source expression is a plain char type, i.e. not explicitly signed / unsigned. */ c.getExpr().getUnspecifiedType() instanceof PlainCharType -select c, "Implicit conversion of plain char type to $@ with an explicitly signed char type", c, - c.getUnspecifiedType().getName() +select c, + "This expression of plain char type is implicitly converted to '" + + c.getUnspecifiedType().getName() + "'." diff --git a/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected b/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected index ad1f57935e..b23be388c6 100644 --- a/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected +++ b/cpp/autosar/test/rules/M5-0-12/SignedCharAndUnsignedCharTypeShallOnlyBeUsedForTheStorageAndUseOfNumericValues.expected @@ -1,28 +1,16 @@ -| test.cpp:93:7:93:9 | (unsigned char)... | Implicit conversion of plain char $@ to 'unsigned char'. | test.cpp:93:7:93:9 | 118 | expression | -| test.cpp:94:21:94:23 | (signed char)... | Implicit conversion of plain char $@ to 'signed char'. | test.cpp:94:21:94:23 | 118 | expression | -| test.cpp:102:7:102:9 | (unsigned char)... | Implicit conversion of plain char $@ to 'unsigned char'. | test.cpp:102:7:102:9 | 118 | expression | -| test.cpp:103:21:103:23 | (signed char)... | Implicit conversion of plain char $@ to 'signed char'. | test.cpp:103:21:103:23 | 118 | expression | -| test.cpp:121:7:121:8 | (unsigned char)... | Implicit conversion of plain char $@ to 'unsigned char'. | test.cpp:121:7:121:8 | x3 | expression | -| test.cpp:124:20:124:21 | (signed char)... | Implicit conversion of plain char $@ to 'signed char'. | test.cpp:124:20:124:21 | x4 | expression | -| test.cpp:134:21:134:22 | (uint8_t)... | Implicit conversion of plain char $@ to 'uint8_t'. | test.cpp:134:21:134:22 | x7 | expression | -| test.cpp:137:20:137:21 | (int8_t)... | Implicit conversion of plain char $@ to 'int8_t'. | test.cpp:137:20:137:21 | x8 | expression | -| test.cpp:147:17:147:18 | definition of c3 | Implicit conversion of plain char $@ to 'unsigned char' from instantiating template 'C1'. | test.cpp:5:12:5:12 | 120 | expression | -| test.cpp:150:17:150:18 | definition of c4 | Implicit conversion of plain char $@ to 'signed char' from instantiating template 'C2'. | test.cpp:13:12:13:12 | 120 | expression | -| test.cpp:160:15:160:16 | definition of c7 | Implicit conversion of plain char $@ to 'uint8_t' from instantiating template 'C5'. | test.cpp:22:12:22:12 | 1 | expression | -| test.cpp:163:15:163:16 | definition of c8 | Implicit conversion of plain char $@ to 'int8_t' from instantiating template 'C6'. | test.cpp:30:12:30:12 | 1 | expression | -| test.cpp:180:7:180:10 | (unsigned char)... | Implicit conversion of plain char $@ to 'unsigned char'. | test.cpp:180:7:180:10 | * ... | expression | -| test.cpp:185:7:185:10 | (signed char)... | Implicit conversion of plain char $@ to 'signed char'. | test.cpp:185:7:185:10 | * ... | expression | -| test.cpp:200:7:200:10 | (uint8_t)... | Implicit conversion of plain char $@ to 'uint8_t'. | test.cpp:200:7:200:10 | * ... | expression | -| test.cpp:205:7:205:10 | (int8_t)... | Implicit conversion of plain char $@ to 'int8_t'. | test.cpp:205:7:205:10 | * ... | expression | -| test.cpp:219:6:219:7 | (unsigned char)... | Implicit conversion of plain char $@ to 'unsigned char'. | test.cpp:219:6:219:7 | a3 | expression | -| test.cpp:222:6:222:7 | (signed char)... | Implicit conversion of plain char $@ to 'signed char'. | test.cpp:222:6:222:7 | a4 | expression | -| test.cpp:232:6:232:7 | (uint8_t)... | Implicit conversion of plain char $@ to 'uint8_t'. | test.cpp:232:6:232:7 | a7 | expression | -| test.cpp:235:7:235:8 | (int8_t)... | Implicit conversion of plain char $@ to 'int8_t'. | test.cpp:235:7:235:8 | a8 | expression | -| test.cpp:249:3:249:4 | call to f5 | Implicit conversion of plain char $@ to 'unsigned char' from instantiating template 'f5'. | test.cpp:43:56:43:56 | x | expression | -| test.cpp:253:3:253:4 | call to f6 | Implicit conversion of plain char $@ to 'signed char' from instantiating template 'f6'. | test.cpp:44:54:44:54 | x | expression | -| test.cpp:266:3:266:5 | call to f13 | Implicit conversion of plain char $@ to 'uint8_t' from instantiating template 'f13'. | test.cpp:47:56:47:56 | x | expression | -| test.cpp:270:3:270:5 | call to f14 | Implicit conversion of plain char $@ to 'int8_t' from instantiating template 'f14'. | test.cpp:48:55:48:55 | x | expression | -| test.cpp:287:12:287:14 | definition of c11 | Implicit conversion of plain char $@ to 'unsigned char' from instantiating template 'C9'. | test.cpp:52:15:52:15 | y | expression | -| test.cpp:292:13:292:15 | definition of c12 | Implicit conversion of plain char $@ to 'signed char' from instantiating template 'C10'. | test.cpp:60:16:60:16 | y | expression | -| test.cpp:307:13:307:15 | definition of c15 | Implicit conversion of plain char $@ to 'uint8_t' from instantiating template 'C13'. | test.cpp:69:16:69:16 | y | expression | -| test.cpp:311:13:311:15 | definition of c16 | Implicit conversion of plain char $@ to 'int8_t' from instantiating template 'C14'. | test.cpp:77:16:77:16 | y | expression | +| test.cpp:58:7:58:8 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:61:20:61:21 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. | +| test.cpp:71:21:71:22 | (uint8_t)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:74:20:74:21 | (int8_t)... | This expression of plain char type is implicitly converted to 'signed char'. | +| test.cpp:84:9:84:11 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:87:9:87:11 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. | +| test.cpp:97:9:97:11 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:100:9:100:11 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. | +| test.cpp:117:7:117:10 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:122:7:122:10 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. | +| test.cpp:137:7:137:10 | (uint8_t)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:142:7:142:10 | (int8_t)... | This expression of plain char type is implicitly converted to 'signed char'. | +| test.cpp:153:6:153:7 | (unsigned char)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:156:6:156:7 | (signed char)... | This expression of plain char type is implicitly converted to 'signed char'. | +| test.cpp:166:6:166:7 | (uint8_t)... | This expression of plain char type is implicitly converted to 'unsigned char'. | +| test.cpp:169:7:169:8 | (int8_t)... | This expression of plain char type is implicitly converted to 'signed char'. | diff --git a/cpp/autosar/test/rules/M5-0-12/test.cpp b/cpp/autosar/test/rules/M5-0-12/test.cpp index 3e9a21ae17..036db12b04 100644 --- a/cpp/autosar/test/rules/M5-0-12/test.cpp +++ b/cpp/autosar/test/rules/M5-0-12/test.cpp @@ -1,33 +1,33 @@ #include -template class C1 { +class C1 { public: - C1() : x(y) {} + C1(unsigned char y) : x(y) {} private: unsigned char x; }; -template class C2 { +class C2 { public: - C2() : x(y) {} + C2(signed char y) : x(y) {} private: signed char x; }; -/* Twin templates for std::uint8_t and std::int8_t */ -template class C5 { +/* Twin classes for std::uint8_t and std::int8_t */ +class C5 { public: - C5() : x(y) {} + C5(unsigned char y) : x(y) {} private: std::uint8_t x; }; -template class C6 { +class C6 { public: - C6() : x(y) {} + C6(signed char y) : x(y) {} private: std::int8_t x; @@ -40,69 +40,6 @@ void f2(signed char x) {} void f9(std::uint8_t x) {} void f10(std::int8_t x) {} -template void f5(T x) { unsigned char y = x; } -template void f6(T x) { signed char y = x; } - -/* Twin template functions for std::uint8_t and std::int8_t */ -template void f13(T x) { std::uint8_t y = x; } -template void f14(T x) { std::int8_t y = x; } - -template class C9 { -public: - C9(T y) : x(y) {} - -private: - unsigned char x; -}; - -template class C10 { -public: - C10(T y) : x(y) {} - -private: - signed char x; -}; - -/* Twin template classes for std::uint8_t and std::int8_t */ -template class C13 { -public: - C13(T y) : x(y) {} - -private: - std::uint8_t x; -}; - -template class C14 { -public: - C14(T y) : x(y) {} - -private: - std::int8_t x; -}; - -template T v1; -template T v2; - -void instantiateTemplateVariables() { - v1 = - 1; // COMPLIANT: unsigned char assigned to an unsigned char - v2 = 1; // COMPLIANT: signed char assigned to a signed char - v2 = 'v'; // COMPLIANT: plain char assigned to a plain char - - v1 = - 'v'; // NON-COMPLIANT: plain char assigned to an unsigned char - v2 = 'v'; // NON-COMPLIANT: plain char assigned to a signed char - - /* Twin cases with std::uint8_t and std::int8_t */ - v1 = 1; // COMPLIANT: std::uint8_t assigned to a std::uint8_t - v2 = 1; // COMPLIANT: std::int8_t assigned to a std::int8_t - v2 = 'v'; // COMPLIANT: plain char assigned to a plain char - - v1 = - 'v'; // NON-COMPLIANT: plain char assigned to a std::uint8_t - v2 = 'v'; // NON-COMPLIANT: plain char assigned to a std::int8_t -} - int main() { /* ========== 1. Assigning a char to another char ========== */ @@ -138,30 +75,30 @@ int main() { /* ===== 1-2. Assigning a char to a char member ===== */ - C1 c1; // COMPLIANT: unsigned char arg passed to an unsigned - // char member through a template + C1 c1(1); // COMPLIANT: unsigned char arg passed to an unsigned + // char member - C2 c2; // COMPLIANT: signed char arg passed to a signed char - // member through a template + C2 c2(1); // COMPLIANT: signed char arg passed to a signed char + // member - C1 c3; // NON-COMPLIANT: plain char arg passed to an unsigned char - // member through a template + C1 c3('x'); // NON-COMPLIANT: plain char arg passed to an unsigned char + // member - C2 c4; // NON-COMPLIANT: plain char arg passed to a signed char - // member through a template + C2 c4('x'); // NON-COMPLIANT: plain char arg passed to a signed char + // member /* Twin cases with std::uint8_t and std::int8_t */ - C5 c5; // COMPLIANT: std::uint8_t arg passed to a - // std::uint8_t member through a template + C5 c5(1); // COMPLIANT: std::uint8_t arg passed to a + // std::uint8_t member - C6 c6; // COMPLIANT: std::int8_t arg passed to a std::int8_t - // member through a template + C6 c6(1); // COMPLIANT: std::int8_t arg passed to a std::int8_t + // member - C5 c7; // NON-COMPLIANT: plain char arg passed to a - // std::uint8_t member through a template + C5 c7('x'); // NON-COMPLIANT: plain char arg passed to a + // std::uint8_t member - C6 c8; // NON-COMPLIANT: plain char arg passed to a std::int8_t - // member through a template + C6 c8('x'); // NON-COMPLIANT: plain char arg passed to a std::int8_t + // member /* ========== 1-3. Assigning a char to a char through a pointer ========== */ @@ -206,9 +143,6 @@ int main() { /* ========== 2. Passing a char argument to a char parameter ========== */ - /* ===== 2-1. Passing char argument to a char parameter of a regular function - * ===== */ - unsigned char a1 = 1; f1(a1); // COMPLIANT: unsigned char arg passed to an unsigned char parameter @@ -233,81 +167,4 @@ int main() { char a8 = 'a'; f10(a8); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter - - /* ===== 2-2. Passing char argument to a char parameter through a template - * ===== */ - - unsigned char a9 = 1; - f5(a9); // COMPLIANT: unsigned char arg passed to an unsigned char parameter - // through a template - - signed char a10 = 1; - f6(a10); // COMPLIANT: signed char arg passed to a signed char parameter - // through a template - - char a11 = 'a'; - f5(a11); // NON-COMPLIANT: plain char arg passed to an unsigned char parameter - // through a template - - char a12 = 'a'; - f6(a12); // NON-COMPLIANT: plain char arg passed to a signed char parameter - // through a template - - /* Twin cases with std::uint8_t and std::int8_t */ - std::uint8_t a13 = 1; - f13(a13); // COMPLIANT: std::uint8_t arg passed to a std::uint8_t parameter - // through a template - - std::int8_t a14 = 1; - f14(a14); // COMPLIANT: std::int8_t arg passed to a std::int8_t parameter - // through a template - - char a15 = 'a'; - f13(a15); // NON-COMPLIANT: plain char arg passed to a std::uint8_t parameter - // through a template - - char a16 = 'a'; - f14(a16); // NON-COMPLIANT: plain char arg passed to a std::int8_t parameter - // through a template - - /* ========== 2-3. Passing a char argument to a char parameter through a - * template ========== */ - - unsigned char a17 = 1; - C9 c9( - a17); // COMPLIANT: unsigned char arg passed to an unsigned char parameter - // of a constructor through a template - - signed char a18 = 1; - C10 c10( - a18); // COMPLIANT: signed char arg passed to an signed - // char parameter of a constructor through a template - - char a19 = 'a'; - C9 c11( - a19); // NON-COMPLIANT: plain char arg passed to an unsigned signed char - // parameter of a constructor through a template - - char a20 = 'a'; - C10 c12(a20); // NON-COMPLIANT: plain char arg passed to an signed char - // parameter of a constructor through a template - - /* Twin cases with std::uint8_t and std::int8_t */ - std::uint8_t a21 = 1; - C13 c13( - a21); // COMPLIANT: std::uint8_t arg passed to a std::uint8_t parameter - // of a constructor through a template - - std::int8_t a22 = 1; - C14 c14( - a22); // COMPLIANT: std::int8_t arg passed to a std::int8_t - // parameter of a constructor through a template - - char a23 = 'a'; - C13 c15(a23); // NON-COMPLIANT: plain char arg passed to a std::uint8_t - // parameter of a constructor through a template - - char a24 = 'a'; - C14 c16(a24); // NON-COMPLIANT: plain char arg passed to a std::int8_t - // parameter of a constructor through a template } From 7d1b27cc0f1914ed8979ca8b5b125fc73c42280c Mon Sep 17 00:00:00 2001 From: knewbury01 Date: Tue, 15 Jul 2025 19:02:45 +0000 Subject: [PATCH 512/628] Bump version to 2.49.0-dev --- c/cert/src/qlpack.yml | 2 +- c/cert/test/qlpack.yml | 2 +- c/common/src/qlpack.yml | 2 +- c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- c/misra/test/qlpack.yml | 2 +- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/qlpack.yml | 2 +- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- docs/user_manual.md | 12 ++++++------ 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index d2ba0816a3..cff1e79631 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.48.0-dev +version: 2.49.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index 98268c5636..9f5f21ba1b 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.48.0-dev +version: 2.49.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 4bbcb5c730..39adc407b9 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.48.0-dev +version: 2.49.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index ce8d7b3ce7..da30625ddb 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.48.0-dev +version: 2.49.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 02f9dceb48..613cb22b26 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.48.0-dev +version: 2.49.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index a720d41779..08e5f579a3 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.48.0-dev +version: 2.49.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index 65ec603f59..4130f08079 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.48.0-dev +version: 2.49.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index f7b3f9ef3f..46f06bed50 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.48.0-dev +version: 2.49.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 999faded05..a89ed8a905 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.48.0-dev +version: 2.49.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index b1c634258a..8634569355 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.48.0-dev +version: 2.49.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index f7938fef71..07a8dc4136 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards -version: 2.48.0-dev +version: 2.49.0-dev license: MIT dependencies: codeql/cpp-all: 2.1.1 diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index 84a581eda1..cb54217f76 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.48.0-dev +version: 2.49.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index f6a4e21428..44baf3efbe 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.48.0-dev +version: 2.49.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index 565c630696..fb0cc1201c 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.48.0-dev +version: 2.49.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index c8a6dd08f8..e563299482 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.48.0-dev +version: 2.49.0-dev license: MIT dependencies: codeql/cpp-all: 2.1.1 diff --git a/docs/user_manual.md b/docs/user_manual.md index fae4623443..f4449082c7 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -36,14 +36,14 @@ ## Release information -This user manual documents release `2.48.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.49.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: - `coding-standards-codeql-packs-2.37.0-dev.zip`: CodeQL packs that can be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `code-scanning-cpp-query-pack-2.48.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.48.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.48.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.48.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.49.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.49.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.49.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.49.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -670,7 +670,7 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.48.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.49.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | From a9c412d9fc2c4034393a4cf8b982d2f7b2f7d6cf Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Tue, 15 Jul 2025 20:57:29 -0700 Subject: [PATCH 513/628] Fix bad joins on function names and unnecessarily large relation on integer constant macros --- .../IncompatibleFunctionDeclarations.ql | 26 +++++++++++-------- ...rectlySizedIntegerConstantMacroArgument.ql | 1 + .../CompatibleDeclarationFunctionDefined.ql | 15 +++++------ ...5-7-15-fix-performance-issues-in-2.20.7.md | 4 +++ 4 files changed, 26 insertions(+), 20 deletions(-) create mode 100644 change_notes/2025-7-15-fix-performance-issues-in-2.20.7.md diff --git a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql index 8c25fe3350..3811d4e417 100644 --- a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql +++ b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql @@ -24,28 +24,32 @@ import codingstandards.c.cert import codingstandards.cpp.types.Compatible import ExternalIdentifiers -predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { +predicate interestedInFunctions( + FunctionDeclarationEntry f1, FunctionDeclarationEntry f2, ExternalIdentifiers d +) { not f1 = f2 and - f1.getDeclaration() = f2.getDeclaration() and - f1.getName() = f2.getName() + d = f1.getDeclaration() and + d = f2.getDeclaration() +} + +predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclarationEntry f2) { + interestedInFunctions(f1, f2, _) } +module FuncDeclEquiv = + FunctionDeclarationTypeEquivalence; + from ExternalIdentifiers d, FunctionDeclarationEntry f1, FunctionDeclarationEntry f2 where not isExcluded(f1, Declarations2Package::incompatibleFunctionDeclarationsQuery()) and not isExcluded(f2, Declarations2Package::incompatibleFunctionDeclarationsQuery()) and - not f1 = f2 and - f1.getDeclaration() = d and - f2.getDeclaration() = d and - f1.getName() = f2.getName() and + interestedInFunctions(f1, f2, d) and ( //return type check - not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, - f2) + not FuncDeclEquiv::equalReturnTypes(f1, f2) or //parameter type check - not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, - f2) + not FuncDeclEquiv::equalParameterTypes(f1, f2) ) and // Apply ordering on start line, trying to avoid the optimiser applying this join too early // in the pipeline diff --git a/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql index 87c945d6b6..1fe052aaae 100644 --- a/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql +++ b/c/misra/src/rules/RULE-7-5/IncorrectlySizedIntegerConstantMacroArgument.ql @@ -20,6 +20,7 @@ predicate matchesSign(IntegerConstantMacro macro, PossiblyNegativeLiteral litera literal.isNegative() implies macro.isSigned() } +bindingset[literal] predicate matchesSize(IntegerConstantMacro macro, PossiblyNegativeLiteral literal) { literal.getRawValue() <= macro.maxValue() and literal.getRawValue() >= macro.minValue() diff --git a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql index 73abc1e048..e7eba7e42a 100644 --- a/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql +++ b/c/misra/src/rules/RULE-8-4/CompatibleDeclarationFunctionDefined.ql @@ -23,13 +23,14 @@ predicate interestedInFunctions(FunctionDeclarationEntry f1, FunctionDeclaration f1.getDeclaration() instanceof ExternalIdentifiers and f1.isDefinition() and f1.getDeclaration() = f2.getDeclaration() and - // This condition should always hold, but removing it affects join order performance. - f1.getName() = f2.getName() and not f2.isDefinition() and not f1.isFromTemplateInstantiation(_) and not f2.isFromTemplateInstantiation(_) } +module FunDeclEquiv = + FunctionDeclarationTypeEquivalence; + from FunctionDeclarationEntry f1 where not isExcluded(f1, Declarations4Package::compatibleDeclarationFunctionDefinedQuery()) and @@ -44,17 +45,13 @@ where or //or one exists that is close but incompatible in some way exists(FunctionDeclarationEntry f2 | - f1.getName() = f2.getName() and - not f2.isDefinition() and - f2.getDeclaration() = f1.getDeclaration() and + interestedInFunctions(f1, f2) and ( //return types differ - not FunctionDeclarationTypeEquivalence::equalReturnTypes(f1, - f2) + not FunDeclEquiv::equalReturnTypes(f1, f2) or //parameter types differ - not FunctionDeclarationTypeEquivalence::equalParameterTypes(f1, - f2) + not FunDeclEquiv::equalParameterTypes(f1, f2) or //parameter names differ parameterNamesUnmatched(f1, f2) diff --git a/change_notes/2025-7-15-fix-performance-issues-in-2.20.7.md b/change_notes/2025-7-15-fix-performance-issues-in-2.20.7.md new file mode 100644 index 0000000000..a936579a97 --- /dev/null +++ b/change_notes/2025-7-15-fix-performance-issues-in-2.20.7.md @@ -0,0 +1,4 @@ + - `DCL40-C`, `RULE-8-4`: `IncompatibleFunctionDeclarations.ql`, `CompatibleDeclarationFunctionDefined.ql`. + - Fixed performance issues introduced when upgrading to CodeQL `2.20.7` by removing unnecessary check that matching function declarations have matching names. + - `RULE-7-5`: `IncorrectlySizedIntegerConstantMacroArgument.ql`. + - Added a `bindingset` to improve performance when checking if a literal matches the size of an integer constant macro. \ No newline at end of file From cfdc0d15f5e517ec6e28ebb8a14e214735203904 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 17 Jul 2025 17:03:56 +0100 Subject: [PATCH 514/628] A7-1-7: Address performance issue on 2.20.7 Poor join ordering on locations. --- ...erDeclarationAndInitializationNotOnSeparateLines.ql | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql b/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql index ac98fe699d..addd8af697 100644 --- a/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql +++ b/cpp/autosar/src/rules/A7-1-7/IdentifierDeclarationAndInitializationNotOnSeparateLines.ql @@ -55,11 +55,9 @@ where //omit the cases where there is one struct identifier on a struct var line used with typedef not exists(Struct s | s.getADeclarationEntry() = e1 and e1 instanceof TypeDeclarationEntry) and not exists(Struct s | s.getATypeNameUse() = e1 and e1 instanceof TypeDeclarationEntry) and - exists(Location l1, Location l2 | - e1.getLocation() = l1 and - e2.getLocation() = l2 and - not l1 = l2 and - l1.getFile() = l2.getFile() and - l1.getStartLine() = l2.getStartLine() + exists(string file, int startline | + e1.getLocation().hasLocationInfo(file, startline, _, _, _) and + e2.getLocation().hasLocationInfo(file, startline, _, _, _) and + not e1.getLocation() = e2.getLocation() ) select e1, "Expression statement and identifier are on the same line." From df2247ef350ed5fb7e4fa46a3e8d679a12afd89d Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 17 Jul 2025 17:46:54 +0100 Subject: [PATCH 515/628] A2-7-3: Address performance issues on upgrade to 2.20.7 - Only consider declarations within user code - as results in system headers will be thrown away, and significantly bloat the interemediate relation sizes. - Inline the function scope exclusion to documentable declaration. - Extract utility predicates for determining if there's a documented definition, or whether there are only definitions. --- .../A2-7-3/UndocumentedUserDefinedType.ql | 81 +++++++++++-------- 1 file changed, 46 insertions(+), 35 deletions(-) diff --git a/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql b/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql index f2dd0dc8bc..020d1d4ee1 100644 --- a/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql +++ b/cpp/autosar/src/rules/A2-7-3/UndocumentedUserDefinedType.ql @@ -65,30 +65,46 @@ class DocumentableDeclaration extends Declaration { string declarationType; DocumentableDeclaration() { - this instanceof UserType and - declarationType = "user-defined type" and - // Exclude template parameter types. - not this.(UserType).involvesTemplateParameter() - or - this instanceof Function and - declarationType = "function" and - // Exclude compiler generated functions, which cannot reasonably be documented. - not this.(Function).isCompilerGenerated() and - // Exclude instantiated template functions, which cannot reasonably be documented. - not this.(Function).isFromTemplateInstantiation(_) and - // Exclude anonymous lambda functions. - not exists(LambdaExpression lc | lc.getLambdaFunction() = this) and - //Exclude friend functions (because they have 2 entries in the database), and only one shows documented truly - not exists(FriendDecl d | - d.getFriend().(Function).getDefinition() = this.getADeclarationEntry() + // Within the users codebase, not a system header + exists(this.getFile().getRelativePath()) and + // Not required to be documented, as used within same scope + not isInFunctionScope(this) and + ( + this instanceof UserType and + declarationType = "user-defined type" and + // Exclude template parameter types. + not this.(UserType).involvesTemplateParameter() + or + this instanceof Function and + declarationType = "function" and + // Exclude compiler generated functions, which cannot reasonably be documented. + not this.(Function).isCompilerGenerated() and + // Exclude instantiated template functions, which cannot reasonably be documented. + not this.(Function).isFromTemplateInstantiation(_) and + // Exclude anonymous lambda functions. + not exists(LambdaExpression lc | lc.getLambdaFunction() = this) and + //Exclude friend functions (because they have 2 entries in the database), and only one shows documented truly + not exists(FriendDecl d | + d.getFriend().(Function).getDefinition() = this.getADeclarationEntry() + ) + or + this instanceof MemberVariable and + declarationType = "member variable" and + // Exclude memeber variables in instantiated templates, which cannot reasonably be documented. + not this.(MemberVariable).isFromTemplateInstantiation(_) and + // Exclude compiler generated variables, such as those for anonymous lambda functions + not this.(MemberVariable).isCompilerGenerated() ) - or - this instanceof MemberVariable and - declarationType = "member variable" and - // Exclude memeber variables in instantiated templates, which cannot reasonably be documented. - not this.(MemberVariable).isFromTemplateInstantiation(_) and - // Exclude compiler generated variables, such as those for anonymous lambda functions - not this.(MemberVariable).isCompilerGenerated() + } + + private predicate hasDocumentedDefinition() { + // Check if the declaration has a documented definition + exists(DeclarationEntry de | de = getADeclarationEntry() and isDocumented(de)) + } + + private predicate hasOnlyDefinitions() { + // Check if the declaration has only definitions, i.e., no non-definition entries + not exists(DeclarationEntry de | de = getADeclarationEntry() and not de.isDefinition()) } /** Gets a `DeclarationEntry` for this declaration that should be documented. */ @@ -96,20 +112,16 @@ class DocumentableDeclaration extends Declaration { // Find a declaration entry that is not documented result = getADeclarationEntry() and not isDocumented(result) and - ( - // Report any non definition DeclarationEntry that is not documented - // as long as there is no corresponding documented definition (which must be for a forward declaration) - not result.isDefinition() and - not exists(DeclarationEntry de | - de = getADeclarationEntry() and de.isDefinition() and isDocumented(de) - ) - or + if result.isDefinition() + then // Report the definition DeclarationEntry, only if there are no non-definition `DeclarationEntry`'s // The rationale here is that documenting both the non-definition and definition declaration entries // is redundant - result.isDefinition() and - not exists(DeclarationEntry de | de = getADeclarationEntry() and not de.isDefinition()) - ) + hasOnlyDefinitions() + else + // Report any non definition DeclarationEntry that is not documented + // as long as there is no corresponding documented definition (which must be for a forward declaration) + not hasDocumentedDefinition() } /** Gets a string describing the type of declaration. */ @@ -144,7 +156,6 @@ from DocumentableDeclaration d, DeclarationEntry de where not isExcluded(de, CommentsPackage::undocumentedUserDefinedTypeQuery()) and not isExcluded(d, CommentsPackage::undocumentedUserDefinedTypeQuery()) and - not isInFunctionScope(d) and d.getAnUndocumentedDeclarationEntry() = de select de, "Declaration entry for " + d.getDeclarationType() + " " + d.getName() + From 1f4654ec5cd027934b0052e3c2f1e3e6a60028b7 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 17 Jul 2025 23:04:08 +0100 Subject: [PATCH 516/628] RecursiveFunctions: Address performance issues with 2.20.7 Avoid cross-product on function. --- ...llThemselvesEitherDirectlyOrIndirectly.qll | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.qll b/cpp/common/src/codingstandards/cpp/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.qll index 87f27c134f..e54e4378e9 100644 --- a/cpp/common/src/codingstandards/cpp/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.qll +++ b/cpp/common/src/codingstandards/cpp/rules/functionscallthemselveseitherdirectlyorindirectly/FunctionsCallThemselvesEitherDirectlyOrIndirectly.qll @@ -19,17 +19,17 @@ class RecursiveCall extends FunctionCall { } } -query predicate problems(FunctionCall fc, string message, Function f, string f_name) { - exists(RecursiveCall call | - not isExcluded(call, getQuery()) and - f = fc.getTarget() and - f_name = fc.getTarget().getName() and - fc.getTarget() = call.getTarget() and - if fc.getTarget() = fc.getEnclosingFunction() - then message = "This call directly invokes its containing function $@." - else - message = - "The function " + fc.getEnclosingFunction() + - " is indirectly recursive via this call to $@." - ) +class RecursiveFunction extends Function { + RecursiveFunction() { exists(RecursiveCall fc | fc.getEnclosingFunction() = this) } +} + +query predicate problems(FunctionCall fc, string message, RecursiveFunction f, string functionName) { + not isExcluded(fc, getQuery()) and + f = fc.getTarget() and + functionName = f.getName() and + if f = fc.getEnclosingFunction() + then message = "This call directly invokes its containing function $@." + else + message = + "The function " + fc.getEnclosingFunction() + " is indirectly recursive via this call to $@." } From fe9a48da4d8ed2fc43794726a3bb5f560624f355 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 18 Jul 2025 08:05:34 +0100 Subject: [PATCH 517/628] EXP16-C: Address compilation error --- .../DoNotCompareFunctionPointersToConstantValues.ql | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql index e65d58a652..5f347d817a 100644 --- a/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql +++ b/c/cert/src/rules/EXP16-C/DoNotCompareFunctionPointersToConstantValues.ql @@ -23,13 +23,17 @@ import codingstandards.cpp.types.FunctionType import codingstandards.cpp.exprs.FunctionExprs import codingstandards.cpp.exprs.Guards -abstract class EffectivelyComparison extends Element { +final class FinalElement = Element; + +abstract class EffectivelyComparison extends FinalElement { abstract string getExplanation(); abstract FunctionExpr getFunctionExpr(); } -class ExplicitComparison extends EffectivelyComparison, ComparisonOperation { +final class FinalComparisonOperation = ComparisonOperation; + +class ExplicitComparison extends EffectivelyComparison, FinalComparisonOperation { Expr constantExpr; FunctionExpr funcExpr; From d078e04d54876f51559d029b1b9eb691c9ece086 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Tue, 29 Jul 2025 09:15:15 +0100 Subject: [PATCH 518/628] Create misra-c++-2023-help.md.template --- .../templates/misra-c++-2023-help.md.template | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 scripts/generate_rules/templates/misra-c++-2023-help.md.template diff --git a/scripts/generate_rules/templates/misra-c++-2023-help.md.template b/scripts/generate_rules/templates/misra-c++-2023-help.md.template new file mode 100644 index 0000000000..4fb7b17ee8 --- /dev/null +++ b/scripts/generate_rules/templates/misra-c++-2023-help.md.template @@ -0,0 +1,49 @@ +# {{ rule_id }}: {{ name }} + +This query implements the {{ standard_name | escape }} rule {{ rule_id | escape }}: + +> {{ rule_title }} + +## Classification + +** REPLACE THIS WITH THE CORRECT CLASSIFICATION ** +* required +* implementation +* automated + +## Rationale + +**REPLACE THIS WITH RATIONAL, IF ANY** + +## Exception + +**REPLACE THIS WITH EXCEPTION, IF ANY** + +## Example + +```cpp +// REPLACE THIS WITH C++ EXAMPLE, IF ANY +``` + +## See more + +** REPLACE THIS WITH THE ANY SEE MORE REFERENCES ** + +## Implementation notes + +{% if implementation_scope is defined %} +{{ implementation_scope["description"] }} +{% if implementation_scope["items"] is iterable %} +{% for implementation_scope_entry in implementation_scope["items"] %} +* {{ implementation_scope_entry }} +{% endfor %} +{% endif %} +{% else %} +None +{% endif %} + +## References + +{% if standard_title | length %} +* {{ standard_title | escape }}: [{{ rule_id }}: {{ rule_title }}]({{ standard_url }}) +{% endif %} From c8f559c1af50db1419c068dfbcac3cf587639449 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 29 Jul 2025 19:33:14 -0400 Subject: [PATCH 519/628] Generate query files for "Statements" package --- .../cpp/exclusions/cpp/RuleMetadata.qll | 3 + .../cpp/exclusions/cpp/Statements.qll | 61 +++++++++++++++ .../AppropriateStructureOfSwitchStatement.ql | 25 ++++++ .../LegacyForStatementsShouldBeSimple.ql | 24 ++++++ ...orRangeInitializerAtMostOneFunctionCall.ql | 25 ++++++ ...opriateStructureOfSwitchStatement.expected | 1 + ...ppropriateStructureOfSwitchStatement.qlref | 1 + ...LegacyForStatementsShouldBeSimple.expected | 1 + .../LegacyForStatementsShouldBeSimple.qlref | 1 + ...eInitializerAtMostOneFunctionCall.expected | 1 + ...angeInitializerAtMostOneFunctionCall.qlref | 1 + rule_packages/cpp/Statements.json | 78 +++++++++++++++++++ 12 files changed, 222 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/cpp/Statements.qll create mode 100644 cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql create mode 100644 cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql create mode 100644 cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql create mode 100644 cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected create mode 100644 cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.qlref create mode 100644 cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected create mode 100644 cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.qlref create mode 100644 cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected create mode 100644 cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.qlref create mode 100644 rule_packages/cpp/Statements.json diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index abd6aeff96..0db51d4224 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -47,6 +47,7 @@ import SideEffects1 import SideEffects2 import SmartPointers1 import SmartPointers2 +import Statements import Strings import Templates import Toolchain @@ -102,6 +103,7 @@ newtype TCPPQuery = TSideEffects2PackageQuery(SideEffects2Query q) or TSmartPointers1PackageQuery(SmartPointers1Query q) or TSmartPointers2PackageQuery(SmartPointers2Query q) or + TStatementsPackageQuery(StatementsQuery q) or TStringsPackageQuery(StringsQuery q) or TTemplatesPackageQuery(TemplatesQuery q) or TToolchainPackageQuery(ToolchainQuery q) or @@ -157,6 +159,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isSideEffects2QueryMetadata(query, queryId, ruleId, category) or isSmartPointers1QueryMetadata(query, queryId, ruleId, category) or isSmartPointers2QueryMetadata(query, queryId, ruleId, category) or + isStatementsQueryMetadata(query, queryId, ruleId, category) or isStringsQueryMetadata(query, queryId, ruleId, category) or isTemplatesQueryMetadata(query, queryId, ruleId, category) or isToolchainQueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Statements.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Statements.qll new file mode 100644 index 0000000000..fe202ce31f --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Statements.qll @@ -0,0 +1,61 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype StatementsQuery = + TAppropriateStructureOfSwitchStatementQuery() or + TLegacyForStatementsShouldBeSimpleQuery() or + TForRangeInitializerAtMostOneFunctionCallQuery() + +predicate isStatementsQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `appropriateStructureOfSwitchStatement` query + StatementsPackage::appropriateStructureOfSwitchStatementQuery() and + queryId = + // `@id` for the `appropriateStructureOfSwitchStatement` query + "cpp/misra/appropriate-structure-of-switch-statement" and + ruleId = "RULE-9-4-2" and + category = "required" + or + query = + // `Query` instance for the `legacyForStatementsShouldBeSimple` query + StatementsPackage::legacyForStatementsShouldBeSimpleQuery() and + queryId = + // `@id` for the `legacyForStatementsShouldBeSimple` query + "cpp/misra/legacy-for-statements-should-be-simple" and + ruleId = "RULE-9-5-1" and + category = "advisory" + or + query = + // `Query` instance for the `forRangeInitializerAtMostOneFunctionCall` query + StatementsPackage::forRangeInitializerAtMostOneFunctionCallQuery() and + queryId = + // `@id` for the `forRangeInitializerAtMostOneFunctionCall` query + "cpp/misra/for-range-initializer-at-most-one-function-call" and + ruleId = "RULE-9-5-2" and + category = "required" +} + +module StatementsPackage { + Query appropriateStructureOfSwitchStatementQuery() { + //autogenerate `Query` type + result = + // `Query` type for `appropriateStructureOfSwitchStatement` query + TQueryCPP(TStatementsPackageQuery(TAppropriateStructureOfSwitchStatementQuery())) + } + + Query legacyForStatementsShouldBeSimpleQuery() { + //autogenerate `Query` type + result = + // `Query` type for `legacyForStatementsShouldBeSimple` query + TQueryCPP(TStatementsPackageQuery(TLegacyForStatementsShouldBeSimpleQuery())) + } + + Query forRangeInitializerAtMostOneFunctionCallQuery() { + //autogenerate `Query` type + result = + // `Query` type for `forRangeInitializerAtMostOneFunctionCall` query + TQueryCPP(TStatementsPackageQuery(TForRangeInitializerAtMostOneFunctionCallQuery())) + } +} diff --git a/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql b/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql new file mode 100644 index 0000000000..8bfa68f5f2 --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/appropriate-structure-of-switch-statement + * @name RULE-9-4-2: The structure of a switch statement shall be appropriate + * @description A switch statement should have an appropriate structure with proper cases, default + * labels, and break statements to ensure clear control flow and prevent unintended + * fall-through behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-9-4-2 + * correctness + * maintainability + * readability + * external/misra/allocated-target/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +from +where + not isExcluded(x, StatementsPackage::appropriateStructureOfSwitchStatementQuery()) and +select diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql new file mode 100644 index 0000000000..1a29e90a40 --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -0,0 +1,24 @@ +/** + * @id cpp/misra/legacy-for-statements-should-be-simple + * @name RULE-9-5-1: Legacy for statements should be simple + * @description Legacy for statements with complex initialization, condition, and increment + * expressions can be difficult to understand and maintain. Simple for loops are more + * readable. + * @kind problem + * @precision high + * @problem.severity recommendation + * @tags external/misra/id/rule-9-5-1 + * maintainability + * readability + * external/misra/allocated-target/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra + +from +where + not isExcluded(x, StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) and +select diff --git a/cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql b/cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql new file mode 100644 index 0000000000..47d27287bc --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/for-range-initializer-at-most-one-function-call + * @name RULE-9-5-2: A for-range-initializer shall contain at most one function call + * @description Multiple function calls in a for-range-initializer can lead to unclear iteration + * behavior and potential side effects that make the code harder to understand and + * debug. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-9-5-2 + * correctness + * maintainability + * readability + * external/misra/allocated-target/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +from +where + not isExcluded(x, StatementsPackage::forRangeInitializerAtMostOneFunctionCallQuery()) and +select diff --git a/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected b/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.qlref b/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.qlref new file mode 100644 index 0000000000..9f475afbe1 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.qlref @@ -0,0 +1 @@ +rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.qlref b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.qlref new file mode 100644 index 0000000000..bf443d6d68 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.qlref @@ -0,0 +1 @@ +rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected b/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected new file mode 100644 index 0000000000..2ec1a0ac6c --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected @@ -0,0 +1 @@ +No expected results have yet been specified \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.qlref b/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.qlref new file mode 100644 index 0000000000..be7fc0ef10 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.qlref @@ -0,0 +1 @@ +rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql \ No newline at end of file diff --git a/rule_packages/cpp/Statements.json b/rule_packages/cpp/Statements.json new file mode 100644 index 0000000000..91a643253d --- /dev/null +++ b/rule_packages/cpp/Statements.json @@ -0,0 +1,78 @@ +{ + "MISRA-C++-2023": { + "RULE-9-4-2": { + "properties": { + "allocated-target": [ + "Single Translation Unit" + ], + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "A switch statement should have an appropriate structure with proper cases, default labels, and break statements to ensure clear control flow and prevent unintended fall-through behavior.", + "kind": "problem", + "name": "The structure of a switch statement shall be appropriate", + "precision": "very-high", + "severity": "error", + "short_name": "AppropriateStructureOfSwitchStatement", + "tags": [ + "correctness", + "maintainability", + "readability" + ] + } + ], + "title": "The structure of a switch statement shall be appropriate" + }, + "RULE-9-5-1": { + "properties": { + "allocated-target": [ + "Single Translation Unit" + ], + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Legacy for statements with complex initialization, condition, and increment expressions can be difficult to understand and maintain. Simple for loops are more readable.", + "kind": "problem", + "name": "Legacy for statements should be simple", + "precision": "high", + "severity": "recommendation", + "short_name": "LegacyForStatementsShouldBeSimple", + "tags": [ + "maintainability", + "readability" + ] + } + ], + "title": "Legacy for statements should be simple" + }, + "RULE-9-5-2": { + "properties": { + "allocated-target": [ + "Single Translation Unit" + ], + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Multiple function calls in a for-range-initializer can lead to unclear iteration behavior and potential side effects that make the code harder to understand and debug.", + "kind": "problem", + "name": "A for-range-initializer shall contain at most one function call", + "precision": "very-high", + "severity": "error", + "short_name": "ForRangeInitializerAtMostOneFunctionCall", + "tags": [ + "correctness", + "maintainability", + "readability" + ] + } + ], + "title": "A for-range-initializer shall contain at most one function call" + } + } +} From ffcb4323eb4ad9d95f1ed6332a06457afb92ed54 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 30 Jul 2025 17:13:22 -0400 Subject: [PATCH 520/628] Add agent-generated first draft --- .../AppropriateStructureOfSwitchStatement.ql | 52 ++- ...opriateStructureOfSwitchStatement.expected | 16 +- cpp/misra/test/rules/RULE-9-4-2/test.cpp | 304 ++++++++++++++++++ 3 files changed, 368 insertions(+), 4 deletions(-) create mode 100644 cpp/misra/test/rules/RULE-9-4-2/test.cpp diff --git a/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql b/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql index 8bfa68f5f2..3d68e31abb 100644 --- a/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql +++ b/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql @@ -18,8 +18,54 @@ import cpp import codingstandards.cpp.misra +import codingstandards.cpp.SwitchStatement -from +from SwitchStmt switch, string message where - not isExcluded(x, StatementsPackage::appropriateStructureOfSwitchStatementQuery()) and -select + not isExcluded(switch, StatementsPackage::appropriateStructureOfSwitchStatementQuery()) and + ( + // RULE-16-1: Switch not well-formed (has inappropriate statements) + exists(SwitchCase case | + case = switch.getASwitchCase() and + switchCaseNotWellFormed(case) and + message = "has a case that contains inappropriate statements (only expression, compound, selection, iteration or try statements are allowed)" + ) + or + // RULE-16-2: Nested switch labels + exists(SwitchCase case | + case = switch.getASwitchCase() and + case instanceof NestedSwitchCase and + message = "contains a switch label that is not directly within the switch body" + ) + or + // RULE-16-3: Non-empty case doesn't terminate with break + exists(SwitchCase case | + case = switch.getASwitchCase() and + case instanceof CaseDoesNotTerminate and + message = "has a non-empty case that does not terminate with an unconditional break or throw statement" + ) + or + // RULE-16-4: Missing default clause + not switch.hasDefaultCase() and + message = "is missing a default clause" + or + // RULE-16-5: Default clause not first or last + exists(SwitchCase defaultCase | + switch.getDefaultCase() = defaultCase and + exists(defaultCase.getPreviousSwitchCase()) and + finalClauseInSwitchNotDefault(switch) and + message = "has a default clause that is not the first or last switch label" + ) + or + // RULE-16-6: Less than two case clauses + count(SwitchCase case | + switch.getASwitchCase() = case and + case.getNextSwitchCase() != case.getFollowingStmt() + ) + 1 < 2 and + message = "has fewer than two switch-clauses" + or + // RULE-16-7: Boolean switch expression + switch instanceof BooleanSwitchStmt and + message = "has a controlling expression of essentially Boolean type" + ) +select switch, "Switch statement " + message + "." diff --git a/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected b/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected index 2ec1a0ac6c..8900facc63 100644 --- a/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected +++ b/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected @@ -1 +1,15 @@ -No expected results have yet been specified \ No newline at end of file +| test.cpp:40:3:40:8 | Switch statement has a case that contains inappropriate statements (only expression, compound, selection, iteration or try statements are allowed). | +| test.cpp:86:3:86:8 | Switch statement has a non-empty case that does not terminate with an unconditional break or throw statement. | +| test.cpp:86:3:86:8 | Switch statement has a non-empty case that does not terminate with an unconditional break or throw statement. | +| test.cpp:98:3:98:8 | Switch statement has a non-empty case that does not terminate with an unconditional break or throw statement. | +| test.cpp:123:3:123:8 | Switch statement is missing a default clause. | +| test.cpp:166:3:166:8 | Switch statement has a default clause that is not the first or last switch label. | +| test.cpp:203:3:203:8 | Switch statement has fewer than two switch-clauses. | +| test.cpp:210:3:210:8 | Switch statement has fewer than two switch-clauses. | +| test.cpp:235:3:235:8 | Switch statement has a controlling expression of essentially Boolean type. | +| test.cpp:245:3:245:8 | Switch statement has a controlling expression of essentially Boolean type. | +| test.cpp:266:3:266:8 | Switch statement has a controlling expression of essentially Boolean type. | +| test.cpp:266:3:266:8 | Switch statement is missing a default clause. | +| test.cpp:266:3:266:8 | Switch statement has fewer than two switch-clauses. | +| test.cpp:275:3:275:8 | Switch statement has a non-empty case that does not terminate with an unconditional break or throw statement. | +| test.cpp:275:3:275:8 | Switch statement has a default clause that is not the first or last switch label. | \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-4-2/test.cpp b/cpp/misra/test/rules/RULE-9-4-2/test.cpp new file mode 100644 index 0000000000..fc948480b2 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-4-2/test.cpp @@ -0,0 +1,304 @@ +// Test cases for RULE-9-4-2: The structure of a switch statement shall be +// appropriate This rule combines RULE-16-1 through RULE-16-7 + +void test_rule_16_1_well_formed(int expr) { + int i = 0; + + // COMPLIANT - well-formed switch with proper statements + switch (expr) { + case 1: + i++; // expression statement + break; + case 2: { // compound statement + i++; + } break; + case 3: + if (i > 0) { // selection statement + i++; + } + break; + case 4: + while (i < 10) { // iteration statement + i++; + } + break; + default: + break; + } + + // NON_COMPLIANT - switch with inappropriate statement (declaration) + switch (expr) { + case 1: + int j = 5; // declaration statement - not allowed + break; + default: + break; + } +} + +void test_rule_16_2_nested_labels(int expr) { + // COMPLIANT - labels directly within switch body + switch (expr) { + case 1: + break; + case 2: + break; + default: + break; + } + + // NON_COMPLIANT - nested switch labels (this would be a compiler error in + // practice) switch (expr) { case 1: + // { + // case 2: // nested label - not allowed + // break; + // } + // break; + // default: + // break; + // } +} + +void test_rule_16_3_termination(int expr) { + int i = 0; + + // COMPLIANT - all cases properly terminated + switch (expr) { + case 1: + i++; + break; + case 2: + case 3: // empty cases are fine + i++; + break; + case 4: + throw "error"; // throw is also valid termination + default: + break; + } + + // NON_COMPLIANT - case 1 falls through without break + switch (expr) { + case 1: // NON_COMPLIANT - missing break + i++; + case 2: // COMPLIANT - properly terminated + i++; + break; + default: + break; + } + + // NON_COMPLIANT - default case falls through + switch (expr) { + case 1: + i++; + break; + default: // NON_COMPLIANT - missing break + i++; + } +} + +void test_rule_16_4_default_label(int expr) { + int i = 0; + + // COMPLIANT - has default label + switch (expr) { + case 1: + i++; + break; + case 2: + i++; + break; + default: + break; + } + + // NON_COMPLIANT - missing default label + switch (expr) { + case 1: + i++; + break; + case 2: + i++; + break; + } +} + +void test_rule_16_5_default_position(int expr) { + int i = 0; + + // COMPLIANT - default is first + switch (expr) { + default: + i++; + break; + case 1: + i++; + break; + case 2: + i++; + break; + } + + // COMPLIANT - default is last + switch (expr) { + case 1: + i++; + break; + case 2: + i++; + break; + default: + i++; + break; + } + + // NON_COMPLIANT - default is in the middle + switch (expr) { + case 1: + i++; + break; + default: // NON_COMPLIANT - not first or last + i++; + break; + case 2: + i++; + break; + } +} + +void test_rule_16_6_two_clauses(int expr) { + int i = 0; + + // COMPLIANT - has multiple clauses + switch (expr) { + case 1: + i++; + break; + case 2: + i++; + break; + default: + break; + } + + // NON_COMPLIANT - only has default (single clause) + switch (expr) { + default: + i++; + break; + } + + // NON_COMPLIANT - only has one case plus default (still only one effective + // clause) + switch (expr) { + case 1: + default: + i++; + break; + } +} + +void test_rule_16_7_boolean_expression() { + int i = 0; + bool flag = true; + + // COMPLIANT - non-boolean expression + switch (i) { + case 0: + break; + case 1: + break; + default: + break; + } + + // NON_COMPLIANT - boolean expression + switch (flag) { + case true: + break; + case false: + break; + default: + break; + } + + // NON_COMPLIANT - boolean comparison expression + switch (i == 0) { + case true: + break; + case false: + break; + default: + break; + } +} + +int f() { return 1; } + +void test_complex_violations(int expr) { + int i = 0; + bool flag = true; + + // NON_COMPLIANT - multiple violations: + // - Boolean expression (16-7) + // - Missing default (16-4) + // - Single clause (16-6) + switch (flag) { + case true: + i++; + } + + // NON_COMPLIANT - multiple violations: + // - Fall-through case (16-3) + // - Default not first/last (16-5) + switch (expr) { + case 1: // NON_COMPLIANT - falls through + i++; + default: // NON_COMPLIANT - not first/last + i++; + break; + case 2: + i++; + break; + } + + switch (expr) { + int i = 0; + case 1: + i++; + } + + switch (int x = f(); x) { + case 1: + i++; + } + + switch (expr = f(); expr) { + case 1: + i++; + } + + switch (expr) { + case 1: + { + case 2: + i++; + } + } + + switch (expr) { + case 1: { + i++; + goto someLabel; + someLabel: + i++; + } + } + + switch (expr) { + int x = 1; + case 1: + i++; + } +} \ No newline at end of file From 221b9b2c4b1be5074aacb763549e8fa1c78bfa52 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 30 Jul 2025 18:41:25 -0400 Subject: [PATCH 521/628] Add some test cases --- cpp/misra/test/rules/RULE-9-4-2/test.cpp | 310 ++++++++++------------- 1 file changed, 128 insertions(+), 182 deletions(-) diff --git a/cpp/misra/test/rules/RULE-9-4-2/test.cpp b/cpp/misra/test/rules/RULE-9-4-2/test.cpp index fc948480b2..e99a2fb1f4 100644 --- a/cpp/misra/test/rules/RULE-9-4-2/test.cpp +++ b/cpp/misra/test/rules/RULE-9-4-2/test.cpp @@ -1,304 +1,250 @@ -// Test cases for RULE-9-4-2: The structure of a switch statement shall be -// appropriate This rule combines RULE-16-1 through RULE-16-7 +int i = 0; -void test_rule_16_1_well_formed(int expr) { - int i = 0; - - // COMPLIANT - well-formed switch with proper statements - switch (expr) { +/** + * Test the initializer of a switch statement. + */ +void testInitializer(int expr) { + switch (expr) { // COMPLIANT: No initializer case 1: - i++; // expression statement - break; - case 2: { // compound statement i++; - } break; - case 3: - if (i > 0) { // selection statement - i++; - } - break; - case 4: - while (i < 10) { // iteration statement - i++; - } break; default: + i--; break; } - // NON_COMPLIANT - switch with inappropriate statement (declaration) - switch (expr) { + switch (int j = 0; + expr) { // COMPLIANT: Only declaration statement can be an initializer case 1: - int j = 5; // declaration statement - not allowed + j++; break; default: + j--; break; } -} -void test_rule_16_2_nested_labels(int expr) { - // COMPLIANT - labels directly within switch body - switch (expr) { + switch ( + i = 1; + expr) { // NON_COMPLIANT: Only declaration statement can be an initializer case 1: - break; - case 2: + i++; break; default: + i--; break; } - - // NON_COMPLIANT - nested switch labels (this would be a compiler error in - // practice) switch (expr) { case 1: - // { - // case 2: // nested label - not allowed - // break; - // } - // break; - // default: - // break; - // } } -void test_rule_16_3_termination(int expr) { - int i = 0; - - // COMPLIANT - all cases properly terminated - switch (expr) { +void testNestedCaseLabels(int expr) { + switch (expr) { // COMPLIANT: Consecutive case labels are allowed case 1: - i++; - break; case 2: - case 3: // empty cases are fine i++; break; - case 4: - throw "error"; // throw is also valid termination default: + i--; break; } - // NON_COMPLIANT - case 1 falls through without break - switch (expr) { - case 1: // NON_COMPLIANT - missing break - i++; - case 2: // COMPLIANT - properly terminated + switch (expr) { // NON_COMPLIANT: Statements with case labels should all be at + // the same level + case 1: { + case 2: i++; break; + } default: break; } - // NON_COMPLIANT - default case falls through - switch (expr) { + switch (expr) { // NON_COMPLIANT: Statements with case labels should all be at + // the same level case 1: i++; break; - default: // NON_COMPLIANT - missing break - i++; + case 2: { + default: + break; + } } } -void test_rule_16_4_default_label(int expr) { - int i = 0; - - // COMPLIANT - has default label - switch (expr) { - case 1: +void testOtherLabelsInBranch(int expr) { + switch (expr) { // NON_COMPLIANT: Non-case labels appearing in a switch branch + case 1: { i++; - break; - case 2: + goto someLabel; + someLabel: i++; break; default: break; } + } +} + +void testLeadingNonCaseStatement(int expr) { + switch (expr) { // NON_COMPLIANT: Non-case statement is the first statement in + // the switch body - // NON_COMPLIANT - missing default label - switch (expr) { case 1: i++; break; - case 2: - i++; + default: break; } } -void test_rule_16_5_default_position(int expr) { - int i = 0; +[[noreturn]] void f() {} +void g() {} - // COMPLIANT - default is first - switch (expr) { - default: - i++; - break; +void testSwitchBranchTerminator(int expr) { + switch (expr) { // COMPLIANT: Break is allowed as a branch terminator case 1: i++; break; - case 2: - i++; + default: break; } - // COMPLIANT - default is last - switch (expr) { + for (int j = 0; j++; j < 10) { + switch (expr) { // COMPLIANT: Continue is allowed as a branch terminator + case 1: + i++; + continue; + default: + continue; + } + } + + switch (expr) { // COMPLIANT: Goto is allowed as a branch terminator case 1: i++; - break; - case 2: - i++; - break; + goto error; default: - i++; - break; + goto error; } - // NON_COMPLIANT - default is in the middle - switch (expr) { + switch (expr) { // COMPLIANT: Throw is allowed as a branch terminator case 1: i++; - break; - default: // NON_COMPLIANT - not first or last - i++; - break; - case 2: - i++; - break; + throw; + default: + throw; } -} - -void test_rule_16_6_two_clauses(int expr) { - int i = 0; - // COMPLIANT - has multiple clauses - switch (expr) { + switch (expr) { // COMPLIANT: Call to a `[[noreturn]]` function is allowed as + // a branch terminator case 1: i++; - break; - case 2: - i++; - break; + f(); default: - break; + f(); } - // NON_COMPLIANT - only has default (single clause) - switch (expr) { + switch (expr) { // NON_COMPLIANT: Branch ends with a call to a function that + // is not `[[noreturn]]` + case 1: + i++; + g(); default: + g(); + } + + switch (expr) { // COMPLIANT: Return is allowed as a branch terminator + case 1: i++; - break; + return; + default: + return; } - // NON_COMPLIANT - only has one case plus default (still only one effective - // clause) - switch (expr) { + switch (expr) { // COMPLIANT: Empty statement with `[[fallthrough]]` is + // allowed as a branch terminator case 1: + i++; + [[fallthrough]]; default: i++; - break; } -} -void test_rule_16_7_boolean_expression() { - int i = 0; - bool flag = true; +error: + return; +} - // COMPLIANT - non-boolean expression - switch (i) { - case 0: - break; +void testSwitchBranchCount(int expr) { + switch (expr) { // COMPLIANT: Branch count is 2 case 1: + i++; break; default: + i++; break; } - // NON_COMPLIANT - boolean expression - switch (flag) { - case true: - break; - case false: - break; + switch (expr) { // NON_COMPLIANT: Branch count is 1 default: + i++; break; } - // NON_COMPLIANT - boolean comparison expression - switch (i == 0) { - case true: - break; - case false: - break; + switch (expr) { // NON_COMPLIANT: Branch count is 1 + case 1: + case 2: default: + i++; break; } } -int f() { return 1; } - -void test_complex_violations(int expr) { - int i = 0; - bool flag = true; - - // NON_COMPLIANT - multiple violations: - // - Boolean expression (16-7) - // - Missing default (16-4) - // - Single clause (16-6) - switch (flag) { - case true: - i++; - } +enum E { V1, V2, V3 }; - // NON_COMPLIANT - multiple violations: - // - Fall-through case (16-3) - // - Default not first/last (16-5) - switch (expr) { - case 1: // NON_COMPLIANT - falls through - i++; - default: // NON_COMPLIANT - not first/last +void testDefaultLabelPresence(int expr) { + switch (expr) { // COMPLIANT: There is a default branch + case 1: i++; break; - case 2: + default: i++; break; } - switch (expr) { - int i = 0; - case 1: - i++; - } - - switch (int x = f(); x) { + switch (expr) { // NON_COMPLIANT: Default branch is missing case 1: i++; + break; } - switch (expr = f(); expr) { - case 1: - i++; - } + E e; - switch (expr) { - case 1: - { - case 2: - i++; - } + switch (e) { // COMPLIANT: There is a default branch + case V1: + i++; + break; + default: + break; } - switch (expr) { - case 1: { + switch (e) { // NON_COMPLIANT: Default branch is missing on a non-exhaustive + // enum switch + case V1: i++; - goto someLabel; - someLabel: + break; + case V2: i++; - } + break; } - switch (expr) { - int x = 1; - case 1: + switch (e) { // COMPLIANT: Default branch can be omitted on an exhaustive enum + // switch + case V1: + i++; + break; + case V2: i++; + break; + case V3: + i++; + break; } } \ No newline at end of file From fabb7e5db8af43e4b245dee1fb61dc971674b1b2 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 31 Jul 2025 18:39:06 -0400 Subject: [PATCH 522/628] Finish first draft --- .../AppropriateStructureOfSwitchStatement.ql | 109 +++++++++++------- ...opriateStructureOfSwitchStatement.expected | 27 ++--- cpp/misra/test/rules/RULE-9-4-2/test.cpp | 9 +- 3 files changed, 83 insertions(+), 62 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql b/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql index 3d68e31abb..f419834325 100644 --- a/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql +++ b/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql @@ -19,53 +19,74 @@ import cpp import codingstandards.cpp.misra import codingstandards.cpp.SwitchStatement +import codingstandards.cpp.Noreturn from SwitchStmt switch, string message where not isExcluded(switch, StatementsPackage::appropriateStructureOfSwitchStatementQuery()) and - ( - // RULE-16-1: Switch not well-formed (has inappropriate statements) - exists(SwitchCase case | - case = switch.getASwitchCase() and - switchCaseNotWellFormed(case) and - message = "has a case that contains inappropriate statements (only expression, compound, selection, iteration or try statements are allowed)" + /* 1. There is a statement that appears as an initializer and is not a declaration statement. */ + exists(Stmt initializer | initializer = switch.getInitialization() | + not initializer instanceof DeclStmt + ) and + message = "contains a statement that that is not a simple declaration" + or + /* 2. There is a switch case label that does not lead a branch (i.e. a switch case label is nested). */ + exists(SwitchCase case | case = switch.getASwitchCase() | case instanceof NestedSwitchCase) and + message = "contains a switch label that is not directly within the switch body" + or + /* 3. There is a non-case label in a label group. */ + exists(SwitchCase case | case = switch.getASwitchCase() | + case.getAStmt().getChildStmt*() instanceof LabelStmt + ) and + message = "contains a statement label that is not a case label" + or + /* 4. There is a statement before the first case label. */ + exists(Stmt switchBody | switchBody = switch.getStmt() | + not switchBody.getChild(0) instanceof SwitchCase + ) and + message = "has a statement that is not a case label as its first element" + or + /* 5. There is a switch case whose terminator is not one of the allowed kinds. */ + exists(SwitchCase case, Stmt lastStmt | + case = switch.getASwitchCase() and lastStmt = case.getLastStmt() + | + not ( + lastStmt instanceof BreakStmt or + lastStmt instanceof ReturnStmt or + lastStmt instanceof GotoStmt or + lastStmt instanceof ContinueStmt or + lastStmt.(ExprStmt).getExpr() instanceof ThrowExpr or + lastStmt.(ExprStmt).getExpr().(Call).getTarget() instanceof NoreturnFunction or + lastStmt.getAnAttribute().getName().matches("%fallthrough") // We'd like to consider compiler variants such as `clang::fallthrough`. ) - or - // RULE-16-2: Nested switch labels - exists(SwitchCase case | - case = switch.getASwitchCase() and - case instanceof NestedSwitchCase and - message = "contains a switch label that is not directly within the switch body" - ) - or - // RULE-16-3: Non-empty case doesn't terminate with break - exists(SwitchCase case | - case = switch.getASwitchCase() and - case instanceof CaseDoesNotTerminate and - message = "has a non-empty case that does not terminate with an unconditional break or throw statement" - ) - or - // RULE-16-4: Missing default clause - not switch.hasDefaultCase() and - message = "is missing a default clause" - or - // RULE-16-5: Default clause not first or last - exists(SwitchCase defaultCase | - switch.getDefaultCase() = defaultCase and - exists(defaultCase.getPreviousSwitchCase()) and - finalClauseInSwitchNotDefault(switch) and - message = "has a default clause that is not the first or last switch label" - ) - or - // RULE-16-6: Less than two case clauses - count(SwitchCase case | - switch.getASwitchCase() = case and - case.getNextSwitchCase() != case.getFollowingStmt() - ) + 1 < 2 and - message = "has fewer than two switch-clauses" - or - // RULE-16-7: Boolean switch expression - switch instanceof BooleanSwitchStmt and - message = "has a controlling expression of essentially Boolean type" - ) + ) and + message = "is missing a terminator that moves the control out of its body" + or + /* 6. The switch statement does not have more than two unique branches. */ + count(SwitchCase case | + case = switch.getASwitchCase() and + /* + * If the next switch case is the following statement of this switch case, then the two + * switch cases are consecutive and should be considered as constituting one branch + * together. + */ + + not case.getNextSwitchCase() = case.getFollowingStmt() + | + case + ) < 2 and + message = "contains less than two branches" + or + /* 7-1. The switch statement is not an enum switch statement and is missing a default case. */ + not switch instanceof EnumSwitch and + not switch.hasDefaultCase() and + message = "lacks a default case" + or + /* + * 7-2. The switch statement is an enum switch statement and is missing a branch for a + * variant. + */ + + exists(switch.(EnumSwitch).getAMissingCase()) and + message = "lacks a case for one of its variants" select switch, "Switch statement " + message + "." diff --git a/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected b/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected index 8900facc63..ab8320ef8f 100644 --- a/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected +++ b/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected @@ -1,15 +1,12 @@ -| test.cpp:40:3:40:8 | Switch statement has a case that contains inappropriate statements (only expression, compound, selection, iteration or try statements are allowed). | -| test.cpp:86:3:86:8 | Switch statement has a non-empty case that does not terminate with an unconditional break or throw statement. | -| test.cpp:86:3:86:8 | Switch statement has a non-empty case that does not terminate with an unconditional break or throw statement. | -| test.cpp:98:3:98:8 | Switch statement has a non-empty case that does not terminate with an unconditional break or throw statement. | -| test.cpp:123:3:123:8 | Switch statement is missing a default clause. | -| test.cpp:166:3:166:8 | Switch statement has a default clause that is not the first or last switch label. | -| test.cpp:203:3:203:8 | Switch statement has fewer than two switch-clauses. | -| test.cpp:210:3:210:8 | Switch statement has fewer than two switch-clauses. | -| test.cpp:235:3:235:8 | Switch statement has a controlling expression of essentially Boolean type. | -| test.cpp:245:3:245:8 | Switch statement has a controlling expression of essentially Boolean type. | -| test.cpp:266:3:266:8 | Switch statement has a controlling expression of essentially Boolean type. | -| test.cpp:266:3:266:8 | Switch statement is missing a default clause. | -| test.cpp:266:3:266:8 | Switch statement has fewer than two switch-clauses. | -| test.cpp:275:3:275:8 | Switch statement has a non-empty case that does not terminate with an unconditional break or throw statement. | -| test.cpp:275:3:275:8 | Switch statement has a default clause that is not the first or last switch label. | \ No newline at end of file +| test.cpp:28:3:37:3 | switch (...) ... | Switch statement contains a statement that that is not a simple declaration. | +| test.cpp:51:3:60:3 | switch (...) ... | Switch statement contains a switch label that is not directly within the switch body. | +| test.cpp:62:3:71:3 | switch (...) ... | Switch statement contains a switch label that is not directly within the switch body. | +| test.cpp:75:3:85:3 | switch (...) ... | Switch statement contains a statement label that is not a case label. | +| test.cpp:89:3:97:3 | switch (...) ... | Switch statement has a statement that is not a case label as its first element. | +| test.cpp:147:3:154:3 | switch (...) ... | Switch statement is missing a terminator that moves the control out of its body. | +| test.cpp:188:3:192:3 | switch (...) ... | Switch statement contains less than two branches. | +| test.cpp:194:3:200:3 | switch (...) ... | Switch statement contains less than two branches. | +| test.cpp:215:3:219:3 | switch (...) ... | Switch statement contains less than two branches. | +| test.cpp:215:3:219:3 | switch (...) ... | Switch statement lacks a default case. | +| test.cpp:223:3:229:3 | switch (...) ... | Switch statement lacks a case for one of its variants. | +| test.cpp:231:3:239:3 | switch (...) ... | Switch statement lacks a case for one of its variants. | diff --git a/cpp/misra/test/rules/RULE-9-4-2/test.cpp b/cpp/misra/test/rules/RULE-9-4-2/test.cpp index e99a2fb1f4..6bbb97e81b 100644 --- a/cpp/misra/test/rules/RULE-9-4-2/test.cpp +++ b/cpp/misra/test/rules/RULE-9-4-2/test.cpp @@ -1,3 +1,5 @@ +#include + int i = 0; /** @@ -77,16 +79,16 @@ void testOtherLabelsInBranch(int expr) { someLabel: i++; break; + } default: break; } - } } void testLeadingNonCaseStatement(int expr) { switch (expr) { // NON_COMPLIANT: Non-case statement is the first statement in // the switch body - + int x = 1; case 1: i++; break; @@ -95,7 +97,7 @@ void testLeadingNonCaseStatement(int expr) { } } -[[noreturn]] void f() {} +[[noreturn]] void f() { exit(0); } void g() {} void testSwitchBranchTerminator(int expr) { @@ -166,6 +168,7 @@ void testSwitchBranchTerminator(int expr) { [[fallthrough]]; default: i++; + break; } error: From 6909528361de035834ce6cdd60e7fa30311560cc Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 1 Aug 2025 14:56:20 -0400 Subject: [PATCH 523/628] Add test case for Rule 9.5.2 --- cpp/misra/test/rules/RULE-9-5-2/test.cpp | 129 +++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 cpp/misra/test/rules/RULE-9-5-2/test.cpp diff --git a/cpp/misra/test/rules/RULE-9-5-2/test.cpp b/cpp/misra/test/rules/RULE-9-5-2/test.cpp new file mode 100644 index 0000000000..9d5255f0c0 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-5-2/test.cpp @@ -0,0 +1,129 @@ +#include + +/* Helper functions */ +std::vector getData() { return {1, 2, 3}; } +std::vector processData(const std::vector &input) { return input; } +std::vector getContainer() { return {4, 5, 6}; } + +class MyContainer { +public: + MyContainer() = default; + MyContainer(std::vector data) : data_(data) {} + std::vector::iterator begin() { return data_.begin(); } + std::vector::iterator end() { return data_.end(); } + +private: + std::vector data_{7, 8, 9}; +}; + +class ConvertibleToVector { +public: + operator std::vector() const { return {}; } + std::array::iterator begin() { return data_.begin(); } + std::array::iterator end() { return data_.end(); } + +private: + std::array data_{7, 8, 9}; +}; + +std::vector operator+(const std::vector &a, + const std::vector &b) { + std::vector result = a; + result.insert(result.end(), b.begin(), b.end()); + return result; +} + +std::vector convertToIntVector(std::vector vector) { return vector; } + +int main() { + std::vector localVec = {1, 2, 3}; + std::vector *vecPtr = &localVec; + ConvertibleToVector convertible; + + /* ========== 1. EXPLICIT FUNCTION CALLS ========== */ + + for (auto x : getContainer()) { // COMPLIANT: 1 function call only + } + + for (auto x : processData(getData())) { // NON_COMPLIANT: 2 function calls + } + + /* ========== 2. OBJECT CREATION (CONSTRUCTOR CALLS) ========== */ + + for (auto x : + std::vector{1, 2, 3}) { // COMPLIANT: 1 constructor call only + } + + for (auto x : MyContainer()) { // COMPLIANT: 1 constructor call only + } + + for (auto x : std::string("hello")) { // COMPLIANT: 1 constructor call only + } + + for (auto x : std::vector( + getData())) { // NON-COMPLIANT: 1 constructor + 1 function call + } + + for (auto x : MyContainer(processData( + localVec))) { // NON-COMPLIANT: 1 constructor + 1 function call + } + + auto data = std::vector(getData()); + for (auto x : data) { // NON-COMPLIANT: 1 constructor + 1 function call + } + + MyContainer myContainer = MyContainer(processData(localVec)); + for (auto x : myContainer) { // NON-COMPLIANT: 1 constructor + 1 function call + } + + /* ========== 3. OPERATOR OVERLOADING ========== */ + + std::vector anotherVec = {4, 5, 6}; + for (auto x : localVec + anotherVec) { // COMPLIANT: 1 operator+ call only + } + + std::vector vec1 = {1}, vec2 = {2}, vec3 = {3}; + for (auto x : (vec1 + vec2) + vec3) { // NON-COMPLIANT: 2 operator+ calls + } + + for (auto x : + getData() + + processData( + localVec)) { // NON-COMPLIANT: 2 function calls + 1 operator call + } + + std::vector vec1 = {1}, vec2 = {2}, vec3 = {3}; + std::vector appendedVector = (vec1 + vec2) + vec3; + for (auto x : appendedVector) { // COMPLIANT: 0 calls + } + + std::vector appendedVector2 = getData() + processData(localVec); + for (auto x : appendedVector2) { // COMPLIANT: 0 calls + } + + /* ========== 4. IMPLICIT CONVERSIONS ========== */ + + ConvertibleToVector convertible; + for (auto x : convertible) { // COMPLIANT: 1 conversion operator call only + } + + for (auto x : + convertToIntVector(convertible)) { // NON_COMPLIANT: 1 function call + 1 + // conversion operator call + } + + for (auto x : + convertToIntVector(convertible)) { // NON_COMPLIANT: 1 function call + 1 + // conversion operator call + } + + std::vector intVector1 = convertToIntVector(convertible); + for (auto x : intVector1) { // NON_COMPLIANT: 1 function call + 1 + // conversion operator call + } + + std::vector intVector2 = convertToIntVector(convertible); + for (auto x : intVector2) { // NON_COMPLIANT: 1 function call + 1 + // conversion operator call + } +} \ No newline at end of file From 0b5250f892849cee3c9959005534c1196513a30f Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 1 Aug 2025 15:07:53 -0400 Subject: [PATCH 524/628] Minor --- cpp/misra/test/rules/RULE-9-5-2/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/misra/test/rules/RULE-9-5-2/test.cpp b/cpp/misra/test/rules/RULE-9-5-2/test.cpp index 9d5255f0c0..ba3bfa191b 100644 --- a/cpp/misra/test/rules/RULE-9-5-2/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-2/test.cpp @@ -18,7 +18,7 @@ class MyContainer { class ConvertibleToVector { public: - operator std::vector() const { return {}; } + operator std::vector() const { return {7, 8, 9}; } std::array::iterator begin() { return data_.begin(); } std::array::iterator end() { return data_.end(); } From b23986210658da7dab5751520793f26aad706c2a Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 1 Aug 2025 15:52:58 -0400 Subject: [PATCH 525/628] Update test case for Rule 9.5.2 --- cpp/misra/test/rules/RULE-9-5-2/test.cpp | 26 +++++++++++------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/cpp/misra/test/rules/RULE-9-5-2/test.cpp b/cpp/misra/test/rules/RULE-9-5-2/test.cpp index ba3bfa191b..025a247ad7 100644 --- a/cpp/misra/test/rules/RULE-9-5-2/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-2/test.cpp @@ -1,4 +1,5 @@ #include +#include /* Helper functions */ std::vector getData() { return {1, 2, 3}; } @@ -9,8 +10,8 @@ class MyContainer { public: MyContainer() = default; MyContainer(std::vector data) : data_(data) {} - std::vector::iterator begin() { return data_.begin(); } - std::vector::iterator end() { return data_.end(); } + std::vector::const_iterator begin() const { return data_.begin(); } + std::vector::const_iterator end() const { return data_.end(); } private: std::vector data_{7, 8, 9}; @@ -19,15 +20,15 @@ class MyContainer { class ConvertibleToVector { public: operator std::vector() const { return {7, 8, 9}; } - std::array::iterator begin() { return data_.begin(); } - std::array::iterator end() { return data_.end(); } + std::array::const_iterator begin() const { return data_.begin(); } + std::array::const_iterator end() const { return data_.end(); } private: std::array data_{7, 8, 9}; }; -std::vector operator+(const std::vector &a, - const std::vector &b) { +std::vector operator+(std::vector a, + std::vector b) { std::vector result = a; result.insert(result.end(), b.begin(), b.end()); return result; @@ -37,8 +38,6 @@ std::vector convertToIntVector(std::vector vector) { return vector; } int main() { std::vector localVec = {1, 2, 3}; - std::vector *vecPtr = &localVec; - ConvertibleToVector convertible; /* ========== 1. EXPLICIT FUNCTION CALLS ========== */ @@ -92,7 +91,6 @@ int main() { localVec)) { // NON-COMPLIANT: 2 function calls + 1 operator call } - std::vector vec1 = {1}, vec2 = {2}, vec3 = {3}; std::vector appendedVector = (vec1 + vec2) + vec3; for (auto x : appendedVector) { // COMPLIANT: 0 calls } @@ -104,26 +102,26 @@ int main() { /* ========== 4. IMPLICIT CONVERSIONS ========== */ ConvertibleToVector convertible; - for (auto x : convertible) { // COMPLIANT: 1 conversion operator call only + for (int x : convertible) { // COMPLIANT: 1 conversion operator call only } - for (auto x : + for (int x : convertToIntVector(convertible)) { // NON_COMPLIANT: 1 function call + 1 // conversion operator call } - for (auto x : + for (int x : convertToIntVector(convertible)) { // NON_COMPLIANT: 1 function call + 1 // conversion operator call } std::vector intVector1 = convertToIntVector(convertible); - for (auto x : intVector1) { // NON_COMPLIANT: 1 function call + 1 + for (int x : intVector1) { // NON_COMPLIANT: 1 function call + 1 // conversion operator call } std::vector intVector2 = convertToIntVector(convertible); - for (auto x : intVector2) { // NON_COMPLIANT: 1 function call + 1 + for (int x : intVector2) { // NON_COMPLIANT: 1 function call + 1 // conversion operator call } } \ No newline at end of file From 9ea891af74447a22b2540ab95f7e3fff9fd2531a Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 1 Aug 2025 17:09:31 -0400 Subject: [PATCH 526/628] Change occurrence of `std::iterator<...>` to `__iterator` Also prefix the member type with `const` depending on the iterator. --- cpp/common/test/includes/standard-library/array | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/common/test/includes/standard-library/array b/cpp/common/test/includes/standard-library/array index ca4d3291ad..9465ccba97 100644 --- a/cpp/common/test/includes/standard-library/array +++ b/cpp/common/test/includes/standard-library/array @@ -8,8 +8,8 @@ namespace std { template struct array { typedef T &reference; typedef const T &const_reference; - typedef std::iterator iterator; - typedef std::iterator const_iterator; + typedef __iterator iterator; + typedef __iterator const_iterator; typedef size_t size_type; typedef ptrdiff_t difference_type; From a0133887da526bb2ab7ed971556ecfe142d07b1a Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 1 Aug 2025 18:01:15 -0400 Subject: [PATCH 527/628] Add first draft of `ForRangeInitializerAtMostOneFunctionCall` --- ...orRangeInitializerAtMostOneFunctionCall.ql | 8 +-- ...eInitializerAtMostOneFunctionCall.expected | 9 +++- cpp/misra/test/rules/RULE-9-5-2/test.cpp | 54 ++++++++++--------- 3 files changed, 43 insertions(+), 28 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql b/cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql index 47d27287bc..b78da2ad99 100644 --- a/cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql +++ b/cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql @@ -19,7 +19,9 @@ import cpp import codingstandards.cpp.misra -from +from RangeBasedForStmt foreach, string message where - not isExcluded(x, StatementsPackage::forRangeInitializerAtMostOneFunctionCallQuery()) and -select + not isExcluded(foreach, StatementsPackage::forRangeInitializerAtMostOneFunctionCallQuery()) and + count(Call call | call = foreach.getRange().getAChild*() | call) >= 2 and + message = "has nested call expression in its initializer" +select foreach, "Range-based for loop " + message + "." diff --git a/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected b/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected index 2ec1a0ac6c..a8567ff48d 100644 --- a/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected +++ b/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected @@ -1 +1,8 @@ -No expected results have yet been specified \ No newline at end of file +| test.cpp:48:3:49:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | +| test.cpp:56:3:59:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | +| test.cpp:71:3:73:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | +| test.cpp:95:3:97:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | +| test.cpp:99:3:101:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | +| test.cpp:103:3:107:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | +| test.cpp:116:3:119:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | +| test.cpp:121:3:124:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | diff --git a/cpp/misra/test/rules/RULE-9-5-2/test.cpp b/cpp/misra/test/rules/RULE-9-5-2/test.cpp index 025a247ad7..b9ec5a0574 100644 --- a/cpp/misra/test/rules/RULE-9-5-2/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-2/test.cpp @@ -1,5 +1,5 @@ -#include #include +#include /* Helper functions */ std::vector getData() { return {1, 2, 3}; } @@ -10,8 +10,8 @@ class MyContainer { public: MyContainer() = default; MyContainer(std::vector data) : data_(data) {} - std::vector::const_iterator begin() const { return data_.begin(); } - std::vector::const_iterator end() const { return data_.end(); } + std::vector::iterator begin() { return data_.begin(); } + std::vector::iterator end() { return data_.end(); } private: std::vector data_{7, 8, 9}; @@ -20,15 +20,16 @@ class MyContainer { class ConvertibleToVector { public: operator std::vector() const { return {7, 8, 9}; } - std::array::const_iterator begin() const { return data_.begin(); } - std::array::const_iterator end() const { return data_.end(); } + std::array::iterator begin() { return data_.begin(); } + std::array::iterator end() { return data_.end(); } + std::array::const_iterator begin() const { return data_.cbegin(); } + std::array::const_iterator end() const { return data_.cend(); } private: std::array data_{7, 8, 9}; }; -std::vector operator+(std::vector a, - std::vector b) { +std::vector operator+(std::vector a, std::vector b) { std::vector result = a; result.insert(result.end(), b.begin(), b.end()); return result; @@ -49,8 +50,12 @@ int main() { /* ========== 2. OBJECT CREATION (CONSTRUCTOR CALLS) ========== */ + for (auto x : std::vector(3)) { // COMPLIANT: 1 constructor call only + } + for (auto x : - std::vector{1, 2, 3}) { // COMPLIANT: 1 constructor call only + std::vector{1, 2, 3}) { // NON_COMPLIANT: 2 constructor call to + // `vector` and `initializer_list`, respectively } for (auto x : MyContainer()) { // COMPLIANT: 1 constructor call only @@ -77,12 +82,22 @@ int main() { /* ========== 3. OPERATOR OVERLOADING ========== */ + std::vector vec1 = {1}, vec2 = {2}, vec3 = {3}; + std::vector appendedVector = (vec1 + vec2) + vec3; + for (auto x : appendedVector) { // COMPLIANT: 0 calls + } + + std::vector appendedVector2 = getData() + processData(localVec); + for (auto x : appendedVector2) { // COMPLIANT: 0 calls + } + std::vector anotherVec = {4, 5, 6}; - for (auto x : localVec + anotherVec) { // COMPLIANT: 1 operator+ call only + for (auto x : localVec + anotherVec) { // NON_COMPLIANT: 2 calls to vector's + // constructor, 1 operator+ call } - std::vector vec1 = {1}, vec2 = {2}, vec3 = {3}; - for (auto x : (vec1 + vec2) + vec3) { // NON-COMPLIANT: 2 operator+ calls + for (auto x : (vec1 + vec2) + vec3) { // NON-COMPLIANT: 3 calls to vector's + // constructor, 2 operator+ calls } for (auto x : @@ -91,18 +106,11 @@ int main() { localVec)) { // NON-COMPLIANT: 2 function calls + 1 operator call } - std::vector appendedVector = (vec1 + vec2) + vec3; - for (auto x : appendedVector) { // COMPLIANT: 0 calls - } - - std::vector appendedVector2 = getData() + processData(localVec); - for (auto x : appendedVector2) { // COMPLIANT: 0 calls - } - /* ========== 4. IMPLICIT CONVERSIONS ========== */ ConvertibleToVector convertible; - for (int x : convertible) { // COMPLIANT: 1 conversion operator call only + for (int x : + ConvertibleToVector()) { // COMPLIANT: 1 conversion operator call only } for (int x : @@ -116,12 +124,10 @@ int main() { } std::vector intVector1 = convertToIntVector(convertible); - for (int x : intVector1) { // NON_COMPLIANT: 1 function call + 1 - // conversion operator call + for (int x : intVector1) { // COMPLIANT: 0 function calls } std::vector intVector2 = convertToIntVector(convertible); - for (int x : intVector2) { // NON_COMPLIANT: 1 function call + 1 - // conversion operator call + for (int x : intVector2) { // COMPLIANT: 0 function calls } } \ No newline at end of file From 1c623f4dc2c3664152114ba5622b9ae515415b2c Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 8 Aug 2025 12:57:43 -0400 Subject: [PATCH 528/628] Add test cases --- cpp/misra/test/rules/RULE-9-5-1/test.cpp | 147 +++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 cpp/misra/test/rules/RULE-9-5-1/test.cpp diff --git a/cpp/misra/test/rules/RULE-9-5-1/test.cpp b/cpp/misra/test/rules/RULE-9-5-1/test.cpp new file mode 100644 index 0000000000..0dafea56ef --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-5-1/test.cpp @@ -0,0 +1,147 @@ +void f(int &x) {} // Function that takes a non-const integer reference +void g(int *x) {} // Function that takes a non-const integer pointer + +int main() { + int j = 5; + + /* ========== 1. Type of the initialized counter variable ========== */ + + for (int i = 0; i < 10; i++) { // COMPLIANT: `i` has an integer type + } + + for (float i = 0.0; i < 10; + i++) { // NON_COMPLIANT: `i` has a non-integer type + } + + /* ========== 2. Termination condition ========== */ + + for (int i = 0; i < 10; i++) { // COMPLIANT: `<` is a relational operator + } + + for (int i = 0; i == 10; + i++) { // NON_COMPLIANT: `==` is not a relational operator + } + + for (int i = 0; j < 10; i++) { // NON_COMPLIANT: `j` is not the loop counter + j++; + } + + /* ========== 3. Updating expression ========== */ + + for (int i = 0; i < 10; + ++i) { // COMPLIANT: Pre-increment operator used as the update expression + } + + for (int i = 0; i < 10; i++) { // COMPLIANT: Post-increment operator used as + // the update expression + } + + for (int i = 0; i < 10; i += 3) { // COMPLIANT: Add-and-assign operator used + // as the update expression with loop step 3 + } + + for (int i = 0; i < 10; + i *= 2) { // NON_COMPLIANT: Mutiplication is not incrementing + } + + /* ========== 4. Type of the loop counter and the loop bound ========== */ + + for (int i = 0; i < 10; i++) { // COMPLIANT: 0 and 10 are of same type + } + + for (unsigned long long int i = 0; i < 10; + i++) { // COMPLIANT: The loop counter has type bigger than that of the + // loop bound + } + + for (int i = 0; i < 10ull; + i++) { // NON_COMPLIANT: The type of the loop counter is not bigger + // than that of the loop bound + } + + for (int i = 0; i < j; + i++) { // NON_COMPLIANT: The loop bound is not a constant + } + + /* ========== 5. Immutability of the loop bound and the loop step ========== + */ + + for (int i = 0; i < 10; + i++) { // COMPLIANT: The update expression is an post-increment operation + // and its loop step is always 1 + } + + for (int i = 0; i < 10; i += 2) { // COMPLIANT: The loop step is always 2 + } + + for (int i = 0; i < 10; + i += + j) { // COMPLIANT: The loop step `j` is not mutated anywhere in the loop + } + + for (int i = 0; i < 10; + i += j) { // NON_COMPLIANT: The loop step `j` is mutated in the loop + j++; + } + + for (int i = 0; i < 10; + i += j, j++) { // NON_COMPLIANT: The loop step `j` is mutated in the loop + } + + for (int i = 0; i < j; i++) { // COMPLIANT: The loop bound `j` is not mutated + // anywhere in the loop + } + + for (int i = 0; i < j; i++) { // COMPLIANT: The loop bound `j` is not mutated + // anywhere in the loop + } + + for (int i = 0; i < j; + i++) { // NON_COMPLIANT: The loop bound `j` is mutated in the loop + j++; + } + + /* ========== 6. Existence of pointers to the loop counter, loop bound, and + * loop step ========== */ + + int k = 10; + int l = 2; + + for (int i = 0; i < k; i += l) { // COMPLIANT: The loop counter, bound, and + // step are not taken addresses of + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed + // as a non-const reference + f(j); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed + // as a non-const pointer + g(&j); + } + + for (int i = j; i < k; + i += + l) { // NON_COMPLIANT: The loop bound is passed as a non-const pointer + f(k); + } + + for (int i = j; i < k; + i += + l) { // NON_COMPLIANT: The loop bound is passed as a non-const pointer + g(&k); + } + + for (int i = j; i < k; + i += + l) { // NON_COMPLIANT: The loop step is passed as a non-const pointer + f(l); + } + + for (int i = j; i < k; + i += + l) { // NON_COMPLIANT: The loop step is passed as a non-const pointer + g(&l); + } +} \ No newline at end of file From 4fdd046e4549d38fcd7949a2d217dd263f995097 Mon Sep 17 00:00:00 2001 From: Jeroen Ketema Date: Fri, 15 Aug 2025 17:01:05 +0200 Subject: [PATCH 529/628] Fix typo in the alert message of `InvalidatedEnvStringPointers.qll` --- .../InvalidatedEnvStringPointers.expected | 12 +++++----- .../2025-08-15-typo-in-alert-message.md | 2 ++ .../InvalidatedEnvStringPointers.qll | 4 ++-- .../InvalidatedEnvStringPointers.expected | 22 +++++++++---------- 4 files changed, 21 insertions(+), 19 deletions(-) create mode 100644 change_notes/2025-08-15-typo-in-alert-message.md diff --git a/c/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected b/c/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected index 9270a5ac15..26a84ecd8a 100644 --- a/c/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected +++ b/c/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected @@ -1,6 +1,6 @@ -| test.c:21:14:21:19 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.c:13:12:13:17 | call to getenv | call to getenv | test.c:17:13:17:18 | call to getenv | call to getenv | -| test.c:134:14:134:17 | temp | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.c:130:12:130:17 | call to getenv | call to getenv | test.c:131:11:131:16 | call to getenv | call to getenv | -| test.c:134:20:134:22 | tmp | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.c:131:11:131:16 | call to getenv | call to getenv | test.c:130:12:130:17 | call to getenv | call to getenv | -| test.c:165:14:165:26 | tmpvar_global | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.c:157:19:157:24 | call to getenv | call to getenv | test.c:161:20:161:25 | call to getenv | call to getenv | -| test.c:188:18:188:18 | r | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.c:185:7:185:15 | call to setlocale | call to setlocale | test.c:187:8:187:17 | call to localeconv | call to localeconv | -| test.c:208:10:208:15 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.c:202:12:202:17 | call to getenv | call to getenv | test.c:206:3:206:8 | call to f11fun | call to f11fun | +| test.c:21:14:21:19 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.c:13:12:13:17 | call to getenv | call to getenv | test.c:17:13:17:18 | call to getenv | call to getenv | +| test.c:134:14:134:17 | temp | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.c:130:12:130:17 | call to getenv | call to getenv | test.c:131:11:131:16 | call to getenv | call to getenv | +| test.c:134:20:134:22 | tmp | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.c:131:11:131:16 | call to getenv | call to getenv | test.c:130:12:130:17 | call to getenv | call to getenv | +| test.c:165:14:165:26 | tmpvar_global | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.c:157:19:157:24 | call to getenv | call to getenv | test.c:161:20:161:25 | call to getenv | call to getenv | +| test.c:188:18:188:18 | r | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.c:185:7:185:15 | call to setlocale | call to setlocale | test.c:187:8:187:17 | call to localeconv | call to localeconv | +| test.c:208:10:208:15 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.c:202:12:202:17 | call to getenv | call to getenv | test.c:206:3:206:8 | call to f11fun | call to f11fun | diff --git a/change_notes/2025-08-15-typo-in-alert-message.md b/change_notes/2025-08-15-typo-in-alert-message.md new file mode 100644 index 0000000000..a953f3e86d --- /dev/null +++ b/change_notes/2025-08-15-typo-in-alert-message.md @@ -0,0 +1,2 @@ +- `ENV34-C`, `RULE-21-20`, `RULE-25-5-3`: `DoNotStorePointersReturnedByEnvFunctions.ql`, `CallToSetlocaleInvalidatesOldPointers.ql`, `CallToSetlocaleInvalidatesOldPointersMisra.ql` + - Fixed a misspelling of "subsequent" in the alert message. diff --git a/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll b/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll index 0f4a98cf6f..50b27d819d 100644 --- a/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll +++ b/cpp/common/src/codingstandards/cpp/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.qll @@ -69,10 +69,10 @@ query predicate problems( // The two calls are incompatible fc1 != fc2 and incompatibleFunctions(fc1.getTarget(), fc2.getFunction()) and - // The pointer returned by fc1 accessed in `e` afer the second `GetenvFunctionCall` + // The pointer returned by fc1 accessed in `e` after the second `GetenvFunctionCall` DataFlow::localExprFlow(fc1, e) and e = fc2.getASuccessor+() and - message = "This pointer was returned by a $@ and may have been overwritten by the susequent $@." and + message = "This pointer was returned by a $@ and may have been overwritten by the subsequent $@." and fc1text = fc1.toString() and fc2text = fc2.toString() } diff --git a/cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected b/cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected index 36c66a94fe..b183ca7c42 100644 --- a/cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected +++ b/cpp/common/test/rules/invalidatedenvstringpointers/InvalidatedEnvStringPointers.expected @@ -1,11 +1,11 @@ -| test.cpp:21:14:21:19 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:13:12:13:17 | call to getenv | call to getenv | test.cpp:17:13:17:18 | call to getenv | call to getenv | -| test.cpp:134:14:134:17 | temp | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:130:12:130:17 | call to getenv | call to getenv | test.cpp:131:11:131:16 | call to getenv | call to getenv | -| test.cpp:134:20:134:22 | tmp | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:131:11:131:16 | call to getenv | call to getenv | test.cpp:130:12:130:17 | call to getenv | call to getenv | -| test.cpp:165:14:165:26 | tmpvar_global | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:157:19:157:24 | call to getenv | call to getenv | test.cpp:161:20:161:25 | call to getenv | call to getenv | -| test.cpp:188:18:188:18 | r | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:185:7:185:15 | call to setlocale | call to setlocale | test.cpp:187:8:187:17 | call to localeconv | call to localeconv | -| test.cpp:208:10:208:15 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:202:12:202:17 | call to getenv | call to getenv | test.cpp:206:3:206:8 | call to f11fun | call to f11fun | -| test.cpp:216:16:216:17 | r1 | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:214:14:214:18 | call to ctime | call to ctime | test.cpp:215:3:215:9 | call to asctime | call to asctime | -| test.cpp:226:16:226:17 | r1 | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:222:14:222:18 | call to ctime | call to ctime | test.cpp:225:14:225:20 | call to asctime | call to asctime | -| test.cpp:231:16:231:17 | r2 | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:225:14:225:20 | call to asctime | call to asctime | test.cpp:229:8:229:12 | call to ctime | call to ctime | -| test.cpp:240:16:240:17 | r1 | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:236:19:236:27 | call to localtime | call to localtime | test.cpp:239:19:239:24 | call to gmtime | call to gmtime | -| test.cpp:245:16:245:17 | r2 | This pointer was returned by a $@ and may have been overwritten by the susequent $@. | test.cpp:239:19:239:24 | call to gmtime | call to gmtime | test.cpp:243:8:243:16 | call to localtime | call to localtime | +| test.cpp:21:14:21:19 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:13:12:13:17 | call to getenv | call to getenv | test.cpp:17:13:17:18 | call to getenv | call to getenv | +| test.cpp:134:14:134:17 | temp | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:130:12:130:17 | call to getenv | call to getenv | test.cpp:131:11:131:16 | call to getenv | call to getenv | +| test.cpp:134:20:134:22 | tmp | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:131:11:131:16 | call to getenv | call to getenv | test.cpp:130:12:130:17 | call to getenv | call to getenv | +| test.cpp:165:14:165:26 | tmpvar_global | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:157:19:157:24 | call to getenv | call to getenv | test.cpp:161:20:161:25 | call to getenv | call to getenv | +| test.cpp:188:18:188:18 | r | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:185:7:185:15 | call to setlocale | call to setlocale | test.cpp:187:8:187:17 | call to localeconv | call to localeconv | +| test.cpp:208:10:208:15 | tmpvar | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:202:12:202:17 | call to getenv | call to getenv | test.cpp:206:3:206:8 | call to f11fun | call to f11fun | +| test.cpp:216:16:216:17 | r1 | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:214:14:214:18 | call to ctime | call to ctime | test.cpp:215:3:215:9 | call to asctime | call to asctime | +| test.cpp:226:16:226:17 | r1 | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:222:14:222:18 | call to ctime | call to ctime | test.cpp:225:14:225:20 | call to asctime | call to asctime | +| test.cpp:231:16:231:17 | r2 | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:225:14:225:20 | call to asctime | call to asctime | test.cpp:229:8:229:12 | call to ctime | call to ctime | +| test.cpp:240:16:240:17 | r1 | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:236:19:236:27 | call to localtime | call to localtime | test.cpp:239:19:239:24 | call to gmtime | call to gmtime | +| test.cpp:245:16:245:17 | r2 | This pointer was returned by a $@ and may have been overwritten by the subsequent $@. | test.cpp:239:19:239:24 | call to gmtime | call to gmtime | test.cpp:243:8:243:16 | call to localtime | call to localtime | From 8c10a1746fc813c1d9493aa7f298e0ebff512abe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 06:43:26 +0000 Subject: [PATCH 530/628] Bump actions/checkout from 4 to 5 Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '5' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/code-scanning-pack-gen.yml | 6 +++--- .github/workflows/codeql_unit_tests.yml | 4 ++-- .github/workflows/dispatch-matrix-test-on-comment.yml | 2 +- .github/workflows/dispatch-release-performance-check.yml | 2 +- .github/workflows/extra-rule-validation.yml | 4 ++-- .github/workflows/finalize-release.yml | 4 ++-- .github/workflows/generate-html-docs.yml | 2 +- .github/workflows/prepare-release.yml | 2 +- .github/workflows/standard_library_upgrade_tests.yml | 4 ++-- .github/workflows/tooling-unit-tests.yml | 8 ++++---- .github/workflows/update-release-status.yml | 2 +- .github/workflows/update-release.yml | 2 +- .github/workflows/upgrade_codeql_dependencies.yml | 2 +- .github/workflows/validate-package-files.yml | 2 +- .github/workflows/validate-query-formatting.yml | 2 +- .github/workflows/validate-query-help.yml | 2 +- .github/workflows/validate-query-test-case-formatting.yml | 2 +- .../workflows/verify-standard-library-dependencies.yml | 4 ++-- 18 files changed, 28 insertions(+), 28 deletions(-) diff --git a/.github/workflows/code-scanning-pack-gen.yml b/.github/workflows/code-scanning-pack-gen.yml index 678b3be403..dde0a1a3f6 100644 --- a/.github/workflows/code-scanning-pack-gen.yml +++ b/.github/workflows/code-scanning-pack-gen.yml @@ -26,7 +26,7 @@ jobs: matrix: ${{ steps.export-code-scanning-pack-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Export Code Scanning pack matrix id: export-code-scanning-pack-matrix run: | @@ -42,7 +42,7 @@ jobs: fail-fast: false matrix: ${{ fromJSON(needs.prepare-code-scanning-pack-matrix.outputs.matrix) }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Cache CodeQL id: cache-codeql @@ -82,7 +82,7 @@ jobs: id: checkout-external-help-files # PRs from forks and dependabot do not have access to an appropriate token for cloning the help files repos if: ${{ !github.event.pull_request.head.repo.fork && github.actor != 'dependabot[bot]' }} - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ssh-key: ${{ secrets.CODEQL_CODING_STANDARDS_HELP_KEY }} repository: "github/codeql-coding-standards-help" diff --git a/.github/workflows/codeql_unit_tests.yml b/.github/workflows/codeql_unit_tests.yml index 2fc28fc900..0f9aadb8b3 100644 --- a/.github/workflows/codeql_unit_tests.yml +++ b/.github/workflows/codeql_unit_tests.yml @@ -23,7 +23,7 @@ jobs: matrix: ${{ steps.export-unit-test-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Export unit test matrix id: export-unit-test-matrix @@ -45,7 +45,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install Python uses: actions/setup-python@v5 diff --git a/.github/workflows/dispatch-matrix-test-on-comment.yml b/.github/workflows/dispatch-matrix-test-on-comment.yml index 972cabdb89..4990694512 100644 --- a/.github/workflows/dispatch-matrix-test-on-comment.yml +++ b/.github/workflows/dispatch-matrix-test-on-comment.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Check permission id: check-write-permission diff --git a/.github/workflows/dispatch-release-performance-check.yml b/.github/workflows/dispatch-release-performance-check.yml index 5886bb2ea8..25e293fa6a 100644 --- a/.github/workflows/dispatch-release-performance-check.yml +++ b/.github/workflows/dispatch-release-performance-check.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Check permission id: check-write-permission diff --git a/.github/workflows/extra-rule-validation.yml b/.github/workflows/extra-rule-validation.yml index 02d37f92b2..7fef7818aa 100644 --- a/.github/workflows/extra-rule-validation.yml +++ b/.github/workflows/extra-rule-validation.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Check Rules shell: pwsh @@ -33,7 +33,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Ensure CPP Shared Rules Have Valid Structure shell: pwsh diff --git a/.github/workflows/finalize-release.yml b/.github/workflows/finalize-release.yml index b3a96f32d3..c6ebc8f3dc 100644 --- a/.github/workflows/finalize-release.yml +++ b/.github/workflows/finalize-release.yml @@ -39,14 +39,14 @@ jobs: fi - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ env.REF }} fetch-depth: 0 path: release - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ env.TOOL_REF }} path: tooling diff --git a/.github/workflows/generate-html-docs.yml b/.github/workflows/generate-html-docs.yml index d63f631421..a28bfd7905 100644 --- a/.github/workflows/generate-html-docs.yml +++ b/.github/workflows/generate-html-docs.yml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install Python uses: actions/setup-python@v5 diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 75e297d42e..a789c8450d 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -34,7 +34,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/standard_library_upgrade_tests.yml b/.github/workflows/standard_library_upgrade_tests.yml index a401150b07..277082d3a5 100644 --- a/.github/workflows/standard_library_upgrade_tests.yml +++ b/.github/workflows/standard_library_upgrade_tests.yml @@ -19,7 +19,7 @@ jobs: matrix: ${{ steps.export-unit-test-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Export unit test matrix id: export-unit-test-matrix @@ -41,7 +41,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Python 3 uses: actions/setup-python@v5 diff --git a/.github/workflows/tooling-unit-tests.yml b/.github/workflows/tooling-unit-tests.yml index 3f4fde932d..00a36d5c6a 100644 --- a/.github/workflows/tooling-unit-tests.yml +++ b/.github/workflows/tooling-unit-tests.yml @@ -22,7 +22,7 @@ jobs: matrix: ${{ steps.export-supported-codeql-env-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Export supported CodeQL environment matrix id: export-supported-codeql-env-matrix @@ -40,7 +40,7 @@ jobs: matrix: ${{ fromJSON(needs.prepare-supported-codeql-env-matrix.outputs.matrix) }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install Python uses: actions/setup-python@v5 @@ -83,7 +83,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install Python uses: actions/setup-python@v5 @@ -102,7 +102,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install Python uses: actions/setup-python@v5 diff --git a/.github/workflows/update-release-status.yml b/.github/workflows/update-release-status.yml index 874bc4d0b2..50df8d8c00 100644 --- a/.github/workflows/update-release-status.yml +++ b/.github/workflows/update-release-status.yml @@ -24,7 +24,7 @@ jobs: conclusion: ${{ steps.set-output.outputs.conclusion }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ inputs.head-sha }} diff --git a/.github/workflows/update-release.yml b/.github/workflows/update-release.yml index e3b8045514..6baf99279b 100644 --- a/.github/workflows/update-release.yml +++ b/.github/workflows/update-release.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 # We need the full history to compute the changelog ref: ${{ inputs.head-sha }} diff --git a/.github/workflows/upgrade_codeql_dependencies.yml b/.github/workflows/upgrade_codeql_dependencies.yml index 1ffc874bb4..de187e0e95 100644 --- a/.github/workflows/upgrade_codeql_dependencies.yml +++ b/.github/workflows/upgrade_codeql_dependencies.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Fetch CodeQL env: diff --git a/.github/workflows/validate-package-files.yml b/.github/workflows/validate-package-files.yml index a716921053..4e0a51a3b5 100644 --- a/.github/workflows/validate-package-files.yml +++ b/.github/workflows/validate-package-files.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/validate-query-formatting.yml b/.github/workflows/validate-query-formatting.yml index 88b4c0d438..ed78505298 100644 --- a/.github/workflows/validate-query-formatting.yml +++ b/.github/workflows/validate-query-formatting.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/validate-query-help.yml b/.github/workflows/validate-query-help.yml index 90f0d16dbc..3ce97d8e9f 100644 --- a/.github/workflows/validate-query-help.yml +++ b/.github/workflows/validate-query-help.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/validate-query-test-case-formatting.yml b/.github/workflows/validate-query-test-case-formatting.yml index 879c1c9058..1777cacdd9 100644 --- a/.github/workflows/validate-query-test-case-formatting.yml +++ b/.github/workflows/validate-query-test-case-formatting.yml @@ -20,7 +20,7 @@ jobs: fail-fast: false steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: ref: ${{ inputs.ref }} diff --git a/.github/workflows/verify-standard-library-dependencies.yml b/.github/workflows/verify-standard-library-dependencies.yml index 06ab4d23e2..4900f11172 100644 --- a/.github/workflows/verify-standard-library-dependencies.yml +++ b/.github/workflows/verify-standard-library-dependencies.yml @@ -22,7 +22,7 @@ jobs: matrix: ${{ steps.export-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Export unit test matrix id: export-matrix @@ -44,7 +44,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Setup Python 3 uses: actions/setup-python@v5 From 1cc458b5b86fefc2d0c85ee05a32c8b9064f1fa6 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 18 Aug 2025 21:44:50 +0100 Subject: [PATCH 531/628] Rule 7.0.3: Address review feedback --- .../RULE-7-0-3/NoCharacterNumericalValue.ql | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql b/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql index c4d294a0b8..0a9ac1028c 100644 --- a/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql +++ b/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql @@ -29,11 +29,6 @@ where // Conversion from non-character type to character type not sourceType instanceof CharacterType and targetType instanceof CharacterType - // or - // // Conversion between different character types - // getTypeCategory(sourceType) instanceof Character and - // getTypeCategory(targetType) instanceof Character and - // not sourceType = targetType ) and // Exclude conversions where both operands have the same character type in equality operations not exists(EqualityOperation eq, CharacterType leftType, CharacterType rightType | @@ -43,19 +38,7 @@ where leftType.getRealType() = rightType.getRealType() ) and // Exclude unevaluated operands - not ( - expr.getParent*() instanceof SizeofExprOperator or - expr.getParent*() instanceof SizeofTypeOperator or - expr.getParent*() instanceof TypeidOperator or - expr.getParent*() = any(Decltype dt).getExpr() or - expr.getParent*() instanceof StaticAssert - ) and - // Exclude optional comparisons that don't involve conversion - not exists(FunctionCall fc | - fc.getTarget().hasName("operator==") and - fc.getAnArgument() = expr and - fc.getQualifier().getType().hasName("optional") - ) + not expr.isUnevaluated() select expr, "Conversion of character type '" + sourceType.getName() + "' to '" + targetType.getName() + "' uses numerical value of character." From 51938afad57f91be9c82b4af9f9482cc5076df14 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 18 Aug 2025 22:23:21 +0100 Subject: [PATCH 532/628] Rule 7.0.1: Address review feedback --- .../src/rules/RULE-7-0-1/NoConversionFromBool.ql | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql b/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql index 600d454863..6c3d5b6d16 100644 --- a/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql +++ b/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql @@ -15,6 +15,7 @@ import cpp import codingstandards.cpp.misra +import codingstandards.cpp.misra.BuiltInTypeRules from Expr e, Conversion conv where @@ -31,13 +32,9 @@ where eq.getRightOperand().getType().stripTopLevelSpecifiers() instanceof BoolType ) or - // Exception: explicit constructor calls - exists(ConstructorCall cc | cc.getAnArgument() = e) - or // Exception: assignment to bit-field of length 1 - exists(AssignExpr assign | - assign.getRValue() = e and - assign.getLValue().(ValueFieldAccess).getTarget().(BitField).getNumBits() = 1 - ) + isAssignedToBitfield(e, _) + // Note: conversions that result in a constructor call are not represented as `Conversion`s + // in our model, so do not need to be excluded here. ) -select e, "Conversion from 'bool' to '" + conv.getType().toString() + "'." +select e, "Conversion from 'bool' to '" + conv.getType() + "'." From 9bbef6f394aea88a5d7e23ce897a8c277e4673b5 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 18 Aug 2025 22:40:56 +0100 Subject: [PATCH 533/628] Rule 7.0.2: Address review feedback --- .../rules/RULE-7-0-2/NoImplicitBoolConversion.ql | 14 ++++++++------ .../RULE-7-0-2/NoImplicitBoolConversion.expected | 2 -- cpp/misra/test/rules/RULE-7-0-2/test.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql b/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql index 308f879f1d..4350b6eac8 100644 --- a/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql +++ b/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql @@ -43,7 +43,6 @@ predicate isBitFieldOfSizeOne(Expr expr) { predicate isPointerType(Type t) { t.getUnspecifiedType() instanceof PointerType or - t.getUnspecifiedType() instanceof ArrayType or t.getUnspecifiedType() instanceof PointerToMemberType } @@ -59,12 +58,15 @@ where // Exception 2: Contextual conversion from pointer not ( isPointerType(conv.getExpr().getType()) and - isInContextualBoolContext(conv.getExpr()) + // Checks if the unconverted expression for this conversion is in a contextual bool context + // This handles the cases where we have multiple stacked conversions, e.g. when converting + // an array to a pointer, then the pointer to bool + isInContextualBoolContext(conv.getUnconverted()) ) and - // Exception 3: Bit-field of size 1 - not isBitFieldOfSizeOne(conv.getExpr()) and - // Exception 4: While condition declaration - not isInWhileConditionDeclaration(conv.getExpr()) and + // Exception 3: Unconverted expression is a bit-field of size 1 + not isBitFieldOfSizeOne(conv.getUnconverted()) and + // Exception 4: Unconverted expression is in a while condition declaration + not isInWhileConditionDeclaration(conv.getUnconverted()) and reason = "Conversion from '" + conv.getExpr().getType().toString() + "' to 'bool'" ) or diff --git a/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected index c000a23dd2..5473a954ac 100644 --- a/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected +++ b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected @@ -21,8 +21,6 @@ | test.cpp:182:7:182:8 | (bool)... | Conversion from 'float' to 'bool'. | | test.cpp:184:7:184:8 | (bool)... | Conversion from 'double' to 'bool'. | | test.cpp:186:7:186:8 | (bool)... | Conversion from 'long double' to 'bool'. | -| test.cpp:195:7:195:8 | (bool)... | Conversion from 'int32_t *' to 'bool'. | -| test.cpp:197:7:197:8 | (bool)... | Conversion from 'int32_t *' to 'bool'. | | test.cpp:199:13:199:14 | (bool)... | Conversion from 'int32_t *' to 'bool'. | | test.cpp:211:13:211:14 | (bool)... | Conversion from '..:: *' to 'bool'. | | test.cpp:212:13:212:14 | (bool)... | Conversion from '..:: *' to 'bool'. | diff --git a/cpp/misra/test/rules/RULE-7-0-2/test.cpp b/cpp/misra/test/rules/RULE-7-0-2/test.cpp index 568980dea3..195648f25d 100644 --- a/cpp/misra/test/rules/RULE-7-0-2/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-2/test.cpp @@ -192,9 +192,9 @@ void test_floating_point_conversion() { void test_array_conversion() { std::int32_t l1[5] = {1, 2, 3, 4, 5}; - if (l1) { // NON_COMPLIANT + if (l1) { // COMPLIANT } - if (g8) { // NON_COMPLIANT + if (g8) { // COMPLIANT } bool l2 = l1; // NON_COMPLIANT bool l3 = (l1 != nullptr); // COMPLIANT From c2cbed3bd746656e34259a00f01014f07a539e0e Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 18 Aug 2025 18:51:46 -0400 Subject: [PATCH 534/628] Update unit test --- cpp/misra/test/rules/RULE-9-5-1/test.cpp | 40 ++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/cpp/misra/test/rules/RULE-9-5-1/test.cpp b/cpp/misra/test/rules/RULE-9-5-1/test.cpp index 0dafea56ef..f4c486ba04 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-1/test.cpp @@ -113,17 +113,51 @@ int main() { for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed // as a non-const reference - f(j); + int &m = i; } for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed // as a non-const pointer - g(&j); + int *m = &i; + } + + for (int i = j; i < k; + i += + l) { // NON_COMPLIANT: The loop bound is passed as a non-const reference + int &m = k; } for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is passed as a non-const pointer + int *m = &k; + } + + for (int i = j; i < k; + i += + l) { // NON_COMPLIANT: The loop step is passed as a non-const reference + int &m = l; + } + + for (int i = j; i < k; + i += + l) { // NON_COMPLIANT: The loop step is passed as a non-const pointer + int *m = &l; + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed + // as a non-const reference + f(i); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed + // as a non-const pointer + g(&i); + } + + for (int i = j; i < k; + i += + l) { // NON_COMPLIANT: The loop bound is passed as a non-const reference f(k); } @@ -135,7 +169,7 @@ int main() { for (int i = j; i < k; i += - l) { // NON_COMPLIANT: The loop step is passed as a non-const pointer + l) { // NON_COMPLIANT: The loop step is passed as a non-const reference f(l); } From b20ea88c9c521894a2546ac061e9196a8fc8163d Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 19 Aug 2025 10:57:07 +0100 Subject: [PATCH 535/628] Add a utility library for unifying binary ops BinaryOperations and AssignOperations do not share a common hierarchy. This commit creates a module for unifying the two, and aliases for the common super classes. --- .../codingstandards/cpp/BinaryOperations.qll | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/BinaryOperations.qll diff --git a/cpp/common/src/codingstandards/cpp/BinaryOperations.qll b/cpp/common/src/codingstandards/cpp/BinaryOperations.qll new file mode 100644 index 0000000000..5302535fef --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/BinaryOperations.qll @@ -0,0 +1,75 @@ +import cpp + +private signature class BinaryOp extends BinaryOperation; + +private signature class AssignBinaryOp extends AssignOperation; + +/** + * A module for unifying the `BinaryOperation` and `AssignOperation` hierarchies. + */ +private module BinaryOpUnifier { + final class FinalExpr = Expr; + + class BinaryExpr extends FinalExpr { + BinaryExpr() { + this instanceof BinaryOpType or + this instanceof AssignBinaryOpType + } + + Expr getLeftOperand() { + result = this.(BinaryOpType).getLeftOperand() + or + result = this.(AssignBinaryOpType).getLValue() + } + + Expr getRightOperand() { + result = this.(BinaryOpType).getRightOperand() + or + result = this.(AssignBinaryOpType).getRValue() + } + + string getOperator() { + result = this.(BinaryOpType).getOperator() + or + result = this.(AssignBinaryOpType).getOperator() + } + } +} + +/** + * A binary shift operation (`<<` or `>>`). + */ +class BinaryShiftOperation extends BinaryOperation { + BinaryShiftOperation() { + this instanceof LShiftExpr or + this instanceof RShiftExpr + } +} + +/** + * A binary shift assignment operation (`<<=` or `>>=`). + */ +class AssignShiftOperation extends AssignOperation { + AssignShiftOperation() { + this instanceof AssignLShiftExpr or + this instanceof AssignRShiftExpr + } +} + +/** + * A binary bitwise operation or binary bitwise assignment operation, including shift operations. + */ +class BinaryBitwiseOpOrAssignOp = + BinaryOpUnifier::BinaryExpr; + +/** + * A binary shift operation (`<<` or `>>`) or shift assignment operation (`<<=` or `>>=`). + */ +class BinaryShiftOpOrAssignOp = + BinaryOpUnifier::BinaryExpr; + +/** + * A binary arithmetic operation or binary arithmetic assignment operation. + */ +class BinaryArithmeticOpOrAssignOp = + BinaryOpUnifier::BinaryExpr; From 3e2534b522205fb734c1d9c1f61935e25624ade6 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 19 Aug 2025 11:20:39 +0100 Subject: [PATCH 536/628] Move isSigned/isUnsigned to BuiltInTypes --- cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll | 4 ++++ .../rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index 0ce4bfd42c..2a6025c31b 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -137,6 +137,10 @@ class NumericType extends Type { Type getRealType() { result = realType } } +predicate isSignedType(NumericType t) { t.getSignedness() = Signed() } + +predicate isUnsignedType(NumericType t) { t.getSignedness() = Unsigned() } + /** * One of the 10 canonical integer types, which are the standard integer types. */ diff --git a/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql index b256beaf71..4dfabee965 100644 --- a/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql +++ b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql @@ -16,10 +16,6 @@ import cpp import codingstandards.cpp.misra import codingstandards.cpp.misra.BuiltInTypeRules -predicate isSignedType(NumericType t) { t.getSignedness() = Signed() } - -predicate isUnsignedType(NumericType t) { t.getSignedness() = Unsigned() } - predicate isConstantExpression(Expr e) { e instanceof Literal or e.isConstant() From 1af908a1c59b57146f724d970f5af1f810a19115 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 19 Aug 2025 11:21:01 +0100 Subject: [PATCH 537/628] Rule 7.0.4: Improve reporting - Use BinaryOperations library to merge reporting of assign and binary operations. - Report the actual type of the operand. - Report the operand which is in contravention, instead of the operation. - Split reporting of cases where a constant is not valid from cases where the it is not unsigned for better reporting. --- .../InappropriateBitwiseOrShiftOperands.ql | 114 ++++++++---------- ...appropriateBitwiseOrShiftOperands.expected | 92 +++++++------- 2 files changed, 96 insertions(+), 110 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql index 4dfabee965..5aff491aff 100644 --- a/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql +++ b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql @@ -15,6 +15,7 @@ import cpp import codingstandards.cpp.misra import codingstandards.cpp.misra.BuiltInTypeRules +import codingstandards.cpp.BinaryOperations predicate isConstantExpression(Expr e) { e instanceof Literal or @@ -50,91 +51,70 @@ predicate isSignedConstantLeftShiftException(LShiftExpr shift) { ) } -class BinaryShiftOperation extends BinaryOperation { - BinaryShiftOperation() { - this instanceof LShiftExpr or - this instanceof RShiftExpr - } -} - -class AssignShiftOperation extends AssignOperation { - AssignShiftOperation() { - this instanceof AssignLShiftExpr or - this instanceof AssignRShiftExpr - } -} - from Expr x, string message where not isExcluded(x, ConversionsPackage::inappropriateBitwiseOrShiftOperandsQuery()) and ( // Binary bitwise operators (excluding shift operations) - both operands must be unsigned - exists(BinaryBitwiseOperation op | - not op instanceof BinaryShiftOperation and - op = x and - not ( - isUnsignedType(op.getLeftOperand().getExplicitlyConverted().getType()) and - isUnsignedType(op.getRightOperand().getExplicitlyConverted().getType()) - ) and + exists(BinaryBitwiseOpOrAssignOp op, Type operandType | + not op instanceof BinaryShiftOpOrAssignOp + | + x = op.getLeftOperand() and + operandType = op.getLeftOperand().getExplicitlyConverted().getType() and + not isUnsignedType(operandType) and message = - "Binary bitwise operator '" + op.getOperator() + "' requires both operands to be unsigned." - ) - or - // Compound assignment bitwise operators - both operands must be unsigned - exists(AssignBitwiseOperation op | - not op instanceof AssignShiftOperation and - op = x and - not ( - isUnsignedType(op.getLValue().getExplicitlyConverted().getType()) and - isUnsignedType(op.getRValue().getExplicitlyConverted().getType()) - ) and + "Bitwise operator '" + op.getOperator() + + "' requires unsigned numeric operands, but the left operand has type '" + operandType + + "'." + or + x = op.getRightOperand() and + operandType = op.getRightOperand().getExplicitlyConverted().getType() and + not isUnsignedType(operandType) and message = - "Compound assignment bitwise operator '" + op.getOperator() + - "' requires both operands to be unsigned." + "Bitwise operator '" + op.getOperator() + + "' requires unsigned numeric operands, but the right operand has type '" + operandType + + "'." ) or // Bit complement operator - operand must be unsigned - exists(ComplementExpr comp | - comp = x and - not isUnsignedType(comp.getOperand().getExplicitlyConverted().getType()) and - message = "Bit complement operator '~' requires unsigned operand." + exists(ComplementExpr comp, Type opType | + x = comp.getOperand() and + opType = comp.getOperand().getExplicitlyConverted().getType() and + not isUnsignedType(opType) and + message = + "Bit complement operator '~' requires unsigned operand, but has type '" + opType + "'." ) or // Shift operators - left operand must be unsigned - exists(BinaryShiftOperation shift | - shift = x and - not isUnsignedType(shift.getLeftOperand().getExplicitlyConverted().getType()) and + exists(BinaryShiftOpOrAssignOp shift, Type leftType | + x = shift.getLeftOperand() and + leftType = shift.getLeftOperand().getExplicitlyConverted().getType() and + not isUnsignedType(leftType) and not isSignedConstantLeftShiftException(shift) and - message = "Shift operator '" + shift.getOperator() + "' requires unsigned left operand." - ) - or - // Compound assignment shift operators - left operand must be unsigned - exists(AssignShiftOperation shift | - shift = x and - not isUnsignedType(shift.getLValue().getExplicitlyConverted().getType()) and - message = "Shift operator '" + shift.getOperator() + "' requires unsigned left operand." - ) - or - // Shift operators - right operand must be unsigned or constant in valid range - exists(BinaryShiftOperation shift, Expr right | - shift = x and - right = shift.getRightOperand() and - not isUnsignedType(right.getExplicitlyConverted().getType()) and - not isValidShiftConstantRange(right, shift.getLeftOperand().getExplicitlyConverted().getType()) and message = "Shift operator '" + shift.getOperator() + - "' requires unsigned right operand or constant in valid range." + "' requires unsigned left operand, but has type '" + leftType + "'." ) or - // Compound assignment shift operators - right operand must be unsigned or constant in valid range - exists(AssignShiftOperation shift, Expr right | - shift = x and - right = shift.getRValue() and - not isUnsignedType(right.getExplicitlyConverted().getType()) and - not isValidShiftConstantRange(right, shift.getLValue().getExplicitlyConverted().getType()) and - message = - "Shift operator '" + shift.getOperator() + - "' requires unsigned right operand or constant in valid range." + // Shift operators - right operand must be unsigned or constant in valid range + exists(BinaryShiftOpOrAssignOp shift, Expr right, Type rightType, Type leftType | + right = shift.getRightOperand() and + x = right and + rightType = right.getExplicitlyConverted().getType() and + leftType = shift.getLeftOperand().getExplicitlyConverted().getType() + | + if exists(right.getValue().toInt()) + then + not isValidShiftConstantRange(right, leftType) and + message = + "Shift operator '" + shift.getOperator() + "' shifts by " + right.getValue().toInt() + + " which is not within the valid range 0.." + ((leftType.getSize() * 8) - 1) + "." + else ( + not isUnsignedType(rightType) and + message = + "Shift operator '" + shift.getOperator() + + "' requires unsigned right operand, but has type '" + rightType + "'." + ) ) ) select x, message diff --git a/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected index 0c9144d018..5f92a9b110 100644 --- a/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected +++ b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected @@ -1,43 +1,49 @@ -| test.cpp:14:3:14:13 | ... & ... | Binary bitwise operator '&' requires both operands to be unsigned. | -| test.cpp:15:3:15:13 | ... \| ... | Binary bitwise operator '\|' requires both operands to be unsigned. | -| test.cpp:16:3:16:13 | ... ^ ... | Binary bitwise operator '^' requires both operands to be unsigned. | -| test.cpp:18:3:18:13 | ... & ... | Binary bitwise operator '&' requires both operands to be unsigned. | -| test.cpp:19:3:19:13 | ... \| ... | Binary bitwise operator '\|' requires both operands to be unsigned. | -| test.cpp:30:3:30:15 | ... &= ... | Compound assignment bitwise operator '&=' requires both operands to be unsigned. | -| test.cpp:31:3:31:15 | ... \|= ... | Compound assignment bitwise operator '\|=' requires both operands to be unsigned. | -| test.cpp:32:3:32:15 | ... ^= ... | Compound assignment bitwise operator '^=' requires both operands to be unsigned. | -| test.cpp:42:3:42:6 | ~ ... | Bit complement operator '~' requires unsigned operand. | -| test.cpp:54:3:54:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:55:3:55:11 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:63:3:63:18 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:74:3:74:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. | -| test.cpp:75:3:75:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. | -| test.cpp:85:3:85:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. | -| test.cpp:86:3:86:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. | -| test.cpp:87:3:87:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. | -| test.cpp:93:3:93:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. | -| test.cpp:94:3:94:11 | ... << ... | Shift operator '<<' requires unsigned right operand or constant in valid range. | -| test.cpp:95:3:95:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. | -| test.cpp:96:3:96:11 | ... >> ... | Shift operator '>>' requires unsigned right operand or constant in valid range. | -| test.cpp:115:3:115:12 | ... <<= ... | Shift operator '<<=' requires unsigned left operand. | -| test.cpp:116:3:116:12 | ... >>= ... | Shift operator '>>=' requires unsigned left operand. | -| test.cpp:117:3:117:11 | ... <<= ... | Shift operator '<<=' requires unsigned left operand. | -| test.cpp:118:3:118:11 | ... >>= ... | Shift operator '>>=' requires unsigned left operand. | -| test.cpp:121:3:121:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. | -| test.cpp:122:3:122:12 | ... >>= ... | Shift operator '>>=' requires unsigned right operand or constant in valid range. | -| test.cpp:125:3:125:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. | -| test.cpp:126:3:126:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. | -| test.cpp:127:3:127:12 | ... >>= ... | Shift operator '>>=' requires unsigned right operand or constant in valid range. | -| test.cpp:130:3:130:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. | -| test.cpp:131:3:131:12 | ... <<= ... | Shift operator '<<=' requires unsigned right operand or constant in valid range. | -| test.cpp:132:3:132:12 | ... >>= ... | Shift operator '>>=' requires unsigned right operand or constant in valid range. | -| test.cpp:133:3:133:12 | ... >>= ... | Shift operator '>>=' requires unsigned right operand or constant in valid range. | -| test.cpp:143:3:143:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:144:3:144:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:145:3:145:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:146:3:146:9 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:150:3:150:11 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:154:3:154:30 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:156:3:156:17 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:162:3:162:10 | ... << ... | Shift operator '<<' requires unsigned left operand. | -| test.cpp:170:3:170:11 | ... >> ... | Shift operator '>>' requires unsigned left operand. | +| test.cpp:14:3:14:6 | s32a | Bitwise operator '&' requires unsigned numeric operands, but the left operand has type 'int32_t'. | +| test.cpp:14:10:14:13 | s32b | Bitwise operator '&' requires unsigned numeric operands, but the right operand has type 'int32_t'. | +| test.cpp:15:3:15:6 | s32a | Bitwise operator '\|' requires unsigned numeric operands, but the left operand has type 'int32_t'. | +| test.cpp:15:10:15:13 | s32b | Bitwise operator '\|' requires unsigned numeric operands, but the right operand has type 'int32_t'. | +| test.cpp:16:3:16:6 | s32a | Bitwise operator '^' requires unsigned numeric operands, but the left operand has type 'int32_t'. | +| test.cpp:16:10:16:13 | s32b | Bitwise operator '^' requires unsigned numeric operands, but the right operand has type 'int32_t'. | +| test.cpp:18:3:18:6 | s32a | Bitwise operator '&' requires unsigned numeric operands, but the left operand has type 'int32_t'. | +| test.cpp:19:10:19:13 | s32b | Bitwise operator '\|' requires unsigned numeric operands, but the right operand has type 'int32_t'. | +| test.cpp:30:3:30:5 | s32 | Bitwise operator '&=' requires unsigned numeric operands, but the left operand has type 'int32_t'. | +| test.cpp:30:10:30:15 | 65535 | Bitwise operator '&=' requires unsigned numeric operands, but the right operand has type 'int'. | +| test.cpp:31:3:31:5 | s32 | Bitwise operator '\|=' requires unsigned numeric operands, but the left operand has type 'int32_t'. | +| test.cpp:31:10:31:15 | 4096 | Bitwise operator '\|=' requires unsigned numeric operands, but the right operand has type 'int'. | +| test.cpp:32:3:32:5 | s32 | Bitwise operator '^=' requires unsigned numeric operands, but the left operand has type 'int32_t'. | +| test.cpp:32:10:32:15 | 21845 | Bitwise operator '^=' requires unsigned numeric operands, but the right operand has type 'int'. | +| test.cpp:42:4:42:6 | s32 | Bit complement operator '~' requires unsigned operand, but has type 'int32_t'. | +| test.cpp:54:3:54:3 | 1 | Shift operator '<<' requires unsigned left operand, but has type 'int'. | +| test.cpp:55:3:55:5 | s32 | Shift operator '<<' requires unsigned left operand, but has type 'int32_t'. | +| test.cpp:63:4:63:11 | ... + ... | Shift operator '<<' requires unsigned left operand, but has type 'int'. | +| test.cpp:74:10:74:11 | s8 | Shift operator '<<' requires unsigned right operand, but has type 'int8_t'. | +| test.cpp:75:10:75:11 | s8 | Shift operator '>>' requires unsigned right operand, but has type 'int8_t'. | +| test.cpp:85:10:85:11 | 32 | Shift operator '<<' shifts by 32 which is not within the valid range 0..31. | +| test.cpp:86:10:86:11 | 64 | Shift operator '<<' shifts by 64 which is not within the valid range 0..31. | +| test.cpp:87:10:87:11 | 32 | Shift operator '>>' shifts by 32 which is not within the valid range 0..31. | +| test.cpp:93:10:93:11 | - ... | Shift operator '<<' shifts by -1 which is not within the valid range 0..31. | +| test.cpp:94:10:94:11 | - ... | Shift operator '<<' shifts by -5 which is not within the valid range 0..31. | +| test.cpp:95:10:95:11 | - ... | Shift operator '>>' shifts by -1 which is not within the valid range 0..31. | +| test.cpp:96:10:96:11 | - ... | Shift operator '>>' shifts by -3 which is not within the valid range 0..31. | +| test.cpp:115:3:115:5 | s32 | Shift operator '<<=' requires unsigned left operand, but has type 'int32_t'. | +| test.cpp:116:3:116:5 | s32 | Shift operator '>>=' requires unsigned left operand, but has type 'int32_t'. | +| test.cpp:117:3:117:5 | s32 | Shift operator '<<=' requires unsigned left operand, but has type 'int32_t'. | +| test.cpp:118:3:118:5 | s32 | Shift operator '>>=' requires unsigned left operand, but has type 'int32_t'. | +| test.cpp:121:11:121:12 | s8 | Shift operator '<<=' requires unsigned right operand, but has type 'int8_t'. | +| test.cpp:122:11:122:12 | s8 | Shift operator '>>=' requires unsigned right operand, but has type 'int8_t'. | +| test.cpp:125:11:125:12 | 32 | Shift operator '<<=' shifts by 32 which is not within the valid range 0..31. | +| test.cpp:126:11:126:12 | 64 | Shift operator '<<=' shifts by 64 which is not within the valid range 0..31. | +| test.cpp:127:11:127:12 | 32 | Shift operator '>>=' shifts by 32 which is not within the valid range 0..31. | +| test.cpp:130:11:130:12 | - ... | Shift operator '<<=' shifts by -1 which is not within the valid range 0..31. | +| test.cpp:131:11:131:12 | - ... | Shift operator '<<=' shifts by -5 which is not within the valid range 0..31. | +| test.cpp:132:11:132:12 | - ... | Shift operator '>>=' shifts by -1 which is not within the valid range 0..31. | +| test.cpp:133:11:133:12 | - ... | Shift operator '>>=' shifts by -3 which is not within the valid range 0..31. | +| test.cpp:143:3:143:3 | 1 | Shift operator '<<' requires unsigned left operand, but has type 'int'. | +| test.cpp:144:3:144:3 | 2 | Shift operator '<<' requires unsigned left operand, but has type 'int'. | +| test.cpp:145:3:145:3 | 4 | Shift operator '<<' requires unsigned left operand, but has type 'int'. | +| test.cpp:146:3:146:3 | 8 | Shift operator '<<' requires unsigned left operand, but has type 'int'. | +| test.cpp:150:3:150:5 | 1 | Shift operator '<<' requires unsigned left operand, but has type 'long long'. | +| test.cpp:154:3:154:25 | 4611686018427387904 | Shift operator '<<' requires unsigned left operand, but has type 'long long'. | +| test.cpp:156:3:156:12 | 1073741824 | Shift operator '<<' requires unsigned left operand, but has type 'int'. | +| test.cpp:162:3:162:5 | s32 | Shift operator '<<' requires unsigned left operand, but has type 'int32_t'. | +| test.cpp:170:3:170:5 | s32 | Shift operator '>>' requires unsigned left operand, but has type 'int32_t'. | From cd8c9606153308a28d3a71c8959664f69e0d59a8 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 19 Aug 2025 11:59:24 +0100 Subject: [PATCH 538/628] Rule 7.0.6: Correctly handle constructor exception Improve handling for constructors with default arguments. --- .../NumericAssignmentTypeMismatch.ql | 19 ++++- .../NumericAssignmentTypeMismatch.expected | 75 ++++++++++--------- cpp/misra/test/rules/RULE-7-0-6/test.cpp | 20 ++++- 3 files changed, 72 insertions(+), 42 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index 94f5210c8d..982757f0a5 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -60,18 +60,29 @@ predicate isValidTypeMatch(NumericType sourceType, NumericType targetType) { sourceType.getRealSize() = targetType.getRealSize() } +/** + * A constructor that can be called with a single argument + */ +private class CallableWithASingleArgumentConstructor extends Constructor { + CallableWithASingleArgumentConstructor() { + // Either a constructor with a single parameter + this.getNumberOfParameters() = 1 + or + // Or the second (and later parameters) all have defaults + exists(this.getParameter(1).getInitializer()) + } +} + predicate hasConstructorException(FunctionCall call) { - exists(Constructor ctor, Class c | + exists(CallableWithASingleArgumentConstructor ctor, Class c | call.getTarget() = ctor and c = ctor.getDeclaringType() and // Constructor callable with single numeric argument - ctor.getNumberOfParameters() = 1 and ctor.getParameter(0).getType() instanceof NumericType and // No other single-argument constructors except copy/move - not exists(Constructor other | + not exists(CallableWithASingleArgumentConstructor other | other.getDeclaringType() = c and other != ctor and - other.getNumberOfParameters() = 1 and not other instanceof CopyConstructor and not other instanceof MoveConstructor ) diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index a6473c6df0..dc57c5ddd0 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -49,42 +49,45 @@ | test.cpp:289:6:289:8 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'size_t'. | | test.cpp:294:12:294:14 | s16 | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | | test.cpp:313:9:313:10 | 42 | Assignment between incompatible numeric types from 'int' to 'long'. | -| test.cpp:346:25:346:27 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned long'. | -| test.cpp:358:19:358:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | -| test.cpp:363:10:363:12 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test.cpp:396:8:396:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. | -| test.cpp:397:8:397:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | -| test.cpp:398:9:398:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | -| test.cpp:409:6:409:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. | -| test.cpp:410:6:410:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. | -| test.cpp:421:8:421:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. | -| test.cpp:422:8:422:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | -| test.cpp:435:9:435:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | -| test.cpp:436:7:436:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. | -| test.cpp:437:7:437:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. | -| test.cpp:448:8:448:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test.cpp:466:7:466:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | -| test.cpp:469:7:469:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | -| test.cpp:518:12:518:13 | l1 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | -| test.cpp:519:12:519:13 | l1 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | -| test.cpp:521:12:521:13 | l2 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | -| test.cpp:522:12:522:13 | l2 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | -| test.cpp:542:12:542:14 | 300 | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test.cpp:543:12:543:16 | 70000 | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | -| test.cpp:544:12:544:27 | 4294967296 | Assignment between incompatible numeric types from 'unsigned long long' to 'uint32_t'. | -| test.cpp:545:12:545:14 | 200 | Assignment between incompatible numeric types from 'int' to 'int8_t'. | -| test.cpp:546:12:546:16 | 40000 | Assignment between incompatible numeric types from 'int' to 'int16_t'. | -| test.cpp:547:12:547:26 | 4294967296 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | -| test.cpp:548:12:548:14 | 1.0 | Assignment between incompatible numeric types from 'double' to 'float'. | -| test.cpp:549:12:549:15 | 1.0 | Assignment between incompatible numeric types from 'float' to 'double'. | -| test.cpp:554:12:554:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | -| test.cpp:555:12:555:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | -| test.cpp:556:12:556:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint32_t'. | -| test.cpp:558:12:558:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int16_t'. | -| test.cpp:559:12:559:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int32_t'. | -| test.cpp:560:12:560:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'float'. | -| test.cpp:561:12:561:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'double'. | -| test.cpp:591:9:591:37 | static_cast... | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | +| test.cpp:339:12:339:13 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | +| test.cpp:340:12:340:13 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | +| test.cpp:342:32:342:33 | s8 | Assignment between incompatible numeric types from 'int8_t' to 'int32_t'. | +| test.cpp:362:25:362:27 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'unsigned long'. | +| test.cpp:374:19:374:25 | ... + ... | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:379:10:379:12 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test.cpp:412:8:412:9 | l6 | Assignment between incompatible numeric types from 'uint32_t &' to 'uint8_t'. | +| test.cpp:413:8:413:9 | l7 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:414:9:414:10 | l8 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:425:6:425:7 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int64_t'. | +| test.cpp:426:6:426:7 | l4 | Assignment between incompatible numeric types from 'uint16_t &' to 'int32_t'. | +| test.cpp:437:8:437:9 | l3 | Assignment between incompatible numeric types from 'uint8_t &' to 'int8_t'. | +| test.cpp:438:8:438:9 | l4 | Assignment between incompatible numeric types from 'int8_t &' to 'uint8_t'. | +| test.cpp:451:9:451:10 | l4 | Assignment between incompatible numeric types from 'float &' to 'int32_t'. | +| test.cpp:452:7:452:8 | l5 | Assignment between incompatible numeric types from 'double &' to 'float'. | +| test.cpp:453:7:453:8 | l6 | Assignment between incompatible numeric types from 'int32_t &' to 'float'. | +| test.cpp:464:8:464:14 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:482:7:482:8 | l3 | Assignment between incompatible numeric types from 'uint16_t &' to 'uint32_t'. | +| test.cpp:485:7:485:8 | l5 | Assignment between incompatible numeric types from 'uint64_t &' to 'uint32_t'. | +| test.cpp:534:12:534:13 | l1 | Assignment between incompatible numeric types from 'uint32_t' to 'uint8_t'. | +| test.cpp:535:12:535:13 | l1 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | +| test.cpp:537:12:537:13 | l2 | Assignment between incompatible numeric types from 'int32_t' to 'int8_t'. | +| test.cpp:538:12:538:13 | l2 | Assignment between incompatible numeric types from 'int32_t' to 'int16_t'. | +| test.cpp:558:12:558:14 | 300 | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:559:12:559:16 | 70000 | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | +| test.cpp:560:12:560:27 | 4294967296 | Assignment between incompatible numeric types from 'unsigned long long' to 'uint32_t'. | +| test.cpp:561:12:561:14 | 200 | Assignment between incompatible numeric types from 'int' to 'int8_t'. | +| test.cpp:562:12:562:16 | 40000 | Assignment between incompatible numeric types from 'int' to 'int16_t'. | +| test.cpp:563:12:563:26 | 4294967296 | Assignment between incompatible numeric types from 'long long' to 'int32_t'. | +| test.cpp:564:12:564:14 | 1.0 | Assignment between incompatible numeric types from 'double' to 'float'. | +| test.cpp:565:12:565:15 | 1.0 | Assignment between incompatible numeric types from 'float' to 'double'. | +| test.cpp:570:12:570:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint8_t'. | +| test.cpp:571:12:571:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint16_t'. | +| test.cpp:572:12:572:18 | ... + ... | Assignment between incompatible numeric types from 'int' to 'uint32_t'. | +| test.cpp:574:12:574:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int16_t'. | +| test.cpp:575:12:575:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'int32_t'. | +| test.cpp:576:12:576:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'float'. | +| test.cpp:577:12:577:13 | l1 | Assignment between incompatible numeric types from 'uint8_t' to 'double'. | +| test.cpp:607:9:607:37 | static_cast... | Assignment between incompatible numeric types from 'int16_t' to 'int32_t'. | | test_aggregate.cpp:29:22:29:24 | u16 | Assignment between incompatible numeric types from 'uint16_t' to 'uint8_t'. | | test_aggregate.cpp:31:26:31:28 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'uint16_t'. | | test_aggregate.cpp:33:31:33:33 | u32 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/test.cpp b/cpp/misra/test/rules/RULE-7-0-6/test.cpp index ae7310bc3d..35aca81707 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test.cpp @@ -317,13 +317,29 @@ void test_member_function_not_overload_independent() { struct MyInt { explicit MyInt(std::int32_t l1) {} MyInt(std::int32_t l1, std::int32_t l2) {} + // Move and copy constructors are allowed + MyInt(MyInt const &) = default; + MyInt(MyInt &&) = default; +}; + +struct ConstructorException { + explicit ConstructorException(std::int32_t l1, std::int32_t l2 = 2) {} +}; + +struct NotInConstructorException { + explicit NotInConstructorException(std::int32_t l1) {} + NotInConstructorException(std::int16_t l1, std::int32_t l2 = 2) {} }; void f9(MyInt l1) {} void test_constructor_exception() { - f9(MyInt{s8}); // COMPLIANT - MyInt l1{s8}; // COMPLIANT + f9(MyInt{s8}); // COMPLIANT + MyInt l1{s8}; // COMPLIANT + f9(MyInt{s8, 10}); // NON_COMPLIANT - not covered by exception + MyInt l2{s8, 10}; // NON_COMPLIANT - not covered by exception + ConstructorException l3{s8}; // COMPLIANT + NotInConstructorException l4{s8}; // NON_COMPLIANT - ambiguous constructor } template struct D { From feccaf7d532e62727c0df16e94fa923db7c96692 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 19 Aug 2025 23:16:48 +0100 Subject: [PATCH 539/628] ConstantExpressions: Correct NotExpr to ComplementExpr --- cpp/common/src/codingstandards/cpp/ConstantExpressions.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/ConstantExpressions.qll b/cpp/common/src/codingstandards/cpp/ConstantExpressions.qll index c75df942db..f6c0863e54 100644 --- a/cpp/common/src/codingstandards/cpp/ConstantExpressions.qll +++ b/cpp/common/src/codingstandards/cpp/ConstantExpressions.qll @@ -56,7 +56,7 @@ class IntegerConstantExpr extends FinalExpr { or result = this.(UnaryPlusExpr).getOperand().getFullyConverted().getValue().toBigInt() or - result = this.(NotExpr).getOperand().getFullyConverted().getValue().toBigInt().bitNot() + result = this.(ComplementExpr).getOperand().getFullyConverted().getValue().toBigInt().bitNot() or exists(BinaryOperation op, QlBuiltins::BigInt left, QlBuiltins::BigInt right | op = this and From 2c0d06bd6be0be84a4d8b0b443750df0fd820b5f Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 20 Aug 2025 11:08:01 +0100 Subject: [PATCH 540/628] Make CanonicalIntegerType singular, use it more widely --- .../src/codingstandards/cpp/misra/BuiltInTypeRules.qll | 8 ++++---- .../rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index 2a6025c31b..7b0068ba91 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -144,8 +144,8 @@ predicate isUnsignedType(NumericType t) { t.getSignedness() = Unsigned() } /** * One of the 10 canonical integer types, which are the standard integer types. */ -class CanonicalIntegerTypes extends NumericType, IntegralType { - CanonicalIntegerTypes() { this = this.getCanonicalArithmeticType() } +class CanonicalIntegerType extends NumericType, IntegralType { + CanonicalIntegerType() { this = this.getCanonicalArithmeticType() } } predicate isAssignment(Expr source, Type targetType, string context) { @@ -264,14 +264,14 @@ predicate isPreConversionAssignment(Expr source, Type targetType, string context * * The type is determined by the signedness of the bit field and the number of bits. */ -CanonicalIntegerTypes getBitFieldType(BitField bf) { +CanonicalIntegerType getBitFieldType(BitField bf) { exists(NumericType bitfieldActualType | bitfieldActualType = bf.getType() and // Integral type with the same signedness as the bit field, and big enough to hold the bit field value result.getSignedness() = bitfieldActualType.getSignedness() and result.getSize() * 8 >= bf.getNumBits() and // No smaller integral type can hold the bit field value - not exists(CanonicalIntegerTypes other | + not exists(CanonicalIntegerType other | other.getSize() * 8 >= bf.getNumBits() and other.getSignedness() = result.getSignedness() | diff --git a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql index 30d75e3dee..0ebcfb8f1e 100644 --- a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql +++ b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql @@ -145,9 +145,8 @@ class ImpliedIntegerPromotion extends RelevantConversion { override NumericType getFromType() { result = fromType } - override NumericType getToType() { + override CanonicalIntegerType getToType() { // Only report the canonical type - e.g. `int` not `signed int` - result = result.(IntegralType).getCanonicalArithmeticType() and if result instanceof Char16Type or result instanceof Char32Type or result instanceof Wchar_t then // Smallest type that can hold the value of the `fromType` From 21cf410fb23a3c2c87c4f916d47d911e17d828d7 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 20 Aug 2025 11:34:24 +0100 Subject: [PATCH 541/628] CanonicalTypes: refactor library - Create new shared library for canonical integer types - Implement `isMinimal` case to handle instances where multiple canonical types have the same size (for example `long` and `long long` on some platforms). - Create a new CanonicalIntegerNumericType for representing the concept of MISRA numeric canonical types. Set isMinimal() in the charpred to automatically filter out multiple canonical types for the same size and signedness. --- .../cpp/types/CanonicalTypes.qll | 18 +++++++++++++ .../cpp/misra/BuiltInTypeRules.qll | 25 +++++++++++-------- .../NoSignednessChangeFromPromotion.ql | 2 +- 3 files changed, 33 insertions(+), 12 deletions(-) create mode 100644 cpp/common/src/codingstandards/cpp/types/CanonicalTypes.qll diff --git a/cpp/common/src/codingstandards/cpp/types/CanonicalTypes.qll b/cpp/common/src/codingstandards/cpp/types/CanonicalTypes.qll new file mode 100644 index 0000000000..4625ea84ae --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/types/CanonicalTypes.qll @@ -0,0 +1,18 @@ +import cpp + +/** + * One of the 10 canonical integer types, which are the standard integer types. + */ +class CanonicalIntegralType extends IntegralType { + CanonicalIntegralType() { this = this.getCanonicalArithmeticType() } + + /** + * Holds if this is the canonical integer type with the shortest name for its size. + */ + predicate isMinimal() { + not exists(CanonicalIntegralType other | + other.getSize() = this.getSize() and + other.getName().length() < this.getName().length() + ) + } +} diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index 7b0068ba91..82a8cc7098 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -6,6 +6,7 @@ import cpp import codingstandards.cpp.misra import codingstandards.cpp.Call import codingstandards.cpp.Type +import codingstandards.cpp.types.CanonicalTypes /** * A MISRA C++ 2023 type category. @@ -142,10 +143,18 @@ predicate isSignedType(NumericType t) { t.getSignedness() = Signed() } predicate isUnsignedType(NumericType t) { t.getSignedness() = Unsigned() } /** - * One of the 10 canonical integer types, which are the standard integer types. + * A canonical integer type for each unique size and signedness combination. + * + * Where multiple canonical arithmetic types exist for a given size/signedness combination, we + * prefer the type with the shortest name. */ -class CanonicalIntegerType extends NumericType, IntegralType { - CanonicalIntegerType() { this = this.getCanonicalArithmeticType() } +class CanonicalIntegerNumericType extends NumericType, CanonicalIntegralType { + CanonicalIntegerNumericType() { + // Where multiple types exist with the same size and signedness, prefer shorter names - mainly + // to disambiguate between `unsigned long` and `unsigned long long` on platforms where they + // are the same size + this.isMinimal() + } } predicate isAssignment(Expr source, Type targetType, string context) { @@ -264,24 +273,18 @@ predicate isPreConversionAssignment(Expr source, Type targetType, string context * * The type is determined by the signedness of the bit field and the number of bits. */ -CanonicalIntegerType getBitFieldType(BitField bf) { +CanonicalIntegerNumericType getBitFieldType(BitField bf) { exists(NumericType bitfieldActualType | bitfieldActualType = bf.getType() and // Integral type with the same signedness as the bit field, and big enough to hold the bit field value result.getSignedness() = bitfieldActualType.getSignedness() and result.getSize() * 8 >= bf.getNumBits() and // No smaller integral type can hold the bit field value - not exists(CanonicalIntegerType other | + not exists(CanonicalIntegerNumericType other | other.getSize() * 8 >= bf.getNumBits() and other.getSignedness() = result.getSignedness() | other.getSize() < result.getRealSize() - or - // Where multiple types exist with the same size and signedness, prefer shorter names - mainly - // to disambiguate between `unsigned long` and `unsigned long long` on platforms where they - // are the same size - other.getSize() = result.getRealSize() and - other.getName().length() < result.getName().length() ) ) } diff --git a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql index 0ebcfb8f1e..e5f812e3be 100644 --- a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql +++ b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql @@ -145,7 +145,7 @@ class ImpliedIntegerPromotion extends RelevantConversion { override NumericType getFromType() { result = fromType } - override CanonicalIntegerType getToType() { + override CanonicalIntegerNumericType getToType() { // Only report the canonical type - e.g. `int` not `signed int` if result instanceof Char16Type or result instanceof Char32Type or result instanceof Wchar_t then From bc7bf5120449ed033ab189d4d60be1c7881fc045 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 20 Aug 2025 12:54:08 +0100 Subject: [PATCH 542/628] Rule 7.0.5: Limit to `Cast`s and refactor naming - Only `Cast`s participate in integer promotions and arithmetic conversions. - Rename conversion classes to clarify what they cover. - Update documentation to improve clarity on coverage. --- .../NoSignednessChangeFromPromotion.ql | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql index e5f812e3be..c7a84c25c8 100644 --- a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql +++ b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql @@ -17,7 +17,13 @@ import cpp import codingstandards.cpp.misra import codingstandards.cpp.misra.BuiltInTypeRules -abstract class RelevantConversion extends Expr { +/** + * An expression that represents a integral promotion or usual arithmetic conversion. + * + * Such conversions are usual either explicitly described with a `Cast`, or, in the case + * of assign operations, implicitly applied to an lvalue. + */ +abstract class IntegerPromotionOrUsualArithmeticConversion extends Expr { abstract NumericType getFromType(); abstract NumericType getToType(); @@ -28,13 +34,15 @@ abstract class RelevantConversion extends Expr { } /** - * A `Conversion` that is relevant for the rule. + * A `Cast` which is either an integer promotion or usual arithmetic conversion. */ -abstract class RelevantRealConversion extends RelevantConversion, Conversion { +abstract class IntegerPromotionOrUsualArithmeticConversionAsCast extends IntegerPromotionOrUsualArithmeticConversion, + Cast +{ NumericType fromType; NumericType toType; - RelevantRealConversion() { + IntegerPromotionOrUsualArithmeticConversionAsCast() { fromType = this.getExpr().getType() and toType = this.getType() and this.isImplicit() @@ -47,7 +55,7 @@ abstract class RelevantRealConversion extends RelevantConversion, Conversion { override Expr getConvertedExpr() { result = this.getExpr() } } -class UsualArithmeticConversion extends RelevantRealConversion { +class UsualArithmeticConversion extends IntegerPromotionOrUsualArithmeticConversionAsCast { UsualArithmeticConversion() { ( // Most binary operations from and to numeric types participate in usual arithmetic conversions @@ -72,9 +80,11 @@ class UsualArithmeticConversion extends RelevantRealConversion { override string getKindOfConversion() { result = "Usual arithmetic conversion" } } -class IntegerPromotion extends RelevantRealConversion { +class IntegerPromotion extends IntegerPromotionOrUsualArithmeticConversionAsCast { IntegerPromotion() { - // Exclude integer promotions combined with usual arithmetic conversions, which are handled separately + // In the case where a conversion involves both an integer promotion and a usual arithmetic conversion + // we only get a single `Conversion` which combines both. According to the rule, only the "final" type + // should be consider, so we handle these combined conversions as `UsualArithmeticConversion`s instead. not this instanceof UsualArithmeticConversion and // Only consider cases where the integer promotion is the last conversion applied exists(Expr e | e.getFullyConverted() = this) and @@ -94,7 +104,7 @@ class IntegerPromotion extends RelevantRealConversion { override string getKindOfConversion() { result = "Integer promotion" } } -class ImpliedUsualArithmeticConversion extends RelevantConversion { +class ImpliedUsualArithmeticConversion extends IntegerPromotionOrUsualArithmeticConversion { NumericType fromType; NumericType toType; @@ -128,7 +138,7 @@ class ImpliedUsualArithmeticConversion extends RelevantConversion { override string getKindOfConversion() { result = "Usual arithmetic conversion" } } -class ImpliedIntegerPromotion extends RelevantConversion { +class ImpliedIntegerPromotion extends IntegerPromotionOrUsualArithmeticConversion { NumericType fromType; ImpliedIntegerPromotion() { @@ -136,7 +146,9 @@ class ImpliedIntegerPromotion extends RelevantConversion { exists(AssignLShiftExpr aop | aop.getLValue() = this) or exists(AssignRShiftExpr aop | aop.getLValue() = this) ) and - // Only consider integer promotions from MISRA C++ "numeric types" as per the rule + // The rule applies to integer promotions from and to MISRA C++ numeric types + // However, you cannot have an integer promotion on a float, so we restrict + // this to integral types only fromType = this.getType() and fromType.getTypeCategory() = Integral() and // If the size is less than int, then it is an implied integer promotion @@ -184,7 +196,9 @@ class ImpliedIntegerPromotion extends RelevantConversion { override string getKindOfConversion() { result = "Integer promotion" } } -from Expr e, RelevantConversion c, NumericType fromType, NumericType toType, string changeType +from + Expr e, IntegerPromotionOrUsualArithmeticConversion c, NumericType fromType, NumericType toType, + string changeType where not isExcluded(e, ConversionsPackage::noSignednessChangeFromPromotionQuery()) and c.getConvertedExpr() = e and From f7cd25eaa661141b9df199037f7bdeca993729bf Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 20 Aug 2025 16:36:00 +0100 Subject: [PATCH 543/628] BuiltInTypeRules: Handle bit fields in switch cases --- .../src/codingstandards/cpp/misra/BuiltInTypeRules.qll | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index 82a8cc7098..75ae9c17e7 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -243,8 +243,16 @@ predicate isPreConversionAssignment(Expr source, Type targetType, string context exists(SwitchCase case, SwitchStmt switch | case.getExpr() = source and case.getSwitchStmt() = switch and - targetType = switch.getExpr().getFullyConverted().getType() and context = "switch case" + | + if switch.getExpr().(FieldAccess).getTarget() instanceof BitField + then + // For the MISRA type rules we treat bit fields as a special case + targetType = getBitFieldType(switch.getExpr().(FieldAccess).getTarget()) + else + // Regular variable initialization + // Get the type of the switch expression, which is the type of the case expression + targetType = switch.getExpr().getFullyConverted().getType() ) or // Class aggregate literal initialization From 2d14c816bdc049710ad596e96b06926776675fc5 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 20 Aug 2025 23:37:19 +0100 Subject: [PATCH 544/628] Fix CanonicalIntegralType classes --- .../src/codingstandards/cpp/types/CanonicalTypes.qll | 5 +++++ .../src/codingstandards/cpp/misra/BuiltInTypeRules.qll | 8 ++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/types/CanonicalTypes.qll b/cpp/common/src/codingstandards/cpp/types/CanonicalTypes.qll index 4625ea84ae..a5f6dbfe40 100644 --- a/cpp/common/src/codingstandards/cpp/types/CanonicalTypes.qll +++ b/cpp/common/src/codingstandards/cpp/types/CanonicalTypes.qll @@ -12,6 +12,11 @@ class CanonicalIntegralType extends IntegralType { predicate isMinimal() { not exists(CanonicalIntegralType other | other.getSize() = this.getSize() and + ( + other.isSigned() and this.isSigned() + or + other.isUnsigned() and this.isUnsigned() + ) and other.getName().length() < this.getName().length() ) } diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index 75ae9c17e7..2963d18877 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -148,12 +148,16 @@ predicate isUnsignedType(NumericType t) { t.getSignedness() = Unsigned() } * Where multiple canonical arithmetic types exist for a given size/signedness combination, we * prefer the type with the shortest name. */ -class CanonicalIntegerNumericType extends NumericType, CanonicalIntegralType { +class CanonicalIntegerNumericType extends NumericType { CanonicalIntegerNumericType() { // Where multiple types exist with the same size and signedness, prefer shorter names - mainly // to disambiguate between `unsigned long` and `unsigned long long` on platforms where they // are the same size - this.isMinimal() + this.(CanonicalIntegralType).isMinimal() + or + // `signed char` is not considered a canonical type (`char` is), but `char` is not a MISRA numeric + // type, so we need to reintroduce `signed char` here. + this instanceof SignedCharType } } From 9ddf6452b50922e19abdef657094349745d498cd Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 09:34:09 +0100 Subject: [PATCH 545/628] BuiltInTypeRules: Rename realType to builtInType --- .../cpp/misra/BuiltInTypeRules.qll | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index 2963d18877..caa2c84d6a 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -22,7 +22,7 @@ newtype TypeCategory = * * This does not apply the rules related to stripping specifiers or typedefs, or references. */ -TypeCategory getTypeCategory(BuiltInType t) { +private TypeCategory getBuiltInTypeCategory(BuiltInType t) { ( t instanceof PlainCharType or t instanceof WideCharType or @@ -64,7 +64,7 @@ TypeCategory getTypeCategory(BuiltInType t) { * * This function will strip specifiers and typedefs to get the underlying built-in type. */ -BuiltInType getBuiltInType(Type t) { +private BuiltInType getBuiltInType(Type t) { // Get the built-in type of a type, if it is a built-in type result = t or @@ -87,15 +87,15 @@ newtype Signedness = class CharacterType extends Type { // The actual character type, which is either a plain char or a wide char - BuiltInType realType; + BuiltInType builtInType; CharacterType() { // A type whose type category is character - getTypeCategory(realType) = Character() and - realType = getBuiltInType(this) + getBuiltInTypeCategory(builtInType) = Character() and + builtInType = getBuiltInType(this) } - Type getRealType() { result = realType } + BuiltInType getRealType() { result = builtInType } } /** @@ -108,34 +108,34 @@ class CharacterType extends Type { */ class NumericType extends Type { // The actual numeric type, which is either an integral or a floating-point type. - Type realType; + BuiltInType builtInType; NumericType() { // A type whose type category is either integral or a floating-point - getTypeCategory(realType) = [Integral().(TypeCategory), FloatingPoint()] and - realType = getBuiltInType(this) + getBuiltInTypeCategory(builtInType) = [Integral().(TypeCategory), FloatingPoint()] and + builtInType = getBuiltInType(this) } Signedness getSignedness() { - if realType.(IntegralType).isUnsigned() then result = Unsigned() else result = Signed() + if builtInType.(IntegralType).isUnsigned() then result = Unsigned() else result = Signed() } /** Gets the size of the actual numeric type. */ - int getRealSize() { result = realType.getSize() } + int getRealSize() { result = builtInType.getSize() } - TypeCategory getTypeCategory() { result = getTypeCategory(realType) } + TypeCategory getTypeCategory() { result = getBuiltInTypeCategory(builtInType) } /** * Gets the integeral upper bound of the numeric type, if it represents an integer type. */ - QlBuiltins::BigInt getIntegralUpperBound() { integralTypeBounds(realType, _, result) } + QlBuiltins::BigInt getIntegralUpperBound() { integralTypeBounds(builtInType, _, result) } /** * Gets the integeral lower bound of the numeric type, if it represents an integer type. */ - QlBuiltins::BigInt getIntegralLowerBound() { integralTypeBounds(realType, result, _) } + QlBuiltins::BigInt getIntegralLowerBound() { integralTypeBounds(builtInType, result, _) } - Type getRealType() { result = realType } + BuiltInType getRealType() { result = builtInType } } predicate isSignedType(NumericType t) { t.getSignedness() = Signed() } From 8be7b3c0060c3dd117c3f8419c93a2b26da807d8 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 09:59:22 +0100 Subject: [PATCH 546/628] BuiltInTypeRules: Add isSameType API --- .../src/codingstandards/cpp/misra/BuiltInTypeRules.qll | 8 ++++++-- .../src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql | 2 +- .../rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql | 2 +- .../src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index caa2c84d6a..3c5965b358 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -95,7 +95,9 @@ class CharacterType extends Type { builtInType = getBuiltInType(this) } - BuiltInType getRealType() { result = builtInType } + private BuiltInType getBuiltInType() { result = builtInType } + + predicate isSameType(CharacterType other) { this.getBuiltInType() = other.getBuiltInType() } } /** @@ -135,7 +137,9 @@ class NumericType extends Type { */ QlBuiltins::BigInt getIntegralLowerBound() { integralTypeBounds(builtInType, result, _) } - BuiltInType getRealType() { result = builtInType } + private BuiltInType getBuiltInType() { result = builtInType } + + predicate isSameType(NumericType other) { this.getBuiltInType() = other.getBuiltInType() } } predicate isSignedType(NumericType t) { t.getSignedness() = Signed() } diff --git a/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql b/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql index 0a9ac1028c..aa3cd2e44f 100644 --- a/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql +++ b/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql @@ -35,7 +35,7 @@ where eq.getAnOperand() = expr and leftType = eq.getLeftOperand().getType() and rightType = eq.getRightOperand().getType() and - leftType.getRealType() = rightType.getRealType() + leftType.isSameType(rightType) ) and // Exclude unevaluated operands not expr.isUnevaluated() diff --git a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql index c7a84c25c8..37f920bdee 100644 --- a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql +++ b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql @@ -125,7 +125,7 @@ class ImpliedUsualArithmeticConversion extends IntegerPromotionOrUsualArithmetic // type will be the same as the converted type of the rvalue. toType = aop.getRValue().getFullyConverted().getType() and // Only consider cases where the conversion is not a no-op, for consistency with the `Conversion` class - not fromType.getRealType() = toType.getRealType() + not fromType.isSameType(toType) ) } diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index 982757f0a5..ebd14de8e0 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -196,7 +196,7 @@ predicate isValidAssignment(Expr source, NumericType targetType, string context) isAssignment(source, targetType, context) and exists(NumericType sourceType | sourceType = source.getType() | if shouldHaveSameType(source) - then sourceType.getRealType() = targetType.getRealType() + then sourceType.isSameType(targetType) else ( // Valid type match isValidTypeMatch(sourceType, targetType) From bcf8ae9fbd5662fe323f1b81c2c8bc20d9f07915 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 10:11:00 +0100 Subject: [PATCH 547/628] BuiltInTypeRules: Rename getRealSize to getBuiltInSize --- .../cpp/misra/BuiltInTypeRules.qll | 52 ++++++++++--------- .../NoSignednessChangeFromPromotion.ql | 6 +-- .../NumericAssignmentTypeMismatch.ql | 4 +- 3 files changed, 33 insertions(+), 29 deletions(-) diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index 3c5965b358..ebe1e49aac 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -85,19 +85,36 @@ newtype Signedness = Signed() or Unsigned() -class CharacterType extends Type { - // The actual character type, which is either a plain char or a wide char +/** + * A `Type` which is considered to be a built-in type by MISRA. + * + * It differs from `BuiltInType` in that includes: + * - Built in types with specifiers (e.g., `const`, `volatile`, `restrict`). + * - Typedefs to built in types + * - References to built in types + * - Enum types with an explicit underlying type that is a built-in type. + */ +class MisraBuiltInType extends Type { + // The built in type underlying this MISRA built in type BuiltInType builtInType; - CharacterType() { - // A type whose type category is character - getBuiltInTypeCategory(builtInType) = Character() and - builtInType = getBuiltInType(this) - } + MisraBuiltInType() { builtInType = getBuiltInType(this) } private BuiltInType getBuiltInType() { result = builtInType } - predicate isSameType(CharacterType other) { this.getBuiltInType() = other.getBuiltInType() } + /** Gets the size of the underlying built in type. */ + int getBuiltInSize() { result = builtInType.getSize() } + + TypeCategory getTypeCategory() { result = getBuiltInTypeCategory(builtInType) } + + predicate isSameType(MisraBuiltInType other) { this.getBuiltInType() = other.getBuiltInType() } +} + +class CharacterType extends MisraBuiltInType { + CharacterType() { + // A type whose type category is character + getBuiltInTypeCategory(builtInType) = Character() + } } /** @@ -108,25 +125,16 @@ class CharacterType extends Type { * - Typedef'd types that are numeric types. * - Numeric types with specifiers (e.g., `const`, `volatile`, `restrict`). */ -class NumericType extends Type { - // The actual numeric type, which is either an integral or a floating-point type. - BuiltInType builtInType; - +class NumericType extends MisraBuiltInType { NumericType() { // A type whose type category is either integral or a floating-point - getBuiltInTypeCategory(builtInType) = [Integral().(TypeCategory), FloatingPoint()] and - builtInType = getBuiltInType(this) + getBuiltInTypeCategory(builtInType) = [Integral().(TypeCategory), FloatingPoint()] } Signedness getSignedness() { if builtInType.(IntegralType).isUnsigned() then result = Unsigned() else result = Signed() } - /** Gets the size of the actual numeric type. */ - int getRealSize() { result = builtInType.getSize() } - - TypeCategory getTypeCategory() { result = getBuiltInTypeCategory(builtInType) } - /** * Gets the integeral upper bound of the numeric type, if it represents an integer type. */ @@ -136,10 +144,6 @@ class NumericType extends Type { * Gets the integeral lower bound of the numeric type, if it represents an integer type. */ QlBuiltins::BigInt getIntegralLowerBound() { integralTypeBounds(builtInType, result, _) } - - private BuiltInType getBuiltInType() { result = builtInType } - - predicate isSameType(NumericType other) { this.getBuiltInType() = other.getBuiltInType() } } predicate isSignedType(NumericType t) { t.getSignedness() = Signed() } @@ -300,7 +304,7 @@ CanonicalIntegerNumericType getBitFieldType(BitField bf) { other.getSize() * 8 >= bf.getNumBits() and other.getSignedness() = result.getSignedness() | - other.getSize() < result.getRealSize() + other.getSize() < result.getBuiltInSize() ) ) } diff --git a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql index 37f920bdee..be3f71019b 100644 --- a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql +++ b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql @@ -89,9 +89,9 @@ class IntegerPromotion extends IntegerPromotionOrUsualArithmeticConversionAsCast // Only consider cases where the integer promotion is the last conversion applied exists(Expr e | e.getFullyConverted() = this) and // Integer promotion occurs where the from type is smaller than int - fromType.getRealSize() < sizeOfInt() and + fromType.getBuiltInSize() < sizeOfInt() and // To type is bigger than or equal to int - toType.getRealSize() >= sizeOfInt() and + toType.getBuiltInSize() >= sizeOfInt() and // An integer promotion is a conversion from an integral type to an integral type // // This deliberately excludes integer promotions from `bool` and unscoped enums which do not @@ -152,7 +152,7 @@ class ImpliedIntegerPromotion extends IntegerPromotionOrUsualArithmeticConversio fromType = this.getType() and fromType.getTypeCategory() = Integral() and // If the size is less than int, then it is an implied integer promotion - fromType.getRealSize() < sizeOfInt() + fromType.getBuiltInSize() < sizeOfInt() } override NumericType getFromType() { result = fromType } diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index ebd14de8e0..b08b2edf83 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -57,7 +57,7 @@ predicate isValidTypeMatch(NumericType sourceType, NumericType targetType) { // Same type category, signedness and size sourceType.getTypeCategory() = targetType.getTypeCategory() and sourceType.getSignedness() = targetType.getSignedness() and - sourceType.getRealSize() = targetType.getRealSize() + sourceType.getBuiltInSize() = targetType.getBuiltInSize() } /** @@ -118,7 +118,7 @@ predicate isValidWidening(Expr source, NumericType sourceType, NumericType targe ) and sourceType.getTypeCategory() = targetType.getTypeCategory() and sourceType.getSignedness() = targetType.getSignedness() and - sourceType.getRealSize() < targetType.getRealSize() + sourceType.getBuiltInSize() < targetType.getBuiltInSize() } /** From 94cfcda31cc7e873ad7f2b1a02891565294fbc6e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 10:14:42 +0100 Subject: [PATCH 548/628] MisraType: Avoid misuse of getSize() --- .../codingstandards/cpp/misra/BuiltInTypeRules.qll | 13 +++++++++---- .../InappropriateBitwiseOrShiftOperands.ql | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index ebe1e49aac..99849c9e0d 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -93,8 +93,11 @@ newtype Signedness = * - Typedefs to built in types * - References to built in types * - Enum types with an explicit underlying type that is a built-in type. + * + * Note: this does not extend `Type` directly, to prevent accidental use of `getSize()`, which + * returns the "wrong" size for e.g. reference types. */ -class MisraBuiltInType extends Type { +class MisraBuiltInType extends Element { // The built in type underlying this MISRA built in type BuiltInType builtInType; @@ -108,6 +111,8 @@ class MisraBuiltInType extends Type { TypeCategory getTypeCategory() { result = getBuiltInTypeCategory(builtInType) } predicate isSameType(MisraBuiltInType other) { this.getBuiltInType() = other.getBuiltInType() } + + string getName() { result = this.(Type).getName() } } class CharacterType extends MisraBuiltInType { @@ -298,13 +303,13 @@ CanonicalIntegerNumericType getBitFieldType(BitField bf) { bitfieldActualType = bf.getType() and // Integral type with the same signedness as the bit field, and big enough to hold the bit field value result.getSignedness() = bitfieldActualType.getSignedness() and - result.getSize() * 8 >= bf.getNumBits() and + result.getBuiltInSize() * 8 >= bf.getNumBits() and // No smaller integral type can hold the bit field value not exists(CanonicalIntegerNumericType other | - other.getSize() * 8 >= bf.getNumBits() and + other.getBuiltInSize() * 8 >= bf.getNumBits() and other.getSignedness() = result.getSignedness() | - other.getSize() < result.getBuiltInSize() + other.getBuiltInSize() < result.getBuiltInSize() ) ) } diff --git a/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql index 5aff491aff..bb2ce44422 100644 --- a/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql +++ b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql @@ -45,7 +45,7 @@ predicate isSignedConstantLeftShiftException(LShiftExpr shift) { leftVal = left.getValue().toBigInt() and rightVal = right.getValue().toInt() and leftVal >= 0.toBigInt() and - maxBit = leftType.getSize() * 8 - 1 and + maxBit = leftType.getBuiltInSize() * 8 - 1 and // Check that no set bit is shifted into or beyond the sign bit leftVal * 2.toBigInt().pow(rightVal) < 2.toBigInt().pow(maxBit) ) From 2c979059285ad752b0add5c774e46815dc2657ae Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 10:54:55 +0100 Subject: [PATCH 549/628] BuiltInTypes: Wrap in MisraCpp23BuiltInTypes module For clarity --- .../cpp/misra/BuiltInTypeRules.qll | 552 +++++++++--------- .../RULE-7-0-3/NoCharacterNumericalValue.ql | 13 +- .../InappropriateBitwiseOrShiftOperands.ql | 16 +- .../NoSignednessChangeFromPromotion.ql | 47 +- .../NumericAssignmentTypeMismatch.ql | 39 +- 5 files changed, 343 insertions(+), 324 deletions(-) diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index 99849c9e0d..84dd8ba947 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -8,310 +8,312 @@ import codingstandards.cpp.Call import codingstandards.cpp.Type import codingstandards.cpp.types.CanonicalTypes -/** - * A MISRA C++ 2023 type category. - */ -newtype TypeCategory = - Integral() or - FloatingPoint() or - Character() or - Other() - -/** - * Gets the type category of a built-in type. - * - * This does not apply the rules related to stripping specifiers or typedefs, or references. - */ -private TypeCategory getBuiltInTypeCategory(BuiltInType t) { - ( - t instanceof PlainCharType or - t instanceof WideCharType or - t instanceof Char16Type or - t instanceof Char32Type or - t instanceof Char8Type - ) and - result = Character() - or - ( - // The 5 standard integral types, covering both signed/unsigned variants - // Explicitly list the signed/unsigned `char` to avoid capturing plain `char`, which is of character type category - t instanceof SignedCharType or - t instanceof UnsignedCharType or - t instanceof ShortType or - t instanceof IntType or - t instanceof LongType or - t instanceof LongLongType - ) and - result = Integral() - or - ( - t instanceof FloatType or - t instanceof DoubleType or - t instanceof LongDoubleType - ) and - result = FloatingPoint() - or - ( - t instanceof BoolType or - t instanceof VoidType or - t instanceof NullPointerType - ) and - result = Other() -} - -/** - * Gets the built-in type of a type, if it is a built-in type. - * - * This function will strip specifiers and typedefs to get the underlying built-in type. - */ -private BuiltInType getBuiltInType(Type t) { - // Get the built-in type of a type, if it is a built-in type - result = t - or - // Strip specifiers and typedefs to get the built-in type - result = getBuiltInType(t.getUnspecifiedType()) - or - // For reference types, get the base type and then the built-in type - result = getBuiltInType(t.(ReferenceType).getBaseType()) - or - // For enum types, get the explicit underlying type and then the built-in type - result = getBuiltInType(t.(Enum).getExplicitUnderlyingType()) -} +module MisraCpp23BuiltInTypes { + /** + * A MISRA C++ 2023 type category. + */ + newtype TypeCategory = + Integral() or + FloatingPoint() or + Character() or + Other() -/** - * The signedness of a MISRA C++ 2023 numeric type. - */ -newtype Signedness = - Signed() or - Unsigned() + /** + * Gets the type category of a built-in type. + * + * This does not apply the rules related to stripping specifiers or typedefs, or references. + */ + private TypeCategory getBuiltInTypeCategory(BuiltInType t) { + ( + t instanceof PlainCharType or + t instanceof WideCharType or + t instanceof Char16Type or + t instanceof Char32Type or + t instanceof Char8Type + ) and + result = Character() + or + ( + // The 5 standard integral types, covering both signed/unsigned variants + // Explicitly list the signed/unsigned `char` to avoid capturing plain `char`, which is of character type category + t instanceof SignedCharType or + t instanceof UnsignedCharType or + t instanceof ShortType or + t instanceof IntType or + t instanceof LongType or + t instanceof LongLongType + ) and + result = Integral() + or + ( + t instanceof FloatType or + t instanceof DoubleType or + t instanceof LongDoubleType + ) and + result = FloatingPoint() + or + ( + t instanceof BoolType or + t instanceof VoidType or + t instanceof NullPointerType + ) and + result = Other() + } -/** - * A `Type` which is considered to be a built-in type by MISRA. - * - * It differs from `BuiltInType` in that includes: - * - Built in types with specifiers (e.g., `const`, `volatile`, `restrict`). - * - Typedefs to built in types - * - References to built in types - * - Enum types with an explicit underlying type that is a built-in type. - * - * Note: this does not extend `Type` directly, to prevent accidental use of `getSize()`, which - * returns the "wrong" size for e.g. reference types. - */ -class MisraBuiltInType extends Element { - // The built in type underlying this MISRA built in type - BuiltInType builtInType; + /** + * Gets the built-in type of a type, if it is a built-in type. + * + * This function will strip specifiers and typedefs to get the underlying built-in type. + */ + private BuiltInType getBuiltInType(Type t) { + // Get the built-in type of a type, if it is a built-in type + result = t + or + // Strip specifiers and typedefs to get the built-in type + result = getBuiltInType(t.getUnspecifiedType()) + or + // For reference types, get the base type and then the built-in type + result = getBuiltInType(t.(ReferenceType).getBaseType()) + or + // For enum types, get the explicit underlying type and then the built-in type + result = getBuiltInType(t.(Enum).getExplicitUnderlyingType()) + } - MisraBuiltInType() { builtInType = getBuiltInType(this) } + /** + * The signedness of a MISRA C++ 2023 numeric type. + */ + newtype Signedness = + Signed() or + Unsigned() - private BuiltInType getBuiltInType() { result = builtInType } + /** + * A `Type` which is considered to be a built-in type by MISRA. + * + * It differs from `BuiltInType` in that includes: + * - Built in types with specifiers (e.g., `const`, `volatile`, `restrict`). + * - Typedefs to built in types + * - References to built in types + * - Enum types with an explicit underlying type that is a built-in type. + * + * Note: this does not extend `Type` directly, to prevent accidental use of `getSize()`, which + * returns the "wrong" size for e.g. reference types. + */ + class MisraBuiltInType extends Element { + // The built in type underlying this MISRA built in type + BuiltInType builtInType; - /** Gets the size of the underlying built in type. */ - int getBuiltInSize() { result = builtInType.getSize() } + MisraBuiltInType() { builtInType = getBuiltInType(this) } - TypeCategory getTypeCategory() { result = getBuiltInTypeCategory(builtInType) } + private BuiltInType getBuiltInType() { result = builtInType } - predicate isSameType(MisraBuiltInType other) { this.getBuiltInType() = other.getBuiltInType() } + /** Gets the size of the underlying built in type. */ + int getBuiltInSize() { result = builtInType.getSize() } - string getName() { result = this.(Type).getName() } -} + TypeCategory getTypeCategory() { result = getBuiltInTypeCategory(builtInType) } -class CharacterType extends MisraBuiltInType { - CharacterType() { - // A type whose type category is character - getBuiltInTypeCategory(builtInType) = Character() - } -} + predicate isSameType(MisraBuiltInType other) { this.getBuiltInType() = other.getBuiltInType() } -/** - * A MISRA C++ 2023 numeric type is a type that represents a number, either an integral or a floating-point. - * - * In addition to the basic integral and floating-point types, it includes: - * - Enum types with an explicit underlying type that is a numeric type. - * - Typedef'd types that are numeric types. - * - Numeric types with specifiers (e.g., `const`, `volatile`, `restrict`). - */ -class NumericType extends MisraBuiltInType { - NumericType() { - // A type whose type category is either integral or a floating-point - getBuiltInTypeCategory(builtInType) = [Integral().(TypeCategory), FloatingPoint()] + string getName() { result = this.(Type).getName() } } - Signedness getSignedness() { - if builtInType.(IntegralType).isUnsigned() then result = Unsigned() else result = Signed() + class CharacterType extends MisraBuiltInType { + CharacterType() { + // A type whose type category is character + getBuiltInTypeCategory(builtInType) = Character() + } } /** - * Gets the integeral upper bound of the numeric type, if it represents an integer type. + * A MISRA C++ 2023 numeric type is a type that represents a number, either an integral or a floating-point. + * + * In addition to the basic integral and floating-point types, it includes: + * - Enum types with an explicit underlying type that is a numeric type. + * - Typedef'd types that are numeric types. + * - Numeric types with specifiers (e.g., `const`, `volatile`, `restrict`). */ - QlBuiltins::BigInt getIntegralUpperBound() { integralTypeBounds(builtInType, _, result) } + class NumericType extends MisraBuiltInType { + NumericType() { + // A type whose type category is either integral or a floating-point + getBuiltInTypeCategory(builtInType) = [Integral().(TypeCategory), FloatingPoint()] + } - /** - * Gets the integeral lower bound of the numeric type, if it represents an integer type. - */ - QlBuiltins::BigInt getIntegralLowerBound() { integralTypeBounds(builtInType, result, _) } -} + Signedness getSignedness() { + if builtInType.(IntegralType).isUnsigned() then result = Unsigned() else result = Signed() + } -predicate isSignedType(NumericType t) { t.getSignedness() = Signed() } + /** + * Gets the integeral upper bound of the numeric type, if it represents an integer type. + */ + QlBuiltins::BigInt getIntegralUpperBound() { integralTypeBounds(builtInType, _, result) } -predicate isUnsignedType(NumericType t) { t.getSignedness() = Unsigned() } + /** + * Gets the integeral lower bound of the numeric type, if it represents an integer type. + */ + QlBuiltins::BigInt getIntegralLowerBound() { integralTypeBounds(builtInType, result, _) } + } -/** - * A canonical integer type for each unique size and signedness combination. - * - * Where multiple canonical arithmetic types exist for a given size/signedness combination, we - * prefer the type with the shortest name. - */ -class CanonicalIntegerNumericType extends NumericType { - CanonicalIntegerNumericType() { - // Where multiple types exist with the same size and signedness, prefer shorter names - mainly - // to disambiguate between `unsigned long` and `unsigned long long` on platforms where they - // are the same size - this.(CanonicalIntegralType).isMinimal() - or - // `signed char` is not considered a canonical type (`char` is), but `char` is not a MISRA numeric - // type, so we need to reintroduce `signed char` here. - this instanceof SignedCharType + predicate isSignedType(NumericType t) { t.getSignedness() = Signed() } + + predicate isUnsignedType(NumericType t) { t.getSignedness() = Unsigned() } + + /** + * A canonical integer type for each unique size and signedness combination. + * + * Where multiple canonical arithmetic types exist for a given size/signedness combination, we + * prefer the type with the shortest name. + */ + class CanonicalIntegerNumericType extends NumericType { + CanonicalIntegerNumericType() { + // Where multiple types exist with the same size and signedness, prefer shorter names - mainly + // to disambiguate between `unsigned long` and `unsigned long long` on platforms where they + // are the same size + this.(CanonicalIntegralType).isMinimal() + or + // `signed char` is not considered a canonical type (`char` is), but `char` is not a MISRA numeric + // type, so we need to reintroduce `signed char` here. + this instanceof SignedCharType + } } -} -predicate isAssignment(Expr source, Type targetType, string context) { - exists(Expr preConversionAssignment | - isPreConversionAssignment(preConversionAssignment, targetType, context) and - preConversionAssignment.getExplicitlyConverted() = source - ) -} + predicate isAssignment(Expr source, Type targetType, string context) { + exists(Expr preConversionAssignment | + isPreConversionAssignment(preConversionAssignment, targetType, context) and + preConversionAssignment.getExplicitlyConverted() = source + ) + } -predicate isPreConversionAssignment(Expr source, Type targetType, string context) { - // Assignment expression (which excludes compound assignments) - exists(AssignExpr assign | - assign.getRValue() = source and - context = "assignment" - | - if isAssignedToBitfield(source, _) - then + predicate isPreConversionAssignment(Expr source, Type targetType, string context) { + // Assignment expression (which excludes compound assignments) + exists(AssignExpr assign | + assign.getRValue() = source and + context = "assignment" + | + if isAssignedToBitfield(source, _) + then + // For the MISRA type rules we treat bit fields as a special case + exists(BitField bf | + isAssignedToBitfield(source, bf) and + targetType = getBitFieldType(bf) + ) + else + exists(Type t | t = assign.getLValue().getType() | + // Unwrap PointerToMemberType e.g `l1.*l2 = x;` + if t instanceof PointerToMemberType + then targetType = t.(PointerToMemberType).getBaseType() + else targetType = t + ) + ) + or + // Variable initialization + exists(Variable v, Initializer init | + init.getExpr() = source and + v.getInitializer() = init and + context = "initialization" + | // For the MISRA type rules we treat bit fields as a special case - exists(BitField bf | - isAssignedToBitfield(source, bf) and - targetType = getBitFieldType(bf) - ) - else - exists(Type t | t = assign.getLValue().getType() | - // Unwrap PointerToMemberType e.g `l1.*l2 = x;` - if t instanceof PointerToMemberType - then targetType = t.(PointerToMemberType).getBaseType() - else targetType = t - ) - ) - or - // Variable initialization - exists(Variable v, Initializer init | - init.getExpr() = source and - v.getInitializer() = init and - context = "initialization" - | - // For the MISRA type rules we treat bit fields as a special case - if v instanceof BitField - then targetType = getBitFieldType(v) - else - // Regular variable initialization - targetType = v.getType() - ) - or - exists(ConstructorFieldInit fi | - fi.getExpr() = source and - context = "constructor field initialization" - | - // For the MISRA type rules we treat bit fields as a special case - if fi.getTarget() instanceof BitField - then targetType = getBitFieldType(fi.getTarget()) - else - // Regular variable initialization - targetType = fi.getTarget().getType() - ) - or - // Passing a function parameter by value - exists(Call call, int i | - call.getArgument(i) = source and - not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and - context = "function argument" - | - // A regular function call - targetType = call.getTarget().getParameter(i).getType() + if v instanceof BitField + then targetType = getBitFieldType(v) + else + // Regular variable initialization + targetType = v.getType() + ) or - // A function call where the argument is passed as varargs - call.getTarget().getNumberOfParameters() <= i and - // The rule states that the type should match the "adjusted" type of the argument - targetType = source.getFullyConverted().getType() + exists(ConstructorFieldInit fi | + fi.getExpr() = source and + context = "constructor field initialization" + | + // For the MISRA type rules we treat bit fields as a special case + if fi.getTarget() instanceof BitField + then targetType = getBitFieldType(fi.getTarget()) + else + // Regular variable initialization + targetType = fi.getTarget().getType() + ) or - // An expression call - get the function type, then the parameter type - targetType = getExprCallFunctionType(call).getParameterType(i) - ) - or - // Return statement - exists(ReturnStmt ret, Function f | - ret.getExpr() = source and - ret.getEnclosingFunction() = f and - targetType = f.getType() and - not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and - context = "return" - ) - or - // Switch case - exists(SwitchCase case, SwitchStmt switch | - case.getExpr() = source and - case.getSwitchStmt() = switch and - context = "switch case" - | - if switch.getExpr().(FieldAccess).getTarget() instanceof BitField - then + // Passing a function parameter by value + exists(Call call, int i | + call.getArgument(i) = source and + not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and + context = "function argument" + | + // A regular function call + targetType = call.getTarget().getParameter(i).getType() + or + // A function call where the argument is passed as varargs + call.getTarget().getNumberOfParameters() <= i and + // The rule states that the type should match the "adjusted" type of the argument + targetType = source.getFullyConverted().getType() + or + // An expression call - get the function type, then the parameter type + targetType = getExprCallFunctionType(call).getParameterType(i) + ) + or + // Return statement + exists(ReturnStmt ret, Function f | + ret.getExpr() = source and + ret.getEnclosingFunction() = f and + targetType = f.getType() and + not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and + context = "return" + ) + or + // Switch case + exists(SwitchCase case, SwitchStmt switch | + case.getExpr() = source and + case.getSwitchStmt() = switch and + context = "switch case" + | + if switch.getExpr().(FieldAccess).getTarget() instanceof BitField + then + // For the MISRA type rules we treat bit fields as a special case + targetType = getBitFieldType(switch.getExpr().(FieldAccess).getTarget()) + else + // Regular variable initialization + // Get the type of the switch expression, which is the type of the case expression + targetType = switch.getExpr().getFullyConverted().getType() + ) + or + // Class aggregate literal initialization + exists(ClassAggregateLiteral al, Field f | + source = al.getAFieldExpr(f) and + context = "class aggregate literal" + | // For the MISRA type rules we treat bit fields as a special case - targetType = getBitFieldType(switch.getExpr().(FieldAccess).getTarget()) - else - // Regular variable initialization - // Get the type of the switch expression, which is the type of the case expression - targetType = switch.getExpr().getFullyConverted().getType() - ) - or - // Class aggregate literal initialization - exists(ClassAggregateLiteral al, Field f | - source = al.getAFieldExpr(f) and - context = "class aggregate literal" - | - // For the MISRA type rules we treat bit fields as a special case - if f instanceof BitField - then targetType = getBitFieldType(f) - else - // Regular variable initialization - targetType = f.getType() - ) - or - // Array or vector aggregate literal initialization - exists(ArrayOrVectorAggregateLiteral vl | - source = vl.getAnElementExpr(_) and - targetType = vl.getElementType() and - context = "array or vector aggregate literal" - ) -} + if f instanceof BitField + then targetType = getBitFieldType(f) + else + // Regular variable initialization + targetType = f.getType() + ) + or + // Array or vector aggregate literal initialization + exists(ArrayOrVectorAggregateLiteral vl | + source = vl.getAnElementExpr(_) and + targetType = vl.getElementType() and + context = "array or vector aggregate literal" + ) + } -/** - * Gets the smallest integral type that can hold the value of a bit field. - * - * The type is determined by the signedness of the bit field and the number of bits. - */ -CanonicalIntegerNumericType getBitFieldType(BitField bf) { - exists(NumericType bitfieldActualType | - bitfieldActualType = bf.getType() and - // Integral type with the same signedness as the bit field, and big enough to hold the bit field value - result.getSignedness() = bitfieldActualType.getSignedness() and - result.getBuiltInSize() * 8 >= bf.getNumBits() and - // No smaller integral type can hold the bit field value - not exists(CanonicalIntegerNumericType other | - other.getBuiltInSize() * 8 >= bf.getNumBits() and - other.getSignedness() = result.getSignedness() - | - other.getBuiltInSize() < result.getBuiltInSize() + /** + * Gets the smallest integral type that can hold the value of a bit field. + * + * The type is determined by the signedness of the bit field and the number of bits. + */ + CanonicalIntegerNumericType getBitFieldType(BitField bf) { + exists(NumericType bitfieldActualType | + bitfieldActualType = bf.getType() and + // Integral type with the same signedness as the bit field, and big enough to hold the bit field value + result.getSignedness() = bitfieldActualType.getSignedness() and + result.getBuiltInSize() * 8 >= bf.getNumBits() and + // No smaller integral type can hold the bit field value + not exists(CanonicalIntegerNumericType other | + other.getBuiltInSize() * 8 >= bf.getNumBits() and + other.getSignedness() = result.getSignedness() + | + other.getBuiltInSize() < result.getBuiltInSize() + ) ) - ) + } } /** diff --git a/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql b/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql index aa3cd2e44f..7ecbd8959f 100644 --- a/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql +++ b/cpp/misra/src/rules/RULE-7-0-3/NoCharacterNumericalValue.ql @@ -23,15 +23,18 @@ where targetType = c.getType() and ( // Conversion from character type to non-character type - sourceType instanceof CharacterType and - not targetType instanceof CharacterType + sourceType instanceof MisraCpp23BuiltInTypes::CharacterType and + not targetType instanceof MisraCpp23BuiltInTypes::CharacterType or // Conversion from non-character type to character type - not sourceType instanceof CharacterType and - targetType instanceof CharacterType + not sourceType instanceof MisraCpp23BuiltInTypes::CharacterType and + targetType instanceof MisraCpp23BuiltInTypes::CharacterType ) and // Exclude conversions where both operands have the same character type in equality operations - not exists(EqualityOperation eq, CharacterType leftType, CharacterType rightType | + not exists( + EqualityOperation eq, MisraCpp23BuiltInTypes::CharacterType leftType, + MisraCpp23BuiltInTypes::CharacterType rightType + | eq.getAnOperand() = expr and leftType = eq.getLeftOperand().getType() and rightType = eq.getRightOperand().getType() and diff --git a/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql index bb2ce44422..e1f1e21069 100644 --- a/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql +++ b/cpp/misra/src/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.ql @@ -32,15 +32,15 @@ predicate isValidShiftConstantRange(Expr right, Type leftType) { predicate isSignedConstantLeftShiftException(LShiftExpr shift) { exists( - Expr left, Expr right, NumericType leftType, QlBuiltins::BigInt leftVal, int rightVal, - int maxBit + Expr left, Expr right, MisraCpp23BuiltInTypes::NumericType leftType, QlBuiltins::BigInt leftVal, + int rightVal, int maxBit | left = shift.getLeftOperand() and right = shift.getRightOperand() and leftType = left.getType() and isConstantExpression(left) and isConstantExpression(right) and - isSignedType(leftType) and + MisraCpp23BuiltInTypes::isSignedType(leftType) and isValidShiftConstantRange(right, leftType) and leftVal = left.getValue().toBigInt() and rightVal = right.getValue().toInt() and @@ -61,7 +61,7 @@ where | x = op.getLeftOperand() and operandType = op.getLeftOperand().getExplicitlyConverted().getType() and - not isUnsignedType(operandType) and + not MisraCpp23BuiltInTypes::isUnsignedType(operandType) and message = "Bitwise operator '" + op.getOperator() + "' requires unsigned numeric operands, but the left operand has type '" + operandType + @@ -69,7 +69,7 @@ where or x = op.getRightOperand() and operandType = op.getRightOperand().getExplicitlyConverted().getType() and - not isUnsignedType(operandType) and + not MisraCpp23BuiltInTypes::isUnsignedType(operandType) and message = "Bitwise operator '" + op.getOperator() + "' requires unsigned numeric operands, but the right operand has type '" + operandType + @@ -80,7 +80,7 @@ where exists(ComplementExpr comp, Type opType | x = comp.getOperand() and opType = comp.getOperand().getExplicitlyConverted().getType() and - not isUnsignedType(opType) and + not MisraCpp23BuiltInTypes::isUnsignedType(opType) and message = "Bit complement operator '~' requires unsigned operand, but has type '" + opType + "'." ) @@ -89,7 +89,7 @@ where exists(BinaryShiftOpOrAssignOp shift, Type leftType | x = shift.getLeftOperand() and leftType = shift.getLeftOperand().getExplicitlyConverted().getType() and - not isUnsignedType(leftType) and + not MisraCpp23BuiltInTypes::isUnsignedType(leftType) and not isSignedConstantLeftShiftException(shift) and message = "Shift operator '" + shift.getOperator() + @@ -110,7 +110,7 @@ where "Shift operator '" + shift.getOperator() + "' shifts by " + right.getValue().toInt() + " which is not within the valid range 0.." + ((leftType.getSize() * 8) - 1) + "." else ( - not isUnsignedType(rightType) and + not MisraCpp23BuiltInTypes::isUnsignedType(rightType) and message = "Shift operator '" + shift.getOperator() + "' requires unsigned right operand, but has type '" + rightType + "'." diff --git a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql index be3f71019b..a8d9e1bc45 100644 --- a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql +++ b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql @@ -24,9 +24,9 @@ import codingstandards.cpp.misra.BuiltInTypeRules * of assign operations, implicitly applied to an lvalue. */ abstract class IntegerPromotionOrUsualArithmeticConversion extends Expr { - abstract NumericType getFromType(); + abstract MisraCpp23BuiltInTypes::NumericType getFromType(); - abstract NumericType getToType(); + abstract MisraCpp23BuiltInTypes::NumericType getToType(); abstract Expr getConvertedExpr(); @@ -39,8 +39,8 @@ abstract class IntegerPromotionOrUsualArithmeticConversion extends Expr { abstract class IntegerPromotionOrUsualArithmeticConversionAsCast extends IntegerPromotionOrUsualArithmeticConversion, Cast { - NumericType fromType; - NumericType toType; + MisraCpp23BuiltInTypes::NumericType fromType; + MisraCpp23BuiltInTypes::NumericType toType; IntegerPromotionOrUsualArithmeticConversionAsCast() { fromType = this.getExpr().getType() and @@ -48,9 +48,9 @@ abstract class IntegerPromotionOrUsualArithmeticConversionAsCast extends Integer this.isImplicit() } - override NumericType getFromType() { result = fromType } + override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } - override NumericType getToType() { result = toType } + override MisraCpp23BuiltInTypes::NumericType getToType() { result = toType } override Expr getConvertedExpr() { result = this.getExpr() } } @@ -97,16 +97,16 @@ class IntegerPromotion extends IntegerPromotionOrUsualArithmeticConversionAsCast // This deliberately excludes integer promotions from `bool` and unscoped enums which do not // have a fixed underlying type, because neither of these are considered integral types in the // MISRA C++ rules. - fromType.getTypeCategory() = Integral() and - toType.getTypeCategory() = Integral() + fromType.getTypeCategory() = MisraCpp23BuiltInTypes::Integral() and + toType.getTypeCategory() = MisraCpp23BuiltInTypes::Integral() } override string getKindOfConversion() { result = "Integer promotion" } } class ImpliedUsualArithmeticConversion extends IntegerPromotionOrUsualArithmeticConversion { - NumericType fromType; - NumericType toType; + MisraCpp23BuiltInTypes::NumericType fromType; + MisraCpp23BuiltInTypes::NumericType toType; ImpliedUsualArithmeticConversion() { // The lvalue of an assignment operation does not have a `Conversion` in our model, but @@ -129,9 +129,9 @@ class ImpliedUsualArithmeticConversion extends IntegerPromotionOrUsualArithmetic ) } - override NumericType getFromType() { result = fromType } + override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } - override NumericType getToType() { result = toType } + override MisraCpp23BuiltInTypes::NumericType getToType() { result = toType } override Expr getConvertedExpr() { result = this } @@ -139,7 +139,7 @@ class ImpliedUsualArithmeticConversion extends IntegerPromotionOrUsualArithmetic } class ImpliedIntegerPromotion extends IntegerPromotionOrUsualArithmeticConversion { - NumericType fromType; + MisraCpp23BuiltInTypes::NumericType fromType; ImpliedIntegerPromotion() { ( @@ -150,20 +150,20 @@ class ImpliedIntegerPromotion extends IntegerPromotionOrUsualArithmeticConversio // However, you cannot have an integer promotion on a float, so we restrict // this to integral types only fromType = this.getType() and - fromType.getTypeCategory() = Integral() and + fromType.getTypeCategory() = MisraCpp23BuiltInTypes::Integral() and // If the size is less than int, then it is an implied integer promotion fromType.getBuiltInSize() < sizeOfInt() } - override NumericType getFromType() { result = fromType } + override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } - override CanonicalIntegerNumericType getToType() { + override MisraCpp23BuiltInTypes::CanonicalIntegerNumericType getToType() { // Only report the canonical type - e.g. `int` not `signed int` if result instanceof Char16Type or result instanceof Char32Type or result instanceof Wchar_t then // Smallest type that can hold the value of the `fromType` result = - min(NumericType candidateType | + min(MisraCpp23BuiltInTypes::NumericType candidateType | ( candidateType instanceof IntType or candidateType instanceof LongType or @@ -176,12 +176,14 @@ class ImpliedIntegerPromotion extends IntegerPromotionOrUsualArithmeticConversio else ( if // If the `fromType` is signed, the result must be signed - fromType.getSignedness() = Signed() + fromType.getSignedness() = MisraCpp23BuiltInTypes::Signed() or // If the `fromType` is unsigned, but the result can fit into the signed int type, then the // result must be signed as well. fromType.getIntegralUpperBound() <= - any(IntType t | t.isSigned()).(NumericType).getIntegralUpperBound() + any(IntType t | t.isSigned()) + .(MisraCpp23BuiltInTypes::NumericType) + .getIntegralUpperBound() then // `int` is returned result.(IntType).isSigned() @@ -197,7 +199,8 @@ class ImpliedIntegerPromotion extends IntegerPromotionOrUsualArithmeticConversio } from - Expr e, IntegerPromotionOrUsualArithmeticConversion c, NumericType fromType, NumericType toType, + Expr e, IntegerPromotionOrUsualArithmeticConversion c, + MisraCpp23BuiltInTypes::NumericType fromType, MisraCpp23BuiltInTypes::NumericType toType, string changeType where not isExcluded(e, ConversionsPackage::noSignednessChangeFromPromotionQuery()) and @@ -220,8 +223,8 @@ where // Exception 2: allow safe conversions from integral to floating-point types not ( e.isConstant() and - fromType.getTypeCategory() = Integral() and - toType.getTypeCategory() = FloatingPoint() + fromType.getTypeCategory() = MisraCpp23BuiltInTypes::Integral() and + toType.getTypeCategory() = MisraCpp23BuiltInTypes::FloatingPoint() ) select e, c.getKindOfConversion() + " from '" + fromType.getName() + "' to '" + toType.getName() + diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index b08b2edf83..dd462d21b6 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -19,14 +19,16 @@ import codingstandards.cpp.ConstantExpressions import codingstandards.cpp.misra.BuiltInTypeRules import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis -predicate isValidConstantAssignment(IntegerConstantExpr source, NumericType targetType) { - isAssignment(source, targetType, _) and +predicate isValidConstantAssignment( + IntegerConstantExpr source, MisraCpp23BuiltInTypes::NumericType targetType +) { + MisraCpp23BuiltInTypes::isAssignment(source, targetType, _) and exists(QlBuiltins::BigInt val | val = source.getConstantValue() | // Bit field assignment: check if the value fits in the bit field exists(BitField bf, int numBits | isAssignedToBitfield(source, bf) and numBits = bf.getNumBits() and - if targetType.getSignedness() = Signed() + if targetType.getSignedness() = MisraCpp23BuiltInTypes::Signed() then // Signed bit field: value must be in the range of signed bit field val >= -2.toBigInt().pow(numBits - 1) and @@ -46,14 +48,16 @@ predicate isValidConstantAssignment(IntegerConstantExpr source, NumericType targ val <= targetType.getIntegralUpperBound() or // All floating point types can represent all integer values - targetType.getTypeCategory() = FloatingPoint() + targetType.getTypeCategory() = MisraCpp23BuiltInTypes::FloatingPoint() ) ) } bindingset[sourceType, targetType] pragma[inline_late] -predicate isValidTypeMatch(NumericType sourceType, NumericType targetType) { +predicate isValidTypeMatch( + MisraCpp23BuiltInTypes::NumericType sourceType, MisraCpp23BuiltInTypes::NumericType targetType +) { // Same type category, signedness and size sourceType.getTypeCategory() = targetType.getTypeCategory() and sourceType.getSignedness() = targetType.getSignedness() and @@ -78,7 +82,7 @@ predicate hasConstructorException(FunctionCall call) { call.getTarget() = ctor and c = ctor.getDeclaringType() and // Constructor callable with single numeric argument - ctor.getParameter(0).getType() instanceof NumericType and + ctor.getParameter(0).getType() instanceof MisraCpp23BuiltInTypes::NumericType and // No other single-argument constructors except copy/move not exists(CallableWithASingleArgumentConstructor other | other.getDeclaringType() = c and @@ -108,8 +112,11 @@ class IdExpression extends VariableAccess { } } -predicate isValidWidening(Expr source, NumericType sourceType, NumericType targetType) { - isAssignment(source, targetType, _) and +predicate isValidWidening( + Expr source, MisraCpp23BuiltInTypes::NumericType sourceType, + MisraCpp23BuiltInTypes::NumericType targetType +) { + MisraCpp23BuiltInTypes::isAssignment(source, targetType, _) and source.getType() = sourceType and // Same type category and signedness, source size smaller, source is id-expression or has constructor exception ( @@ -177,7 +184,7 @@ predicate isOverloadIndependent(Call call, Expr arg) { predicate shouldHaveSameType(Expr source) { exists(Call call | call.getAnArgument().getExplicitlyConverted() = source and - isAssignment(source, _, _) and + MisraCpp23BuiltInTypes::isAssignment(source, _, _) and not hasConstructorException(call) | not isOverloadIndependent(call, source) @@ -192,9 +199,11 @@ predicate shouldHaveSameType(Expr source) { ) } -predicate isValidAssignment(Expr source, NumericType targetType, string context) { - isAssignment(source, targetType, context) and - exists(NumericType sourceType | sourceType = source.getType() | +predicate isValidAssignment( + Expr source, MisraCpp23BuiltInTypes::NumericType targetType, string context +) { + MisraCpp23BuiltInTypes::isAssignment(source, targetType, context) and + exists(MisraCpp23BuiltInTypes::NumericType sourceType | sourceType = source.getType() | if shouldHaveSameType(source) then sourceType.isSameType(targetType) else ( @@ -210,10 +219,12 @@ predicate isValidAssignment(Expr source, NumericType targetType, string context) ) } -from Expr source, NumericType sourceType, NumericType targetType, string context +from + Expr source, MisraCpp23BuiltInTypes::NumericType sourceType, + MisraCpp23BuiltInTypes::NumericType targetType, string context where not isExcluded(source, ConversionsPackage::numericAssignmentTypeMismatchQuery()) and - isAssignment(source, targetType, context) and + MisraCpp23BuiltInTypes::isAssignment(source, targetType, context) and // The assignment must be between numeric types sourceType = source.getType() and not isValidAssignment(source, targetType, context) From 5ca11e9537710d7dcd8479fd2a86196bfdf72adb Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 10:58:59 +0100 Subject: [PATCH 550/628] Add TypeCategory suffix --- .../cpp/misra/BuiltInTypeRules.qll | 21 ++++++++++--------- .../NoSignednessChangeFromPromotion.ql | 10 ++++----- .../NumericAssignmentTypeMismatch.ql | 2 +- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index 84dd8ba947..2d88cef68b 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -13,10 +13,10 @@ module MisraCpp23BuiltInTypes { * A MISRA C++ 2023 type category. */ newtype TypeCategory = - Integral() or - FloatingPoint() or - Character() or - Other() + IntegralTypeCategory() or + FloatingPointTypeCategory() or + CharacterTypeCategory() or + OtherTypeCategory() /** * Gets the type category of a built-in type. @@ -31,7 +31,7 @@ module MisraCpp23BuiltInTypes { t instanceof Char32Type or t instanceof Char8Type ) and - result = Character() + result = CharacterTypeCategory() or ( // The 5 standard integral types, covering both signed/unsigned variants @@ -43,21 +43,21 @@ module MisraCpp23BuiltInTypes { t instanceof LongType or t instanceof LongLongType ) and - result = Integral() + result = IntegralTypeCategory() or ( t instanceof FloatType or t instanceof DoubleType or t instanceof LongDoubleType ) and - result = FloatingPoint() + result = FloatingPointTypeCategory() or ( t instanceof BoolType or t instanceof VoidType or t instanceof NullPointerType ) and - result = Other() + result = OtherTypeCategory() } /** @@ -119,7 +119,7 @@ module MisraCpp23BuiltInTypes { class CharacterType extends MisraBuiltInType { CharacterType() { // A type whose type category is character - getBuiltInTypeCategory(builtInType) = Character() + getBuiltInTypeCategory(builtInType) = CharacterTypeCategory() } } @@ -134,7 +134,8 @@ module MisraCpp23BuiltInTypes { class NumericType extends MisraBuiltInType { NumericType() { // A type whose type category is either integral or a floating-point - getBuiltInTypeCategory(builtInType) = [Integral().(TypeCategory), FloatingPoint()] + getBuiltInTypeCategory(builtInType) = + [IntegralTypeCategory().(TypeCategory), FloatingPointTypeCategory()] } Signedness getSignedness() { diff --git a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql index a8d9e1bc45..948873be84 100644 --- a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql +++ b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql @@ -97,8 +97,8 @@ class IntegerPromotion extends IntegerPromotionOrUsualArithmeticConversionAsCast // This deliberately excludes integer promotions from `bool` and unscoped enums which do not // have a fixed underlying type, because neither of these are considered integral types in the // MISRA C++ rules. - fromType.getTypeCategory() = MisraCpp23BuiltInTypes::Integral() and - toType.getTypeCategory() = MisraCpp23BuiltInTypes::Integral() + fromType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() and + toType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() } override string getKindOfConversion() { result = "Integer promotion" } @@ -150,7 +150,7 @@ class ImpliedIntegerPromotion extends IntegerPromotionOrUsualArithmeticConversio // However, you cannot have an integer promotion on a float, so we restrict // this to integral types only fromType = this.getType() and - fromType.getTypeCategory() = MisraCpp23BuiltInTypes::Integral() and + fromType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() and // If the size is less than int, then it is an implied integer promotion fromType.getBuiltInSize() < sizeOfInt() } @@ -223,8 +223,8 @@ where // Exception 2: allow safe conversions from integral to floating-point types not ( e.isConstant() and - fromType.getTypeCategory() = MisraCpp23BuiltInTypes::Integral() and - toType.getTypeCategory() = MisraCpp23BuiltInTypes::FloatingPoint() + fromType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() and + toType.getTypeCategory() = MisraCpp23BuiltInTypes::FloatingPointTypeCategory() ) select e, c.getKindOfConversion() + " from '" + fromType.getName() + "' to '" + toType.getName() + diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index dd462d21b6..d4dda6349a 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -48,7 +48,7 @@ predicate isValidConstantAssignment( val <= targetType.getIntegralUpperBound() or // All floating point types can represent all integer values - targetType.getTypeCategory() = MisraCpp23BuiltInTypes::FloatingPoint() + targetType.getTypeCategory() = MisraCpp23BuiltInTypes::FloatingPointTypeCategory() ) ) } From 611077076104ffc5034ea0b17cc47093dee79556 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 10:59:44 +0100 Subject: [PATCH 551/628] Update reference to MisraBuiltInTypes --- .../src/rules/RULE-7-11-3/FunctionPointerConversionContext.ql | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cpp/misra/src/rules/RULE-7-11-3/FunctionPointerConversionContext.ql b/cpp/misra/src/rules/RULE-7-11-3/FunctionPointerConversionContext.ql index 7dadbb734d..f58629f536 100644 --- a/cpp/misra/src/rules/RULE-7-11-3/FunctionPointerConversionContext.ql +++ b/cpp/misra/src/rules/RULE-7-11-3/FunctionPointerConversionContext.ql @@ -57,7 +57,9 @@ where c.getType().getUnspecifiedType() instanceof FunctionPointerIshType ) and // Not a MISRA compliant assignment to a function pointer type - not exists(FunctionPointerIshType targetType | isAssignment(f, targetType, _)) + not exists(FunctionPointerIshType targetType | + MisraCpp23BuiltInTypes::isAssignment(f, targetType, _) + ) select f, "Inappropriate conversion from function type to pointer-to-function type in '" + f.toString() + "'." From 8b999e9d7b521b67cf9ce813488dbcc929a813e5 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 11:21:45 +0100 Subject: [PATCH 552/628] BuiltInTypes: Refactor bitfield handling Simplify the handling of bitfields. --- .../cpp/misra/BuiltInTypeRules.qll | 188 ++++++++---------- .../rules/RULE-7-0-1/NoConversionFromBool.ql | 2 +- .../NumericAssignmentTypeMismatch.ql | 4 +- 3 files changed, 90 insertions(+), 104 deletions(-) diff --git a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll index 2d88cef68b..eb6652c342 100644 --- a/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll +++ b/cpp/misra/src/codingstandards/cpp/misra/BuiltInTypeRules.qll @@ -184,114 +184,95 @@ module MisraCpp23BuiltInTypes { } predicate isPreConversionAssignment(Expr source, Type targetType, string context) { - // Assignment expression (which excludes compound assignments) - exists(AssignExpr assign | - assign.getRValue() = source and - context = "assignment" - | - if isAssignedToBitfield(source, _) - then - // For the MISRA type rules we treat bit fields as a special case - exists(BitField bf | - isAssignedToBitfield(source, bf) and - targetType = getBitFieldType(bf) - ) - else + if isAssignedToBitfield(source, _) + then + // For the MISRA type rules we treat bit fields as a special case + exists(BitField bf | + isAssignedToBitfield(source, bf) and + targetType = getBitFieldType(bf) and + context = "assignment to bitfield" + ) + else ( + // Assignment expression (which excludes compound assignments) + exists(AssignExpr assign | + assign.getRValue() = source and + context = "assignment" + | exists(Type t | t = assign.getLValue().getType() | // Unwrap PointerToMemberType e.g `l1.*l2 = x;` if t instanceof PointerToMemberType then targetType = t.(PointerToMemberType).getBaseType() else targetType = t ) - ) - or - // Variable initialization - exists(Variable v, Initializer init | - init.getExpr() = source and - v.getInitializer() = init and - context = "initialization" - | - // For the MISRA type rules we treat bit fields as a special case - if v instanceof BitField - then targetType = getBitFieldType(v) - else - // Regular variable initialization + ) + or + // Variable initialization + exists(Variable v, Initializer init | + init.getExpr() = source and + v.getInitializer() = init and + context = "initialization" + | targetType = v.getType() - ) - or - exists(ConstructorFieldInit fi | - fi.getExpr() = source and - context = "constructor field initialization" - | - // For the MISRA type rules we treat bit fields as a special case - if fi.getTarget() instanceof BitField - then targetType = getBitFieldType(fi.getTarget()) - else - // Regular variable initialization + ) + or + exists(ConstructorFieldInit fi | + fi.getExpr() = source and + context = "constructor field initialization" + | targetType = fi.getTarget().getType() - ) - or - // Passing a function parameter by value - exists(Call call, int i | - call.getArgument(i) = source and - not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and - context = "function argument" - | - // A regular function call - targetType = call.getTarget().getParameter(i).getType() + ) or - // A function call where the argument is passed as varargs - call.getTarget().getNumberOfParameters() <= i and - // The rule states that the type should match the "adjusted" type of the argument - targetType = source.getFullyConverted().getType() + // Passing a function parameter by value + exists(Call call, int i | + call.getArgument(i) = source and + not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and + context = "function argument" + | + // A regular function call + targetType = call.getTarget().getParameter(i).getType() + or + // A function call where the argument is passed as varargs + call.getTarget().getNumberOfParameters() <= i and + // The rule states that the type should match the "adjusted" type of the argument + targetType = source.getFullyConverted().getType() + or + // An expression call - get the function type, then the parameter type + targetType = getExprCallFunctionType(call).getParameterType(i) + ) or - // An expression call - get the function type, then the parameter type - targetType = getExprCallFunctionType(call).getParameterType(i) - ) - or - // Return statement - exists(ReturnStmt ret, Function f | - ret.getExpr() = source and - ret.getEnclosingFunction() = f and - targetType = f.getType() and - not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and - context = "return" - ) - or - // Switch case - exists(SwitchCase case, SwitchStmt switch | - case.getExpr() = source and - case.getSwitchStmt() = switch and - context = "switch case" - | - if switch.getExpr().(FieldAccess).getTarget() instanceof BitField - then - // For the MISRA type rules we treat bit fields as a special case - targetType = getBitFieldType(switch.getExpr().(FieldAccess).getTarget()) - else - // Regular variable initialization + // Return statement + exists(ReturnStmt ret, Function f | + ret.getExpr() = source and + ret.getEnclosingFunction() = f and + targetType = f.getType() and + not targetType.stripTopLevelSpecifiers() instanceof ReferenceType and + context = "return" + ) + or + // Switch case + exists(SwitchCase case, SwitchStmt switch | + case.getExpr() = source and + case.getSwitchStmt() = switch and + context = "switch case" + | // Get the type of the switch expression, which is the type of the case expression targetType = switch.getExpr().getFullyConverted().getType() - ) - or - // Class aggregate literal initialization - exists(ClassAggregateLiteral al, Field f | - source = al.getAFieldExpr(f) and - context = "class aggregate literal" - | - // For the MISRA type rules we treat bit fields as a special case - if f instanceof BitField - then targetType = getBitFieldType(f) - else - // Regular variable initialization + ) + or + // Class aggregate literal initialization + exists(ClassAggregateLiteral al, Field f | + source = al.getAFieldExpr(f) and + context = "class aggregate literal" + | targetType = f.getType() - ) - or - // Array or vector aggregate literal initialization - exists(ArrayOrVectorAggregateLiteral vl | - source = vl.getAnElementExpr(_) and - targetType = vl.getElementType() and - context = "array or vector aggregate literal" + ) + or + // Array or vector aggregate literal initialization + exists(ArrayOrVectorAggregateLiteral vl | + source = vl.getAnElementExpr(_) and + targetType = vl.getElementType() and + context = "array or vector aggregate literal" + ) ) } @@ -315,11 +296,16 @@ module MisraCpp23BuiltInTypes { ) ) } -} -/** - * Holds if the `source` expression is assigned to a bit field. - */ -predicate isAssignedToBitfield(Expr source, BitField bf) { - source = bf.getAnAssignedValue().getExplicitlyConverted() + /** + * Holds if the `source` expression is "assigned" to a bit field per MISRA C++ 2023. + */ + predicate isAssignedToBitfield(Expr source, BitField bf) { + source = bf.getAnAssignedValue().getExplicitlyConverted() + or + exists(SwitchStmt switch, SwitchCase case | + bf = switch.getExpr().(FieldAccess).getTarget() and + source = case.getExpr() + ) + } } diff --git a/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql b/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql index 6c3d5b6d16..6baa1ed648 100644 --- a/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql +++ b/cpp/misra/src/rules/RULE-7-0-1/NoConversionFromBool.ql @@ -33,7 +33,7 @@ where ) or // Exception: assignment to bit-field of length 1 - isAssignedToBitfield(e, _) + MisraCpp23BuiltInTypes::isAssignedToBitfield(e, _) // Note: conversions that result in a constructor call are not represented as `Conversion`s // in our model, so do not need to be excluded here. ) diff --git a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql index d4dda6349a..972f151f9d 100644 --- a/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql +++ b/cpp/misra/src/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.ql @@ -26,7 +26,7 @@ predicate isValidConstantAssignment( exists(QlBuiltins::BigInt val | val = source.getConstantValue() | // Bit field assignment: check if the value fits in the bit field exists(BitField bf, int numBits | - isAssignedToBitfield(source, bf) and + MisraCpp23BuiltInTypes::isAssignedToBitfield(source, bf) and numBits = bf.getNumBits() and if targetType.getSignedness() = MisraCpp23BuiltInTypes::Signed() then @@ -41,7 +41,7 @@ predicate isValidConstantAssignment( ) or // Regular assignment: check if the value fits in the target type range - not isAssignedToBitfield(source, _) and + not MisraCpp23BuiltInTypes::isAssignedToBitfield(source, _) and ( // Integer types: check if the value fits in the target type range targetType.getIntegralLowerBound() <= val and From 258dadff5bd16fc8138232bf06a2bcc04006a4e3 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 11:30:10 +0100 Subject: [PATCH 553/628] Create MISRA arithmetic conversions library --- .../cpp/misra/ArithmeticConversions.qll | 183 ++++++++++++++++++ .../NoSignednessChangeFromPromotion.ql | 182 +---------------- 2 files changed, 184 insertions(+), 181 deletions(-) create mode 100644 cpp/misra/src/codingstandards/cpp/misra/ArithmeticConversions.qll diff --git a/cpp/misra/src/codingstandards/cpp/misra/ArithmeticConversions.qll b/cpp/misra/src/codingstandards/cpp/misra/ArithmeticConversions.qll new file mode 100644 index 0000000000..42ec1f3a10 --- /dev/null +++ b/cpp/misra/src/codingstandards/cpp/misra/ArithmeticConversions.qll @@ -0,0 +1,183 @@ +import cpp +import BuiltInTypeRules + +/** + * An expression that represents a integral promotion or usual arithmetic conversion. + * + * Such conversions are usual either explicitly described with a `Cast`, or, in the case + * of assign operations, implicitly applied to an lvalue. + */ +abstract class IntegerPromotionOrUsualArithmeticConversion extends Expr { + abstract MisraCpp23BuiltInTypes::NumericType getFromType(); + + abstract MisraCpp23BuiltInTypes::NumericType getToType(); + + abstract Expr getConvertedExpr(); + + abstract string getKindOfConversion(); +} + +/** + * A `Cast` which is either an integer promotion or usual arithmetic conversion. + */ +abstract class IntegerPromotionOrUsualArithmeticConversionAsCast extends IntegerPromotionOrUsualArithmeticConversion, + Cast +{ + MisraCpp23BuiltInTypes::NumericType fromType; + MisraCpp23BuiltInTypes::NumericType toType; + + IntegerPromotionOrUsualArithmeticConversionAsCast() { + fromType = this.getExpr().getType() and + toType = this.getType() and + this.isImplicit() + } + + override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } + + override MisraCpp23BuiltInTypes::NumericType getToType() { result = toType } + + override Expr getConvertedExpr() { result = this.getExpr() } +} + +class UsualArithmeticConversion extends IntegerPromotionOrUsualArithmeticConversionAsCast { + UsualArithmeticConversion() { + ( + // Most binary operations from and to numeric types participate in usual arithmetic conversions + exists(BinaryOperation op | + // Shifts do not participate in usual arithmetic conversions + not op instanceof LShiftExpr and + not op instanceof RShiftExpr and + op.getAnOperand().getFullyConverted() = this + ) + or + // Most binary assignment operations from and to numeric types participate in usual arithmetic + // conversions + exists(AssignOperation ao | + // Shifts do not participate in usual arithmetic conversions + not ao instanceof AssignLShiftExpr and + not ao instanceof AssignRShiftExpr and + ao.getRValue().getFullyConverted() = this + ) + ) + } + + override string getKindOfConversion() { result = "Usual arithmetic conversion" } +} + +class IntegerPromotion extends IntegerPromotionOrUsualArithmeticConversionAsCast { + IntegerPromotion() { + // In the case where a conversion involves both an integer promotion and a usual arithmetic conversion + // we only get a single `Conversion` which combines both. According to the rule, only the "final" type + // should be consider, so we handle these combined conversions as `UsualArithmeticConversion`s instead. + not this instanceof UsualArithmeticConversion and + // Only consider cases where the integer promotion is the last conversion applied + exists(Expr e | e.getFullyConverted() = this) and + // Integer promotion occurs where the from type is smaller than int + fromType.getBuiltInSize() < sizeOfInt() and + // To type is bigger than or equal to int + toType.getBuiltInSize() >= sizeOfInt() and + // An integer promotion is a conversion from an integral type to an integral type + // + // This deliberately excludes integer promotions from `bool` and unscoped enums which do not + // have a fixed underlying type, because neither of these are considered integral types in the + // MISRA C++ rules. + fromType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() and + toType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() + } + + override string getKindOfConversion() { result = "Integer promotion" } +} + +class ImpliedUsualArithmeticConversion extends IntegerPromotionOrUsualArithmeticConversion { + MisraCpp23BuiltInTypes::NumericType fromType; + MisraCpp23BuiltInTypes::NumericType toType; + + ImpliedUsualArithmeticConversion() { + // The lvalue of an assignment operation does not have a `Conversion` in our model, but + // it is still subject to usual arithmetic conversions (excepting shifts). + // + // rvalues are handled separately in the `UsualArithmeticConversion` class. + exists(AssignOperation aop | + not aop instanceof AssignLShiftExpr and + not aop instanceof AssignRShiftExpr and + // lvalue subject to usual arithmetic conversions + aop.getLValue() = this and + // From type is the type of the lvalue, which should be a numeric type under the MISRA rule + fromType = this.getType() and + // Under usual arithmetic conversions, the converted types of both arguments will be the same, + // so even though we don't have an explicit conversion, we can still deduce that the target + // type will be the same as the converted type of the rvalue. + toType = aop.getRValue().getFullyConverted().getType() and + // Only consider cases where the conversion is not a no-op, for consistency with the `Conversion` class + not fromType.isSameType(toType) + ) + } + + override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } + + override MisraCpp23BuiltInTypes::NumericType getToType() { result = toType } + + override Expr getConvertedExpr() { result = this } + + override string getKindOfConversion() { result = "Usual arithmetic conversion" } +} + +class ImpliedIntegerPromotion extends IntegerPromotionOrUsualArithmeticConversion { + MisraCpp23BuiltInTypes::NumericType fromType; + + ImpliedIntegerPromotion() { + ( + exists(AssignLShiftExpr aop | aop.getLValue() = this) or + exists(AssignRShiftExpr aop | aop.getLValue() = this) + ) and + // The rule applies to integer promotions from and to MISRA C++ numeric types + // However, you cannot have an integer promotion on a float, so we restrict + // this to integral types only + fromType = this.getType() and + fromType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() and + // If the size is less than int, then it is an implied integer promotion + fromType.getBuiltInSize() < sizeOfInt() + } + + override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } + + override MisraCpp23BuiltInTypes::CanonicalIntegerNumericType getToType() { + // Only report the canonical type - e.g. `int` not `signed int` + if result instanceof Char16Type or result instanceof Char32Type or result instanceof Wchar_t + then + // Smallest type that can hold the value of the `fromType` + result = + min(MisraCpp23BuiltInTypes::NumericType candidateType | + ( + candidateType instanceof IntType or + candidateType instanceof LongType or + candidateType instanceof LongLongType + ) and + fromType.getIntegralUpperBound() <= candidateType.getIntegralUpperBound() + | + candidateType order by candidateType.getIntegralUpperBound() + ) + else ( + if + // If the `fromType` is signed, the result must be signed + fromType.getSignedness() = MisraCpp23BuiltInTypes::Signed() + or + // If the `fromType` is unsigned, but the result can fit into the signed int type, then the + // result must be signed as well. + fromType.getIntegralUpperBound() <= + any(IntType t | t.isSigned()) + .(MisraCpp23BuiltInTypes::NumericType) + .getIntegralUpperBound() + then + // `int` is returned + result.(IntType).isSigned() + else + // Otherwise `unsigned int` is returned + result.(IntType).isUnsigned() + ) + } + + override Expr getConvertedExpr() { result = this } + + override string getKindOfConversion() { result = "Integer promotion" } +} diff --git a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql index 948873be84..05261d6f6c 100644 --- a/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql +++ b/cpp/misra/src/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.ql @@ -15,189 +15,9 @@ import cpp import codingstandards.cpp.misra +import codingstandards.cpp.misra.ArithmeticConversions import codingstandards.cpp.misra.BuiltInTypeRules -/** - * An expression that represents a integral promotion or usual arithmetic conversion. - * - * Such conversions are usual either explicitly described with a `Cast`, or, in the case - * of assign operations, implicitly applied to an lvalue. - */ -abstract class IntegerPromotionOrUsualArithmeticConversion extends Expr { - abstract MisraCpp23BuiltInTypes::NumericType getFromType(); - - abstract MisraCpp23BuiltInTypes::NumericType getToType(); - - abstract Expr getConvertedExpr(); - - abstract string getKindOfConversion(); -} - -/** - * A `Cast` which is either an integer promotion or usual arithmetic conversion. - */ -abstract class IntegerPromotionOrUsualArithmeticConversionAsCast extends IntegerPromotionOrUsualArithmeticConversion, - Cast -{ - MisraCpp23BuiltInTypes::NumericType fromType; - MisraCpp23BuiltInTypes::NumericType toType; - - IntegerPromotionOrUsualArithmeticConversionAsCast() { - fromType = this.getExpr().getType() and - toType = this.getType() and - this.isImplicit() - } - - override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } - - override MisraCpp23BuiltInTypes::NumericType getToType() { result = toType } - - override Expr getConvertedExpr() { result = this.getExpr() } -} - -class UsualArithmeticConversion extends IntegerPromotionOrUsualArithmeticConversionAsCast { - UsualArithmeticConversion() { - ( - // Most binary operations from and to numeric types participate in usual arithmetic conversions - exists(BinaryOperation op | - // Shifts do not participate in usual arithmetic conversions - not op instanceof LShiftExpr and - not op instanceof RShiftExpr and - op.getAnOperand().getFullyConverted() = this - ) - or - // Most binary assignment operations from and to numeric types participate in usual arithmetic - // conversions - exists(AssignOperation ao | - // Shifts do not participate in usual arithmetic conversions - not ao instanceof AssignLShiftExpr and - not ao instanceof AssignRShiftExpr and - ao.getRValue().getFullyConverted() = this - ) - ) - } - - override string getKindOfConversion() { result = "Usual arithmetic conversion" } -} - -class IntegerPromotion extends IntegerPromotionOrUsualArithmeticConversionAsCast { - IntegerPromotion() { - // In the case where a conversion involves both an integer promotion and a usual arithmetic conversion - // we only get a single `Conversion` which combines both. According to the rule, only the "final" type - // should be consider, so we handle these combined conversions as `UsualArithmeticConversion`s instead. - not this instanceof UsualArithmeticConversion and - // Only consider cases where the integer promotion is the last conversion applied - exists(Expr e | e.getFullyConverted() = this) and - // Integer promotion occurs where the from type is smaller than int - fromType.getBuiltInSize() < sizeOfInt() and - // To type is bigger than or equal to int - toType.getBuiltInSize() >= sizeOfInt() and - // An integer promotion is a conversion from an integral type to an integral type - // - // This deliberately excludes integer promotions from `bool` and unscoped enums which do not - // have a fixed underlying type, because neither of these are considered integral types in the - // MISRA C++ rules. - fromType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() and - toType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() - } - - override string getKindOfConversion() { result = "Integer promotion" } -} - -class ImpliedUsualArithmeticConversion extends IntegerPromotionOrUsualArithmeticConversion { - MisraCpp23BuiltInTypes::NumericType fromType; - MisraCpp23BuiltInTypes::NumericType toType; - - ImpliedUsualArithmeticConversion() { - // The lvalue of an assignment operation does not have a `Conversion` in our model, but - // it is still subject to usual arithmetic conversions (excepting shifts). - // - // rvalues are handled separately in the `UsualArithmeticConversion` class. - exists(AssignOperation aop | - not aop instanceof AssignLShiftExpr and - not aop instanceof AssignRShiftExpr and - // lvalue subject to usual arithmetic conversions - aop.getLValue() = this and - // From type is the type of the lvalue, which should be a numeric type under the MISRA rule - fromType = this.getType() and - // Under usual arithmetic conversions, the converted types of both arguments will be the same, - // so even though we don't have an explicit conversion, we can still deduce that the target - // type will be the same as the converted type of the rvalue. - toType = aop.getRValue().getFullyConverted().getType() and - // Only consider cases where the conversion is not a no-op, for consistency with the `Conversion` class - not fromType.isSameType(toType) - ) - } - - override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } - - override MisraCpp23BuiltInTypes::NumericType getToType() { result = toType } - - override Expr getConvertedExpr() { result = this } - - override string getKindOfConversion() { result = "Usual arithmetic conversion" } -} - -class ImpliedIntegerPromotion extends IntegerPromotionOrUsualArithmeticConversion { - MisraCpp23BuiltInTypes::NumericType fromType; - - ImpliedIntegerPromotion() { - ( - exists(AssignLShiftExpr aop | aop.getLValue() = this) or - exists(AssignRShiftExpr aop | aop.getLValue() = this) - ) and - // The rule applies to integer promotions from and to MISRA C++ numeric types - // However, you cannot have an integer promotion on a float, so we restrict - // this to integral types only - fromType = this.getType() and - fromType.getTypeCategory() = MisraCpp23BuiltInTypes::IntegralTypeCategory() and - // If the size is less than int, then it is an implied integer promotion - fromType.getBuiltInSize() < sizeOfInt() - } - - override MisraCpp23BuiltInTypes::NumericType getFromType() { result = fromType } - - override MisraCpp23BuiltInTypes::CanonicalIntegerNumericType getToType() { - // Only report the canonical type - e.g. `int` not `signed int` - if result instanceof Char16Type or result instanceof Char32Type or result instanceof Wchar_t - then - // Smallest type that can hold the value of the `fromType` - result = - min(MisraCpp23BuiltInTypes::NumericType candidateType | - ( - candidateType instanceof IntType or - candidateType instanceof LongType or - candidateType instanceof LongLongType - ) and - fromType.getIntegralUpperBound() <= candidateType.getIntegralUpperBound() - | - candidateType order by candidateType.getIntegralUpperBound() - ) - else ( - if - // If the `fromType` is signed, the result must be signed - fromType.getSignedness() = MisraCpp23BuiltInTypes::Signed() - or - // If the `fromType` is unsigned, but the result can fit into the signed int type, then the - // result must be signed as well. - fromType.getIntegralUpperBound() <= - any(IntType t | t.isSigned()) - .(MisraCpp23BuiltInTypes::NumericType) - .getIntegralUpperBound() - then - // `int` is returned - result.(IntType).isSigned() - else - // Otherwise `unsigned int` is returned - result.(IntType).isUnsigned() - ) - } - - override Expr getConvertedExpr() { result = this } - - override string getKindOfConversion() { result = "Integer promotion" } -} - from Expr e, IntegerPromotionOrUsualArithmeticConversion c, MisraCpp23BuiltInTypes::NumericType fromType, MisraCpp23BuiltInTypes::NumericType toType, From 3186c703ad0f072f576eb3aeda01c02c3971374f Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 11:35:15 +0100 Subject: [PATCH 554/628] Test case formatting --- cpp/misra/test/rules/RULE-7-0-4/test.cpp | 6 +++--- cpp/misra/test/rules/RULE-7-0-5/test.cpp | 8 ++++---- cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cpp/misra/test/rules/RULE-7-0-4/test.cpp b/cpp/misra/test/rules/RULE-7-0-4/test.cpp index 1735d59e58..61a850ef5d 100644 --- a/cpp/misra/test/rules/RULE-7-0-4/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-4/test.cpp @@ -7,15 +7,15 @@ void test_binary_bitwise_operators_unsigned_operands() { std::int32_t s32a = 0x12345678; std::int32_t s32b = 0x87654321; - u32a & u32b; // COMPLIANT + u32a &u32b; // COMPLIANT u32a | u32b; // COMPLIANT u32a ^ u32b; // COMPLIANT - s32a & s32b; // NON_COMPLIANT + s32a &s32b; // NON_COMPLIANT s32a | s32b; // NON_COMPLIANT s32a ^ s32b; // NON_COMPLIANT - s32a & u32b; // NON_COMPLIANT + s32a &u32b; // NON_COMPLIANT u32a | s32b; // NON_COMPLIANT } diff --git a/cpp/misra/test/rules/RULE-7-0-5/test.cpp b/cpp/misra/test/rules/RULE-7-0-5/test.cpp index 6e36d80d68..0319fa4bef 100644 --- a/cpp/misra/test/rules/RULE-7-0-5/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-5/test.cpp @@ -24,7 +24,7 @@ void test_binary_arithmetic_operations() { l1 - l2; // NON_COMPLIANT - u8 - u8 -> signed int l1 / l2; // NON_COMPLIANT - u8 / u8 -> signed int l1 % l2; // NON_COMPLIANT - u8 % u8 -> signed int - l1 & l2; // NON_COMPLIANT - u8 & u8 -> signed int + l1 &l2; // NON_COMPLIANT - u8 & u8 -> signed int l1 | l2; // NON_COMPLIANT - u8 | u8 -> signed int l1 ^ l2; // NON_COMPLIANT - u8 ^ u8 -> signed int @@ -166,7 +166,7 @@ void test_mixed_signed_unsigned_arithmetic() { l1 *l2; // NON_COMPLIANT - l1 and l2 -> signed int l1 / l2; // NON_COMPLIANT - l1 and l2 -> signed int l1 % l2; // NON_COMPLIANT - l1 and l2 -> signed int - l1 & l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 &l2; // NON_COMPLIANT - l1 and l2 -> signed int l1 | l2; // NON_COMPLIANT - l1 and l2 -> signed int l1 ^ l2; // NON_COMPLIANT - l1 and l2 -> signed int @@ -264,12 +264,12 @@ void test_enum_types() { // type l1 + l2; // COMPLIANT - rule does not apply l1 *l2; // COMPLIANT - rule does not apply - l1 & l2; // COMPLIANT - rule does not apply + l1 &l2; // COMPLIANT - rule does not apply // Unscoped enum with explicit underlying type - considered numeric type l3 + l4; // NON_COMPLIANT - uint8_t + uint8_t -> signed int l3 *l4; // NON_COMPLIANT - uint8_t * uint8_t -> signed int - l3 & l4; // NON_COMPLIANT - uint8_t & uint8_t -> signed int + l3 &l4; // NON_COMPLIANT - uint8_t & uint8_t -> signed int l3 - l4; // NON_COMPLIANT - uint8_t - uint8_t -> signed int l3 | l4; // NON_COMPLIANT - uint8_t | uint8_t -> signed int l3 ^ l4; // NON_COMPLIANT - uint8_t ^ uint8_t -> signed int diff --git a/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp b/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp index f8823bfa03..4f2e256b26 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp @@ -119,10 +119,10 @@ void test_user_defined_operators() { l1 % l4; // NON_COMPLIANT - different type l1 % l5; // NON_COMPLIANT - different signedness - l1 & l2; // COMPLIANT - exact type match - l1 & l3; // COMPLIANT - widening conversion is allowed - l1 & l4; // NON_COMPLIANT - different type - l1 & l5; // NON_COMPLIANT - different signedness + l1 &l2; // COMPLIANT - exact type match + l1 &l3; // COMPLIANT - widening conversion is allowed + l1 &l4; // NON_COMPLIANT - different type + l1 &l5; // NON_COMPLIANT - different signedness l1 | l2; // COMPLIANT - exact type match l1 | l3; // COMPLIANT - widening conversion is allowed From 23be3dba7f8fca85bea87c99c753fe2b3fe421d5 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 11:39:12 +0100 Subject: [PATCH 555/628] More test case formatting --- cpp/misra/test/rules/RULE-7-0-4/test.cpp | 6 +++--- cpp/misra/test/rules/RULE-7-0-5/test.cpp | 8 ++++---- cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cpp/misra/test/rules/RULE-7-0-4/test.cpp b/cpp/misra/test/rules/RULE-7-0-4/test.cpp index 61a850ef5d..110c50070e 100644 --- a/cpp/misra/test/rules/RULE-7-0-4/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-4/test.cpp @@ -7,15 +7,15 @@ void test_binary_bitwise_operators_unsigned_operands() { std::int32_t s32a = 0x12345678; std::int32_t s32b = 0x87654321; - u32a &u32b; // COMPLIANT + u32a &u32b; // COMPLIANT u32a | u32b; // COMPLIANT u32a ^ u32b; // COMPLIANT - s32a &s32b; // NON_COMPLIANT + s32a &s32b; // NON_COMPLIANT s32a | s32b; // NON_COMPLIANT s32a ^ s32b; // NON_COMPLIANT - s32a &u32b; // NON_COMPLIANT + s32a &u32b; // NON_COMPLIANT u32a | s32b; // NON_COMPLIANT } diff --git a/cpp/misra/test/rules/RULE-7-0-5/test.cpp b/cpp/misra/test/rules/RULE-7-0-5/test.cpp index 0319fa4bef..2571f725fd 100644 --- a/cpp/misra/test/rules/RULE-7-0-5/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-5/test.cpp @@ -24,7 +24,7 @@ void test_binary_arithmetic_operations() { l1 - l2; // NON_COMPLIANT - u8 - u8 -> signed int l1 / l2; // NON_COMPLIANT - u8 / u8 -> signed int l1 % l2; // NON_COMPLIANT - u8 % u8 -> signed int - l1 &l2; // NON_COMPLIANT - u8 & u8 -> signed int + l1 &l2; // NON_COMPLIANT - u8 & u8 -> signed int l1 | l2; // NON_COMPLIANT - u8 | u8 -> signed int l1 ^ l2; // NON_COMPLIANT - u8 ^ u8 -> signed int @@ -166,7 +166,7 @@ void test_mixed_signed_unsigned_arithmetic() { l1 *l2; // NON_COMPLIANT - l1 and l2 -> signed int l1 / l2; // NON_COMPLIANT - l1 and l2 -> signed int l1 % l2; // NON_COMPLIANT - l1 and l2 -> signed int - l1 &l2; // NON_COMPLIANT - l1 and l2 -> signed int + l1 &l2; // NON_COMPLIANT - l1 and l2 -> signed int l1 | l2; // NON_COMPLIANT - l1 and l2 -> signed int l1 ^ l2; // NON_COMPLIANT - l1 and l2 -> signed int @@ -264,12 +264,12 @@ void test_enum_types() { // type l1 + l2; // COMPLIANT - rule does not apply l1 *l2; // COMPLIANT - rule does not apply - l1 &l2; // COMPLIANT - rule does not apply + l1 &l2; // COMPLIANT - rule does not apply // Unscoped enum with explicit underlying type - considered numeric type l3 + l4; // NON_COMPLIANT - uint8_t + uint8_t -> signed int l3 *l4; // NON_COMPLIANT - uint8_t * uint8_t -> signed int - l3 &l4; // NON_COMPLIANT - uint8_t & uint8_t -> signed int + l3 &l4; // NON_COMPLIANT - uint8_t & uint8_t -> signed int l3 - l4; // NON_COMPLIANT - uint8_t - uint8_t -> signed int l3 | l4; // NON_COMPLIANT - uint8_t | uint8_t -> signed int l3 ^ l4; // NON_COMPLIANT - uint8_t ^ uint8_t -> signed int diff --git a/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp b/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp index 4f2e256b26..a9eae097e1 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp @@ -119,10 +119,10 @@ void test_user_defined_operators() { l1 % l4; // NON_COMPLIANT - different type l1 % l5; // NON_COMPLIANT - different signedness - l1 &l2; // COMPLIANT - exact type match - l1 &l3; // COMPLIANT - widening conversion is allowed - l1 &l4; // NON_COMPLIANT - different type - l1 &l5; // NON_COMPLIANT - different signedness + l1 &l2; // COMPLIANT - exact type match + l1 &l3; // COMPLIANT - widening conversion is allowed + l1 &l4; // NON_COMPLIANT - different type + l1 &l5; // NON_COMPLIANT - different signedness l1 | l2; // COMPLIANT - exact type match l1 | l3; // COMPLIANT - widening conversion is allowed From 61ae04ff5f2f461a89a650da9dc594251f9bdf4e Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 11:40:59 +0100 Subject: [PATCH 556/628] More formatting --- cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp b/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp index a9eae097e1..4f2e256b26 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp +++ b/cpp/misra/test/rules/RULE-7-0-6/test_operators.cpp @@ -119,10 +119,10 @@ void test_user_defined_operators() { l1 % l4; // NON_COMPLIANT - different type l1 % l5; // NON_COMPLIANT - different signedness - l1 &l2; // COMPLIANT - exact type match - l1 &l3; // COMPLIANT - widening conversion is allowed - l1 &l4; // NON_COMPLIANT - different type - l1 &l5; // NON_COMPLIANT - different signedness + l1 &l2; // COMPLIANT - exact type match + l1 &l3; // COMPLIANT - widening conversion is allowed + l1 &l4; // NON_COMPLIANT - different type + l1 &l5; // NON_COMPLIANT - different signedness l1 | l2; // COMPLIANT - exact type match l1 | l3; // COMPLIANT - widening conversion is allowed From 668e5189ef3db32723e94dfaf64e306cfde06c7c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 11:59:02 +0100 Subject: [PATCH 557/628] Address compilation issue with FunctionType. --- cpp/common/src/codingstandards/cpp/Call.qll | 1 + .../codingstandards/cpp/types/Compatible.qll | 1 - .../src/codingstandards/cpp/types/Type.qll | 18 ------------------ 3 files changed, 1 insertion(+), 19 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Call.qll b/cpp/common/src/codingstandards/cpp/Call.qll index 706d66e01c..4edbb454a6 100644 --- a/cpp/common/src/codingstandards/cpp/Call.qll +++ b/cpp/common/src/codingstandards/cpp/Call.qll @@ -1,5 +1,6 @@ import cpp import codingstandards.cpp.types.Type +import codingstandards.cpp.types.FunctionType /** * Gets the `FunctionType` of an expression call. diff --git a/cpp/common/src/codingstandards/cpp/types/Compatible.qll b/cpp/common/src/codingstandards/cpp/types/Compatible.qll index 0090ff7888..eb6fa6446f 100644 --- a/cpp/common/src/codingstandards/cpp/types/Compatible.qll +++ b/cpp/common/src/codingstandards/cpp/types/Compatible.qll @@ -527,7 +527,6 @@ module FunctionDeclarationTypeEquivalence< private class LeafType extends Type { LeafType() { not this instanceof DerivedType and - not this instanceof FunctionType and not this instanceof FunctionType } } diff --git a/cpp/common/src/codingstandards/cpp/types/Type.qll b/cpp/common/src/codingstandards/cpp/types/Type.qll index dba3af7a4a..0e55b3ad58 100644 --- a/cpp/common/src/codingstandards/cpp/types/Type.qll +++ b/cpp/common/src/codingstandards/cpp/types/Type.qll @@ -124,21 +124,3 @@ int sizeOfInt() { size ) } - -/** - * Convenience class to reduce the awkwardness of how `RoutineType` and `FunctionPointerIshType` - * don't have a common ancestor. - */ -class FunctionType extends Type { - FunctionType() { this instanceof RoutineType or this instanceof FunctionPointerIshType } - - Type getReturnType() { - result = this.(RoutineType).getReturnType() or - result = this.(FunctionPointerIshType).getReturnType() - } - - Type getParameterType(int i) { - result = this.(RoutineType).getParameterType(i) or - result = this.(FunctionPointerIshType).getParameterType(i) - } -} From 3575db1436cfc0d6457bae337a0b4745d9f20299 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 23:25:06 +0100 Subject: [PATCH 558/628] Rule 7.0.2: Use getUnconverted. --- cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql b/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql index 4350b6eac8..fe936f9543 100644 --- a/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql +++ b/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql @@ -90,7 +90,7 @@ where // Exception 2: Contextual conversion from class with explicit operator bool is allowed not ( op.isExplicit() and - isInContextualBoolContext(conversionCall) + isInContextualBoolContext(conversionCall.getUnconverted()) ) and reason = "Conversion operator call from '" + conversionCall.getQualifier().getType().toString() + From 0b9e2cb4a358c387d27d91585debfe841a38d8c4 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 23:36:04 +0100 Subject: [PATCH 559/628] Rule 7.0.2: Treat nullptr_t as a pointer for this rule --- cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql | 3 ++- .../test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected | 1 - cpp/misra/test/rules/RULE-7-0-2/test.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql b/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql index fe936f9543..ae70b20259 100644 --- a/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql +++ b/cpp/misra/src/rules/RULE-7-0-2/NoImplicitBoolConversion.ql @@ -43,7 +43,8 @@ predicate isBitFieldOfSizeOne(Expr expr) { predicate isPointerType(Type t) { t.getUnspecifiedType() instanceof PointerType or - t.getUnspecifiedType() instanceof PointerToMemberType + t.getUnspecifiedType() instanceof PointerToMemberType or + t.getUnspecifiedType() instanceof NullPointerType } from Element e, string reason diff --git a/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected index 5473a954ac..274b20a954 100644 --- a/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected +++ b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected @@ -9,7 +9,6 @@ | test.cpp:99:30:99:31 | (bool)... | Conversion from 'int32_t' to 'bool'. | | test.cpp:112:12:112:13 | (bool)... | Conversion from 'int32_t' to 'bool'. | | test.cpp:127:13:127:16 | (bool)... | Conversion from 'int32_t *' to 'bool'. | -| test.cpp:130:7:130:13 | (bool)... | Conversion from 'decltype(nullptr)' to 'bool'. | | test.cpp:135:13:135:32 | static_cast... | Conversion from 'int' to 'bool'. | | test.cpp:136:13:136:14 | (bool)... | Conversion from 'uint8_t' to 'bool'. | | test.cpp:148:13:148:13 | call to operator bool | Conversion operator call from 'TestClassImplicit' to 'bool'. | diff --git a/cpp/misra/test/rules/RULE-7-0-2/test.cpp b/cpp/misra/test/rules/RULE-7-0-2/test.cpp index 195648f25d..918f6c3b8f 100644 --- a/cpp/misra/test/rules/RULE-7-0-2/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-2/test.cpp @@ -127,7 +127,7 @@ void test_pointer_conversions() { bool l1 = f3(); // NON_COMPLIANT bool l2 = f3() != nullptr; // COMPLIANT - if (nullptr) { // NON_COMPLIANT + if (nullptr) { // COMPLIANT } } From 8d0bb2967bc22c9e08dd1e2aa658fd23524cccf6 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 22 Aug 2025 09:15:29 +0100 Subject: [PATCH 560/628] Rule 7.0.1: Expand test case to cover non_compliant cases For bool to class conversions. --- .../RULE-7-0-1/NoConversionFromBool.expected | 40 ++++++++++--------- cpp/misra/test/rules/RULE-7-0-1/test.cpp | 18 ++++++--- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected b/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected index 8e0795fc6a..525ba1711a 100644 --- a/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected +++ b/cpp/misra/test/rules/RULE-7-0-1/NoConversionFromBool.expected @@ -1,29 +1,33 @@ -| test.cpp:23:7:23:8 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:23:12:23:13 | b2 | Conversion from 'bool' to 'int'. | | test.cpp:25:7:25:8 | b1 | Conversion from 'bool' to 'int'. | | test.cpp:25:12:25:13 | b2 | Conversion from 'bool' to 'int'. | | test.cpp:27:7:27:8 | b1 | Conversion from 'bool' to 'int'. | | test.cpp:27:12:27:13 | b2 | Conversion from 'bool' to 'int'. | -| test.cpp:29:8:29:9 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:33:7:33:8 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:33:12:33:13 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:29:7:29:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:29:12:29:13 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:31:8:31:9 | b1 | Conversion from 'bool' to 'int'. | | test.cpp:35:7:35:8 | b1 | Conversion from 'bool' to 'int'. | | test.cpp:35:12:35:13 | b2 | Conversion from 'bool' to 'int'. | | test.cpp:37:7:37:8 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:37:13:37:14 | b2 | Conversion from 'bool' to 'int'. | +| test.cpp:37:12:37:13 | b2 | Conversion from 'bool' to 'int'. | | test.cpp:39:7:39:8 | b1 | Conversion from 'bool' to 'int'. | | test.cpp:39:13:39:14 | b2 | Conversion from 'bool' to 'int'. | -| test.cpp:43:7:43:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:41:7:41:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:41:13:41:14 | b2 | Conversion from 'bool' to 'int'. | | test.cpp:45:7:45:8 | b1 | Conversion from 'bool' to 'int'. | | test.cpp:47:7:47:8 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:51:20:51:21 | b1 | Conversion from 'bool' to 'double'. | -| test.cpp:52:20:52:21 | b1 | Conversion from 'bool' to 'double'. | -| test.cpp:53:28:53:29 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:56:34:56:35 | b1 | Conversion from 'bool' to 'int8_t'. | -| test.cpp:57:36:57:37 | b1 | Conversion from 'bool' to 'int32_t'. | -| test.cpp:60:6:60:7 | b1 | Conversion from 'bool' to 'int32_t'. | -| test.cpp:61:6:61:7 | b1 | Conversion from 'bool' to 'double'. | -| test.cpp:64:11:64:12 | b1 | Conversion from 'bool' to 'int'. | -| test.cpp:72:9:72:10 | b1 | Conversion from 'bool' to 'int8_t'. | -| test.cpp:73:10:73:11 | b1 | Conversion from 'bool' to 'int32_t'. | -| test.cpp:74:8:74:9 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:49:7:49:8 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:53:20:53:21 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:54:20:54:21 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:55:28:55:29 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:58:34:58:35 | b1 | Conversion from 'bool' to 'int8_t'. | +| test.cpp:59:36:59:37 | b1 | Conversion from 'bool' to 'int32_t'. | +| test.cpp:62:6:62:7 | b1 | Conversion from 'bool' to 'int32_t'. | +| test.cpp:63:6:63:7 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:66:11:66:12 | b1 | Conversion from 'bool' to 'int'. | +| test.cpp:74:9:74:10 | b1 | Conversion from 'bool' to 'int8_t'. | +| test.cpp:75:10:75:11 | b1 | Conversion from 'bool' to 'int32_t'. | +| test.cpp:76:8:76:9 | b1 | Conversion from 'bool' to 'double'. | +| test.cpp:113:33:113:36 | 1 | Conversion from 'bool' to 'A *'. | +| test.cpp:116:8:116:11 | 1 | Conversion from 'bool' to 'int'. | +| test.cpp:117:8:117:12 | 0 | Conversion from 'bool' to 'int'. | +| test.cpp:118:25:118:28 | 1 | Conversion from 'bool' to 'int'. | diff --git a/cpp/misra/test/rules/RULE-7-0-1/test.cpp b/cpp/misra/test/rules/RULE-7-0-1/test.cpp index 57243e1c9a..29fc311e3f 100644 --- a/cpp/misra/test/rules/RULE-7-0-1/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-1/test.cpp @@ -3,7 +3,9 @@ struct A { explicit A(bool) {} }; - +struct B { + B(int) {} +}; struct BitField { std::uint8_t bit : 1; }; @@ -105,12 +107,18 @@ void test_bool_conversion_compliant() { f1(b1 ? 1 : 0); // COMPLIANT // Explicit constructor calls - compliant - A l1{true}; // COMPLIANT - A l2(false); // COMPLIANT - A l3 = static_cast(true); // COMPLIANT + A l1{true}; // COMPLIANT + A l2(false); // COMPLIANT + A l3 = static_cast(true); // COMPLIANT + A *l4 = reinterpret_cast(true); // NON_COMPLIANT - converted to integer + // then pointer, does not + // use constructor. + B l5{true}; // NON_COMPLIANT + B l6(false); // NON_COMPLIANT + B l7 = static_cast(true); // NON_COMPLIANT // Assignment to constructor - compliant - A l4 = A{false}; // COMPLIANT + A l8 = A{false}; // COMPLIANT // Bit-field assignment exception - compliant bf.bit = b1; // COMPLIANT From 96b644e323577f1d0f81c6dad40374e07b107397 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 22 Aug 2025 09:19:45 +0100 Subject: [PATCH 561/628] Rule 7.0.2: Add extra cast test cases --- .../NoImplicitBoolConversion.expected | 26 ++++++++++--------- cpp/misra/test/rules/RULE-7-0-2/test.cpp | 2 ++ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected index 274b20a954..cc1db5b723 100644 --- a/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected +++ b/cpp/misra/test/rules/RULE-7-0-2/NoImplicitBoolConversion.expected @@ -11,15 +11,17 @@ | test.cpp:127:13:127:16 | (bool)... | Conversion from 'int32_t *' to 'bool'. | | test.cpp:135:13:135:32 | static_cast... | Conversion from 'int' to 'bool'. | | test.cpp:136:13:136:14 | (bool)... | Conversion from 'uint8_t' to 'bool'. | -| test.cpp:148:13:148:13 | call to operator bool | Conversion operator call from 'TestClassImplicit' to 'bool'. | -| test.cpp:161:13:161:14 | (bool)... | Conversion from 'Color' to 'bool'. | -| test.cpp:162:7:162:8 | (bool)... | Conversion from 'Color' to 'bool'. | -| test.cpp:179:13:179:14 | (bool)... | Conversion from 'float' to 'bool'. | -| test.cpp:180:13:180:14 | (bool)... | Conversion from 'double' to 'bool'. | -| test.cpp:181:13:181:14 | (bool)... | Conversion from 'long double' to 'bool'. | -| test.cpp:182:7:182:8 | (bool)... | Conversion from 'float' to 'bool'. | -| test.cpp:184:7:184:8 | (bool)... | Conversion from 'double' to 'bool'. | -| test.cpp:186:7:186:8 | (bool)... | Conversion from 'long double' to 'bool'. | -| test.cpp:199:13:199:14 | (bool)... | Conversion from 'int32_t *' to 'bool'. | -| test.cpp:211:13:211:14 | (bool)... | Conversion from '..:: *' to 'bool'. | -| test.cpp:212:13:212:14 | (bool)... | Conversion from '..:: *' to 'bool'. | +| test.cpp:139:13:139:19 | (bool)... | Conversion from 'int' to 'bool'. | +| test.cpp:140:13:140:19 | (bool)... | Conversion from 'int' to 'bool'. | +| test.cpp:150:13:150:13 | call to operator bool | Conversion operator call from 'TestClassImplicit' to 'bool'. | +| test.cpp:163:13:163:14 | (bool)... | Conversion from 'Color' to 'bool'. | +| test.cpp:164:7:164:8 | (bool)... | Conversion from 'Color' to 'bool'. | +| test.cpp:181:13:181:14 | (bool)... | Conversion from 'float' to 'bool'. | +| test.cpp:182:13:182:14 | (bool)... | Conversion from 'double' to 'bool'. | +| test.cpp:183:13:183:14 | (bool)... | Conversion from 'long double' to 'bool'. | +| test.cpp:184:7:184:8 | (bool)... | Conversion from 'float' to 'bool'. | +| test.cpp:186:7:186:8 | (bool)... | Conversion from 'double' to 'bool'. | +| test.cpp:188:7:188:8 | (bool)... | Conversion from 'long double' to 'bool'. | +| test.cpp:201:13:201:14 | (bool)... | Conversion from 'int32_t *' to 'bool'. | +| test.cpp:213:13:213:14 | (bool)... | Conversion from '..:: *' to 'bool'. | +| test.cpp:214:13:214:14 | (bool)... | Conversion from '..:: *' to 'bool'. | diff --git a/cpp/misra/test/rules/RULE-7-0-2/test.cpp b/cpp/misra/test/rules/RULE-7-0-2/test.cpp index 918f6c3b8f..01e53c15e4 100644 --- a/cpp/misra/test/rules/RULE-7-0-2/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-2/test.cpp @@ -136,6 +136,8 @@ void test_assignment_to_bool() { bool l2 = g1; // NON_COMPLIANT bool l3 = (g1 < g2); // COMPLIANT bool l4 = g7; // COMPLIANT + bool l5 = bool(4); // NON_COMPLIANT + bool l6 = (bool)4; // NON_COMPLIANT } void test_classes_with_bool_operators() { From 189f8c0ee5c9e8ed932a3777d2ef7b3d7bb968be Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 22 Aug 2025 09:22:49 +0100 Subject: [PATCH 562/628] Update expected results after formatting --- .../RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected | 2 +- .../RULE-7-0-5/NoSignednessChangeFromPromotion.expected | 6 +++--- .../rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected index 5f92a9b110..3022ea3923 100644 --- a/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected +++ b/cpp/misra/test/rules/RULE-7-0-4/InappropriateBitwiseOrShiftOperands.expected @@ -1,5 +1,5 @@ | test.cpp:14:3:14:6 | s32a | Bitwise operator '&' requires unsigned numeric operands, but the left operand has type 'int32_t'. | -| test.cpp:14:10:14:13 | s32b | Bitwise operator '&' requires unsigned numeric operands, but the right operand has type 'int32_t'. | +| test.cpp:14:9:14:12 | s32b | Bitwise operator '&' requires unsigned numeric operands, but the right operand has type 'int32_t'. | | test.cpp:15:3:15:6 | s32a | Bitwise operator '\|' requires unsigned numeric operands, but the left operand has type 'int32_t'. | | test.cpp:15:10:15:13 | s32b | Bitwise operator '\|' requires unsigned numeric operands, but the right operand has type 'int32_t'. | | test.cpp:16:3:16:6 | s32a | Bitwise operator '^' requires unsigned numeric operands, but the left operand has type 'int32_t'. | diff --git a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected index a9f1f37c63..7603386f12 100644 --- a/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected +++ b/cpp/misra/test/rules/RULE-7-0-5/NoSignednessChangeFromPromotion.expected @@ -9,7 +9,7 @@ | test.cpp:26:3:26:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:26:8:26:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:27:3:27:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:27:8:27:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:27:7:27:8 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:28:3:28:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:28:8:28:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:29:3:29:4 | l1 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | @@ -62,7 +62,7 @@ | test.cpp:166:7:166:8 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:167:8:167:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:168:8:168:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | -| test.cpp:169:8:169:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | +| test.cpp:169:7:169:8 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:170:8:170:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:171:8:171:9 | l2 | Usual arithmetic conversion from 'uint8_t' to 'int' changes signedness. | | test.cpp:173:8:173:9 | l4 | Usual arithmetic conversion from 'uint16_t' to 'int' changes signedness. | @@ -82,7 +82,7 @@ | test.cpp:271:3:271:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | | test.cpp:271:7:271:8 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | | test.cpp:272:3:272:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | -| test.cpp:272:8:272:9 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | +| test.cpp:272:7:272:8 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | | test.cpp:273:3:273:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | | test.cpp:273:8:273:9 | l4 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | | test.cpp:274:3:274:4 | l3 | Usual arithmetic conversion from 'UnscopedEnumExplicit' to 'int' changes signedness. | diff --git a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected index dc57c5ddd0..068608c126 100644 --- a/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected +++ b/cpp/misra/test/rules/RULE-7-0-6/NumericAssignmentTypeMismatch.expected @@ -166,8 +166,8 @@ | test_operators.cpp:115:8:115:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | | test_operators.cpp:119:8:119:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | | test_operators.cpp:120:8:120:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | -| test_operators.cpp:124:8:124:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | -| test_operators.cpp:125:8:125:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | +| test_operators.cpp:124:7:124:8 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | +| test_operators.cpp:125:7:125:8 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | | test_operators.cpp:129:8:129:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | | test_operators.cpp:130:8:130:9 | l5 | Assignment between incompatible numeric types from 'uint32_t' to 'int32_t'. | | test_operators.cpp:134:8:134:9 | l4 | Assignment between incompatible numeric types from 'int64_t' to 'int32_t'. | From 9f46766ce951ffb4cab922169abe2becc01194e1 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 22 Aug 2025 09:48:02 +0100 Subject: [PATCH 563/628] Rule 7.0.3: Split unevaluated operands test case Make it clearer that a static_assert is not unevaluated. --- .../NoCharacterNumericalValue.expected | 19 ++++++++++--------- cpp/misra/test/rules/RULE-7-0-3/test.cpp | 5 +++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.expected b/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.expected index 0b6088d34e..a6419404da 100644 --- a/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.expected +++ b/cpp/misra/test/rules/RULE-7-0-3/NoCharacterNumericalValue.expected @@ -16,12 +16,13 @@ | test.cpp:53:7:53:8 | l1 | Conversion of character type 'char' to 'bool' uses numerical value of character. | | test.cpp:55:8:55:9 | l2 | Conversion of character type 'char' to 'bool' uses numerical value of character. | | test.cpp:73:39:73:41 | 97 | Conversion of character type 'char' to 'int_type' uses numerical value of character. | -| test.cpp:89:8:89:9 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | -| test.cpp:89:14:89:16 | 48 | Conversion of character type 'char' to 'int' uses numerical value of character. | -| test.cpp:89:23:89:24 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | -| test.cpp:89:29:89:31 | 57 | Conversion of character type 'char' to 'int' uses numerical value of character. | -| test.cpp:102:25:102:26 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | -| test.cpp:117:15:117:16 | l2 | Conversion of character type 'int_type' to 'char' uses numerical value of character. | -| test.cpp:123:31:123:32 | 65 | Conversion of character type 'int' to 'char' uses numerical value of character. | -| test.cpp:124:29:124:31 | 65 | Conversion of character type 'char' to 'int' uses numerical value of character. | -| test.cpp:130:6:130:7 | l2 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:84:17:84:19 | 120 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:90:8:90:9 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:90:14:90:16 | 48 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:90:23:90:24 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:90:29:90:31 | 57 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:103:25:103:26 | l1 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:118:15:118:16 | l2 | Conversion of character type 'int_type' to 'char' uses numerical value of character. | +| test.cpp:124:31:124:32 | 65 | Conversion of character type 'int' to 'char' uses numerical value of character. | +| test.cpp:125:29:125:31 | 65 | Conversion of character type 'char' to 'int' uses numerical value of character. | +| test.cpp:131:6:131:7 | l2 | Conversion of character type 'char' to 'int' uses numerical value of character. | diff --git a/cpp/misra/test/rules/RULE-7-0-3/test.cpp b/cpp/misra/test/rules/RULE-7-0-3/test.cpp index 205712b1ff..0338f4757f 100644 --- a/cpp/misra/test/rules/RULE-7-0-3/test.cpp +++ b/cpp/misra/test/rules/RULE-7-0-3/test.cpp @@ -80,8 +80,9 @@ void test_optional_comparison() { } void test_unevaluated_operand() { - decltype('s' + 't') l1; // COMPLIANT - static_assert(sizeof('x') > 0); // COMPLIANT + decltype('s' + 't') l1; // COMPLIANT + static_assert('x' > 0); // NON_COMPLIANT + sizeof('x'); // COMPLIANT } void test_range_check_non_compliant() { From 2b1c06bf1c279171806e8757d5ffda4d1417ccdd Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 15 Aug 2025 10:19:32 +0100 Subject: [PATCH 564/628] M5-2-2: Make into shared query This shared implementation will be used for implementing MISRA C++ 2023 8.2.1. --- ...ointerToAVirtualBaseClassCastToAPointer.ql | 16 +++++------- ...terToAVirtualBaseClassCastToAPointer.qlref | 1 - ...interToAVirtualBaseClassCastToAPointer.qll | 26 +++++++++++++++++++ ...ToAVirtualBaseClassCastToAPointer.expected | 0 ...ointerToAVirtualBaseClassCastToAPointer.ql | 4 +++ .../test.cpp | 0 rule_packages/cpp/Pointers.json | 3 ++- 7 files changed, 38 insertions(+), 12 deletions(-) delete mode 100644 cpp/autosar/test/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.qlref create mode 100644 cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll rename cpp/{autosar/test/rules/M5-2-2 => common/test/rules/pointertoavirtualbaseclasscasttoapointer}/PointerToAVirtualBaseClassCastToAPointer.expected (100%) create mode 100644 cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.ql rename cpp/{autosar/test/rules/M5-2-2 => common/test/rules/pointertoavirtualbaseclasscasttoapointer}/test.cpp (100%) diff --git a/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql b/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql index 086aa40ae7..57eda7f146 100644 --- a/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql +++ b/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql @@ -15,14 +15,10 @@ import cpp import codingstandards.cpp.autosar +import codingstandards.cpp.rules.pointertoavirtualbaseclasscasttoapointer.PointerToAVirtualBaseClassCastToAPointer -from Cast cast, VirtualBaseClass castFrom, Class castTo -where - not isExcluded(cast, PointersPackage::pointerToAVirtualBaseClassCastToAPointerQuery()) and - not cast instanceof DynamicCast and - castFrom = cast.getExpr().getType().(PointerType).getBaseType() and - cast.getType().(PointerType).getBaseType() = castTo and - castTo = castFrom.getADerivedClass+() -select cast, - "A pointer to virtual base class $@ is not cast to a pointer of derived class $@ using a dynamic_cast.", - castFrom, castFrom.getName(), castTo, castTo.getName() +class PointerToAVirtualBaseClassCastToAPointerQuery extends PointerToAVirtualBaseClassCastToAPointerSharedQuery { + PointerToAVirtualBaseClassCastToAPointerQuery() { + this = PointersPackage::pointerToAVirtualBaseClassCastToAPointerQuery() + } +} diff --git a/cpp/autosar/test/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.qlref b/cpp/autosar/test/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.qlref deleted file mode 100644 index c48e9498cc..0000000000 --- a/cpp/autosar/test/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll b/cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll new file mode 100644 index 0000000000..37425e0dd2 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll @@ -0,0 +1,26 @@ +/** + * Provides a library with a `problems` predicate for the following issue: + * A pointer to a virtual base class shall only be cast to a pointer to a derived class + * by means of dynamic_cast, otherwise the cast has undefined behavior. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class PointerToAVirtualBaseClassCastToAPointerSharedQuery extends Query { } + +Query getQuery() { result instanceof PointerToAVirtualBaseClassCastToAPointerSharedQuery } + +query predicate problems(Cast cast, string message) { + exists(VirtualBaseClass castFrom, Class castTo | + not isExcluded(cast, getQuery()) and + not cast instanceof DynamicCast and + castFrom = cast.getExpr().getType().(PointerType).getBaseType() and + cast.getType().(PointerType).getBaseType() = castTo and + castTo = castFrom.getADerivedClass+() and + message = + "A pointer to virtual base class " + castFrom.getName() + + " is not cast to a pointer of derived class " + castTo.getName() + " using a dynamic_cast." + ) +} diff --git a/cpp/autosar/test/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.expected b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.expected similarity index 100% rename from cpp/autosar/test/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.expected rename to cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.expected diff --git a/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.ql b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.ql new file mode 100644 index 0000000000..973b707e13 --- /dev/null +++ b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.ql @@ -0,0 +1,4 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.pointertoavirtualbaseclasscasttoapointer.PointerToAVirtualBaseClassCastToAPointer + +class TestFileQuery extends PointerToAVirtualBaseClassCastToAPointerSharedQuery, TestQuery { } diff --git a/cpp/autosar/test/rules/M5-2-2/test.cpp b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/test.cpp similarity index 100% rename from cpp/autosar/test/rules/M5-2-2/test.cpp rename to cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/test.cpp diff --git a/rule_packages/cpp/Pointers.json b/rule_packages/cpp/Pointers.json index fb1fbe2918..3815ba521c 100644 --- a/rule_packages/cpp/Pointers.json +++ b/rule_packages/cpp/Pointers.json @@ -306,7 +306,8 @@ "short_name": "PointerToAVirtualBaseClassCastToAPointer", "tags": [ "correctness" - ] + ], + "shared_implementation_short_name": "PointerToAVirtualBaseClassCastToAPointer" } ], "title": "A pointer to a virtual base class shall only be cast to a pointer to a derived class by means of dynamic_cast." From 7e9fe0bef5c4a6da56cbb1571090da1165280f6c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 15 Aug 2025 10:24:31 +0100 Subject: [PATCH 565/628] Add Conversions2 package --- .../cpp/exclusions/cpp/Conversions2.qll | 112 ++++++++++++++++ .../cpp/exclusions/cpp/RuleMetadata.qll | 3 + rule_packages/cpp/Conversions2.json | 125 ++++++++++++++++++ 3 files changed, 240 insertions(+) create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions2.qll create mode 100644 rule_packages/cpp/Conversions2.json diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions2.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions2.qll new file mode 100644 index 0000000000..a250b4b5b1 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Conversions2.qll @@ -0,0 +1,112 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Conversions2Query = + TVirtualBaseClassCastToDerivedQuery() or + TNoCStyleOrFunctionalCastsQuery() or + TIntToPointerCastProhibitedQuery() or + TNoPointerToIntegralCastQuery() or + TPointerToIntegralCastQuery() or + TNoStandaloneTypeCastExpressionQuery() + +predicate isConversions2QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `virtualBaseClassCastToDerived` query + Conversions2Package::virtualBaseClassCastToDerivedQuery() and + queryId = + // `@id` for the `virtualBaseClassCastToDerived` query + "cpp/misra/virtual-base-class-cast-to-derived" and + ruleId = "RULE-8-2-1" and + category = "required" + or + query = + // `Query` instance for the `noCStyleOrFunctionalCasts` query + Conversions2Package::noCStyleOrFunctionalCastsQuery() and + queryId = + // `@id` for the `noCStyleOrFunctionalCasts` query + "cpp/misra/no-c-style-or-functional-casts" and + ruleId = "RULE-8-2-2" and + category = "required" + or + query = + // `Query` instance for the `intToPointerCastProhibited` query + Conversions2Package::intToPointerCastProhibitedQuery() and + queryId = + // `@id` for the `intToPointerCastProhibited` query + "cpp/misra/int-to-pointer-cast-prohibited" and + ruleId = "RULE-8-2-6" and + category = "required" + or + query = + // `Query` instance for the `noPointerToIntegralCast` query + Conversions2Package::noPointerToIntegralCastQuery() and + queryId = + // `@id` for the `noPointerToIntegralCast` query + "cpp/misra/no-pointer-to-integral-cast" and + ruleId = "RULE-8-2-7" and + category = "advisory" + or + query = + // `Query` instance for the `pointerToIntegralCast` query + Conversions2Package::pointerToIntegralCastQuery() and + queryId = + // `@id` for the `pointerToIntegralCast` query + "cpp/misra/pointer-to-integral-cast" and + ruleId = "RULE-8-2-8" and + category = "required" + or + query = + // `Query` instance for the `noStandaloneTypeCastExpression` query + Conversions2Package::noStandaloneTypeCastExpressionQuery() and + queryId = + // `@id` for the `noStandaloneTypeCastExpression` query + "cpp/misra/no-standalone-type-cast-expression" and + ruleId = "RULE-9-2-1" and + category = "required" +} + +module Conversions2Package { + Query virtualBaseClassCastToDerivedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `virtualBaseClassCastToDerived` query + TQueryCPP(TConversions2PackageQuery(TVirtualBaseClassCastToDerivedQuery())) + } + + Query noCStyleOrFunctionalCastsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noCStyleOrFunctionalCasts` query + TQueryCPP(TConversions2PackageQuery(TNoCStyleOrFunctionalCastsQuery())) + } + + Query intToPointerCastProhibitedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `intToPointerCastProhibited` query + TQueryCPP(TConversions2PackageQuery(TIntToPointerCastProhibitedQuery())) + } + + Query noPointerToIntegralCastQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noPointerToIntegralCast` query + TQueryCPP(TConversions2PackageQuery(TNoPointerToIntegralCastQuery())) + } + + Query pointerToIntegralCastQuery() { + //autogenerate `Query` type + result = + // `Query` type for `pointerToIntegralCast` query + TQueryCPP(TConversions2PackageQuery(TPointerToIntegralCastQuery())) + } + + Query noStandaloneTypeCastExpressionQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noStandaloneTypeCastExpression` query + TQueryCPP(TConversions2PackageQuery(TNoStandaloneTypeCastExpressionQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index 88e4d55358..27ae7e2f52 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -13,6 +13,7 @@ import Concurrency import Conditionals import Const import Conversions +import Conversions2 import DeadCode import Declarations import ExceptionSafety @@ -69,6 +70,7 @@ newtype TCPPQuery = TConditionalsPackageQuery(ConditionalsQuery q) or TConstPackageQuery(ConstQuery q) or TConversionsPackageQuery(ConversionsQuery q) or + TConversions2PackageQuery(Conversions2Query q) or TDeadCodePackageQuery(DeadCodeQuery q) or TDeclarationsPackageQuery(DeclarationsQuery q) or TExceptionSafetyPackageQuery(ExceptionSafetyQuery q) or @@ -125,6 +127,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isConditionalsQueryMetadata(query, queryId, ruleId, category) or isConstQueryMetadata(query, queryId, ruleId, category) or isConversionsQueryMetadata(query, queryId, ruleId, category) or + isConversions2QueryMetadata(query, queryId, ruleId, category) or isDeadCodeQueryMetadata(query, queryId, ruleId, category) or isDeclarationsQueryMetadata(query, queryId, ruleId, category) or isExceptionSafetyQueryMetadata(query, queryId, ruleId, category) or diff --git a/rule_packages/cpp/Conversions2.json b/rule_packages/cpp/Conversions2.json new file mode 100644 index 0000000000..6c178effc6 --- /dev/null +++ b/rule_packages/cpp/Conversions2.json @@ -0,0 +1,125 @@ +{ + "MISRA-C++-2023": { + "RULE-8-2-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Casting from a virtual base class to a derived class using anything other than dynamic_cast causes undefined behavior.", + "kind": "problem", + "name": "A virtual base class shall only be cast to a derived class by means of dynamic_cast", + "precision": "very-high", + "severity": "error", + "short_name": "VirtualBaseClassCastToDerived", + "tags": [ + "scope/single-translation-unit" + ], + "shared_implementation_short_name": "PointerToAVirtualBaseClassCastToAPointer" + } + ], + "title": "A virtual base class shall only be cast to a derived class by means of dynamic_cast" + }, + "RULE-8-2-2": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using C-style casts or functional notation casts allows unsafe type conversions and makes code harder to maintain compared to using named casts like const_cast, dynamic_cast, static_cast and reinterpret_cast.", + "kind": "problem", + "name": "C-style casts and functional notation casts shall not be used", + "precision": "very-high", + "severity": "error", + "short_name": "NoCStyleOrFunctionalCasts", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "C-style casts and functional notation casts shall not be used" + }, + "RULE-8-2-6": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Casting from an integral type, enumerated type, or pointer to void type to a pointer type leads to unspecified behavior and is error prone.", + "kind": "problem", + "name": "An object with integral, enumerated, or pointer to void type shall not be cast to a pointer type", + "precision": "very-high", + "severity": "error", + "short_name": "IntToPointerCastProhibited", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "An object with integral, enumerated, or pointer to void type shall not be cast to a pointer type" + }, + "RULE-8-2-7": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Casting between pointer types and integral types makes code behavior harder to understand and may cause pointer tracking tools to become unreliable.", + "kind": "problem", + "name": "A cast should not convert a pointer type to an integral type", + "precision": "very-high", + "severity": "error", + "short_name": "NoPointerToIntegralCast", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "A cast should not convert a pointer type to an integral type" + }, + "RULE-8-2-8": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Casting object pointers to integral types other than std::uintptr_t or std::intptr_t can lead to implementation-defined behavior and potential loss of pointer information.", + "kind": "problem", + "name": "An object pointer type shall not be cast to an integral type other than std::uintptr_t or", + "precision": "very-high", + "severity": "error", + "short_name": "PointerToIntegralCast", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "An object pointer type shall not be cast to an integral type other than std::uintptr_t or std::intptr_t" + }, + "RULE-9-2-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using an explicit type conversion as an expression statement creates a temporary object that is immediately discarded, which can lead to unintended premature resource cleanup.", + "kind": "problem", + "name": "An explicit type conversion shall not be an expression statement", + "precision": "very-high", + "severity": "error", + "short_name": "NoStandaloneTypeCastExpression", + "tags": [ + "scope/single-translation-unit" + ] + } + ], + "title": "An explicit type conversion shall not be an expression statement" + } + } +} \ No newline at end of file From c81f2462cc61ebd439c50bf6956cee6c0a32e4a2 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 15 Aug 2025 10:28:57 +0100 Subject: [PATCH 566/628] Rule 8.2.1: Implement as a shared query --- .../VirtualBaseClassCastToDerived.ql | 23 +++++++++++++++++++ .../VirtualBaseClassCastToDerived.testref | 1 + 2 files changed, 24 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql create mode 100644 cpp/misra/test/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.testref diff --git a/cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql b/cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql new file mode 100644 index 0000000000..cd9cb150a8 --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql @@ -0,0 +1,23 @@ +/** + * @id cpp/misra/virtual-base-class-cast-to-derived + * @name RULE-8-2-1: A virtual base class shall only be cast to a derived class by means of dynamic_cast + * @description Casting from a virtual base class to a derived class using anything other than + * dynamic_cast causes undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-2-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.rules.pointertoavirtualbaseclasscasttoapointer.PointerToAVirtualBaseClassCastToAPointer + +class VirtualBaseClassCastToDerivedQuery extends PointerToAVirtualBaseClassCastToAPointerSharedQuery { + VirtualBaseClassCastToDerivedQuery() { + this = Conversions2Package::virtualBaseClassCastToDerivedQuery() + } +} diff --git a/cpp/misra/test/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.testref b/cpp/misra/test/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.testref new file mode 100644 index 0000000000..475d3fd8be --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.testref @@ -0,0 +1 @@ +cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.ql \ No newline at end of file From 75837e2b8e7a71657bee90066cf918576e9fc458 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 15 Aug 2025 12:01:05 +0100 Subject: [PATCH 567/628] PointerToAVirtualBaseClass: Handle reference types and type defs --- .../2025-08-15-m5-2-2-virtual-base.md | 3 + ...interToAVirtualBaseClassCastToAPointer.qll | 12 +++- ...ToAVirtualBaseClassCastToAPointer.expected | 3 + .../test.cpp | 63 ++++++++++++++++++- 4 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 change_notes/2025-08-15-m5-2-2-virtual-base.md diff --git a/change_notes/2025-08-15-m5-2-2-virtual-base.md b/change_notes/2025-08-15-m5-2-2-virtual-base.md new file mode 100644 index 0000000000..072ad41ea6 --- /dev/null +++ b/change_notes/2025-08-15-m5-2-2-virtual-base.md @@ -0,0 +1,3 @@ + - `M5-2-2` - `PointerToAVirtualBaseClassCastToAPointer.ql`: + - Report casts where the from or to types are typedefs to virtual base classes or derived classes. + - Report casts to a reference type which is a derived type. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll b/cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll index 37425e0dd2..207b6da415 100644 --- a/cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll +++ b/cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll @@ -16,11 +16,19 @@ query predicate problems(Cast cast, string message) { exists(VirtualBaseClass castFrom, Class castTo | not isExcluded(cast, getQuery()) and not cast instanceof DynamicCast and - castFrom = cast.getExpr().getType().(PointerType).getBaseType() and - cast.getType().(PointerType).getBaseType() = castTo and castTo = castFrom.getADerivedClass+() and message = "A pointer to virtual base class " + castFrom.getName() + " is not cast to a pointer of derived class " + castTo.getName() + " using a dynamic_cast." + | + // Pointer cast + castFrom = cast.getExpr().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and + cast.getType().stripTopLevelSpecifiers().(PointerType).getBaseType() = castTo + or + // Reference type cast + castFrom = cast.getExpr().getType().stripTopLevelSpecifiers() and + // Not actually represented as a reference type in our model - instead as the + // type itself + cast.getType().stripTopLevelSpecifiers() = castTo ) } diff --git a/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.expected b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.expected index e69de29bb2..7f64ab5d1c 100644 --- a/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.expected +++ b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.expected @@ -0,0 +1,3 @@ +| test.cpp:36:12:36:37 | reinterpret_cast... | A pointer to virtual base class C1 is not cast to a pointer of derived class C2 using a dynamic_cast. | +| test.cpp:42:12:42:38 | reinterpret_cast... | A pointer to virtual base class C1 is not cast to a pointer of derived class C2 using a dynamic_cast. | +| test.cpp:48:17:48:48 | reinterpret_cast... | A pointer to virtual base class C1 is not cast to a pointer of derived class C2 using a dynamic_cast. | diff --git a/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/test.cpp b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/test.cpp index 59c0cb4b37..419bc0764e 100644 --- a/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/test.cpp +++ b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/test.cpp @@ -2,17 +2,74 @@ class C1 { public: virtual ~C1() {} }; + class C2 : public virtual C1 { public: C2() {} ~C2() {} }; -void f1() { +typedef C1 Base; +typedef C2 Derived; + +void test_dynamic_cast_pointer_compliant() { C2 l1; C1 *p1 = &l1; + C2 *p2 = dynamic_cast(p1); // COMPLIANT +} - // C2 *p2 = static_cast(p1); // NON_COMPLIANT, prohibited by compiler - C2 *p3 = dynamic_cast(p1); // COMPLIANT +void test_dynamic_cast_reference_compliant() { + C2 l1; + C1 *p1 = &l1; C2 &l2 = dynamic_cast(*p1); // COMPLIANT } + +void test_dynamic_cast_reference_compliant_typedefs() { + Derived l1; + Base *p1 = &l1; + Derived &l2 = dynamic_cast(*p1); // COMPLIANT +} + +void test_reinterpret_cast_pointer_non_compliant() { + C2 l1; + C1 *p1 = &l1; + C2 *p2 = reinterpret_cast(p1); // NON_COMPLIANT +} + +void test_reinterpret_cast_reference_non_compliant() { + C2 l1; + C1 *p1 = &l1; + C2 &l2 = reinterpret_cast(*p1); // NON_COMPLIANT +} + +void test_reinterpret_cast_typedefs_non_compliant() { + Derived l1; + Base *p1 = &l1; + Derived &l2 = reinterpret_cast(*p1); // NON_COMPLIANT +} + +void test_c_style_cast_pointer_non_compliant() { + C2 l1; + C1 *p1 = &l1; + // C2 *p2 = (C2 *)p1; // NON_COMPLIANT - prohibited by the compiler +} + +void test_c_style_cast_reference_non_compliant() { + C2 l1; + C1 *p1 = &l1; + // C2 &l2 = (C2 &)*p1; // NON_COMPLIANT - prohibited by the compiler +} + +void test_static_cast_pointer_non_compliant() { + C2 l1; + C1 *p1 = &l1; + // C2 *p2 = static_cast(p1); // NON_COMPLIANT - prohibited by the + // compiler +} + +void test_static_cast_reference_non_compliant() { + C2 l1; + C1 *p1 = &l1; + // C2 &l2 = static_cast(*p1); // NON_COMPLIANT - prohibited by the + // compiler +} \ No newline at end of file From 1792e8806cdfa9e589cbced7dc5c985984b4c409 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Fri, 15 Aug 2025 15:19:34 +0100 Subject: [PATCH 568/628] A5-2-2: Refactor query to extract shared components MISRA C++ Rule 8.2.2 is similar, but not identical. --- .../rules/A5-2-2/TraditionalCStyleCastsUsed.ql | 13 +++---------- cpp/autosar/test/rules/A5-2-2/test.cpp | 2 +- .../src/codingstandards/cpp/CStyleCasts.qll | 18 ++++++++++++++++++ 3 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 cpp/common/src/codingstandards/cpp/CStyleCasts.qll diff --git a/cpp/autosar/src/rules/A5-2-2/TraditionalCStyleCastsUsed.ql b/cpp/autosar/src/rules/A5-2-2/TraditionalCStyleCastsUsed.ql index 66a289dfe0..7e2d19d336 100644 --- a/cpp/autosar/src/rules/A5-2-2/TraditionalCStyleCastsUsed.ql +++ b/cpp/autosar/src/rules/A5-2-2/TraditionalCStyleCastsUsed.ql @@ -16,6 +16,7 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.Macro +import codingstandards.cpp.CStyleCasts /** * Gets the macro (if any) that generated the given `CStyleCast`. @@ -61,18 +62,10 @@ Macro getGeneratedFrom(CStyleCast c) { * argument type is compatible with a single-argument constructor. */ -from CStyleCast c, string extraMessage, Locatable l, string supplementary +from ExplicitUserDefinedCStyleCast c, string extraMessage, Locatable l, string supplementary where not isExcluded(c, BannedSyntaxPackage::traditionalCStyleCastsUsedQuery()) and - not c.isImplicit() and - not c.getType() instanceof UnknownType and - // For casts in templates that occur on types related to a template parameter, the copy of th - // cast in the uninstantiated template is represented as a `CStyleCast` even if in practice all - // the instantiations represent it as a `ConstructorCall`. To avoid the common false positive case - // of using the functional cast notation to call a constructor we exclude all `CStyleCast`s on - // uninstantiated templates, and instead rely on reporting results within instantiations. - not c.isFromUninstantiatedTemplate(_) and - // Exclude casts created from macro invocations of macros defined by third parties + // Not generated from a library macro not getGeneratedFrom(c) instanceof LibraryMacro and // If the cast was generated from a user-provided macro, then report the macro that generated the // cast, as the macro itself may have generated the cast diff --git a/cpp/autosar/test/rules/A5-2-2/test.cpp b/cpp/autosar/test/rules/A5-2-2/test.cpp index fb39868560..d585efc37b 100644 --- a/cpp/autosar/test/rules/A5-2-2/test.cpp +++ b/cpp/autosar/test/rules/A5-2-2/test.cpp @@ -2,7 +2,7 @@ #include #include int foo() { return 1; } - +// A copy of 8.2,2 test.cpp, but with different cases compliant/non-compliant void test_c_style_cast() { double f = 3.14; std::uint32_t n1 = (std::uint32_t)f; // NON_COMPLIANT - C-style cast diff --git a/cpp/common/src/codingstandards/cpp/CStyleCasts.qll b/cpp/common/src/codingstandards/cpp/CStyleCasts.qll new file mode 100644 index 0000000000..b387f9898e --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/CStyleCasts.qll @@ -0,0 +1,18 @@ +import cpp +import codingstandards.cpp.Macro + +/** + * A C-style cast that is explicitly user written and has a known target type. + */ +class ExplicitUserDefinedCStyleCast extends CStyleCast { + ExplicitUserDefinedCStyleCast() { + not this.isImplicit() and + not this.getType() instanceof UnknownType and + // For casts in templates that occur on types related to a template parameter, the copy of th + // cast in the uninstantiated template is represented as a `CStyleCast` even if in practice all + // the instantiations represent it as a `ConstructorCall`. To avoid the common false positive case + // of using the functional cast notation to call a constructor we exclude all `CStyleCast`s on + // uninstantiated templates, and instead rely on reporting results within instantiations. + not this.isFromUninstantiatedTemplate(_) + } +} From 9b9a68c570409b2f1bb48b6180b82623c4727115 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 17 Aug 2025 23:18:36 +0100 Subject: [PATCH 569/628] Fix AlertReporting for nested macros Nested macro invocations do not have getExpandedElements(), but do have getAffectedElements(). --- cpp/common/src/codingstandards/cpp/AlertReporting.qll | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/AlertReporting.qll b/cpp/common/src/codingstandards/cpp/AlertReporting.qll index 3ef5315906..97c46c0629 100644 --- a/cpp/common/src/codingstandards/cpp/AlertReporting.qll +++ b/cpp/common/src/codingstandards/cpp/AlertReporting.qll @@ -14,15 +14,21 @@ module MacroUnwrapper { * Gets a macro invocation that applies to the result element. */ private MacroInvocation getAMacroInvocation(ResultElement re) { - result.getAnExpandedElement() = re + result.getAnAffectedElement() = re } /** * Gets the primary macro invocation that generated the result element. + * + * Does not hold for cases where the result element is located at a macro argument site. */ MacroInvocation getPrimaryMacroInvocation(ResultElement re) { exists(MacroInvocation mi | mi = getAMacroInvocation(re) and + // Only report cases where the element is not located at the macro expansion site + // This means we'll report results in macro arguments in the macro argument + // location, not within the macro itself + mi.getLocation().getStartColumn() = re.getLocation().getStartColumn() and // No other more specific macro that expands to element not exists(MacroInvocation otherMi | otherMi = getAMacroInvocation(re) and otherMi.getParentInvocation() = mi From 9aa5e214cd87a8d583ac0fc11c9608806a449711 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 17 Aug 2025 23:19:58 +0100 Subject: [PATCH 570/628] RULE-8-2-2 - NoCStyleOrFunctionalCasts Detects C-style casts and functional notation casts that should be replaced with explicit cast operators. Prevents unsafe type conversions that lack clear intent and proper type checking constraints. [a] --- .../RULE-8-2-2/NoCStyleOrFunctionalCasts.ql | 33 ++++ .../NoCStyleOrFunctionalCasts.expected | 7 + .../NoCStyleOrFunctionalCasts.qlref | 1 + cpp/misra/test/rules/RULE-8-2-2/test.cpp | 158 ++++++++++++++++++ 4 files changed, 199 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.ql create mode 100644 cpp/misra/test/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.expected create mode 100644 cpp/misra/test/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.qlref create mode 100644 cpp/misra/test/rules/RULE-8-2-2/test.cpp diff --git a/cpp/misra/src/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.ql b/cpp/misra/src/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.ql new file mode 100644 index 0000000000..3515d0ec1b --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.ql @@ -0,0 +1,33 @@ +/** + * @id cpp/misra/no-c-style-or-functional-casts + * @name RULE-8-2-2: C-style casts and functional notation casts shall not be used + * @description Using C-style casts or functional notation casts allows unsafe type conversions and + * makes code harder to maintain compared to using named casts like const_cast, + * dynamic_cast, static_cast and reinterpret_cast. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-2-2 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import codingstandards.cpp.CStyleCasts +import codingstandards.cpp.AlertReporting + +class MISRACPPProhibitedCStyleCasts extends ExplicitUserDefinedCStyleCast { + MISRACPPProhibitedCStyleCasts() { + // MISRA C++ permits casts to void types + not getType() instanceof VoidType + } +} + +from Element reportingElement, MISRACPPProhibitedCStyleCasts c +where + not isExcluded(c, Conversions2Package::noCStyleOrFunctionalCastsQuery()) and + reportingElement = MacroUnwrapper::unwrapElement(c) and + exists(reportingElement.getFile().getRelativePath()) // within user code - validated during testing +select reportingElement, "Use of explicit c-style cast to " + c.getType().getName() + "." diff --git a/cpp/misra/test/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.expected b/cpp/misra/test/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.expected new file mode 100644 index 0000000000..a2b3b522cc --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.expected @@ -0,0 +1,7 @@ +| test.cpp:8:22:8:37 | (uint32_t)... | Use of explicit c-style cast to uint32_t. | +| test.cpp:9:22:9:32 | (unsigned int)... | Use of explicit c-style cast to unsigned int. | +| test.cpp:70:1:70:31 | #define ADD_ONE(x) ((int)x) + 1 | Use of explicit c-style cast to int. | +| test.cpp:83:19:83:26 | (int)... | Use of explicit c-style cast to int. | +| test.cpp:84:27:84:34 | (int)... | Use of explicit c-style cast to int. | +| test.cpp:112:10:112:13 | (int)... | Use of explicit c-style cast to int. | +| test.cpp:147:12:147:26 | (unsigned int)... | Use of explicit c-style cast to unsigned int. | diff --git a/cpp/misra/test/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.qlref b/cpp/misra/test/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.qlref new file mode 100644 index 0000000000..cbd07ad124 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.qlref @@ -0,0 +1 @@ +rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-2/test.cpp b/cpp/misra/test/rules/RULE-8-2-2/test.cpp new file mode 100644 index 0000000000..3d57d7f3c8 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-2/test.cpp @@ -0,0 +1,158 @@ +#include +#include +#include +int foo() { return 1; } +// A copy of A5-2-2 test.cpp, but with different cases compliant/non-compliant +void test_c_style_cast() { + double f = 3.14; + std::uint32_t n1 = (std::uint32_t)f; // NON_COMPLIANT - C-style cast + std::uint32_t n2 = unsigned(f); // NON_COMPLIANT - functional notation + + std::uint8_t n3 = 1; + std::uint8_t n4 = 1; + std::uint8_t n5 = n3 + n4; // ignored, implicit casts + + (void)foo(); // COMPLIANT - permitted by MISRA C++ +} + +class A { +public: + virtual void f1() {} +}; + +class B : A { +public: + virtual void f1() {} +}; + +class C { + void f1() {} +}; + +void test_cpp_style_cast() { + // These cases may contravene other rules, but are marked as COMPLIANT for + // this rule + A a1; + const A *a2 = &a1; + A *a3 = const_cast(a2); // COMPLIANT + B *b = dynamic_cast(a3); // COMPLIANT + C *c = reinterpret_cast(a3); // COMPLIANT + std::int16_t n8 = 0; + std::int32_t n9 = static_cast(n8); // COMPLIANT + static_cast(foo()); // COMPLIANT +} + +class A5_2_2a { +public: + template + static void Foo(const std::string &name, As &&...rest) { + Fun(Log(std::forward( + rest)...)); // COMPLIANT - previously reported as a false positive + } + + template static std::string Log(As &&...tail) { + return std::string(); + } + + static void Fun(const std::string &message) {} +}; + +class A5_2_2 final { +public: + void f(const std::string &s) const { A5_2_2a::Foo("name", "x", "y", "z"); } +}; + +void a5_2_2_test() { + A5_2_2 a; + a.f(""); +} + +#define ADD_ONE(x) ((int)x) + 1 // NON_COMPLIANT +#define NESTED_ADD_ONE(x) ADD_ONE(x) // Not reported - reported at ADD_ONE +#define NO_CAST_ADD_ONE(x) x + 1 // COMPLIANT + +#include "macro_c_style_casts.h" + +void test_macro_cast() { + ADD_ONE(1); // Reported at macro definition site + NESTED_ADD_ONE(1); // reported at macro definition site + LIBRARY_ADD_TWO(1); // COMPLIANT - macro generating the cast is defined in a + // library, and is not modifiable by the user + LIBRARY_NESTED_ADD_TWO(1); // COMPLIANT - macro generating the cast is defined + // in a library, and is not modifiable by the user + NO_CAST_ADD_ONE((int)1.0); // NON_COMPLIANT - cast in argument to macro + LIBRARY_NO_CAST_ADD_TWO((int)1.0); // NON_COMPLIANT - library macro with + // c-style cast in argument, written by + // user so should be reported +} + +class D { +public: + D(int x) : fx(x), fy(0) {} + D(int x, int y) : fx(x), fy(y) {} + +private: + int fx; + int fy; +}; + +D testNonFunctionalCast() { + return (D)1; // COMPLIANT +} + +D testFunctionalCast() { + return D(1); // COMPLIANT +} + +D testFunctionalCastMulti() { + return D(1, 2); // COMPLIANT +} + +template T testFunctionalCastTemplate() { + return T(1); // NON_COMPLIANT - used with an int +} + +template T testFunctionalCastTemplateMulti() { + return T(1, 2); // COMPLIANT +} + +void testFunctionalCastTemplateUse() { + testFunctionalCastTemplate(); + testFunctionalCastTemplate(); + testFunctionalCastTemplateMulti(); +} + +template class E { +public: + class F { + public: + F(int x) : fx(x), fy(0) {} + F(int x, int y) : fx(x), fy(y) {} + + private: + int fx; + int fy; + }; + + F f() { + return F(1); // COMPLIANT + } + + D d() { + return D(1); // COMPLIANT + } + + int i() { + double f = 3.14; + return (unsigned int)f; // NON_COMPLIANT + } +}; + +class G {}; + +void testE() { + E e; + e.f(); + e.d(); + e.i(); +} From 9118b81101baca05ec21e5dac71b89b8f07381c9 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 17 Aug 2025 23:39:30 +0100 Subject: [PATCH 571/628] RULE-8-2-6 - IntToPointerCastProhibited Detects casts from integral, enumerated, or void pointer types to object pointer types that may lead to unspecified behavior. [a] --- .../RULE-8-2-6/IntToPointerCastProhibited.ql | 43 +++++++++ .../IntToPointerCastProhibited.expected | 11 +++ .../IntToPointerCastProhibited.qlref | 1 + cpp/misra/test/rules/RULE-8-2-6/test.cpp | 90 +++++++++++++++++++ 4 files changed, 145 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql create mode 100644 cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.expected create mode 100644 cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.qlref create mode 100644 cpp/misra/test/rules/RULE-8-2-6/test.cpp diff --git a/cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql b/cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql new file mode 100644 index 0000000000..dd1c7d15a4 --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql @@ -0,0 +1,43 @@ +/** + * @id cpp/misra/int-to-pointer-cast-prohibited + * @name RULE-8-2-6: An object with integral, enumerated, or pointer to void type shall not be cast to a pointer type + * @description Casting from an integral type, enumerated type, or pointer to void type to a pointer + * type leads to unspecified behavior and is error prone. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-2-6 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +from Cast cast, Type sourceType, Type targetType +where + not isExcluded(cast, Conversions2Package::intToPointerCastProhibitedQuery()) and + sourceType = cast.getExpr().getType().stripTopLevelSpecifiers() and + targetType = cast.getType().stripTopLevelSpecifiers() and + targetType instanceof PointerType and + not targetType instanceof FunctionPointerType and + not ( + // Exception: casts between void pointers are allowed + targetType.(PointerType).getBaseType().stripTopLevelSpecifiers() instanceof VoidType and + sourceType instanceof PointerType and + sourceType.(PointerType).getBaseType().stripTopLevelSpecifiers() instanceof VoidType + ) and + ( + // Integral types + sourceType instanceof IntegralType + or + // Enumerated types + sourceType instanceof Enum + or + // Pointer to void type + sourceType instanceof PointerType and + sourceType.(PointerType).getBaseType().stripTopLevelSpecifiers() instanceof VoidType + ) +select cast, + "Cast from '" + sourceType.toString() + "' to '" + targetType.toString() + "' is prohibited." diff --git a/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.expected b/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.expected new file mode 100644 index 0000000000..806c70a661 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.expected @@ -0,0 +1,11 @@ +| test.cpp:15:20:15:53 | reinterpret_cast... | Cast from 'signed int' to 'TestStruct *' is prohibited. | +| test.cpp:16:20:16:53 | reinterpret_cast... | Cast from 'signed long' to 'TestStruct *' is prohibited. | +| test.cpp:17:22:17:57 | reinterpret_cast... | Cast from 'signed long' to 'int32_t *' is prohibited. | +| test.cpp:24:20:24:53 | reinterpret_cast... | Cast from 'TestEnum' to 'TestStruct *' is prohibited. | +| test.cpp:25:22:25:57 | reinterpret_cast... | Cast from 'TestEnum' to 'int32_t *' is prohibited. | +| test.cpp:32:20:32:48 | static_cast... | Cast from 'void *' to 'TestStruct *' is prohibited. | +| test.cpp:33:20:33:53 | reinterpret_cast... | Cast from 'void *' to 'TestStruct *' is prohibited. | +| test.cpp:34:22:34:52 | static_cast... | Cast from 'void *' to 'int32_t *' is prohibited. | +| test.cpp:35:22:35:57 | reinterpret_cast... | Cast from 'void *' to 'int32_t *' is prohibited. | +| test.cpp:43:14:43:41 | reinterpret_cast... | Cast from 'signed int' to 'void *' is prohibited. | +| test.cpp:44:14:44:41 | reinterpret_cast... | Cast from 'signed long' to 'void *' is prohibited. | diff --git a/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.qlref b/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.qlref new file mode 100644 index 0000000000..c6f30b00f6 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.qlref @@ -0,0 +1 @@ +rules/RULE-8-2-6/IntToPointerCastProhibited.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-6/test.cpp b/cpp/misra/test/rules/RULE-8-2-6/test.cpp new file mode 100644 index 0000000000..5abd52242e --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-6/test.cpp @@ -0,0 +1,90 @@ +#include + +struct TestStruct { + std::int32_t m1; + std::int32_t m2; +}; + +enum TestEnum { VALUE1, VALUE2 }; + +void test_integral_to_pointer_cast() { + std::int32_t l1 = 42; + std::int64_t l2 = 0x1000; + + // Casting integral types to pointer types + TestStruct *l4 = reinterpret_cast(l1); // NON_COMPLIANT + TestStruct *l5 = reinterpret_cast(l2); // NON_COMPLIANT + std::int32_t *l7 = reinterpret_cast(l2); // NON_COMPLIANT +} + +void test_enumerated_to_pointer_cast() { + TestEnum l1 = VALUE1; + + // Casting enumerated types to pointer types + TestStruct *l3 = reinterpret_cast(l1); // NON_COMPLIANT + std::int32_t *l5 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_void_pointer_to_object_pointer_cast() { + void *l1 = nullptr; + + // Casting void pointer to object pointer types + TestStruct *l2 = static_cast(l1); // NON_COMPLIANT + TestStruct *l3 = reinterpret_cast(l1); // NON_COMPLIANT + std::int32_t *l4 = static_cast(l1); // NON_COMPLIANT + std::int32_t *l5 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_integral_to_void_pointer_cast() { + std::int32_t l1 = 42; + std::int64_t l2 = 0x1000; + + // Casting integral types to void pointer + void *l3 = reinterpret_cast(l1); // NON_COMPLIANT + void *l4 = reinterpret_cast(l2); // NON_COMPLIANT +} + +void test_compliant_void_pointer_casts() { + void *l1 = nullptr; + const void *l2 = nullptr; + + // Casts between void pointers are allowed + const void *l3 = const_cast(l1); // COMPLIANT + void *l4 = const_cast(l2); // COMPLIANT + volatile void *l5 = static_cast(l1); // COMPLIANT +} + +void f1() {} +void f2(int) {} + +void test_compliant_function_pointer_exceptions() { + std::int64_t l1 = 0x1000; + + // Function pointer casts are exceptions to this rule + void (*l2)() = reinterpret_cast(l1); // COMPLIANT + void (*l3)(int) = reinterpret_cast(l1); // COMPLIANT +} + +struct TestClass { + void memberFunc(); + std::int32_t m1; +}; + +void test_compliant_member_function_pointer_exceptions() { + void *l1 = nullptr; + + // Member function pointer casts are technically exceptions to this rule, but + // are prohibited by the compiler. + // void (TestClass::*l2)() = + // reinterpret_cast(l1); // COMPLIANT +} + +void test_compliant_regular_pointer_operations() { + TestStruct l1; + TestStruct *l2 = &l1; + std::int32_t *l3 = &l1.m1; + + // Regular pointer operations that don't involve forbidden casts + TestStruct *l4 = l2; // COMPLIANT + std::int32_t *l5 = l3; // COMPLIANT +} \ No newline at end of file From 13e184e5fc65c4fef3f77093a08a7257608c4dc9 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 17 Aug 2025 23:57:07 +0100 Subject: [PATCH 572/628] Add intptr_t and uintptr_t stubs --- cpp/common/test/includes/standard-library/cstdint.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpp/common/test/includes/standard-library/cstdint.h b/cpp/common/test/includes/standard-library/cstdint.h index 6a691637ff..888162dc36 100644 --- a/cpp/common/test/includes/standard-library/cstdint.h +++ b/cpp/common/test/includes/standard-library/cstdint.h @@ -15,5 +15,7 @@ typedef uint8_t uint_fast8_t; typedef uint16_t uint_fast16_t; typedef uint32_t uint_fast32_t; typedef uint64_t uint_fast64_t; +typedef long intptr_t; +typedef unsigned long uintptr_t; } // namespace std #endif // _GHLIBCPP_CSTDINT \ No newline at end of file From 72d24a152418b08c854aa28d71c8b78cd883c738 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Sun, 17 Aug 2025 23:57:30 +0100 Subject: [PATCH 573/628] RULE-8-2-7 - NoPointerToIntegralCast Detects casts that convert pointer types to integral types, which can make code harder to understand and may break pointer tracking in analysis tools. [a] --- .../RULE-8-2-7/NoPointerToIntegralCast.ql | 25 ++++++ .../NoPointerToIntegralCast.expected | 17 +++++ .../RULE-8-2-7/NoPointerToIntegralCast.qlref | 1 + cpp/misra/test/rules/RULE-8-2-7/test.cpp | 76 +++++++++++++++++++ 4 files changed, 119 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql create mode 100644 cpp/misra/test/rules/RULE-8-2-7/NoPointerToIntegralCast.expected create mode 100644 cpp/misra/test/rules/RULE-8-2-7/NoPointerToIntegralCast.qlref create mode 100644 cpp/misra/test/rules/RULE-8-2-7/test.cpp diff --git a/cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql b/cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql new file mode 100644 index 0000000000..e38467bd40 --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql @@ -0,0 +1,25 @@ +/** + * @id cpp/misra/no-pointer-to-integral-cast + * @name RULE-8-2-7: A cast should not convert a pointer type to an integral type + * @description Casting between pointer types and integral types makes code behavior harder to + * understand and may cause pointer tracking tools to become unreliable. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-2-7 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra + +from Cast cast, Type sourceType, Type targetType +where + not isExcluded(cast, Conversions2Package::noPointerToIntegralCastQuery()) and + sourceType = cast.getExpr().getType().getUnspecifiedType() and + targetType = cast.getType().getUnspecifiedType() and + (sourceType instanceof PointerType or sourceType instanceof FunctionPointerType) and + targetType instanceof IntegralType +select cast, "Cast converts pointer type to integral type '" + targetType.toString() + "'." diff --git a/cpp/misra/test/rules/RULE-8-2-7/NoPointerToIntegralCast.expected b/cpp/misra/test/rules/RULE-8-2-7/NoPointerToIntegralCast.expected new file mode 100644 index 0000000000..7a5f729206 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-7/NoPointerToIntegralCast.expected @@ -0,0 +1,17 @@ +| test.cpp:22:22:22:59 | reinterpret_cast... | Cast converts pointer type to integral type 'long'. | +| test.cpp:23:23:23:61 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned long'. | +| test.cpp:24:20:24:55 | reinterpret_cast... | Cast converts pointer type to integral type 'signed char'. | +| test.cpp:25:21:25:57 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned char'. | +| test.cpp:26:21:26:57 | reinterpret_cast... | Cast converts pointer type to integral type 'signed short'. | +| test.cpp:27:22:27:59 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned short'. | +| test.cpp:28:21:28:59 | reinterpret_cast... | Cast converts pointer type to integral type 'signed int'. | +| test.cpp:29:22:29:61 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned int'. | +| test.cpp:30:22:30:61 | reinterpret_cast... | Cast converts pointer type to integral type 'signed long'. | +| test.cpp:32:7:32:47 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned long'. | +| test.cpp:33:14:33:42 | reinterpret_cast... | Cast converts pointer type to integral type 'long'. | +| test.cpp:34:23:34:60 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned long'. | +| test.cpp:35:13:35:40 | reinterpret_cast... | Cast converts pointer type to integral type 'int'. | +| test.cpp:36:22:36:58 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned int'. | +| test.cpp:64:7:64:47 | reinterpret_cast... | Cast converts pointer type to integral type 'long'. | +| test.cpp:66:7:66:48 | reinterpret_cast... | Cast converts pointer type to integral type 'unsigned long'. | +| test.cpp:67:14:67:45 | reinterpret_cast... | Cast converts pointer type to integral type 'long'. | diff --git a/cpp/misra/test/rules/RULE-8-2-7/NoPointerToIntegralCast.qlref b/cpp/misra/test/rules/RULE-8-2-7/NoPointerToIntegralCast.qlref new file mode 100644 index 0000000000..c46a48360b --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-7/NoPointerToIntegralCast.qlref @@ -0,0 +1 @@ +rules/RULE-8-2-7/NoPointerToIntegralCast.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-7/test.cpp b/cpp/misra/test/rules/RULE-8-2-7/test.cpp new file mode 100644 index 0000000000..6f89118c21 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-7/test.cpp @@ -0,0 +1,76 @@ +#include + +struct S { + int m1; +}; + +class C { +public: + int m1; +}; + +void test_pointer_to_integral_casts() { + S s; + S *s_ptr = &s; + C c; + C *c_ptr = &c; + int l1 = 42; + int *int_ptr = &l1; + void *void_ptr = &l1; + + // Non-compliant cases - pointer to integral type casts + std::intptr_t l2 = reinterpret_cast(s_ptr); // NON_COMPLIANT + std::uintptr_t l3 = reinterpret_cast(s_ptr); // NON_COMPLIANT + std::int8_t l4 = reinterpret_cast(s_ptr); // NON_COMPLIANT + std::uint8_t l5 = reinterpret_cast(s_ptr); // NON_COMPLIANT + std::int16_t l6 = reinterpret_cast(c_ptr); // NON_COMPLIANT + std::uint16_t l7 = reinterpret_cast(c_ptr); // NON_COMPLIANT + std::int32_t l8 = reinterpret_cast(int_ptr); // NON_COMPLIANT + std::uint32_t l9 = reinterpret_cast(int_ptr); // NON_COMPLIANT + std::int64_t l10 = reinterpret_cast(void_ptr); // NON_COMPLIANT + std::uint64_t l11 = + reinterpret_cast(void_ptr); // NON_COMPLIANT + long l12 = reinterpret_cast(s_ptr); // NON_COMPLIANT + unsigned long l13 = reinterpret_cast(s_ptr); // NON_COMPLIANT + int l14 = reinterpret_cast(s_ptr); // NON_COMPLIANT + unsigned int l15 = reinterpret_cast(s_ptr); // NON_COMPLIANT +} + +void test_compliant_pointer_operations() { + S s; + S *s_ptr = &s; + C c; + C *c_ptr = &c; + int l1 = 42; + int *int_ptr = &l1; + + // Compliant cases - pointer to pointer casts + void *l16 = static_cast(s_ptr); // COMPLIANT + S *l17 = static_cast(static_cast(s_ptr)); // COMPLIANT + C *l18 = reinterpret_cast(s_ptr); // COMPLIANT + + // Compliant cases - using pointers without casting to integral + S *l19 = s_ptr; // COMPLIANT + if (s_ptr != nullptr) { // COMPLIANT + s_ptr->m1 = 10; // COMPLIANT + } +} + +void test_function_pointer_to_integral() { + void (*func_ptr)() = nullptr; + + // Non-compliant cases - function pointer to integral type casts + std::intptr_t l20 = + reinterpret_cast(func_ptr); // NON_COMPLIANT + std::uintptr_t l21 = + reinterpret_cast(func_ptr); // NON_COMPLIANT + long l22 = reinterpret_cast(func_ptr); // NON_COMPLIANT +} + +void test_member_pointer_to_integral() { + // Member pointer to integral type casts are forbidden by the rule, but also + // prohibited by the compiler, e.g. + // int S::*member_ptr = &S::m1; + // std::intptr_t l23 = reinterpret_cast(member_ptr); + // std::uintptr_t l24 = reinterpret_cast(member_ptr); +} \ No newline at end of file From 8804fecce236fed51212d34a2ea69133f4f59e40 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 18 Aug 2025 00:11:39 +0100 Subject: [PATCH 574/628] RULE-8-2-8 - PointerToIntegralCast Detects pointer-to-integral casts that use types other than std::uintptr_t or std::intptr_t, which may not guarantee representation of all pointer values. [a] --- .../rules/RULE-8-2-8/PointerToIntegralCast.ql | 32 ++++++++ .../RULE-8-2-8/PointerToIntegralCast.expected | 9 ++ .../RULE-8-2-8/PointerToIntegralCast.qlref | 1 + cpp/misra/test/rules/RULE-8-2-8/test.cpp | 82 +++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql create mode 100644 cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.expected create mode 100644 cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.qlref create mode 100644 cpp/misra/test/rules/RULE-8-2-8/test.cpp diff --git a/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql b/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql new file mode 100644 index 0000000000..f7c2c4ffbd --- /dev/null +++ b/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql @@ -0,0 +1,32 @@ +/** + * @id cpp/misra/pointer-to-integral-cast + * @name RULE-8-2-8: An object pointer type shall not be cast to an integral type other than std::uintptr_t or + * @description Casting object pointers to integral types other than std::uintptr_t or std::intptr_t + * can lead to implementation-defined behavior and potential loss of pointer + * information. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-8-2-8 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +from ReinterpretCast cast, Type targetType, Type sourceType +where + not isExcluded(cast, Conversions2Package::pointerToIntegralCastQuery()) and + sourceType = cast.getExpr().getType().getUnspecifiedType() and + sourceType instanceof PointerType and + targetType = cast.getType() and + targetType.getUnspecifiedType() instanceof IntegralType and + not ( + targetType.(UserType).hasGlobalOrStdName("uintptr_t") or + targetType.(UserType).hasGlobalOrStdName("intptr_t") + ) +select cast, + "Cast of object pointer type to integral type '" + targetType.toString() + + "' instead of 'std::uintptr_t' or 'std::intptr_t'." diff --git a/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.expected b/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.expected new file mode 100644 index 0000000000..7a541ff406 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.expected @@ -0,0 +1,9 @@ +| test.cpp:37:13:37:47 | reinterpret_cast... | Cast of object pointer type to integral type 'unsigned long' instead of 'std::uintptr_t' or 'std::intptr_t'. | +| test.cpp:42:13:42:46 | reinterpret_cast... | Cast of object pointer type to integral type 'unsigned int' instead of 'std::uintptr_t' or 'std::intptr_t'. | +| test.cpp:47:13:47:38 | reinterpret_cast... | Cast of object pointer type to integral type 'long' instead of 'std::uintptr_t' or 'std::intptr_t'. | +| test.cpp:52:13:52:45 | reinterpret_cast... | Cast of object pointer type to integral type 'size_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | +| test.cpp:57:13:57:43 | reinterpret_cast... | Cast of object pointer type to integral type 'hashPtr_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | +| test.cpp:62:13:62:42 | reinterpret_cast... | Cast of object pointer type to integral type 'MyIntPtr' instead of 'std::uintptr_t' or 'std::intptr_t'. | +| test.cpp:67:13:67:35 | reinterpret_cast... | Cast of object pointer type to integral type 'unsigned long' instead of 'std::uintptr_t' or 'std::intptr_t'. | +| test.cpp:72:13:72:47 | reinterpret_cast... | Cast of object pointer type to integral type 'uint64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | +| test.cpp:77:13:77:46 | reinterpret_cast... | Cast of object pointer type to integral type 'int64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | diff --git a/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.qlref b/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.qlref new file mode 100644 index 0000000000..ed46d08aeb --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.qlref @@ -0,0 +1 @@ +rules/RULE-8-2-8/PointerToIntegralCast.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-8-2-8/test.cpp b/cpp/misra/test/rules/RULE-8-2-8/test.cpp new file mode 100644 index 0000000000..75b3d7cb88 --- /dev/null +++ b/cpp/misra/test/rules/RULE-8-2-8/test.cpp @@ -0,0 +1,82 @@ +#include +#include +struct S {}; +class C {}; + +void *g1 = nullptr; +S *g2 = nullptr; +const int *g3 = nullptr; + +using hashPtr_t = std::uintptr_t; +using MyIntPtr = std::intptr_t; + +void test_compliant_uintptr_t_cast() { + S *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // COMPLIANT +} + +void test_compliant_intptr_t_cast() { + C *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // COMPLIANT +} + +void test_compliant_void_pointer_cast() { + void *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // COMPLIANT + auto l3 = reinterpret_cast(l1); // COMPLIANT +} + +void test_compliant_const_pointer_cast() { + const int *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // COMPLIANT + auto l3 = reinterpret_cast(l1); // COMPLIANT +} + +void test_non_compliant_unsigned_long_cast() { + S *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_non_compliant_unsigned_int_cast() { + S *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_non_compliant_long_cast() { + C *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_non_compliant_size_t_cast() { + void *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_non_compliant_typedef_cast() { + S *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_non_compliant_using_alias_cast() { + C *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +template void test_non_compliant_template_cast() { + S *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_non_compliant_uint64_t_cast() { + S *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_non_compliant_int64_t_cast() { + void *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT +} + +void test_instantiate_template() { + test_non_compliant_template_cast(); +} \ No newline at end of file From 29f1bbdc87e523c9d4f44681d23f95a4b802628a Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 18 Aug 2025 14:33:07 +0100 Subject: [PATCH 575/628] RULE-9-2-1 - NoStandaloneTypeCastExpression Detects explicit type conversions using functional notation as standalone expression statements that create immediately-destroyed temporary objects. [a] --- .../NoStandaloneTypeCastExpression.ql | 36 +++++++++ .../NoStandaloneTypeCastExpression.expected | 7 ++ .../NoStandaloneTypeCastExpression.qlref | 1 + cpp/misra/test/rules/RULE-9-2-1/test.cpp | 74 +++++++++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 cpp/misra/src/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.ql create mode 100644 cpp/misra/test/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.expected create mode 100644 cpp/misra/test/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.qlref create mode 100644 cpp/misra/test/rules/RULE-9-2-1/test.cpp diff --git a/cpp/misra/src/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.ql b/cpp/misra/src/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.ql new file mode 100644 index 0000000000..ce1cde0b59 --- /dev/null +++ b/cpp/misra/src/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.ql @@ -0,0 +1,36 @@ +/** + * @id cpp/misra/no-standalone-type-cast-expression + * @name RULE-9-2-1: An explicit type conversion shall not be an expression statement + * @description Using an explicit type conversion as an expression statement creates a temporary + * object that is immediately discarded, which can lead to unintended premature + * resource cleanup. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-9-2-1 + * scope/single-translation-unit + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +from ExprStmt stmt, Expr expr +where + not isExcluded(stmt, Conversions2Package::noStandaloneTypeCastExpressionQuery()) and + expr = stmt.getExpr() and + ( + // Explicit conversions which call a constructor + expr instanceof ConstructorCall + or + // Cast expressions using functional notation + expr instanceof Cast + ) and + // Exclude init-statements in if/for statements + // This is because the extractor has a bug as of 2.20.7 which means it does not parse + // these two cases separately. We choose to ignore if statements, which can cause false + // negatives, but will prevent false positives + not exists(IfStmt ifStmt | ifStmt.getInitialization() = stmt) +select stmt, + "Explicit type conversion used as expression statement creates temporary object that is immediately discarded." diff --git a/cpp/misra/test/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.expected b/cpp/misra/test/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.expected new file mode 100644 index 0000000000..eb58109070 --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.expected @@ -0,0 +1,7 @@ +| test.cpp:20:3:20:35 | ExprStmt | Explicit type conversion used as expression statement creates temporary object that is immediately discarded. | +| test.cpp:21:3:21:23 | ExprStmt | Explicit type conversion used as expression statement creates temporary object that is immediately discarded. | +| test.cpp:22:3:22:27 | ExprStmt | Explicit type conversion used as expression statement creates temporary object that is immediately discarded. | +| test.cpp:23:3:23:34 | ExprStmt | Explicit type conversion used as expression statement creates temporary object that is immediately discarded. | +| test.cpp:42:8:42:40 | ExprStmt | Explicit type conversion used as expression statement creates temporary object that is immediately discarded. | +| test.cpp:66:3:66:17 | ExprStmt | Explicit type conversion used as expression statement creates temporary object that is immediately discarded. | +| test.cpp:67:3:67:17 | ExprStmt | Explicit type conversion used as expression statement creates temporary object that is immediately discarded. | diff --git a/cpp/misra/test/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.qlref b/cpp/misra/test/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.qlref new file mode 100644 index 0000000000..5aec9cdada --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.qlref @@ -0,0 +1 @@ +rules/RULE-9-2-1/NoStandaloneTypeCastExpression.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-9-2-1/test.cpp b/cpp/misra/test/rules/RULE-9-2-1/test.cpp new file mode 100644 index 0000000000..75aed0a90e --- /dev/null +++ b/cpp/misra/test/rules/RULE-9-2-1/test.cpp @@ -0,0 +1,74 @@ +#include +#include +#include + +std::mutex g1; +std::mutex g2; + +void f1(std::unique_lock l1) { + // Function parameter for testing compliant cases +} + +void test_explicit_type_conversion_expression_statement() { + // Compliant cases - declarations + std::unique_lock l1(g1); // COMPLIANT + std::unique_lock l2{g1}; // COMPLIANT + std::unique_lock(l3); // COMPLIANT - declaration with redundant + // parentheses around variable name + + // Non-compliant cases - explicit type conversions as expression statements + std::unique_lock{g1}; // NON_COMPLIANT + std::scoped_lock{g1}; // NON_COMPLIANT + std::scoped_lock(g1, g2); // NON_COMPLIANT + std::lock_guard{g1}; // NON_COMPLIANT + + // Compliant cases - type conversions not as expression statements + f1(std::unique_lock(g1)); // COMPLIANT + f1(std::unique_lock{g1}); // COMPLIANT + auto l4 = std::unique_lock(g1); // COMPLIANT + auto l5 = std::unique_lock{g1}; // COMPLIANT + + // The extractor has a bug as of 2.20.7 which means it does not parse + // these two cases separately. We choose to ignore if statements, which + // can cause false negatives, but will prevent false positives + if (std::unique_lock(g1); true) { // COMPLIANT - init-statement + } + if (std::unique_lock{g1}; true) { // NON_COMPLIANT[FALSE_NEGATIVE] + } + + for (std::unique_lock(g1);;) { // COMPLIANT - init-statement + break; + } + for (std::unique_lock{g1};;) { // NON_COMPLIANT - init-statement + break; + } +} + +void test_primitive_type_conversions() { + // Non-compliant cases with primitive types + std::int32_t(42); // NON_COMPLIANT + float(3.14); // NON_COMPLIANT + double(2.71); // NON_COMPLIANT + bool(true); // NON_COMPLIANT + + // Compliant cases + auto l1 = std::int32_t(42); // COMPLIANT + auto l2 = float(3.14); // COMPLIANT + std::int32_t l3(42); // COMPLIANT - declaration + std::int32_t l4{42}; // COMPLIANT - declaration +} + +struct CustomType { + CustomType(std::int32_t) {} +}; +void test_custom_types() { + // Non-compliant cases + CustomType(42); // NON_COMPLIANT + CustomType{42}; // NON_COMPLIANT + + // Compliant cases + CustomType l1(42); // COMPLIANT - declaration + CustomType l2{42}; // COMPLIANT - declaration + auto l3 = CustomType(42); // COMPLIANT + auto l4 = CustomType{42}; // COMPLIANT +} \ No newline at end of file From d6456703581e2120543ebf693721557ab842b1e6 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 18 Aug 2025 14:49:16 +0100 Subject: [PATCH 576/628] Update mutex to include scoped_lock stubs --- cpp/common/test/includes/standard-library/mutex.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cpp/common/test/includes/standard-library/mutex.h b/cpp/common/test/includes/standard-library/mutex.h index 4c49819ddd..d21042dcf7 100644 --- a/cpp/common/test/includes/standard-library/mutex.h +++ b/cpp/common/test/includes/standard-library/mutex.h @@ -1,6 +1,6 @@ #ifndef _GHLIBCPP_MUTEX #define _GHLIBCPP_MUTEX -#include "chrono.h" +#include namespace std { @@ -77,6 +77,14 @@ template class lock_guard { mutex_type &_m; }; +template class scoped_lock { +public: + explicit scoped_lock(MutexTypes &...m); + scoped_lock(const scoped_lock &) = delete; + scoped_lock &operator=(const scoped_lock &) = delete; + ~scoped_lock(); +}; + } // namespace std #endif // _GHLIBCPP_MUTEX From 5efc380eddfdb6781872a648c3c8fffc6e9a1315 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 18 Aug 2025 14:49:29 +0100 Subject: [PATCH 577/628] Rule 8.2.6: Query improvements - Simplify the query implementation - Improve query message --- .../RULE-8-2-6/IntToPointerCastProhibited.ql | 29 +++++++++---------- .../IntToPointerCastProhibited.expected | 22 +++++++------- 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql b/cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql index dd1c7d15a4..0ab4c96f2d 100644 --- a/cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql +++ b/cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql @@ -15,29 +15,26 @@ import cpp import codingstandards.cpp.misra -from Cast cast, Type sourceType, Type targetType +from Cast cast, Type sourceType, PointerType targetType, string typeKind where not isExcluded(cast, Conversions2Package::intToPointerCastProhibitedQuery()) and - sourceType = cast.getExpr().getType().stripTopLevelSpecifiers() and - targetType = cast.getType().stripTopLevelSpecifiers() and - targetType instanceof PointerType and - not targetType instanceof FunctionPointerType and - not ( - // Exception: casts between void pointers are allowed - targetType.(PointerType).getBaseType().stripTopLevelSpecifiers() instanceof VoidType and - sourceType instanceof PointerType and - sourceType.(PointerType).getBaseType().stripTopLevelSpecifiers() instanceof VoidType - ) and + sourceType = cast.getExpr().getType().getUnspecifiedType() and + targetType = cast.getType().getUnspecifiedType() and ( // Integral types - sourceType instanceof IntegralType + sourceType instanceof IntegralType and + typeKind = "integral" or // Enumerated types - sourceType instanceof Enum + sourceType instanceof Enum and + typeKind = "enumerated" or // Pointer to void type - sourceType instanceof PointerType and - sourceType.(PointerType).getBaseType().stripTopLevelSpecifiers() instanceof VoidType + sourceType.(PointerType).getBaseType() instanceof VoidType and + typeKind = "pointer to void" and + // Exception: casts between void pointers are allowed + not targetType.getBaseType() instanceof VoidType ) select cast, - "Cast from '" + sourceType.toString() + "' to '" + targetType.toString() + "' is prohibited." + "Cast from " + typeKind + " type '" + cast.getExpr().getType() + "' to pointer type '" + + cast.getType() + "'." diff --git a/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.expected b/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.expected index 806c70a661..18accdc95e 100644 --- a/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.expected +++ b/cpp/misra/test/rules/RULE-8-2-6/IntToPointerCastProhibited.expected @@ -1,11 +1,11 @@ -| test.cpp:15:20:15:53 | reinterpret_cast... | Cast from 'signed int' to 'TestStruct *' is prohibited. | -| test.cpp:16:20:16:53 | reinterpret_cast... | Cast from 'signed long' to 'TestStruct *' is prohibited. | -| test.cpp:17:22:17:57 | reinterpret_cast... | Cast from 'signed long' to 'int32_t *' is prohibited. | -| test.cpp:24:20:24:53 | reinterpret_cast... | Cast from 'TestEnum' to 'TestStruct *' is prohibited. | -| test.cpp:25:22:25:57 | reinterpret_cast... | Cast from 'TestEnum' to 'int32_t *' is prohibited. | -| test.cpp:32:20:32:48 | static_cast... | Cast from 'void *' to 'TestStruct *' is prohibited. | -| test.cpp:33:20:33:53 | reinterpret_cast... | Cast from 'void *' to 'TestStruct *' is prohibited. | -| test.cpp:34:22:34:52 | static_cast... | Cast from 'void *' to 'int32_t *' is prohibited. | -| test.cpp:35:22:35:57 | reinterpret_cast... | Cast from 'void *' to 'int32_t *' is prohibited. | -| test.cpp:43:14:43:41 | reinterpret_cast... | Cast from 'signed int' to 'void *' is prohibited. | -| test.cpp:44:14:44:41 | reinterpret_cast... | Cast from 'signed long' to 'void *' is prohibited. | +| test.cpp:15:20:15:53 | reinterpret_cast... | Cast from integral type 'int32_t' to pointer type 'TestStruct *'. | +| test.cpp:16:20:16:53 | reinterpret_cast... | Cast from integral type 'int64_t' to pointer type 'TestStruct *'. | +| test.cpp:17:22:17:57 | reinterpret_cast... | Cast from integral type 'int64_t' to pointer type 'int32_t *'. | +| test.cpp:24:20:24:53 | reinterpret_cast... | Cast from enumerated type 'TestEnum' to pointer type 'TestStruct *'. | +| test.cpp:25:22:25:57 | reinterpret_cast... | Cast from enumerated type 'TestEnum' to pointer type 'int32_t *'. | +| test.cpp:32:20:32:48 | static_cast... | Cast from pointer to void type 'void *' to pointer type 'TestStruct *'. | +| test.cpp:33:20:33:53 | reinterpret_cast... | Cast from pointer to void type 'void *' to pointer type 'TestStruct *'. | +| test.cpp:34:22:34:52 | static_cast... | Cast from pointer to void type 'void *' to pointer type 'int32_t *'. | +| test.cpp:35:22:35:57 | reinterpret_cast... | Cast from pointer to void type 'void *' to pointer type 'int32_t *'. | +| test.cpp:43:14:43:41 | reinterpret_cast... | Cast from integral type 'int32_t' to pointer type 'void *'. | +| test.cpp:44:14:44:41 | reinterpret_cast... | Cast from integral type 'int64_t' to pointer type 'void *'. | From b0d18ceaf99594620012e7ffbe48a603aaf0d56a Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 18 Aug 2025 14:52:11 +0100 Subject: [PATCH 578/628] Rule 8.2.7: Simplify CodeQL --- cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql b/cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql index e38467bd40..3b477cce66 100644 --- a/cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql +++ b/cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql @@ -15,11 +15,10 @@ import cpp import codingstandards.cpp.misra -from Cast cast, Type sourceType, Type targetType +from Cast cast, Type sourceType, IntegralType targetType where not isExcluded(cast, Conversions2Package::noPointerToIntegralCastQuery()) and sourceType = cast.getExpr().getType().getUnspecifiedType() and targetType = cast.getType().getUnspecifiedType() and - (sourceType instanceof PointerType or sourceType instanceof FunctionPointerType) and - targetType instanceof IntegralType -select cast, "Cast converts pointer type to integral type '" + targetType.toString() + "'." + (sourceType instanceof PointerType or sourceType instanceof FunctionPointerType) +select cast, "Cast converts pointer type to integral type '" + targetType + "'." From 51ef7bd7426013723d6dfcda525cfb9408578c8d Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 18 Aug 2025 14:56:55 +0100 Subject: [PATCH 579/628] Rule 8.2.8: Improve CodeQL query - Remove redundant code - Use stripSpecifiers(..) to check for use of (u)intptr_t. --- .../src/rules/RULE-8-2-8/PointerToIntegralCast.ql | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql b/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql index f7c2c4ffbd..668b3103d6 100644 --- a/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql +++ b/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql @@ -15,18 +15,15 @@ import cpp import codingstandards.cpp.misra +import codingstandards.cpp.types.Type -from ReinterpretCast cast, Type targetType, Type sourceType +from ReinterpretCast cast, PointerType sourceType, Type targetType where not isExcluded(cast, Conversions2Package::pointerToIntegralCastQuery()) and sourceType = cast.getExpr().getType().getUnspecifiedType() and - sourceType instanceof PointerType and targetType = cast.getType() and targetType.getUnspecifiedType() instanceof IntegralType and - not ( - targetType.(UserType).hasGlobalOrStdName("uintptr_t") or - targetType.(UserType).hasGlobalOrStdName("intptr_t") - ) + not stripSpecifiers(targetType).(UserType).hasGlobalOrStdName(["uintptr_t", "intptr_t"]) select cast, - "Cast of object pointer type to integral type '" + targetType.toString() + + "Cast of object pointer type to integral type '" + targetType + "' instead of 'std::uintptr_t' or 'std::intptr_t'." From 550f38c366ce21b00392859eb5575736c751b576 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 18 Aug 2025 14:58:53 +0100 Subject: [PATCH 580/628] Rule 9.2.1: Add proviso for if statement initializers --- rule_packages/cpp/Conversions2.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rule_packages/cpp/Conversions2.json b/rule_packages/cpp/Conversions2.json index 6c178effc6..4258fd16bf 100644 --- a/rule_packages/cpp/Conversions2.json +++ b/rule_packages/cpp/Conversions2.json @@ -116,7 +116,10 @@ "short_name": "NoStandaloneTypeCastExpression", "tags": [ "scope/single-translation-unit" - ] + ], + "implementation_scope": { + "description": "Expression statements in if statement initializers are not currently supported." + } } ], "title": "An explicit type conversion shall not be an expression statement" From 3ab9104e4a4d6325454a8561d89d18b451c8169a Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Mon, 18 Aug 2025 15:06:34 +0100 Subject: [PATCH 581/628] Add change note for AlertReporting behaviour --- change_notes/2025-08-18-fix-alert-reporting.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 change_notes/2025-08-18-fix-alert-reporting.md diff --git a/change_notes/2025-08-18-fix-alert-reporting.md b/change_notes/2025-08-18-fix-alert-reporting.md new file mode 100644 index 0000000000..fc1883ed7a --- /dev/null +++ b/change_notes/2025-08-18-fix-alert-reporting.md @@ -0,0 +1,3 @@ + - `RULE-1-2`, `RULE-23-3`, `RULE-23-5`, `RULE-23-6`: + - Results that occur in nested macro invocations are now reported in the macro that defines the contravening code, rather than the macro which is first expanded. + - Results the occur in arguments to macro invocations are now reported in at the macro invocation site, instead of the macro definition site. \ No newline at end of file From 1d0736eddf82f8296a980c7f3193ea00f19e8791 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 17:15:45 +0100 Subject: [PATCH 582/628] PointerToAVirtualBaseClass: Support casts from parents of virtual base classes. --- .../2025-08-15-m5-2-2-virtual-base.md | 4 +++- ...interToAVirtualBaseClassCastToAPointer.qll | 22 +++++++++++++------ ...ToAVirtualBaseClassCastToAPointer.expected | 7 +++--- .../test.cpp | 14 +++++++++++- 4 files changed, 35 insertions(+), 12 deletions(-) diff --git a/change_notes/2025-08-15-m5-2-2-virtual-base.md b/change_notes/2025-08-15-m5-2-2-virtual-base.md index 072ad41ea6..f57b630ad9 100644 --- a/change_notes/2025-08-15-m5-2-2-virtual-base.md +++ b/change_notes/2025-08-15-m5-2-2-virtual-base.md @@ -1,3 +1,5 @@ - `M5-2-2` - `PointerToAVirtualBaseClassCastToAPointer.ql`: - Report casts where the from or to types are typedefs to virtual base classes or derived classes. - - Report casts to a reference type which is a derived type. \ No newline at end of file + - Report casts to a reference type which is a derived type. + - Report casts where the base class is the parent of a virtual base class. + - The alert message has been updated to refer to the virtual base class derivation. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll b/cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll index 207b6da415..6993778a4d 100644 --- a/cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll +++ b/cpp/common/src/codingstandards/cpp/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.qll @@ -12,23 +12,31 @@ abstract class PointerToAVirtualBaseClassCastToAPointerSharedQuery extends Query Query getQuery() { result instanceof PointerToAVirtualBaseClassCastToAPointerSharedQuery } -query predicate problems(Cast cast, string message) { - exists(VirtualBaseClass castFrom, Class castTo | +query predicate problems( + Cast cast, string message, VirtualClassDerivation derivation, string derivationDescription +) { + exists(Class castFrom, VirtualBaseClass virtualBaseClass, Class castTo, string type | not isExcluded(cast, getQuery()) and not cast instanceof DynamicCast and - castTo = castFrom.getADerivedClass+() and + castTo = virtualBaseClass.getADerivedClass+() and + virtualBaseClass = castFrom.getADerivedClass*() and + derivation = virtualBaseClass.getAVirtualDerivation() and + derivation.getDerivedClass().getADerivedClass*() = castTo and + derivationDescription = "derived through virtual base class " + virtualBaseClass.getName() and message = - "A pointer to virtual base class " + castFrom.getName() + - " is not cast to a pointer of derived class " + castTo.getName() + " using a dynamic_cast." + "dynamic_cast not used for cast from " + type + " to base class " + castFrom.getName() + + " to derived class " + castTo.getName() + " which is $@." | // Pointer cast castFrom = cast.getExpr().getType().stripTopLevelSpecifiers().(PointerType).getBaseType() and - cast.getType().stripTopLevelSpecifiers().(PointerType).getBaseType() = castTo + cast.getType().stripTopLevelSpecifiers().(PointerType).getBaseType() = castTo and + type = "pointer" or // Reference type cast castFrom = cast.getExpr().getType().stripTopLevelSpecifiers() and // Not actually represented as a reference type in our model - instead as the // type itself - cast.getType().stripTopLevelSpecifiers() = castTo + cast.getType().stripTopLevelSpecifiers() = castTo and + type = "reference" ) } diff --git a/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.expected b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.expected index 7f64ab5d1c..37e2557b81 100644 --- a/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.expected +++ b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/PointerToAVirtualBaseClassCastToAPointer.expected @@ -1,3 +1,4 @@ -| test.cpp:36:12:36:37 | reinterpret_cast... | A pointer to virtual base class C1 is not cast to a pointer of derived class C2 using a dynamic_cast. | -| test.cpp:42:12:42:38 | reinterpret_cast... | A pointer to virtual base class C1 is not cast to a pointer of derived class C2 using a dynamic_cast. | -| test.cpp:48:17:48:48 | reinterpret_cast... | A pointer to virtual base class C1 is not cast to a pointer of derived class C2 using a dynamic_cast. | +| test.cpp:41:12:41:37 | reinterpret_cast... | dynamic_cast not used for cast from pointer to base class C1 to derived class C2 which is $@. | test.cpp:11:12:11:28 | derivation | derived through virtual base class C1 | +| test.cpp:47:12:47:38 | reinterpret_cast... | dynamic_cast not used for cast from reference to base class C1 to derived class C2 which is $@. | test.cpp:11:12:11:28 | derivation | derived through virtual base class C1 | +| test.cpp:53:17:53:48 | reinterpret_cast... | dynamic_cast not used for cast from reference to base class C1 to derived class C2 which is $@. | test.cpp:11:12:11:28 | derivation | derived through virtual base class C1 | +| test.cpp:86:12:86:37 | reinterpret_cast... | dynamic_cast not used for cast from pointer to base class C0 to derived class C2 which is $@. | test.cpp:11:12:11:28 | derivation | derived through virtual base class C1 | diff --git a/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/test.cpp b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/test.cpp index 419bc0764e..ab4666069e 100644 --- a/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/test.cpp +++ b/cpp/common/test/rules/pointertoavirtualbaseclasscasttoapointer/test.cpp @@ -1,4 +1,9 @@ -class C1 { +class C0 { +public: + virtual ~C0() {} +}; + +class C1 : public C0 { public: virtual ~C1() {} }; @@ -72,4 +77,11 @@ void test_static_cast_reference_non_compliant() { C1 *p1 = &l1; // C2 &l2 = static_cast(*p1); // NON_COMPLIANT - prohibited by the // compiler +} + +void test_skipped_base_class() { + C2 l1; + C0 *p1 = &l1; + C2 *l2 = dynamic_cast(p1); // COMPLIANT + C2 *p2 = reinterpret_cast(p1); // NON_COMPLIANT } \ No newline at end of file From 6bce7f8538fa50a72851392a869da2596dd24405 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 21 Aug 2025 23:22:16 +0100 Subject: [PATCH 583/628] Rule 8.2.8: Handle results in templates per rule --- .../rules/RULE-8-2-8/PointerToIntegralCast.ql | 58 ++++++++++++++++--- .../RULE-8-2-8/PointerToIntegralCast.expected | 22 ++++--- cpp/misra/test/rules/RULE-8-2-8/test.cpp | 23 ++++++-- 3 files changed, 82 insertions(+), 21 deletions(-) diff --git a/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql b/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql index 668b3103d6..8a39c6bea4 100644 --- a/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql +++ b/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql @@ -17,13 +17,55 @@ import cpp import codingstandards.cpp.misra import codingstandards.cpp.types.Type -from ReinterpretCast cast, PointerType sourceType, Type targetType +class InvalidReinterpretCast extends ReinterpretCast { + InvalidReinterpretCast() { + this.getExpr().getType().stripTopLevelSpecifiers() instanceof PointerType and + this.getType().getUnspecifiedType() instanceof IntegralType and + not stripSpecifiers(this.getType()).(UserType).hasGlobalOrStdName(["uintptr_t", "intptr_t"]) + } +} + +from + InvalidReinterpretCast cast, string message, Element optionalTemplateUseSite, + string optionalTemplateUseSiteString where not isExcluded(cast, Conversions2Package::pointerToIntegralCastQuery()) and - sourceType = cast.getExpr().getType().getUnspecifiedType() and - targetType = cast.getType() and - targetType.getUnspecifiedType() instanceof IntegralType and - not stripSpecifiers(targetType).(UserType).hasGlobalOrStdName(["uintptr_t", "intptr_t"]) -select cast, - "Cast of object pointer type to integral type '" + targetType + - "' instead of 'std::uintptr_t' or 'std::intptr_t'." + // Where a result occurs in both the instantiated and uninstantiated template, + // prefer the uninstantiated version. + not exists(InvalidReinterpretCast otherCast | + otherCast.getLocation() = cast.getLocation() and + not otherCast = cast and + otherCast.isFromUninstantiatedTemplate(_) + ) and + if not cast.isFromTemplateInstantiation(_) + then + // Either not in a template, or appears in the uninstantiated template and is + // therefore not argument dependent. + message = + "Cast of object pointer type to integral type '" + cast.getType() + + "' instead of 'std::uintptr_t' or 'std::intptr_t'." and + optionalTemplateUseSite = cast and + optionalTemplateUseSiteString = "" + else + // This is from a template instantiation and is dependent on a template argument, + // so attempt to identify the locations which instantiate the template. + exists(Element instantiation | + cast.isFromTemplateInstantiation(instantiation) and + message = "Cast of object pointer type to integral type inside $@." + | + optionalTemplateUseSite = instantiation.(ClassTemplateInstantiation).getATypeNameUse() and + optionalTemplateUseSiteString = + "instantiation of class " + instantiation.(ClassTemplateInstantiation).getName() + or + optionalTemplateUseSite = + instantiation.(FunctionTemplateInstantiation).getACallToThisFunction() and + optionalTemplateUseSiteString = + "call to instantiated template f of " + + instantiation.(FunctionTemplateInstantiation).getName() + or + optionalTemplateUseSite = instantiation.(VariableTemplateInstantiation).getAnAccess() and + optionalTemplateUseSiteString = + "reference to instantiated template variable " + + instantiation.(VariableTemplateInstantiation).getName() + ) +select cast, message, optionalTemplateUseSite, optionalTemplateUseSiteString diff --git a/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.expected b/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.expected index 7a541ff406..dd85d003c2 100644 --- a/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.expected +++ b/cpp/misra/test/rules/RULE-8-2-8/PointerToIntegralCast.expected @@ -1,9 +1,13 @@ -| test.cpp:37:13:37:47 | reinterpret_cast... | Cast of object pointer type to integral type 'unsigned long' instead of 'std::uintptr_t' or 'std::intptr_t'. | -| test.cpp:42:13:42:46 | reinterpret_cast... | Cast of object pointer type to integral type 'unsigned int' instead of 'std::uintptr_t' or 'std::intptr_t'. | -| test.cpp:47:13:47:38 | reinterpret_cast... | Cast of object pointer type to integral type 'long' instead of 'std::uintptr_t' or 'std::intptr_t'. | -| test.cpp:52:13:52:45 | reinterpret_cast... | Cast of object pointer type to integral type 'size_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | -| test.cpp:57:13:57:43 | reinterpret_cast... | Cast of object pointer type to integral type 'hashPtr_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | -| test.cpp:62:13:62:42 | reinterpret_cast... | Cast of object pointer type to integral type 'MyIntPtr' instead of 'std::uintptr_t' or 'std::intptr_t'. | -| test.cpp:67:13:67:35 | reinterpret_cast... | Cast of object pointer type to integral type 'unsigned long' instead of 'std::uintptr_t' or 'std::intptr_t'. | -| test.cpp:72:13:72:47 | reinterpret_cast... | Cast of object pointer type to integral type 'uint64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | -| test.cpp:77:13:77:46 | reinterpret_cast... | Cast of object pointer type to integral type 'int64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | +| test.cpp:35:13:35:47 | reinterpret_cast... | Cast of object pointer type to integral type 'unsigned long' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:35:13:35:47 | reinterpret_cast... | | +| test.cpp:40:13:40:46 | reinterpret_cast... | Cast of object pointer type to integral type 'unsigned int' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:40:13:40:46 | reinterpret_cast... | | +| test.cpp:45:13:45:38 | reinterpret_cast... | Cast of object pointer type to integral type 'long' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:45:13:45:38 | reinterpret_cast... | | +| test.cpp:50:13:50:45 | reinterpret_cast... | Cast of object pointer type to integral type 'size_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:50:13:50:45 | reinterpret_cast... | | +| test.cpp:55:13:55:43 | reinterpret_cast... | Cast of object pointer type to integral type 'hashPtr_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:55:13:55:43 | reinterpret_cast... | | +| test.cpp:60:13:60:42 | reinterpret_cast... | Cast of object pointer type to integral type 'MyIntPtr' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:60:13:60:42 | reinterpret_cast... | | +| test.cpp:65:13:65:35 | reinterpret_cast... | Cast of object pointer type to integral type inside $@. | test.cpp:94:3:94:50 | call to test_non_compliant_template_cast | call to instantiated template f of test_non_compliant_template_cast | +| test.cpp:67:13:67:47 | reinterpret_cast... | Cast of object pointer type to integral type 'uint64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:67:13:67:47 | reinterpret_cast... | | +| test.cpp:72:13:72:47 | reinterpret_cast... | Cast of object pointer type to integral type 'uint64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:72:13:72:47 | reinterpret_cast... | | +| test.cpp:77:13:77:46 | reinterpret_cast... | Cast of object pointer type to integral type 'int64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:77:13:77:46 | reinterpret_cast... | | +| test.cpp:84:15:84:37 | reinterpret_cast... | Cast of object pointer type to integral type inside $@. | test.cpp:95:48:95:48 | definition of x | instantiation of class TestNonCompliantTemplateCast | +| test.cpp:86:15:86:49 | reinterpret_cast... | Cast of object pointer type to integral type 'uint64_t' instead of 'std::uintptr_t' or 'std::intptr_t'. | test.cpp:86:15:86:49 | reinterpret_cast... | | +| test.cpp:91:23:91:45 | reinterpret_cast... | Cast of object pointer type to integral type inside $@. | test.cpp:96:3:96:35 | variable_template | reference to instantiated template variable variable_template | diff --git a/cpp/misra/test/rules/RULE-8-2-8/test.cpp b/cpp/misra/test/rules/RULE-8-2-8/test.cpp index 75b3d7cb88..6b3dbd7685 100644 --- a/cpp/misra/test/rules/RULE-8-2-8/test.cpp +++ b/cpp/misra/test/rules/RULE-8-2-8/test.cpp @@ -3,9 +3,7 @@ struct S {}; class C {}; -void *g1 = nullptr; -S *g2 = nullptr; -const int *g3 = nullptr; +S *g1 = nullptr; using hashPtr_t = std::uintptr_t; using MyIntPtr = std::intptr_t; @@ -64,7 +62,9 @@ void test_non_compliant_using_alias_cast() { template void test_non_compliant_template_cast() { S *l1 = nullptr; - auto l2 = reinterpret_cast(l1); // NON_COMPLIANT + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT + auto l3 = reinterpret_cast(l1); // COMPLIANT + auto l4 = reinterpret_cast(l1); // NON_COMPLIANT } void test_non_compliant_uint64_t_cast() { @@ -77,6 +77,21 @@ void test_non_compliant_int64_t_cast() { auto l2 = reinterpret_cast(l1); // NON_COMPLIANT } +template class TestNonCompliantTemplateCast { +public: + TestNonCompliantTemplateCast() { + S *l1 = nullptr; + auto l2 = reinterpret_cast(l1); // NON_COMPLIANT + auto l3 = reinterpret_cast(l1); // COMPLIANT + auto l4 = reinterpret_cast(l1); // NON_COMPLIANT + } +}; + +template +T variable_template = reinterpret_cast(g1); // NON_COMPLIANT + void test_instantiate_template() { test_non_compliant_template_cast(); + TestNonCompliantTemplateCast x{}; + variable_template; } \ No newline at end of file From 6e9ee92c521585412aa13f5fb4a346ef209d33b1 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 26 Aug 2025 21:45:29 +0100 Subject: [PATCH 584/628] Conversions2: Add rule tags --- .../VirtualBaseClassCastToDerived.ql | 1 + .../RULE-8-2-2/NoCStyleOrFunctionalCasts.ql | 2 ++ .../RULE-8-2-6/IntToPointerCastProhibited.ql | 2 ++ .../RULE-8-2-7/NoPointerToIntegralCast.ql | 2 ++ .../rules/RULE-8-2-8/PointerToIntegralCast.ql | 1 + .../NoStandaloneTypeCastExpression.ql | 1 + rule_packages/cpp/Conversions2.json | 21 +++++++++++++------ 7 files changed, 24 insertions(+), 6 deletions(-) diff --git a/cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql b/cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql index cd9cb150a8..6803483c95 100644 --- a/cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql +++ b/cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql @@ -8,6 +8,7 @@ * @problem.severity error * @tags external/misra/id/rule-8-2-1 * scope/single-translation-unit + * correctness * external/misra/enforcement/decidable * external/misra/obligation/required */ diff --git a/cpp/misra/src/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.ql b/cpp/misra/src/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.ql index 3515d0ec1b..441720c5e4 100644 --- a/cpp/misra/src/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.ql +++ b/cpp/misra/src/rules/RULE-8-2-2/NoCStyleOrFunctionalCasts.ql @@ -9,6 +9,8 @@ * @problem.severity error * @tags external/misra/id/rule-8-2-2 * scope/single-translation-unit + * readability + * correctness * external/misra/enforcement/decidable * external/misra/obligation/required */ diff --git a/cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql b/cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql index 0ab4c96f2d..0a97dc5359 100644 --- a/cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql +++ b/cpp/misra/src/rules/RULE-8-2-6/IntToPointerCastProhibited.ql @@ -8,6 +8,8 @@ * @problem.severity error * @tags external/misra/id/rule-8-2-6 * scope/single-translation-unit + * correctness + * maintainability * external/misra/enforcement/decidable * external/misra/obligation/required */ diff --git a/cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql b/cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql index 3b477cce66..dde10b0e40 100644 --- a/cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql +++ b/cpp/misra/src/rules/RULE-8-2-7/NoPointerToIntegralCast.ql @@ -8,6 +8,8 @@ * @problem.severity error * @tags external/misra/id/rule-8-2-7 * scope/single-translation-unit + * correctness + * maintainability * external/misra/enforcement/decidable * external/misra/obligation/advisory */ diff --git a/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql b/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql index 8a39c6bea4..357513305b 100644 --- a/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql +++ b/cpp/misra/src/rules/RULE-8-2-8/PointerToIntegralCast.ql @@ -9,6 +9,7 @@ * @problem.severity error * @tags external/misra/id/rule-8-2-8 * scope/single-translation-unit + * correctness * external/misra/enforcement/decidable * external/misra/obligation/required */ diff --git a/cpp/misra/src/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.ql b/cpp/misra/src/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.ql index ce1cde0b59..e3be797b9d 100644 --- a/cpp/misra/src/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.ql +++ b/cpp/misra/src/rules/RULE-9-2-1/NoStandaloneTypeCastExpression.ql @@ -9,6 +9,7 @@ * @problem.severity error * @tags external/misra/id/rule-9-2-1 * scope/single-translation-unit + * correctness * external/misra/enforcement/decidable * external/misra/obligation/required */ diff --git a/rule_packages/cpp/Conversions2.json b/rule_packages/cpp/Conversions2.json index 4258fd16bf..a4fc4f565d 100644 --- a/rule_packages/cpp/Conversions2.json +++ b/rule_packages/cpp/Conversions2.json @@ -14,7 +14,8 @@ "severity": "error", "short_name": "VirtualBaseClassCastToDerived", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "correctness" ], "shared_implementation_short_name": "PointerToAVirtualBaseClassCastToAPointer" } @@ -35,7 +36,9 @@ "severity": "error", "short_name": "NoCStyleOrFunctionalCasts", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "readability", + "correctness" ] } ], @@ -55,7 +58,9 @@ "severity": "error", "short_name": "IntToPointerCastProhibited", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "correctness", + "maintainability" ] } ], @@ -75,7 +80,9 @@ "severity": "error", "short_name": "NoPointerToIntegralCast", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "correctness", + "maintainability" ] } ], @@ -95,7 +102,8 @@ "severity": "error", "short_name": "PointerToIntegralCast", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "correctness" ] } ], @@ -115,7 +123,8 @@ "severity": "error", "short_name": "NoStandaloneTypeCastExpression", "tags": [ - "scope/single-translation-unit" + "scope/single-translation-unit", + "correctness" ], "implementation_scope": { "description": "Expression statements in if statement initializers are not currently supported." From 3477dcf1a2d9df92e1c767fdfd926df806052610 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Tue, 26 Aug 2025 21:49:10 +0100 Subject: [PATCH 585/628] Query formatting --- .../rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql | 3 ++- .../src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql b/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql index 57eda7f146..ad49d9e151 100644 --- a/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql +++ b/cpp/autosar/src/rules/M5-2-2/PointerToAVirtualBaseClassCastToAPointer.ql @@ -17,7 +17,8 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.rules.pointertoavirtualbaseclasscasttoapointer.PointerToAVirtualBaseClassCastToAPointer -class PointerToAVirtualBaseClassCastToAPointerQuery extends PointerToAVirtualBaseClassCastToAPointerSharedQuery { +class PointerToAVirtualBaseClassCastToAPointerQuery extends PointerToAVirtualBaseClassCastToAPointerSharedQuery +{ PointerToAVirtualBaseClassCastToAPointerQuery() { this = PointersPackage::pointerToAVirtualBaseClassCastToAPointerQuery() } diff --git a/cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql b/cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql index 6803483c95..858aaec42c 100644 --- a/cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql +++ b/cpp/misra/src/rules/RULE-8-2-1/VirtualBaseClassCastToDerived.ql @@ -17,7 +17,8 @@ import cpp import codingstandards.cpp.misra import codingstandards.cpp.rules.pointertoavirtualbaseclasscasttoapointer.PointerToAVirtualBaseClassCastToAPointer -class VirtualBaseClassCastToDerivedQuery extends PointerToAVirtualBaseClassCastToAPointerSharedQuery { +class VirtualBaseClassCastToDerivedQuery extends PointerToAVirtualBaseClassCastToAPointerSharedQuery +{ VirtualBaseClassCastToDerivedQuery() { this = Conversions2Package::virtualBaseClassCastToDerivedQuery() } From b7ae38e82281e0411068e9e13bc51c8457e5f687 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 27 Aug 2025 18:54:50 -0400 Subject: [PATCH 586/628] Add more cases and more vocabularies to reason about them --- .../LegacyForStatementsShouldBeSimple.ql | 234 +++++++++++++++++- cpp/misra/test/rules/RULE-9-5-1/test.cpp | 140 ++++++++--- 2 files changed, 337 insertions(+), 37 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index 1a29e90a40..257e151580 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -18,7 +18,235 @@ import cpp import codingstandards.cpp.misra -from +/** + * A comparison expression that has the minimum qualification as being a valid termination + * condition of a legacy for-loop. It is characterized by a value read from a variable being + * compared to a value, which is supposed to be the loop bound. + */ +class LegacyForLoopCondition extends RelationalOperation { + ForStmt forLoop; + VariableAccess loopCounter; + Expr loopBound; + + LegacyForLoopCondition() { + loopCounter = this.getAnOperand() and + loopBound = this.getAnOperand() and + loopCounter.getTarget() = forLoop.getInitialization().(DeclStmt).getADeclaration() and + loopBound != loopCounter + } + + VariableAccess getLoopCounter() { result = loopCounter } + + Expr getLoopBound() { result = loopBound } +} + +/** + * Holds if the given expression is impure and contains an access to the variable, and + * thus may mutate the variable. + * + * Note that this relation over-approximates and might include impure expressions that + * in fact do not mutate the variable. + */ +predicate exprWithVarAccessMaybeImpure(Expr expr, Variable variable) { + exists(VariableAccess varAccess | + expr.mayBeImpure() and + expr.getAChild*() = varAccess and + variable = varAccess.getTarget() + ) +} + +/** + * Gets the loop step of a legacy for loop. + * + * This predicate assumes the update expression of the given for loop is an add-and-assign + * (`+=`) or sub-and-assign (`-=`) expression, so the update expression that is an increment + * (`++`) or a decrement (`--`) operation should be handled using different means than this + * predicate. + */ +Expr getLoopStepOfForStmt(ForStmt forLoop) { + result = forLoop.getUpdate().(AssignAddExpr).getRValue() or + result = forLoop.getUpdate().(AssignSubExpr).getRValue() +} + +/** + * Holds if the given function has as parameter at a given index a pointer to a + * constant value or a reference of a constant value. + */ +predicate functionHasConstPointerOrReferenceParameter(Function function, int index) { + function.getParameter(index).getType().(PointerType).getBaseType().isConst() or + function.getParameter(index).getType().(ReferenceType).getBaseType().isConst() +} + +/** + * Holds if the the variable behind a given variable access is taken its address + * in a declaration in either the body of the for-loop or in its update expression. + * + * e.g.1. The loop counter variable `i` in the body is taken its address in the + * declaration of a pointer variable `m`. + * ``` C++ + * for (int i = 0; i < k; i += l) { + * int *m = &i; + * } + * ``` + * e.g.2. The loop bound variable `k` in the body is taken its address in the + * declaration of a pointer variable `m`. + * ``` C++ + * for (int i = j; i < k; i += l) { + * int *m = &k; + * } + * ``` + */ +predicate variableAddressTakenInDeclaration(ForStmt forLoop, VariableAccess baseVariableAccess) { + exists(AddressOfExpr addressOfExpr, DeclStmt decl | + decl.getParentStmt+() = forLoop and + decl.getADeclarationEntry().(VariableDeclarationEntry).getVariable().getInitializer().getExpr() = + addressOfExpr and + baseVariableAccess.getTarget() = + forLoop.getCondition().(LegacyForLoopCondition).getLoopBound().(VariableAccess).getTarget() + ) +} + +/** + * Holds if the the variable behind a given variable access is taken its address + * as an argument of a call in either the body of the for-loop or in its update + * expression. + * + * e.g.1. The loop counter variable `i` in the body is taken its address in the + * declaration of a pointer variable `m`. + * ``` C++ + * for (int i = 0; i < k; i += l) { + * g(&i); + * } + * ``` + * e.g.2. The loop bound variable `k` in the body is taken its address in the + * declaration of a pointer variable `m`. + * ``` C++ + * for (int i = j; i < k; i += l) { + * g(&k); + * } + * ``` + */ +predicate variableAddressTakenAsConstArgument( + ForStmt forLoop, VariableAccess baseVariableAccess, Call call +) { + exists(AddressOfExpr addressOfExpr, int index | + call.getParent+() = forLoop.getAChild+() and + call.getArgument(index).getAChild*() = addressOfExpr and + functionHasConstPointerOrReferenceParameter(call.getTarget(), index) and + addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess() + ) +} + +/** + * Holds if the the variable behind a given variable access is taken its address + * as an argument of a complex expression in either the body of the for-loop or + * in its update expression. + * + * e.g. The loop counter variable `i` in the body and the loop bound variable `k` + * is taken its address in a compound expression. + * ``` C++ + * for (int i = 0; i < k; i += l) { + * *(cond ? &i : &k) += 1; + * } + * ``` + */ +predicate variableAddressTakenInExpression(ForStmt forLoop, VariableAccess baseVariableAccess) { + exists(AddressOfExpr addressOfExpr | + baseVariableAccess.getParent+() = forLoop.getAChild+() and + addressOfExpr.getParent+() = forLoop.getAChild+() and + addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess() + ) and + not exists(Call call | variableAddressTakenAsConstArgument(forLoop, baseVariableAccess, call)) +} + +from ForStmt forLoop where - not isExcluded(x, StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) and -select + not isExcluded(forLoop, StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) and + /* 1. There is a counter variable that is not of an integer type. */ + exists(Type type | type = forLoop.getAnIterationVariable().getType() | + not ( + type instanceof IntegralType or + type instanceof FixedWidthIntegralType + ) + ) + or + /* + * 2. The loop condition checks termination without comparing the counter variable and the + * loop bound using a relational operator. + */ + + not forLoop.getCondition() instanceof LegacyForLoopCondition + or + /* 3. The loop counter is mutated somewhere other than its update expression. */ + exists(Expr mutatingExpr, Variable loopCounter | + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild() and + loopCounter = forLoop.getAnIterationVariable() + | + exprWithVarAccessMaybeImpure(mutatingExpr, loopCounter) + ) + or + /* 4. The type size of the loop counter is not greater or equal to that of the loop counter. */ + exists(LegacyForLoopCondition forLoopCondition | forLoopCondition = forLoop.getCondition() | + exists(Type loopCounterType, Type loopBoundType | + loopCounterType = forLoopCondition.getLoopCounter().getType() and + loopBoundType = forLoopCondition.getLoopBound().getType() + | + loopCounterType.getSize() < loopBoundType.getSize() + ) + ) + or + /* 5. The loop bound and the loop step is a variable that is mutated in the for loop. */ + exists(Expr mutatingExpr | + ( + /* 1. The mutating expression may be in the loop body. */ + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() + or + /* 2. The mutating expression may be in the loop updating expression. */ + mutatingExpr = forLoop.getUpdate().getAChild*() + ) + | + /* 5-1. The mutating expression mutates the loop bound. */ + exists(LegacyForLoopCondition forLoopCondition, Variable loopBoundVariable | + forLoopCondition = forLoop.getCondition() and + loopBoundVariable = forLoopCondition.getLoopBound().(VariableAccess).getTarget() + | + exprWithVarAccessMaybeImpure(mutatingExpr, loopBoundVariable) + ) + or + /* 5-2. The mutating expression mutates the loop step. */ + exists(VariableAccess loopStep | loopStep = getLoopStepOfForStmt(forLoop) | + exprWithVarAccessMaybeImpure(mutatingExpr, loopStep.getTarget()) + ) + ) + or + /* + * 6. Any of the loop counter, loop bound, or a loop step is taken as a mutable reference + * or its address to a mutable pointer. + */ + + /* 6-1. The loop counter is taken a mutable reference or its address to a mutable pointer. */ + variableAddressTakenInDeclaration(forLoop, + forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter()) + or + /* 6-2. The loop bound is taken a mutable reference or its address to a mutable pointer. */ + none() + or + /* 6-3. The loop step is taken a mutable reference or its address to a mutable pointer. */ + none() +select forLoop, "TODO" + +private module Notebook { + private predicate test(Function function) { + function.getParameter(_).getType().(PointerType).getBaseType().isConst() or + function.getParameter(_).getType().(ReferenceType).getBaseType().isConst() + } + + private predicate test2(Expr expr, string qlClasses) { + expr.getType().isConst() and + qlClasses = expr.getPrimaryQlClasses() + } + + private predicate test3(Function function, string qlClasses) { + qlClasses = function.getParameter(_).getType().getAQlClass() + } +} diff --git a/cpp/misra/test/rules/RULE-9-5-1/test.cpp b/cpp/misra/test/rules/RULE-9-5-1/test.cpp index f4c486ba04..08bdea3b61 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-1/test.cpp @@ -1,5 +1,7 @@ -void f(int &x) {} // Function that takes a non-const integer reference -void g(int *x) {} // Function that takes a non-const integer pointer +void f1(int &x) {} // Function that takes a non-const integer reference +void g1(int *x) {} // Function that takes a non-const integer pointer +void f2(const int &x) {} // Function that takes a non-const integer reference +void g2(const int *x) {} // Function that takes a non-const integer pointer int main() { int j = 5; @@ -111,71 +113,141 @@ int main() { // step are not taken addresses of } - for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is taken // as a non-const reference int &m = i; } - for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is taken // as a non-const pointer int *m = &i; } - for (int i = j; i < k; - i += - l) { // NON_COMPLIANT: The loop bound is passed as a non-const reference + for (int i = j; i < k; i += l) { // COMPLIANT: The loop counter is taken + // as a const reference + const int &m = i; + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop counter is taken + // as a const pointer + const int *m = &i; + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is taken as + // a non-const reference int &m = k; } - for (int i = j; i < k; - i += - l) { // NON_COMPLIANT: The loop bound is passed as a non-const pointer + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is taken as + // a non-const pointer int *m = &k; } - for (int i = j; i < k; - i += - l) { // NON_COMPLIANT: The loop step is passed as a non-const reference + for (int i = j; i < k; i += l) { // COMPLIANT: The loop counter is taken + // as a const reference + const int &m = k; + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop counter is taken + // as a const pointer + const int *m = &k; + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is taken as + // a non-const reference int &m = l; } - for (int i = j; i < k; - i += - l) { // NON_COMPLIANT: The loop step is passed as a non-const pointer + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is taken as + // a non-const pointer int *m = &l; } + for (int i = j; i < k; i += l) { // COMPLIANT: The loop step is taken as + // a const reference + const int &m = l; + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop step is taken as + // a const pointer + const int *m = &l; + } + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed - // as a non-const reference - f(i); + // to a non-const reference parameter + f1(i); } for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed - // as a non-const pointer - g(&i); + // to a non-const pointer parameter + g1(&i); } - for (int i = j; i < k; - i += - l) { // NON_COMPLIANT: The loop bound is passed as a non-const reference - f(k); + for (int i = j; i < k; i += l) { // COMPLIANT: The loop counter is passed + // to a const reference parameter + f2(i); } - for (int i = j; i < k; - i += - l) { // NON_COMPLIANT: The loop bound is passed as a non-const pointer - g(&k); + for (int i = j; i < k; i += l) { // COMPLIANT: The loop counter is passed + // to a const pointer parameter + g2(&i); } - for (int i = j; i < k; - i += - l) { // NON_COMPLIANT: The loop step is passed as a non-const reference - f(l); + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is passed to + // a non-const reference parameter + f1(k); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is passed to + // a non-const pointer parameter + g1(&k); + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop bound is passed to a + // const reference parameter + f2(k); } for (int i = j; i < k; i += - l) { // NON_COMPLIANT: The loop step is passed as a non-const pointer - g(&l); + l) { // COMPLIANT: The loop bound is passed to a const pointer parameter + g2(&k); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to + // a non-const reference parameter + f1(l); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to + // a non-const pointer parameter + g1(&l); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to + // a non-const reference parameter + f2(l); + } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to + // a non-const pointer parameter + g2(&l); + } + + int n = 0; + + for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop counter is taken + // as a non-const pointer + *(true ? &i : &n) += 1; + } + + for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop counter is taken + // as a non-const pointer + *(true ? &k : &n) += 1; + } + + for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop counter is taken + // as a non-const pointer + *(true ? &l : &n) += 1; } } \ No newline at end of file From 0ee0a0accf4ec224189ce0fddafdcc44fe96fdd4 Mon Sep 17 00:00:00 2001 From: Luke Cartey <5377966+lcartey@users.noreply.github.com> Date: Fri, 29 Aug 2025 10:04:37 +0100 Subject: [PATCH 587/628] Update Safety manager in iso_26262_tool_qualification.md --- docs/iso_26262_tool_qualification.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/iso_26262_tool_qualification.md b/docs/iso_26262_tool_qualification.md index 53b5a4303d..3c1442b1a7 100644 --- a/docs/iso_26262_tool_qualification.md +++ b/docs/iso_26262_tool_qualification.md @@ -13,6 +13,7 @@ | 0.5.0 | 2021-11-29 | Remco Vermeulen | Add document management section. | | 0.6.0 | 2023-08-14 | Luke Cartey | Update use and testing statement after LGTM.com deprecation. | | 0.7.0 | 2024-07-23 | Luke Cartey | Fix development handbook link | +| 0.8.0 | 2025-08-29 | Luke Cartey | Update Safety Manager | ## Introduction @@ -138,7 +139,7 @@ In addition to this black box testing of the components, we also provide validat ## Safety manager - - **Safety Manager**: @lcartey - - **Deputy Safety Manager**: @rvermeulen + - **Safety Manager**: @michaelrfairhurst + - **Deputy Safety Manager**: @nicolaswill In the event of the Safety Manager being on leave, the Deputy Safety Manager will be responsible for all duties. From 0124f5e9a8e3a9e35f211c2d4a5428d87df49e7e Mon Sep 17 00:00:00 2001 From: Mike Fairhurst Date: Fri, 29 Aug 2025 09:55:25 -0700 Subject: [PATCH 588/628] Fix performance issue from join on start column. --- .../src/codingstandards/cpp/AlertReporting.qll | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/AlertReporting.qll b/cpp/common/src/codingstandards/cpp/AlertReporting.qll index 97c46c0629..a85ae4097b 100644 --- a/cpp/common/src/codingstandards/cpp/AlertReporting.qll +++ b/cpp/common/src/codingstandards/cpp/AlertReporting.qll @@ -17,6 +17,17 @@ module MacroUnwrapper { result.getAnAffectedElement() = re } + private MacroInvocation getASubsumedMacroInvocation(ResultElement re) { + result = getAMacroInvocation(re) and + // Only report cases where the element is not located at the macro expansion site + // This means we'll report results in macro arguments in the macro argument + // location, not within the macro itself. + // + // Do not join start column values. + pragma[only_bind_out](result.getLocation().getStartColumn()) = + pragma[only_bind_out](re.getLocation().getStartColumn()) + } + /** * Gets the primary macro invocation that generated the result element. * @@ -24,11 +35,7 @@ module MacroUnwrapper { */ MacroInvocation getPrimaryMacroInvocation(ResultElement re) { exists(MacroInvocation mi | - mi = getAMacroInvocation(re) and - // Only report cases where the element is not located at the macro expansion site - // This means we'll report results in macro arguments in the macro argument - // location, not within the macro itself - mi.getLocation().getStartColumn() = re.getLocation().getStartColumn() and + mi = getASubsumedMacroInvocation(re) and // No other more specific macro that expands to element not exists(MacroInvocation otherMi | otherMi = getAMacroInvocation(re) and otherMi.getParentInvocation() = mi From 86aaa0ee4a52dff29c11875144269d6b8b699ad2 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 8 Sep 2025 15:59:53 -0400 Subject: [PATCH 589/628] Fix labeling of two cases --- cpp/misra/test/rules/RULE-9-5-1/test.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/misra/test/rules/RULE-9-5-1/test.cpp b/cpp/misra/test/rules/RULE-9-5-1/test.cpp index 08bdea3b61..78f7f17d2f 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-1/test.cpp @@ -224,13 +224,13 @@ int main() { g1(&l); } - for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to - // a non-const reference parameter + for (int i = j; i < k; i += l) { // COMPLIANT: The loop step is passed to + // a const reference parameter f2(l); } - for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to - // a non-const pointer parameter + for (int i = j; i < k; i += l) { // COMPLIANT: The loop step is passed to + // a const pointer parameter g2(&l); } From 49bdc0768521e643d6b740b81b862cefa1a078a5 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 8 Sep 2025 16:00:13 -0400 Subject: [PATCH 590/628] Add cases of addresses taken as part of non-const declaration or expressions --- .../LegacyForStatementsShouldBeSimple.ql | 42 +++++++++++++------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index 257e151580..fa42c56606 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -72,14 +72,14 @@ Expr getLoopStepOfForStmt(ForStmt forLoop) { * Holds if the given function has as parameter at a given index a pointer to a * constant value or a reference of a constant value. */ -predicate functionHasConstPointerOrReferenceParameter(Function function, int index) { +private predicate functionHasConstPointerOrReferenceParameter(Function function, int index) { function.getParameter(index).getType().(PointerType).getBaseType().isConst() or function.getParameter(index).getType().(ReferenceType).getBaseType().isConst() } /** * Holds if the the variable behind a given variable access is taken its address - * in a declaration in either the body of the for-loop or in its update expression. + * in a non-const variable declaration, in the body of the for-loop. * * e.g.1. The loop counter variable `i` in the body is taken its address in the * declaration of a pointer variable `m`. @@ -96,13 +96,21 @@ predicate functionHasConstPointerOrReferenceParameter(Function function, int ind * } * ``` */ -predicate variableAddressTakenInDeclaration(ForStmt forLoop, VariableAccess baseVariableAccess) { +predicate variableAddressTakenInNonConstDeclaration( + ForStmt forLoop, VariableAccess baseVariableAccess +) { exists(AddressOfExpr addressOfExpr, DeclStmt decl | decl.getParentStmt+() = forLoop and decl.getADeclarationEntry().(VariableDeclarationEntry).getVariable().getInitializer().getExpr() = addressOfExpr and - baseVariableAccess.getTarget() = - forLoop.getCondition().(LegacyForLoopCondition).getLoopBound().(VariableAccess).getTarget() + addressOfExpr.getOperand() = baseVariableAccess and + not decl.getADeclarationEntry() + .(VariableDeclarationEntry) + .getVariable() + .getType() + .(PointerType) + .getBaseType() + .isConst() ) } @@ -126,14 +134,15 @@ predicate variableAddressTakenInDeclaration(ForStmt forLoop, VariableAccess base * } * ``` */ -predicate variableAddressTakenAsConstArgument( +private predicate variableAddressTakenAsConstArgument( ForStmt forLoop, VariableAccess baseVariableAccess, Call call ) { exists(AddressOfExpr addressOfExpr, int index | - call.getParent+() = forLoop.getAChild+() and + call.getParent+() = forLoop.getAChild+() and // TODO: Bad call.getArgument(index).getAChild*() = addressOfExpr and functionHasConstPointerOrReferenceParameter(call.getTarget(), index) and - addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess() + addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess() and + baseVariableAccess.getParent+() = forLoop ) } @@ -152,11 +161,11 @@ predicate variableAddressTakenAsConstArgument( */ predicate variableAddressTakenInExpression(ForStmt forLoop, VariableAccess baseVariableAccess) { exists(AddressOfExpr addressOfExpr | - baseVariableAccess.getParent+() = forLoop.getAChild+() and + baseVariableAccess.getParent+() = forLoop.getAChild+() and // TODO: Bad addressOfExpr.getParent+() = forLoop.getAChild+() and addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess() ) and - not exists(Call call | variableAddressTakenAsConstArgument(forLoop, baseVariableAccess, call)) + not variableAddressTakenAsConstArgument(forLoop, baseVariableAccess.getTarget().getAnAccess(), _) } from ForStmt forLoop @@ -225,8 +234,17 @@ where */ /* 6-1. The loop counter is taken a mutable reference or its address to a mutable pointer. */ - variableAddressTakenInDeclaration(forLoop, - forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter()) + exists(VariableAccess loopCounterAccessInCondition | + loopCounterAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() + | + exists(VariableAccess loopCounterAccessTakenAddress | + loopCounterAccessInCondition.getTarget() = loopCounterAccessTakenAddress.getTarget() + | + variableAddressTakenInNonConstDeclaration(forLoop, loopCounterAccessTakenAddress) + or + variableAddressTakenInExpression(forLoop, loopCounterAccessTakenAddress) + ) + ) or /* 6-2. The loop bound is taken a mutable reference or its address to a mutable pointer. */ none() From 07a5cfe6c382db7bc34bb8c2fcfb0e5052bd0a67 Mon Sep 17 00:00:00 2001 From: knewbury01 Date: Mon, 8 Sep 2025 20:54:18 +0000 Subject: [PATCH 591/628] Bump version to 2.51.0-dev --- c/cert/src/qlpack.yml | 2 +- c/cert/test/qlpack.yml | 2 +- c/common/src/qlpack.yml | 2 +- c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- c/misra/test/qlpack.yml | 2 +- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/qlpack.yml | 2 +- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- docs/user_manual.md | 12 ++++++------ 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index f79744a4fc..52f44f7370 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.49.0-dev +version: 2.51.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index 9f5f21ba1b..5588edec2a 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.49.0-dev +version: 2.51.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 068e7c3f2f..3dbcd1a492 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.49.0-dev +version: 2.51.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index da30625ddb..22772323b9 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.49.0-dev +version: 2.51.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index 8b98f26fb0..ca5a163b4f 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.49.0-dev +version: 2.51.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index 08e5f579a3..7dec042c19 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.49.0-dev +version: 2.51.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index 6c763ef633..367a4a3f18 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.49.0-dev +version: 2.51.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index 46f06bed50..07de7dd182 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.49.0-dev +version: 2.51.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index e842352f1c..328c837fb6 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.49.0-dev +version: 2.51.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index 8634569355..c92c074dce 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.49.0-dev +version: 2.51.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index 8b60314b91..0e220b7752 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards -version: 2.49.0-dev +version: 2.51.0-dev license: MIT dependencies: codeql/cpp-all: 4.0.3 diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index cb54217f76..f5dc77c16d 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.49.0-dev +version: 2.51.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 201291b135..1505587a55 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.49.0-dev +version: 2.51.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index fb0cc1201c..080dcdebff 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.49.0-dev +version: 2.51.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index 1574721c0f..7a0817da16 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.49.0-dev +version: 2.51.0-dev license: MIT dependencies: codeql/cpp-all: 4.0.3 diff --git a/docs/user_manual.md b/docs/user_manual.md index f4449082c7..14290aa8a4 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -36,14 +36,14 @@ ## Release information -This user manual documents release `2.49.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.51.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: - `coding-standards-codeql-packs-2.37.0-dev.zip`: CodeQL packs that can be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `code-scanning-cpp-query-pack-2.49.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.49.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.49.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.49.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.51.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.51.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.51.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.51.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -670,7 +670,7 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.49.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.51.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | From 01e32760d6955ab5c9166903e753890ca02d370a Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 9 Sep 2025 14:55:31 -0400 Subject: [PATCH 592/628] Finish first draft --- .../LegacyForStatementsShouldBeSimple.ql | 206 ++++++++++++++---- 1 file changed, 165 insertions(+), 41 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index fa42c56606..ce14aac596 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -24,6 +24,9 @@ import codingstandards.cpp.misra * compared to a value, which is supposed to be the loop bound. */ class LegacyForLoopCondition extends RelationalOperation { + /** + * The legacy for-loop this relational operation is a condition of. + */ ForStmt forLoop; VariableAccess loopCounter; Expr loopBound; @@ -35,8 +38,14 @@ class LegacyForLoopCondition extends RelationalOperation { loopBound != loopCounter } + /** + * Gets the variable access to the loop counter variable, embedded in this loop condition. + */ VariableAccess getLoopCounter() { result = loopCounter } + /** + * Gets the variable access to the loop bound variable, embedded in this loop condition. + */ Expr getLoopBound() { result = loopBound } } @@ -69,17 +78,16 @@ Expr getLoopStepOfForStmt(ForStmt forLoop) { } /** - * Holds if the given function has as parameter at a given index a pointer to a - * constant value or a reference of a constant value. + * Holds if the given function has as parameter a pointer to a constant + * value, at a given index. */ -private predicate functionHasConstPointerOrReferenceParameter(Function function, int index) { - function.getParameter(index).getType().(PointerType).getBaseType().isConst() or - function.getParameter(index).getType().(ReferenceType).getBaseType().isConst() +private predicate functionHasConstPointerParameter(Function function, int index) { + function.getParameter(index).getType().(PointerType).getBaseType().isConst() } /** - * Holds if the the variable behind a given variable access is taken its address - * in a non-const variable declaration, in the body of the for-loop. + * Holds if the variable behind a given variable access is taken its address in + * a non-const variable declaration, in the body of the for-loop. * * e.g.1. The loop counter variable `i` in the body is taken its address in the * declaration of a pointer variable `m`. @@ -115,22 +123,26 @@ predicate variableAddressTakenInNonConstDeclaration( } /** - * Holds if the the variable behind a given variable access is taken its address + * Holds if the variable behind a given variable access is taken its address * as an argument of a call in either the body of the for-loop or in its update * expression. * - * e.g.1. The loop counter variable `i` in the body is taken its address in the - * declaration of a pointer variable `m`. + * e.g.1. The address of the loop counter variable `i` is passed as argument + * to the call to `g`. * ``` C++ + * void g1(int *x); + * * for (int i = 0; i < k; i += l) { - * g(&i); + * g1(&i); * } * ``` - * e.g.2. The loop bound variable `k` in the body is taken its address in the - * declaration of a pointer variable `m`. + * e.g.2. The address of the loop counter variable `k` is passed as argument + * to the call to `g`. * ``` C++ + * void g1(int *x); + * * for (int i = j; i < k; i += l) { - * g(&k); + * g1(&k); * } * ``` */ @@ -140,18 +152,30 @@ private predicate variableAddressTakenAsConstArgument( exists(AddressOfExpr addressOfExpr, int index | call.getParent+() = forLoop.getAChild+() and // TODO: Bad call.getArgument(index).getAChild*() = addressOfExpr and - functionHasConstPointerOrReferenceParameter(call.getTarget(), index) and + exists(PointerType parameterType | + parameterType = call.getTarget().getParameter(index).getType() and + not parameterType.getBaseType().isConst() + ) and addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess() and baseVariableAccess.getParent+() = forLoop ) } /** - * Holds if the the variable behind a given variable access is taken its address + * Holds if the variable behind a given variable access is taken its address * as an argument of a complex expression in either the body of the for-loop or * in its update expression. * - * e.g. The loop counter variable `i` in the body and the loop bound variable `k` + * e.g.1. The loop counter variable `i` in the body and the loop bound variable `k` + * is taken its address in a call. + * ``` C++ + * void g1(int *x); + * + * for (int i = j; i < k; i += l) { + * g1(&i); + * } + * ``` + * e.g.2. The loop counter variable `i` in the body and the loop bound variable `k` * is taken its address in a compound expression. * ``` C++ * for (int i = 0; i < k; i += l) { @@ -159,13 +183,88 @@ private predicate variableAddressTakenAsConstArgument( * } * ``` */ +/* TODO: Do we need to use Expr.getUnderlyingType() to ensure that the expression is non-const? */ predicate variableAddressTakenInExpression(ForStmt forLoop, VariableAccess baseVariableAccess) { exists(AddressOfExpr addressOfExpr | baseVariableAccess.getParent+() = forLoop.getAChild+() and // TODO: Bad addressOfExpr.getParent+() = forLoop.getAChild+() and addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess() - ) and - not variableAddressTakenAsConstArgument(forLoop, baseVariableAccess.getTarget().getAnAccess(), _) + ) +} + +/** + * Holds if the variable behind a given variable access is taken its reference + * in a non-const variable declaration, in the body of the for-loop. + * + * e.g.1. The loop counter variable `i` in the body is taken its reference in + * the declaration of a variable `m`. + * ``` C++ + * for (int i = j; i < k; i += l) { + * int &m = i; + * } + * ``` + * e.g.2. The loop bound variable `k` in the body is taken its reference in the + * declaration of a variable `m`. + * ``` C++ + * for (int i = j; i < k; i += l) { + * int &m = k; + * } + * ``` + */ +predicate variableReferenceTakenInNonConstDeclaration( + ForStmt forLoop, VariableAccess baseVariableAccess +) { + exists(DeclStmt decl, Variable definedVariable, ReferenceType definedVariableType | + decl.getParentStmt+() = forLoop and + not decl = forLoop.getInitialization() and // Exclude the for-loop counter initialization. + definedVariable = decl.getADeclarationEntry().(VariableDeclarationEntry).getVariable() and + definedVariable.getInitializer().getExpr() = baseVariableAccess and + definedVariableType = definedVariable.getType() and + not definedVariableType.getBaseType().isConst() + ) +} + +/** + * Holds if the variable behind a given variable access is taken its reference + * as an argument of a call in either the body of the for-loop or in its update + * expression. + * + * e.g.1. The loop counter variable `i` in the body is passed by reference to the + * call to `f1`. + * ``` C++ + * void f1(int &x); + * + * for (int i = j; i < k; i += l) { + * f1(i); + * } + * ``` + * e.g.2. The loop bound variable `k` in the body is passed by reference to the + * call to `f1`. + * ``` C++ + * void f1(int &x); + * + * for (int i = j; i < k; i += l) { + * f1(k); + * } + * ``` + */ +private predicate variableReferenceTakenAsNonConstArgument( + ForStmt forLoop, VariableAccess baseVariableAccess, Call call +) { + exists(int index | + call.getParent+() = forLoop.getAChild+() and + call.getArgument(index).getAChild*() = baseVariableAccess.getTarget().getAnAccess() and + /* + * The given function has as parameter a reference of a constant + * value, at a given index. + */ + + exists(ReferenceType parameterType | + parameterType = call.getTarget().getParameter(index).getType() and + not parameterType.getBaseType().isConst() + ) and + baseVariableAccess.getParent+() = forLoop + ) } from ForStmt forLoop @@ -237,34 +336,59 @@ where exists(VariableAccess loopCounterAccessInCondition | loopCounterAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() | - exists(VariableAccess loopCounterAccessTakenAddress | - loopCounterAccessInCondition.getTarget() = loopCounterAccessTakenAddress.getTarget() + exists(VariableAccess loopCounterAccessTakenAddressOrReference | + loopCounterAccessInCondition.getTarget() = + loopCounterAccessTakenAddressOrReference.getTarget() | - variableAddressTakenInNonConstDeclaration(forLoop, loopCounterAccessTakenAddress) + variableAddressTakenInNonConstDeclaration(forLoop, loopCounterAccessTakenAddressOrReference) + or + variableAddressTakenInExpression(forLoop, loopCounterAccessTakenAddressOrReference) and + not variableAddressTakenAsConstArgument(forLoop, + loopCounterAccessTakenAddressOrReference.getTarget().getAnAccess(), _) + or + variableReferenceTakenInNonConstDeclaration(forLoop, loopCounterAccessTakenAddressOrReference) or - variableAddressTakenInExpression(forLoop, loopCounterAccessTakenAddress) + variableReferenceTakenAsNonConstArgument(forLoop, + loopCounterAccessTakenAddressOrReference.getTarget().getAnAccess(), _) ) ) or /* 6-2. The loop bound is taken a mutable reference or its address to a mutable pointer. */ - none() + exists(VariableAccess loopBoundAccessInCondition | + loopBoundAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() + | + exists(VariableAccess loopBoundAccessTakenAddressOrReference | + loopBoundAccessInCondition.getTarget() = loopBoundAccessTakenAddressOrReference.getTarget() + | + variableAddressTakenInNonConstDeclaration(forLoop, loopBoundAccessTakenAddressOrReference) + or + variableAddressTakenInExpression(forLoop, loopBoundAccessTakenAddressOrReference) and + not variableAddressTakenAsConstArgument(forLoop, + loopBoundAccessTakenAddressOrReference.getTarget().getAnAccess(), _) + or + variableReferenceTakenInNonConstDeclaration(forLoop, loopBoundAccessTakenAddressOrReference) + or + variableReferenceTakenAsNonConstArgument(forLoop, loopBoundAccessTakenAddressOrReference, _) + ) + ) or /* 6-3. The loop step is taken a mutable reference or its address to a mutable pointer. */ - none() + exists(VariableAccess loopStepAccessInCondition | + loopStepAccessInCondition = getLoopStepOfForStmt(forLoop) + | + exists(VariableAccess loopStepAccessTakenAddressOrReference | + loopStepAccessInCondition.getTarget() = loopStepAccessTakenAddressOrReference.getTarget() + | + variableAddressTakenInNonConstDeclaration(forLoop, loopStepAccessTakenAddressOrReference) + or + variableAddressTakenInExpression(forLoop, loopStepAccessTakenAddressOrReference) and + not variableAddressTakenAsConstArgument(forLoop, + loopStepAccessTakenAddressOrReference.getTarget().getAnAccess(), _) + or + variableReferenceTakenInNonConstDeclaration(forLoop, loopStepAccessTakenAddressOrReference) + or + variableReferenceTakenAsNonConstArgument(forLoop, + loopStepAccessTakenAddressOrReference.getTarget().getAnAccess(), _) + ) + ) select forLoop, "TODO" - -private module Notebook { - private predicate test(Function function) { - function.getParameter(_).getType().(PointerType).getBaseType().isConst() or - function.getParameter(_).getType().(ReferenceType).getBaseType().isConst() - } - - private predicate test2(Expr expr, string qlClasses) { - expr.getType().isConst() and - qlClasses = expr.getPrimaryQlClasses() - } - - private predicate test3(Function function, string qlClasses) { - qlClasses = function.getParameter(_).getType().getAQlClass() - } -} From 2f6fc3dd94e72794d3c6d55390ac43f315a75dbf Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 10 Sep 2025 17:49:11 -0400 Subject: [PATCH 593/628] Finish first draft --- .../LegacyForStatementsShouldBeSimple.ql | 123 +++++++++--------- 1 file changed, 65 insertions(+), 58 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index ce14aac596..dfc54bc7f6 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -17,6 +17,8 @@ import cpp import codingstandards.cpp.misra +import codingstandards.cpp.Call +import codingstandards.cpp.misra.BuiltInTypeRules::MisraCpp23BuiltInTypes /** * A comparison expression that has the minimum qualification as being a valid termination @@ -59,7 +61,7 @@ class LegacyForLoopCondition extends RelationalOperation { predicate exprWithVarAccessMaybeImpure(Expr expr, Variable variable) { exists(VariableAccess varAccess | expr.mayBeImpure() and - expr.getAChild*() = varAccess and + expr.getAChild*() = varAccess and // TODO: the `l` in the `i += l` is not mutated! variable = varAccess.getTarget() ) } @@ -267,6 +269,61 @@ private predicate variableReferenceTakenAsNonConstArgument( ) } +predicate loopVariableAssignedToPointerOrReferenceType( + ForStmt forLoop, VariableAccess loopVariableAccessInCondition +) { + exists(Expr assignmentRhs, DerivedType targetType | + assignmentRhs.getEnclosingStmt().getParent*() = forLoop.getStmt() and + ( + assignmentRhs.(AddressOfExpr).getOperand() = + loopVariableAccessInCondition.getTarget().getAnAccess() or + assignmentRhs = loopVariableAccessInCondition.getTarget().getAnAccess() + ) and + isAssignment(assignmentRhs, targetType, _) and + ( + targetType instanceof PointerType or + targetType instanceof ReferenceType + ) and + not targetType.getBaseType().isConst() + ) +} + +/* + * An adapted part of `BuiltinTypeRules::MisraCpp23BuiltInTypes::isPreConversionAssignment` + * that is only relevant to an argument passed to a parameter, seen as an assignment. + * + * This predicate adds two constraints to the target type, as compared to the original + * portion of the predicate: + * + * 1. This predicate adds type constraint that the target type is a `ReferenceType`. + * 2. This predicate adds the constraint that the target type is not `const`. + * + * Also, this predicate requires that the call is the body of the given for-loop. + */ + +predicate loopVariablePassedAsArgumentToReferenceParameter( + ForStmt forLoop, Expr loopVariableAccessInCondition +) { + exists(ReferenceType targetType | + exists(Call call, int i | + call.getArgument(i) = loopVariableAccessInCondition and + call.getEnclosingStmt().getParent*() = forLoop.getStmt() and + not targetType.getBaseType().isConst() + | + /* A regular function call */ + targetType = call.getTarget().getParameter(i).getType() + or + /* A function call where the argument is passed as varargs */ + call.getTarget().getNumberOfParameters() <= i and + /* The rule states that the type should match the "adjusted" type of the argument */ + targetType = loopVariableAccessInCondition.getFullyConverted().getType() + or + /* An expression call - get the function type, then the parameter type */ + targetType = getExprCallFunctionType(call).getParameterType(i) + ) + ) +} + from ForStmt forLoop where not isExcluded(forLoop, StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) and @@ -332,63 +389,13 @@ where * or its address to a mutable pointer. */ - /* 6-1. The loop counter is taken a mutable reference or its address to a mutable pointer. */ - exists(VariableAccess loopCounterAccessInCondition | - loopCounterAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() + exists(VariableAccess loopVariableAccessInCondition | + loopVariableAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() or + loopVariableAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() or + loopVariableAccessInCondition = getLoopStepOfForStmt(forLoop) | - exists(VariableAccess loopCounterAccessTakenAddressOrReference | - loopCounterAccessInCondition.getTarget() = - loopCounterAccessTakenAddressOrReference.getTarget() - | - variableAddressTakenInNonConstDeclaration(forLoop, loopCounterAccessTakenAddressOrReference) - or - variableAddressTakenInExpression(forLoop, loopCounterAccessTakenAddressOrReference) and - not variableAddressTakenAsConstArgument(forLoop, - loopCounterAccessTakenAddressOrReference.getTarget().getAnAccess(), _) - or - variableReferenceTakenInNonConstDeclaration(forLoop, loopCounterAccessTakenAddressOrReference) - or - variableReferenceTakenAsNonConstArgument(forLoop, - loopCounterAccessTakenAddressOrReference.getTarget().getAnAccess(), _) - ) - ) - or - /* 6-2. The loop bound is taken a mutable reference or its address to a mutable pointer. */ - exists(VariableAccess loopBoundAccessInCondition | - loopBoundAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() - | - exists(VariableAccess loopBoundAccessTakenAddressOrReference | - loopBoundAccessInCondition.getTarget() = loopBoundAccessTakenAddressOrReference.getTarget() - | - variableAddressTakenInNonConstDeclaration(forLoop, loopBoundAccessTakenAddressOrReference) - or - variableAddressTakenInExpression(forLoop, loopBoundAccessTakenAddressOrReference) and - not variableAddressTakenAsConstArgument(forLoop, - loopBoundAccessTakenAddressOrReference.getTarget().getAnAccess(), _) - or - variableReferenceTakenInNonConstDeclaration(forLoop, loopBoundAccessTakenAddressOrReference) - or - variableReferenceTakenAsNonConstArgument(forLoop, loopBoundAccessTakenAddressOrReference, _) - ) - ) - or - /* 6-3. The loop step is taken a mutable reference or its address to a mutable pointer. */ - exists(VariableAccess loopStepAccessInCondition | - loopStepAccessInCondition = getLoopStepOfForStmt(forLoop) - | - exists(VariableAccess loopStepAccessTakenAddressOrReference | - loopStepAccessInCondition.getTarget() = loopStepAccessTakenAddressOrReference.getTarget() - | - variableAddressTakenInNonConstDeclaration(forLoop, loopStepAccessTakenAddressOrReference) - or - variableAddressTakenInExpression(forLoop, loopStepAccessTakenAddressOrReference) and - not variableAddressTakenAsConstArgument(forLoop, - loopStepAccessTakenAddressOrReference.getTarget().getAnAccess(), _) - or - variableReferenceTakenInNonConstDeclaration(forLoop, loopStepAccessTakenAddressOrReference) - or - variableReferenceTakenAsNonConstArgument(forLoop, - loopStepAccessTakenAddressOrReference.getTarget().getAnAccess(), _) - ) + loopVariableAssignedToPointerOrReferenceType(forLoop, loopVariableAccessInCondition) + or + loopVariablePassedAsArgumentToReferenceParameter(forLoop, loopVariableAccessInCondition) ) select forLoop, "TODO" From 999e87027bcb81ca2be126c03751336a91cafd41 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 17 Sep 2025 17:16:20 -0400 Subject: [PATCH 594/628] Tidy up, refine a bit more, add a series of test cases --- .../LegacyForStatementsShouldBeSimple.ql | 324 +++++------------- cpp/misra/test/rules/RULE-9-5-1/test.cpp | 59 ++-- 2 files changed, 120 insertions(+), 263 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index dfc54bc7f6..3fd271c444 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -16,8 +16,10 @@ */ import cpp +import semmle.code.cpp.dataflow.internal.AddressFlow import codingstandards.cpp.misra import codingstandards.cpp.Call +import codingstandards.cpp.Loops import codingstandards.cpp.misra.BuiltInTypeRules::MisraCpp23BuiltInTypes /** @@ -36,7 +38,7 @@ class LegacyForLoopCondition extends RelationalOperation { LegacyForLoopCondition() { loopCounter = this.getAnOperand() and loopBound = this.getAnOperand() and - loopCounter.getTarget() = forLoop.getInitialization().(DeclStmt).getADeclaration() and + loopCounter.getTarget() = getAnIterationVariable(forLoop) and loopBound != loopCounter } @@ -52,18 +54,22 @@ class LegacyForLoopCondition extends RelationalOperation { } /** - * Holds if the given expression is impure and contains an access to the variable, and - * thus may mutate the variable. - * - * Note that this relation over-approximates and might include impure expressions that - * in fact do not mutate the variable. + * Holds if the given expression may mutate the variable. */ -predicate exprWithVarAccessMaybeImpure(Expr expr, Variable variable) { - exists(VariableAccess varAccess | - expr.mayBeImpure() and - expr.getAChild*() = varAccess and // TODO: the `l` in the `i += l` is not mutated! - variable = varAccess.getTarget() - ) +predicate variableModifiedInExpression(Expr expr, VariableAccess va) { + /* + * 1. Direct modification (assignment, increment, etc.) or a function call. + */ + + expr.getAChild+() = va and + va.isModified() + or + /* + * 2. Address taken for non-const access that can potentially lead to modification. + * This overlaps with the former example on cases where `expr` is a function call. + */ + + valueToUpdate(va, _, expr) } /** @@ -79,212 +85,26 @@ Expr getLoopStepOfForStmt(ForStmt forLoop) { result = forLoop.getUpdate().(AssignSubExpr).getRValue() } -/** - * Holds if the given function has as parameter a pointer to a constant - * value, at a given index. - */ -private predicate functionHasConstPointerParameter(Function function, int index) { - function.getParameter(index).getType().(PointerType).getBaseType().isConst() -} - -/** - * Holds if the variable behind a given variable access is taken its address in - * a non-const variable declaration, in the body of the for-loop. - * - * e.g.1. The loop counter variable `i` in the body is taken its address in the - * declaration of a pointer variable `m`. - * ``` C++ - * for (int i = 0; i < k; i += l) { - * int *m = &i; - * } - * ``` - * e.g.2. The loop bound variable `k` in the body is taken its address in the - * declaration of a pointer variable `m`. - * ``` C++ - * for (int i = j; i < k; i += l) { - * int *m = &k; - * } - * ``` - */ -predicate variableAddressTakenInNonConstDeclaration( - ForStmt forLoop, VariableAccess baseVariableAccess -) { - exists(AddressOfExpr addressOfExpr, DeclStmt decl | - decl.getParentStmt+() = forLoop and - decl.getADeclarationEntry().(VariableDeclarationEntry).getVariable().getInitializer().getExpr() = - addressOfExpr and - addressOfExpr.getOperand() = baseVariableAccess and - not decl.getADeclarationEntry() - .(VariableDeclarationEntry) - .getVariable() - .getType() - .(PointerType) - .getBaseType() - .isConst() - ) -} - -/** - * Holds if the variable behind a given variable access is taken its address - * as an argument of a call in either the body of the for-loop or in its update - * expression. - * - * e.g.1. The address of the loop counter variable `i` is passed as argument - * to the call to `g`. - * ``` C++ - * void g1(int *x); - * - * for (int i = 0; i < k; i += l) { - * g1(&i); - * } - * ``` - * e.g.2. The address of the loop counter variable `k` is passed as argument - * to the call to `g`. - * ``` C++ - * void g1(int *x); - * - * for (int i = j; i < k; i += l) { - * g1(&k); - * } - * ``` - */ -private predicate variableAddressTakenAsConstArgument( - ForStmt forLoop, VariableAccess baseVariableAccess, Call call -) { - exists(AddressOfExpr addressOfExpr, int index | - call.getParent+() = forLoop.getAChild+() and // TODO: Bad - call.getArgument(index).getAChild*() = addressOfExpr and - exists(PointerType parameterType | - parameterType = call.getTarget().getParameter(index).getType() and - not parameterType.getBaseType().isConst() - ) and - addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess() and - baseVariableAccess.getParent+() = forLoop - ) -} - -/** - * Holds if the variable behind a given variable access is taken its address - * as an argument of a complex expression in either the body of the for-loop or - * in its update expression. - * - * e.g.1. The loop counter variable `i` in the body and the loop bound variable `k` - * is taken its address in a call. - * ``` C++ - * void g1(int *x); - * - * for (int i = j; i < k; i += l) { - * g1(&i); - * } - * ``` - * e.g.2. The loop counter variable `i` in the body and the loop bound variable `k` - * is taken its address in a compound expression. - * ``` C++ - * for (int i = 0; i < k; i += l) { - * *(cond ? &i : &k) += 1; - * } - * ``` - */ -/* TODO: Do we need to use Expr.getUnderlyingType() to ensure that the expression is non-const? */ -predicate variableAddressTakenInExpression(ForStmt forLoop, VariableAccess baseVariableAccess) { - exists(AddressOfExpr addressOfExpr | - baseVariableAccess.getParent+() = forLoop.getAChild+() and // TODO: Bad - addressOfExpr.getParent+() = forLoop.getAChild+() and - addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess() - ) -} - -/** - * Holds if the variable behind a given variable access is taken its reference - * in a non-const variable declaration, in the body of the for-loop. - * - * e.g.1. The loop counter variable `i` in the body is taken its reference in - * the declaration of a variable `m`. - * ``` C++ - * for (int i = j; i < k; i += l) { - * int &m = i; - * } - * ``` - * e.g.2. The loop bound variable `k` in the body is taken its reference in the - * declaration of a variable `m`. - * ``` C++ - * for (int i = j; i < k; i += l) { - * int &m = k; - * } - * ``` - */ -predicate variableReferenceTakenInNonConstDeclaration( - ForStmt forLoop, VariableAccess baseVariableAccess -) { - exists(DeclStmt decl, Variable definedVariable, ReferenceType definedVariableType | - decl.getParentStmt+() = forLoop and - not decl = forLoop.getInitialization() and // Exclude the for-loop counter initialization. - definedVariable = decl.getADeclarationEntry().(VariableDeclarationEntry).getVariable() and - definedVariable.getInitializer().getExpr() = baseVariableAccess and - definedVariableType = definedVariable.getType() and - not definedVariableType.getBaseType().isConst() - ) -} - -/** - * Holds if the variable behind a given variable access is taken its reference - * as an argument of a call in either the body of the for-loop or in its update - * expression. - * - * e.g.1. The loop counter variable `i` in the body is passed by reference to the - * call to `f1`. - * ``` C++ - * void f1(int &x); - * - * for (int i = j; i < k; i += l) { - * f1(i); - * } - * ``` - * e.g.2. The loop bound variable `k` in the body is passed by reference to the - * call to `f1`. - * ``` C++ - * void f1(int &x); - * - * for (int i = j; i < k; i += l) { - * f1(k); - * } - * ``` - */ -private predicate variableReferenceTakenAsNonConstArgument( - ForStmt forLoop, VariableAccess baseVariableAccess, Call call -) { - exists(int index | - call.getParent+() = forLoop.getAChild+() and - call.getArgument(index).getAChild*() = baseVariableAccess.getTarget().getAnAccess() and - /* - * The given function has as parameter a reference of a constant - * value, at a given index. - */ - - exists(ReferenceType parameterType | - parameterType = call.getTarget().getParameter(index).getType() and - not parameterType.getBaseType().isConst() - ) and - baseVariableAccess.getParent+() = forLoop - ) -} - -predicate loopVariableAssignedToPointerOrReferenceType( +predicate loopVariableAssignedToNonConstPointerOrReferenceType( ForStmt forLoop, VariableAccess loopVariableAccessInCondition ) { exists(Expr assignmentRhs, DerivedType targetType | - assignmentRhs.getEnclosingStmt().getParent*() = forLoop.getStmt() and - ( - assignmentRhs.(AddressOfExpr).getOperand() = - loopVariableAccessInCondition.getTarget().getAnAccess() or - assignmentRhs = loopVariableAccessInCondition.getTarget().getAnAccess() - ) and isAssignment(assignmentRhs, targetType, _) and + not targetType.getBaseType().isConst() and ( targetType instanceof PointerType or targetType instanceof ReferenceType - ) and - not targetType.getBaseType().isConst() + ) + | + assignmentRhs.getEnclosingStmt().getParent*() = forLoop.getStmt() and + ( + /* 1. The address is taken: A loop variable access */ + assignmentRhs.(AddressOfExpr).getOperand() = + loopVariableAccessInCondition.getTarget().getAnAccess() + or + /* 2. The address is taken: A loop variable access */ + assignmentRhs = loopVariableAccessInCondition.getTarget().getAnAccess() + ) ) } @@ -301,12 +121,12 @@ predicate loopVariableAssignedToPointerOrReferenceType( * Also, this predicate requires that the call is the body of the given for-loop. */ -predicate loopVariablePassedAsArgumentToReferenceParameter( - ForStmt forLoop, Expr loopVariableAccessInCondition +predicate loopVariablePassedAsArgumentToNonConstReferenceParameter( + ForStmt forLoop, VariableAccess loopVariableAccessInCondition ) { exists(ReferenceType targetType | exists(Call call, int i | - call.getArgument(i) = loopVariableAccessInCondition and + call.getArgument(i) = loopVariableAccessInCondition.getTarget().getAnAccess() and call.getEnclosingStmt().getParent*() = forLoop.getStmt() and not targetType.getBaseType().isConst() | @@ -343,11 +163,8 @@ where not forLoop.getCondition() instanceof LegacyForLoopCondition or /* 3. The loop counter is mutated somewhere other than its update expression. */ - exists(Expr mutatingExpr, Variable loopCounter | - mutatingExpr = forLoop.getStmt().getChildStmt().getAChild() and - loopCounter = forLoop.getAnIterationVariable() - | - exprWithVarAccessMaybeImpure(mutatingExpr, loopCounter) + exists(Variable loopCounter | + isIrregularLoopCounterModification(forLoop, loopCounter, loopCounter.getAnAccess()) ) or /* 4. The type size of the loop counter is not greater or equal to that of the loop counter. */ @@ -360,27 +177,45 @@ where ) ) or - /* 5. The loop bound and the loop step is a variable that is mutated in the for loop. */ - exists(Expr mutatingExpr | - ( - /* 1. The mutating expression may be in the loop body. */ + /* + * 5. The loop bound and the loop step are non-const expressions, or are variables that are + * mutated in the for loop. + */ + + /* 5-1. The mutating expression mutates the loop bound. */ + exists(Expr loopBound | + loopBound = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() + | + exists(Expr mutatingExpr | + /* The mutating expression may be in the loop body. */ mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() or - /* 2. The mutating expression may be in the loop updating expression. */ + /* The mutating expression may be in the loop updating expression. */ mutatingExpr = forLoop.getUpdate().getAChild*() - ) - | - /* 5-1. The mutating expression mutates the loop bound. */ - exists(LegacyForLoopCondition forLoopCondition, Variable loopBoundVariable | - forLoopCondition = forLoop.getCondition() and - loopBoundVariable = forLoopCondition.getLoopBound().(VariableAccess).getTarget() | - exprWithVarAccessMaybeImpure(mutatingExpr, loopBoundVariable) + /* 5-1-1. The loop bound is a variable that is mutated in the for loop. */ + variableModifiedInExpression(mutatingExpr, + loopBound.(VariableAccess).getTarget().getAnAccess()) + or + /* 5-1-2. The loop bound is not a variable access and is not a constant expression. */ + not loopBound instanceof VariableAccess and not loopBound.isConstant() ) - or - /* 5-2. The mutating expression mutates the loop step. */ - exists(VariableAccess loopStep | loopStep = getLoopStepOfForStmt(forLoop) | - exprWithVarAccessMaybeImpure(mutatingExpr, loopStep.getTarget()) + ) + or + /* 5-2. The mutating expression mutates the loop step. */ + exists(Expr loopStep | loopStep = getLoopStepOfForStmt(forLoop) | + exists(Expr mutatingExpr | + /* The mutating expression may be in the loop body. */ + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() + or + /* The mutating expression may be in the loop updating expression. */ + mutatingExpr = forLoop.getUpdate().getAChild*() + | + /* 5-1-2. The loop step is a variable that is mutated in the for loop. */ + variableModifiedInExpression(mutatingExpr, loopStep.(VariableAccess).getTarget().getAnAccess()) + or + /* 5-1-2. The loop bound is not a variable access and is not a constant expression. */ + not loopStep instanceof VariableAccess and not loopStep.isConstant() ) ) or @@ -390,12 +225,17 @@ where */ exists(VariableAccess loopVariableAccessInCondition | - loopVariableAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() or - loopVariableAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() or - loopVariableAccessInCondition = getLoopStepOfForStmt(forLoop) - | - loopVariableAssignedToPointerOrReferenceType(forLoop, loopVariableAccessInCondition) - or - loopVariablePassedAsArgumentToReferenceParameter(forLoop, loopVariableAccessInCondition) + ( + loopVariableAccessInCondition = + forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() or + loopVariableAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() or + loopVariableAccessInCondition = getLoopStepOfForStmt(forLoop) + ) and + ( + loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, loopVariableAccessInCondition) + or + loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, + loopVariableAccessInCondition) + ) ) select forLoop, "TODO" diff --git a/cpp/misra/test/rules/RULE-9-5-1/test.cpp b/cpp/misra/test/rules/RULE-9-5-1/test.cpp index 78f7f17d2f..0d8cfa35fb 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-1/test.cpp @@ -1,3 +1,6 @@ +#include +#include + void f1(int &x) {} // Function that takes a non-const integer reference void g1(int *x) {} // Function that takes a non-const integer pointer void f2(const int &x) {} // Function that takes a non-const integer reference @@ -5,6 +8,8 @@ void g2(const int *x) {} // Function that takes a non-const integer pointer int main() { int j = 5; + int k = 10; + int l = 2; /* ========== 1. Type of the initialized counter variable ========== */ @@ -62,7 +67,7 @@ int main() { } for (int i = 0; i < j; - i++) { // NON_COMPLIANT: The loop bound is not a constant + i++) { // COMPLIANT: The loop step and the loop bound has the same type } /* ========== 5. Immutability of the loop bound and the loop step ========== @@ -103,12 +108,41 @@ int main() { j++; } + int n = 0; + + for (int i = 0; i < k; + i += l) { // NON_COMPLIANT: The loop bound is mutated through an address + *(true ? &k : &n) += 1; + } + + for (int i = 0; i < k; + i += l) { // NON_COMPLIANT: The loop step is mutated through an address + *(true ? &l : &n) += 1; + } + + std::string hello1 = "hello"; + std::string_view hello2{"hello"}; + + for (int i = 0; i < hello1.size(); + i++) { // NON_COMPLIANT: The loop bound is not a constant expression + } + + for (int i = 0; i < hello2.size(); + i++) { // COMPLIANT: The loop bound is a constant expression + } + + for (int i = 0; i < j; i += hello1.size()) { // NON_COMPLIANT: The loop step + // is not a constant expression + } + + for (int i = 0; i < j; + i += + hello2.size()) { // COMPLIANT: The loop step is a constant expression + } + /* ========== 6. Existence of pointers to the loop counter, loop bound, and * loop step ========== */ - int k = 10; - int l = 2; - for (int i = 0; i < k; i += l) { // COMPLIANT: The loop counter, bound, and // step are not taken addresses of } @@ -233,21 +267,4 @@ int main() { // a const pointer parameter g2(&l); } - - int n = 0; - - for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop counter is taken - // as a non-const pointer - *(true ? &i : &n) += 1; - } - - for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop counter is taken - // as a non-const pointer - *(true ? &k : &n) += 1; - } - - for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop counter is taken - // as a non-const pointer - *(true ? &l : &n) += 1; - } } \ No newline at end of file From 562c7bea40d922e03a1326b5b938ed321ee0b4f9 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 17 Sep 2025 18:14:39 -0400 Subject: [PATCH 595/628] Add two more cases --- cpp/misra/test/rules/RULE-9-5-1/test.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/cpp/misra/test/rules/RULE-9-5-1/test.cpp b/cpp/misra/test/rules/RULE-9-5-1/test.cpp index 0d8cfa35fb..718bc4d068 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-1/test.cpp @@ -6,6 +6,9 @@ void g1(int *x) {} // Function that takes a non-const integer pointer void f2(const int &x) {} // Function that takes a non-const integer reference void g2(const int *x) {} // Function that takes a non-const integer pointer +int h1() { return 1; } +constexpr int h2() { return 1; } + int main() { int j = 5; int k = 10; @@ -120,24 +123,20 @@ int main() { *(true ? &l : &n) += 1; } - std::string hello1 = "hello"; - std::string_view hello2{"hello"}; - - for (int i = 0; i < hello1.size(); + for (int i = 0; i < h1(); i++) { // NON_COMPLIANT: The loop bound is not a constant expression } - for (int i = 0; i < hello2.size(); + for (int i = 0; i < h2(); i++) { // COMPLIANT: The loop bound is a constant expression } - for (int i = 0; i < j; i += hello1.size()) { // NON_COMPLIANT: The loop step - // is not a constant expression + for (int i = 0; i < j; + i += h1()) { // NON_COMPLIANT: The loop step is not a constant expression } for (int i = 0; i < j; - i += - hello2.size()) { // COMPLIANT: The loop step is a constant expression + i += h2()) { // COMPLIANT: The loop step is a constant expression } /* ========== 6. Existence of pointers to the loop counter, loop bound, and From 6855e6a2df445c7e14fc3e2cd24984c3aa16bdf6 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 17 Sep 2025 18:14:50 -0400 Subject: [PATCH 596/628] Add QLDocs to two helper predicates --- .../LegacyForStatementsShouldBeSimple.ql | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index 3fd271c444..00f6f12f64 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -85,6 +85,21 @@ Expr getLoopStepOfForStmt(ForStmt forLoop) { result = forLoop.getUpdate().(AssignSubExpr).getRValue() } +/** + * Holds if either of the following holds for the given variable access: + * 1. Another variable access of the same variable as the given variable access is taken an + * address and is assigned to a non-const pointer variable, i.e. initialization, assignment, + * and pass-by-value. + * 2. Another variable access of the same variable as the given variable access is assigned + * to a non-const reference variable (thus constituting a `T` -> `&T` conversion.), i.e. + * initialization and assignment. + */ +/* + * Note that pass-by-reference is dealt with in a different predicate named + * `loopVariablePassedAsArgumentToNonConstReferenceParameter`, due to implementation + * limitations. + */ + predicate loopVariableAssignedToNonConstPointerOrReferenceType( ForStmt forLoop, VariableAccess loopVariableAccessInCondition ) { @@ -121,6 +136,11 @@ predicate loopVariableAssignedToNonConstPointerOrReferenceType( * Also, this predicate requires that the call is the body of the given for-loop. */ +/** + * Holds if the given variable access has another variable access with the same target + * variable that is passed as reference to a non-const reference parameter of a function, + * constituting a `T` -> `&T` conversion. + */ predicate loopVariablePassedAsArgumentToNonConstReferenceParameter( ForStmt forLoop, VariableAccess loopVariableAccessInCondition ) { From 5e24d1bd07fd0e535879ecc336af667993345488 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 22 Sep 2025 11:30:53 -0400 Subject: [PATCH 597/628] Introduce `from` variables and fix logical operator association --- .../LegacyForStatementsShouldBeSimple.ql | 191 ++++++++++-------- 1 file changed, 104 insertions(+), 87 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index 00f6f12f64..5ed79e2747 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -164,98 +164,115 @@ predicate loopVariablePassedAsArgumentToNonConstReferenceParameter( ) } -from ForStmt forLoop +from ForStmt forLoop, Locatable forLoopExpr, string message where not isExcluded(forLoop, StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) and - /* 1. There is a counter variable that is not of an integer type. */ - exists(Type type | type = forLoop.getAnIterationVariable().getType() | - not ( - type instanceof IntegralType or - type instanceof FixedWidthIntegralType - ) - ) - or - /* - * 2. The loop condition checks termination without comparing the counter variable and the - * loop bound using a relational operator. - */ + ( + /* 1. There is a counter variable that is not of an integer type. */ + exists(Type type | type = forLoop.getAnIterationVariable().getType() | + not ( + type instanceof IntegralType or + type instanceof FixedWidthIntegralType + ) + ) and + forLoopExpr = forLoop.getAnIterationVariable() and + message = "The counter variable is not of an integer type." + or + /* + * 2. The loop condition checks termination without comparing the counter variable to the + * loop bound using a relational operator. + */ - not forLoop.getCondition() instanceof LegacyForLoopCondition - or - /* 3. The loop counter is mutated somewhere other than its update expression. */ - exists(Variable loopCounter | - isIrregularLoopCounterModification(forLoop, loopCounter, loopCounter.getAnAccess()) - ) - or - /* 4. The type size of the loop counter is not greater or equal to that of the loop counter. */ - exists(LegacyForLoopCondition forLoopCondition | forLoopCondition = forLoop.getCondition() | - exists(Type loopCounterType, Type loopBoundType | - loopCounterType = forLoopCondition.getLoopCounter().getType() and - loopBoundType = forLoopCondition.getLoopBound().getType() - | - loopCounterType.getSize() < loopBoundType.getSize() - ) - ) - or - /* - * 5. The loop bound and the loop step are non-const expressions, or are variables that are - * mutated in the for loop. - */ + not forLoop.getCondition() instanceof LegacyForLoopCondition and + forLoopExpr = forLoop.getCondition() and + message = "TODO" + or + /* 3. The loop counter is mutated somewhere other than its update expression. */ + exists(Variable loopCounter | + isIrregularLoopCounterModification(forLoop, loopCounter, loopCounter.getAnAccess()) + ) and + forLoopExpr = forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() and + message = "TODO" + or + /* 4. The type size of the loop counter is not greater or equal to that of the loop counter. */ + exists(LegacyForLoopCondition forLoopCondition | forLoopCondition = forLoop.getCondition() | + exists(Type loopCounterType, Type loopBoundType | + loopCounterType = forLoopCondition.getLoopCounter().getType() and + loopBoundType = forLoopCondition.getLoopBound().getType() + | + loopCounterType.getSize() < loopBoundType.getSize() + ) + ) and + forLoopExpr = forLoop.getCondition() and + message = "TODO" + or + /* + * 5. The loop bound and the loop step are non-const expressions, or are variables that are + * mutated in the for loop. + */ - /* 5-1. The mutating expression mutates the loop bound. */ - exists(Expr loopBound | - loopBound = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() - | - exists(Expr mutatingExpr | - /* The mutating expression may be in the loop body. */ - mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() - or - /* The mutating expression may be in the loop updating expression. */ - mutatingExpr = forLoop.getUpdate().getAChild*() + /* 5-1. The mutating expression mutates the loop bound. */ + exists(Expr loopBound | + loopBound = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() | - /* 5-1-1. The loop bound is a variable that is mutated in the for loop. */ - variableModifiedInExpression(mutatingExpr, - loopBound.(VariableAccess).getTarget().getAnAccess()) - or - /* 5-1-2. The loop bound is not a variable access and is not a constant expression. */ - not loopBound instanceof VariableAccess and not loopBound.isConstant() - ) - ) - or - /* 5-2. The mutating expression mutates the loop step. */ - exists(Expr loopStep | loopStep = getLoopStepOfForStmt(forLoop) | - exists(Expr mutatingExpr | - /* The mutating expression may be in the loop body. */ - mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() - or - /* The mutating expression may be in the loop updating expression. */ - mutatingExpr = forLoop.getUpdate().getAChild*() - | - /* 5-1-2. The loop step is a variable that is mutated in the for loop. */ - variableModifiedInExpression(mutatingExpr, loopStep.(VariableAccess).getTarget().getAnAccess()) - or - /* 5-1-2. The loop bound is not a variable access and is not a constant expression. */ - not loopStep instanceof VariableAccess and not loopStep.isConstant() - ) - ) - or - /* - * 6. Any of the loop counter, loop bound, or a loop step is taken as a mutable reference - * or its address to a mutable pointer. - */ + exists(Expr mutatingExpr | + /* The mutating expression may be in the loop body. */ + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() + or + /* The mutating expression may be in the loop updating expression. */ + mutatingExpr = forLoop.getUpdate().getAChild*() + | + /* 5-1-1. The loop bound is a variable that is mutated in the for loop. */ + variableModifiedInExpression(mutatingExpr, + loopBound.(VariableAccess).getTarget().getAnAccess()) + or + /* 5-1-2. The loop bound is not a variable access and is not a constant expression. */ + not loopBound instanceof VariableAccess and not loopBound.isConstant() + ) + ) and + forLoopExpr = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and + message = "TODO" + or + /* 5-2. The mutating expression mutates the loop step. */ + exists(Expr loopStep | loopStep = getLoopStepOfForStmt(forLoop) | + exists(Expr mutatingExpr | + /* The mutating expression may be in the loop body. */ + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() + or + /* The mutating expression may be in the loop updating expression. */ + mutatingExpr = forLoop.getUpdate().getAChild*() + | + /* 5-1-2. The loop step is a variable that is mutated in the for loop. */ + variableModifiedInExpression(mutatingExpr, + loopStep.(VariableAccess).getTarget().getAnAccess()) + or + /* 5-1-2. The loop bound is not a variable access and is not a constant expression. */ + not loopStep instanceof VariableAccess and not loopStep.isConstant() + ) + ) and + forLoopExpr = getLoopStepOfForStmt(forLoop) and + message = "TODO" + or + /* + * 6. Any of the loop counter, loop bound, or a loop step is taken as a mutable reference + * or its address to a mutable pointer. + */ - exists(VariableAccess loopVariableAccessInCondition | - ( - loopVariableAccessInCondition = - forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() or - loopVariableAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() or - loopVariableAccessInCondition = getLoopStepOfForStmt(forLoop) + exists(VariableAccess loopVariableAccessInCondition | + ( + loopVariableAccessInCondition = + forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() or + loopVariableAccessInCondition = + forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() or + loopVariableAccessInCondition = getLoopStepOfForStmt(forLoop) + ) and + ( + loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, loopVariableAccessInCondition) + or + loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, + loopVariableAccessInCondition) + ) ) and - ( - loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, loopVariableAccessInCondition) - or - loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, - loopVariableAccessInCondition) - ) + message = "TODO" ) -select forLoop, "TODO" +select forLoop, message, forLoopExpr, "???" From 18daff7c1e2d5c58414b75f33cade74b84d2139e Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 22 Sep 2025 16:17:36 -0400 Subject: [PATCH 598/628] Introduce newtype --- .../LegacyForStatementsShouldBeSimple.ql | 374 +++++++++++++----- 1 file changed, 274 insertions(+), 100 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index 5ed79e2747..a78e6e7d43 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -164,115 +164,289 @@ predicate loopVariablePassedAsArgumentToNonConstReferenceParameter( ) } -from ForStmt forLoop, Locatable forLoopExpr, string message -where - not isExcluded(forLoop, StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) and - ( - /* 1. There is a counter variable that is not of an integer type. */ - exists(Type type | type = forLoop.getAnIterationVariable().getType() | +private newtype TAlertType = + /* 1. There is a counter variable that is not of an integer type. */ + TNonIntegerTypeCounterVariable(ForStmt forLoop, Variable iterationVariable) { + iterationVariable = forLoop.getAnIterationVariable() and + exists(Type type | type = iterationVariable.getType() | not ( type instanceof IntegralType or type instanceof FixedWidthIntegralType ) + ) + } or + /* + * 2. The loop condition checks termination without comparing the counter variable to the + * loop bound using a relational operator. + */ + + TNoRelationalOperatorInLoopCondition(ForStmt forLoop, Expr condition) { + condition = forLoop.getCondition() and + not condition instanceof LegacyForLoopCondition + } or + /* 3. The loop counter is mutated somewhere other than its update expression. */ + TLoopCounterMutatedInLoopBody(ForStmt forLoop, Variable loopCounter) { + isIrregularLoopCounterModification(forLoop, loopCounter, loopCounter.getAnAccess()) + } or + /* 4. The type size of the loop counter is smaller than that of the loop bound. */ + TLoopCounterSmallerThanLoopBound(ForStmt forLoop, LegacyForLoopCondition forLoopCondition) { + forLoopCondition = forLoop.getCondition() and + exists(Type loopCounterType, Type loopBoundType | + loopCounterType = forLoopCondition.getLoopCounter().getType() and + loopBoundType = forLoopCondition.getLoopBound().getType() + | + loopCounterType.getSize() < loopBoundType.getSize() + ) + } or + /* + * 5-1. The loop bound is a non-const expression, or a variable that is mutated in the for loop. + */ + + TLoopBoundIsNonConstExprOrMutatedVariableAccess(ForStmt forLoop, Expr loopBound, Expr mutatingExpr) { + loopBound = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and + ( + /* The mutating expression may be in the loop body. */ + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() + or + /* The mutating expression may be in the loop updating expression. */ + mutatingExpr = forLoop.getUpdate().getAChild*() ) and - forLoopExpr = forLoop.getAnIterationVariable() and - message = "The counter variable is not of an integer type." + /* 5-1-1. The loop bound is a variable that is mutated in the for loop. */ + ( + variableModifiedInExpression(mutatingExpr, + loopBound.(VariableAccess).getTarget().getAnAccess()) + or + /* 5-1-2. The loop bound is not a variable access nor a constant expression. */ + not loopBound instanceof VariableAccess and not loopBound.isConstant() + ) + } or + /* + * 5-2. The loop step is a non-const expression, or are variable that is mutated in the for loop. + */ + + TLoopStepIsNonConstExprOrMutatedVariableAccess(ForStmt forLoop, Expr loopStep, Expr mutatingExpr) { + loopStep = getLoopStepOfForStmt(forLoop) and + ( + /* The mutating expression may be in the loop body. */ + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() + or + /* The mutating expression may be in the loop updating expression. */ + mutatingExpr = forLoop.getUpdate().getAChild*() + ) and + ( + /* 5-2-2. The loop step is a variable that is mutated in the for loop. */ + variableModifiedInExpression(mutatingExpr, loopStep.(VariableAccess).getTarget().getAnAccess()) + or + /* 5-2-2. The loop step is not a variable access nor a constant expression. */ + not loopStep instanceof VariableAccess and not loopStep.isConstant() + ) + } or + /* + * 6-1. The loop counter is taken as a mutable reference or its address to a mutable pointer. + */ + + TLoopCounterIsTakenNonConstAddress(ForStmt forLoop, VariableAccess loopVariableAccessInCondition) { + loopVariableAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() and + ( + loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, loopVariableAccessInCondition) + or + loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, + loopVariableAccessInCondition) + ) + } or + /* + * 6-2. The loop bound is taken as a mutable reference or its address to a mutable pointer. + */ + + TLoopBoundIsTakenNonConstAddress(ForStmt forLoop, Expr loopVariableAccessInCondition) { + loopVariableAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and + ( + loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, loopVariableAccessInCondition) + or + loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, + loopVariableAccessInCondition) + ) + } or + /* + * 6-3. The loop step is taken as a mutable reference or its address to a mutable pointer. + */ + + TLoopStepIsTakenNonConstAddress(ForStmt forLoop, Expr loopVariableAccessInCondition) { + loopVariableAccessInCondition = getLoopStepOfForStmt(forLoop) and + ( + loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, loopVariableAccessInCondition) + or + loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, + loopVariableAccessInCondition) + ) + } + +class AlertType extends TAlertType { + /** + * Extract the primary location depending on the case of this instance. + */ + Location getLocation() { result = this.asElement().getLocation() } + + Element asElement() { + this = TNonIntegerTypeCounterVariable(result, _) or + this = TNoRelationalOperatorInLoopCondition(result, _) or + this = TLoopCounterMutatedInLoopBody(result, _) or + this = TLoopCounterSmallerThanLoopBound(result, _) or + this = TLoopBoundIsNonConstExprOrMutatedVariableAccess(result, _, _) or + this = TLoopStepIsNonConstExprOrMutatedVariableAccess(result, _, _) or + this = TLoopCounterIsTakenNonConstAddress(result, _) or + this = TLoopBoundIsTakenNonConstAddress(result, _) or + this = TLoopStepIsTakenNonConstAddress(result, _) + } + + /** + * Gets the target the link leads to depending on the case of this instance. + */ + Locatable getLinkTarget1() { + this = TNonIntegerTypeCounterVariable(_, result) + or + this = TNoRelationalOperatorInLoopCondition(_, result) + or + this = TLoopCounterMutatedInLoopBody(_, result) + or + exists(LegacyForLoopCondition forLoopCondition | + this = TLoopCounterSmallerThanLoopBound(_, forLoopCondition) and + result = forLoopCondition.getLoopCounter() + ) + or + this = TLoopBoundIsNonConstExprOrMutatedVariableAccess(_, result, _) + or + this = TLoopStepIsNonConstExprOrMutatedVariableAccess(_, result, _) + or + this = TLoopCounterIsTakenNonConstAddress(_, result) or - /* - * 2. The loop condition checks termination without comparing the counter variable to the - * loop bound using a relational operator. - */ + this = TLoopBoundIsTakenNonConstAddress(_, result) + or + this = TLoopStepIsTakenNonConstAddress(_, result) + } - not forLoop.getCondition() instanceof LegacyForLoopCondition and - forLoopExpr = forLoop.getCondition() and - message = "TODO" + /** + * Gets the text of the link depending on the case of this instance. + */ + string getLinkText1() { + this = TNonIntegerTypeCounterVariable(_, _) and + result = "counter variable" or - /* 3. The loop counter is mutated somewhere other than its update expression. */ - exists(Variable loopCounter | - isIrregularLoopCounterModification(forLoop, loopCounter, loopCounter.getAnAccess()) - ) and - forLoopExpr = forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() and - message = "TODO" - or - /* 4. The type size of the loop counter is not greater or equal to that of the loop counter. */ - exists(LegacyForLoopCondition forLoopCondition | forLoopCondition = forLoop.getCondition() | - exists(Type loopCounterType, Type loopBoundType | - loopCounterType = forLoopCondition.getLoopCounter().getType() and - loopBoundType = forLoopCondition.getLoopBound().getType() - | - loopCounterType.getSize() < loopBoundType.getSize() - ) - ) and - forLoopExpr = forLoop.getCondition() and - message = "TODO" + this = TNoRelationalOperatorInLoopCondition(_, _) and + result = "loop condition" or - /* - * 5. The loop bound and the loop step are non-const expressions, or are variables that are - * mutated in the for loop. - */ + this = TLoopCounterMutatedInLoopBody(_, _) and + result = "counter variable" + or + this = TLoopCounterSmallerThanLoopBound(_, _) and + result = "counter variable" + or + this = TLoopBoundIsNonConstExprOrMutatedVariableAccess(_, _, _) and + result = "loop bound" + or + this = TLoopStepIsNonConstExprOrMutatedVariableAccess(_, _, _) and + result = "loop step" + or + this = TLoopCounterIsTakenNonConstAddress(_, _) and + result = "loop counter" + or + this = TLoopBoundIsTakenNonConstAddress(_, _) and + result = "loop bound" + or + this = TLoopStepIsTakenNonConstAddress(_, _) and + result = "loop step" + } - /* 5-1. The mutating expression mutates the loop bound. */ - exists(Expr loopBound | - loopBound = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() - | - exists(Expr mutatingExpr | - /* The mutating expression may be in the loop body. */ - mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() - or - /* The mutating expression may be in the loop updating expression. */ - mutatingExpr = forLoop.getUpdate().getAChild*() - | - /* 5-1-1. The loop bound is a variable that is mutated in the for loop. */ - variableModifiedInExpression(mutatingExpr, - loopBound.(VariableAccess).getTarget().getAnAccess()) - or - /* 5-1-2. The loop bound is not a variable access and is not a constant expression. */ - not loopBound instanceof VariableAccess and not loopBound.isConstant() - ) - ) and - forLoopExpr = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and - message = "TODO" - or - /* 5-2. The mutating expression mutates the loop step. */ - exists(Expr loopStep | loopStep = getLoopStepOfForStmt(forLoop) | - exists(Expr mutatingExpr | - /* The mutating expression may be in the loop body. */ - mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() - or - /* The mutating expression may be in the loop updating expression. */ - mutatingExpr = forLoop.getUpdate().getAChild*() - | - /* 5-1-2. The loop step is a variable that is mutated in the for loop. */ - variableModifiedInExpression(mutatingExpr, - loopStep.(VariableAccess).getTarget().getAnAccess()) - or - /* 5-1-2. The loop bound is not a variable access and is not a constant expression. */ - not loopStep instanceof VariableAccess and not loopStep.isConstant() - ) - ) and - forLoopExpr = getLoopStepOfForStmt(forLoop) and - message = "TODO" + /** + * Gets the message with a placeholder, depending on the case of this instance. + */ + string getMessage() { + this = TNonIntegerTypeCounterVariable(_, _) and + result = "The $@ is not of an integer type." // Throwaway placeholder + or + this = TNoRelationalOperatorInLoopCondition(_, _) and + result = + "The $@ does not compare the counter variable to an expression using a relational operator." // Throwaway placeholder + or + this = TLoopCounterMutatedInLoopBody(_, _) and + result = "The $@ may be mutated in a location other than its update expression." + or + this = TLoopCounterSmallerThanLoopBound(_, _) and + result = "The $@ has a smaller type than that of the $@." + or + this = TLoopBoundIsNonConstExprOrMutatedVariableAccess(_, _, _) and + result = "The $@ is a non-const expression, or a variable that is $@ in the loop." + or + this = TLoopStepIsNonConstExprOrMutatedVariableAccess(_, _, _) and + result = "The $@ is a non-const expression, or a variable that is $@ in the loop." + or + this = TLoopCounterIsTakenNonConstAddress(_, _) and + result = "The $@ is taken as a mutable reference or its address to a mutable pointer." + or + this = TLoopBoundIsTakenNonConstAddress(_, _) and + result = "The $@ is taken as a mutable reference or its address to a mutable pointer." or - /* - * 6. Any of the loop counter, loop bound, or a loop step is taken as a mutable reference - * or its address to a mutable pointer. - */ + this = TLoopStepIsTakenNonConstAddress(_, _) and + result = "The $@ is taken as a mutable reference or its address to a mutable pointer." + } + + Locatable getLinkTarget2() { + this = TNonIntegerTypeCounterVariable(_, result) // Throwaway + or + this = TNoRelationalOperatorInLoopCondition(_, result) // Throwaway + or + this = TLoopCounterMutatedInLoopBody(_, _) // Throwaway + or + exists(LegacyForLoopCondition forLoopCondition | + this = TLoopCounterSmallerThanLoopBound(_, forLoopCondition) and + result = forLoopCondition.getLoopBound() + ) + or + this = TLoopBoundIsNonConstExprOrMutatedVariableAccess(_, _, result) + or + this = TLoopStepIsNonConstExprOrMutatedVariableAccess(_, _, result) + or + this = TLoopCounterIsTakenNonConstAddress(_, result) // Throwaway + or + this = TLoopBoundIsTakenNonConstAddress(_, result) // Throwaway + or + this = TLoopStepIsTakenNonConstAddress(_, result) // Throwaway + } + + string getLinkText2() { + this = TNonIntegerTypeCounterVariable(_, _) and + result = "N/A" // Throwaway + or + this = TNoRelationalOperatorInLoopCondition(_, _) and + result = "N/A" // Throwaway + or + this = TLoopCounterMutatedInLoopBody(_, _) and + result = "N/A" // Throwaway + or + this = TLoopCounterSmallerThanLoopBound(_, _) and + result = "loop bound" + or + this = TLoopBoundIsNonConstExprOrMutatedVariableAccess(_, _, _) and + result = "mutated" + or + this = TLoopStepIsNonConstExprOrMutatedVariableAccess(_, _, _) and + result = "mutated" + or + this = TLoopCounterIsTakenNonConstAddress(_, _) and + result = "N/A" // Throwaway + or + this = TLoopBoundIsTakenNonConstAddress(_, _) and + result = "N/A" // Throwaway + or + this = TLoopStepIsTakenNonConstAddress(_, _) and + result = "N/A" // Throwaway + } + + string toString() { result = this.asElement().toString() } +} + +from AlertType alert +where not isExcluded(alert.asElement(), StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) +select alert, alert.getMessage(), alert.getLinkTarget1(), alert.getLinkText1(), + alert.getLinkTarget2(), alert.getLinkText2() - exists(VariableAccess loopVariableAccessInCondition | - ( - loopVariableAccessInCondition = - forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() or - loopVariableAccessInCondition = - forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() or - loopVariableAccessInCondition = getLoopStepOfForStmt(forLoop) - ) and - ( - loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, loopVariableAccessInCondition) - or - loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, - loopVariableAccessInCondition) - ) - ) and - message = "TODO" - ) -select forLoop, message, forLoopExpr, "???" From 55b847637bf0411c295aa3200e5467de09e178fc Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 22 Sep 2025 17:26:43 -0400 Subject: [PATCH 599/628] Split cases `5-1` and `5-2` --- .../LegacyForStatementsShouldBeSimple.ql | 100 ++++++++++++------ 1 file changed, 66 insertions(+), 34 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index a78e6e7d43..a22c15ed45 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -198,11 +198,8 @@ private newtype TAlertType = loopCounterType.getSize() < loopBoundType.getSize() ) } or - /* - * 5-1. The loop bound is a non-const expression, or a variable that is mutated in the for loop. - */ - - TLoopBoundIsNonConstExprOrMutatedVariableAccess(ForStmt forLoop, Expr loopBound, Expr mutatingExpr) { + /* 5-1-1. The loop bound is a variable that is mutated in the for loop. */ + TLoopBoundIsMutatedVariableAccess(ForStmt forLoop, Expr loopBound, Expr mutatingExpr) { loopBound = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and ( /* The mutating expression may be in the loop body. */ @@ -211,20 +208,22 @@ private newtype TAlertType = /* The mutating expression may be in the loop updating expression. */ mutatingExpr = forLoop.getUpdate().getAChild*() ) and - /* 5-1-1. The loop bound is a variable that is mutated in the for loop. */ + variableModifiedInExpression(mutatingExpr, loopBound.(VariableAccess).getTarget().getAnAccess()) + } or + /* 5-1-2. The loop bound is not a variable access nor a constant expression. */ + TLoopBoundIsNonConstExpr(ForStmt forLoop, Expr loopBound, Expr mutatingExpr) { + loopBound = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and ( - variableModifiedInExpression(mutatingExpr, - loopBound.(VariableAccess).getTarget().getAnAccess()) + /* The mutating expression may be in the loop body. */ + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() or - /* 5-1-2. The loop bound is not a variable access nor a constant expression. */ - not loopBound instanceof VariableAccess and not loopBound.isConstant() - ) + /* The mutating expression may be in the loop updating expression. */ + mutatingExpr = forLoop.getUpdate().getAChild*() + ) and + (not loopBound instanceof VariableAccess and not loopBound.isConstant()) } or - /* - * 5-2. The loop step is a non-const expression, or are variable that is mutated in the for loop. - */ - - TLoopStepIsNonConstExprOrMutatedVariableAccess(ForStmt forLoop, Expr loopStep, Expr mutatingExpr) { + /* 5-2-1. The loop step is a variable that is mutated in the for loop. */ + TLoopStepIsMutatedVariableAccess(ForStmt forLoop, Expr loopStep, Expr mutatingExpr) { loopStep = getLoopStepOfForStmt(forLoop) and ( /* The mutating expression may be in the loop body. */ @@ -233,13 +232,19 @@ private newtype TAlertType = /* The mutating expression may be in the loop updating expression. */ mutatingExpr = forLoop.getUpdate().getAChild*() ) and + variableModifiedInExpression(mutatingExpr, loopStep.(VariableAccess).getTarget().getAnAccess()) + } or + /* 5-2-2. The loop step is not a variable access nor a constant expression. */ + TLoopStepIsNonConstExpr(ForStmt forLoop, Expr loopStep, Expr mutatingExpr) { + loopStep = getLoopStepOfForStmt(forLoop) and ( - /* 5-2-2. The loop step is a variable that is mutated in the for loop. */ - variableModifiedInExpression(mutatingExpr, loopStep.(VariableAccess).getTarget().getAnAccess()) + /* The mutating expression may be in the loop body. */ + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() or - /* 5-2-2. The loop step is not a variable access nor a constant expression. */ - not loopStep instanceof VariableAccess and not loopStep.isConstant() - ) + /* The mutating expression may be in the loop updating expression. */ + mutatingExpr = forLoop.getUpdate().getAChild*() + ) and + (not loopStep instanceof VariableAccess and not loopStep.isConstant()) } or /* * 6-1. The loop counter is taken as a mutable reference or its address to a mutable pointer. @@ -292,8 +297,10 @@ class AlertType extends TAlertType { this = TNoRelationalOperatorInLoopCondition(result, _) or this = TLoopCounterMutatedInLoopBody(result, _) or this = TLoopCounterSmallerThanLoopBound(result, _) or - this = TLoopBoundIsNonConstExprOrMutatedVariableAccess(result, _, _) or - this = TLoopStepIsNonConstExprOrMutatedVariableAccess(result, _, _) or + this = TLoopBoundIsMutatedVariableAccess(result, _, _) or + this = TLoopStepIsNonConstExpr(result, _, _) or + this = TLoopBoundIsMutatedVariableAccess(result, _, _) or + this = TLoopStepIsNonConstExpr(result, _, _) or this = TLoopCounterIsTakenNonConstAddress(result, _) or this = TLoopBoundIsTakenNonConstAddress(result, _) or this = TLoopStepIsTakenNonConstAddress(result, _) @@ -314,9 +321,13 @@ class AlertType extends TAlertType { result = forLoopCondition.getLoopCounter() ) or - this = TLoopBoundIsNonConstExprOrMutatedVariableAccess(_, result, _) + this = TLoopBoundIsNonConstExpr(_, result, _) + or + this = TLoopBoundIsMutatedVariableAccess(_, result, _) or - this = TLoopStepIsNonConstExprOrMutatedVariableAccess(_, result, _) + this = TLoopStepIsNonConstExpr(_, result, _) + or + this = TLoopStepIsMutatedVariableAccess(_, result, _) or this = TLoopCounterIsTakenNonConstAddress(_, result) or @@ -341,10 +352,16 @@ class AlertType extends TAlertType { this = TLoopCounterSmallerThanLoopBound(_, _) and result = "counter variable" or - this = TLoopBoundIsNonConstExprOrMutatedVariableAccess(_, _, _) and + this = TLoopBoundIsMutatedVariableAccess(_, _, _) and + result = "loop bound" + or + this = TLoopBoundIsNonConstExpr(_, _, _) and result = "loop bound" or - this = TLoopStepIsNonConstExprOrMutatedVariableAccess(_, _, _) and + this = TLoopStepIsMutatedVariableAccess(_, _, _) and + result = "loop step" + or + this = TLoopStepIsNonConstExpr(_, _, _) and result = "loop step" or this = TLoopCounterIsTakenNonConstAddress(_, _) and @@ -374,10 +391,16 @@ class AlertType extends TAlertType { this = TLoopCounterSmallerThanLoopBound(_, _) and result = "The $@ has a smaller type than that of the $@." or - this = TLoopBoundIsNonConstExprOrMutatedVariableAccess(_, _, _) and + this = TLoopBoundIsNonConstExpr(_, _, _) and + result = "The $@ is a non-const expression, or a variable that is $@ in the loop." + or + this = TLoopBoundIsMutatedVariableAccess(_, _, _) and result = "The $@ is a non-const expression, or a variable that is $@ in the loop." or - this = TLoopStepIsNonConstExprOrMutatedVariableAccess(_, _, _) and + this = TLoopStepIsNonConstExpr(_, _, _) and + result = "The $@ is a non-const expression, or a variable that is $@ in the loop." + or + this = TLoopStepIsMutatedVariableAccess(_, _, _) and result = "The $@ is a non-const expression, or a variable that is $@ in the loop." or this = TLoopCounterIsTakenNonConstAddress(_, _) and @@ -402,9 +425,13 @@ class AlertType extends TAlertType { result = forLoopCondition.getLoopBound() ) or - this = TLoopBoundIsNonConstExprOrMutatedVariableAccess(_, _, result) + this = TLoopBoundIsNonConstExpr(_, _, result) + or + this = TLoopBoundIsMutatedVariableAccess(_, _, result) or - this = TLoopStepIsNonConstExprOrMutatedVariableAccess(_, _, result) + this = TLoopStepIsNonConstExpr(_, _, result) + or + this = TLoopStepIsMutatedVariableAccess(_, _, result) or this = TLoopCounterIsTakenNonConstAddress(_, result) // Throwaway or @@ -426,10 +453,16 @@ class AlertType extends TAlertType { this = TLoopCounterSmallerThanLoopBound(_, _) and result = "loop bound" or - this = TLoopBoundIsNonConstExprOrMutatedVariableAccess(_, _, _) and + this = TLoopBoundIsNonConstExpr(_, _, _) and result = "mutated" or - this = TLoopStepIsNonConstExprOrMutatedVariableAccess(_, _, _) and + this = TLoopBoundIsMutatedVariableAccess(_, _, _) and + result = "mutated" + or + this = TLoopStepIsNonConstExpr(_, _, _) and + result = "mutated" + or + this = TLoopStepIsMutatedVariableAccess(_, _, _) and result = "mutated" or this = TLoopCounterIsTakenNonConstAddress(_, _) and @@ -449,4 +482,3 @@ from AlertType alert where not isExcluded(alert.asElement(), StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) select alert, alert.getMessage(), alert.getLinkTarget1(), alert.getLinkText1(), alert.getLinkTarget2(), alert.getLinkText2() - From 662f51f1fe8f51d2c1918a85b7ba641310ee5386 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 22 Sep 2025 17:52:07 -0400 Subject: [PATCH 600/628] Debug 5-1-2 and 5-2-2 not being reported --- .../LegacyForStatementsShouldBeSimple.ql | 52 +++++++------------ 1 file changed, 19 insertions(+), 33 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index a22c15ed45..a7054a3407 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -211,15 +211,8 @@ private newtype TAlertType = variableModifiedInExpression(mutatingExpr, loopBound.(VariableAccess).getTarget().getAnAccess()) } or /* 5-1-2. The loop bound is not a variable access nor a constant expression. */ - TLoopBoundIsNonConstExpr(ForStmt forLoop, Expr loopBound, Expr mutatingExpr) { + TLoopBoundIsNonConstExpr(ForStmt forLoop, Expr loopBound) { loopBound = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and - ( - /* The mutating expression may be in the loop body. */ - mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() - or - /* The mutating expression may be in the loop updating expression. */ - mutatingExpr = forLoop.getUpdate().getAChild*() - ) and (not loopBound instanceof VariableAccess and not loopBound.isConstant()) } or /* 5-2-1. The loop step is a variable that is mutated in the for loop. */ @@ -235,15 +228,8 @@ private newtype TAlertType = variableModifiedInExpression(mutatingExpr, loopStep.(VariableAccess).getTarget().getAnAccess()) } or /* 5-2-2. The loop step is not a variable access nor a constant expression. */ - TLoopStepIsNonConstExpr(ForStmt forLoop, Expr loopStep, Expr mutatingExpr) { + TLoopStepIsNonConstExpr(ForStmt forLoop, Expr loopStep) { loopStep = getLoopStepOfForStmt(forLoop) and - ( - /* The mutating expression may be in the loop body. */ - mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() - or - /* The mutating expression may be in the loop updating expression. */ - mutatingExpr = forLoop.getUpdate().getAChild*() - ) and (not loopStep instanceof VariableAccess and not loopStep.isConstant()) } or /* @@ -298,9 +284,9 @@ class AlertType extends TAlertType { this = TLoopCounterMutatedInLoopBody(result, _) or this = TLoopCounterSmallerThanLoopBound(result, _) or this = TLoopBoundIsMutatedVariableAccess(result, _, _) or - this = TLoopStepIsNonConstExpr(result, _, _) or - this = TLoopBoundIsMutatedVariableAccess(result, _, _) or - this = TLoopStepIsNonConstExpr(result, _, _) or + this = TLoopBoundIsNonConstExpr(result, _) or + this = TLoopStepIsMutatedVariableAccess(result, _, _) or + this = TLoopStepIsNonConstExpr(result, _) or this = TLoopCounterIsTakenNonConstAddress(result, _) or this = TLoopBoundIsTakenNonConstAddress(result, _) or this = TLoopStepIsTakenNonConstAddress(result, _) @@ -321,11 +307,11 @@ class AlertType extends TAlertType { result = forLoopCondition.getLoopCounter() ) or - this = TLoopBoundIsNonConstExpr(_, result, _) + this = TLoopBoundIsNonConstExpr(_, result) or this = TLoopBoundIsMutatedVariableAccess(_, result, _) or - this = TLoopStepIsNonConstExpr(_, result, _) + this = TLoopStepIsNonConstExpr(_, result) or this = TLoopStepIsMutatedVariableAccess(_, result, _) or @@ -355,13 +341,13 @@ class AlertType extends TAlertType { this = TLoopBoundIsMutatedVariableAccess(_, _, _) and result = "loop bound" or - this = TLoopBoundIsNonConstExpr(_, _, _) and + this = TLoopBoundIsNonConstExpr(_, _) and result = "loop bound" or this = TLoopStepIsMutatedVariableAccess(_, _, _) and result = "loop step" or - this = TLoopStepIsNonConstExpr(_, _, _) and + this = TLoopStepIsNonConstExpr(_, _) and result = "loop step" or this = TLoopCounterIsTakenNonConstAddress(_, _) and @@ -391,14 +377,14 @@ class AlertType extends TAlertType { this = TLoopCounterSmallerThanLoopBound(_, _) and result = "The $@ has a smaller type than that of the $@." or - this = TLoopBoundIsNonConstExpr(_, _, _) and - result = "The $@ is a non-const expression, or a variable that is $@ in the loop." + this = TLoopBoundIsNonConstExpr(_, _) and + result = "The $@ is a $@." or this = TLoopBoundIsMutatedVariableAccess(_, _, _) and result = "The $@ is a non-const expression, or a variable that is $@ in the loop." or - this = TLoopStepIsNonConstExpr(_, _, _) and - result = "The $@ is a non-const expression, or a variable that is $@ in the loop." + this = TLoopStepIsNonConstExpr(_, _) and + result = "The $@ is a $@." or this = TLoopStepIsMutatedVariableAccess(_, _, _) and result = "The $@ is a non-const expression, or a variable that is $@ in the loop." @@ -425,11 +411,11 @@ class AlertType extends TAlertType { result = forLoopCondition.getLoopBound() ) or - this = TLoopBoundIsNonConstExpr(_, _, result) + this = TLoopBoundIsNonConstExpr(_, result) or this = TLoopBoundIsMutatedVariableAccess(_, _, result) or - this = TLoopStepIsNonConstExpr(_, _, result) + this = TLoopStepIsNonConstExpr(_, result) or this = TLoopStepIsMutatedVariableAccess(_, _, result) or @@ -453,14 +439,14 @@ class AlertType extends TAlertType { this = TLoopCounterSmallerThanLoopBound(_, _) and result = "loop bound" or - this = TLoopBoundIsNonConstExpr(_, _, _) and - result = "mutated" + this = TLoopBoundIsNonConstExpr(_, _) and + result = "non-const expression" or this = TLoopBoundIsMutatedVariableAccess(_, _, _) and result = "mutated" or - this = TLoopStepIsNonConstExpr(_, _, _) and - result = "mutated" + this = TLoopStepIsNonConstExpr(_, _) and + result = "non-const expression" or this = TLoopStepIsMutatedVariableAccess(_, _, _) and result = "mutated" From a653b66511c1eef3f7a94932a333546b4f0c9b83 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 23 Sep 2025 17:05:36 -0400 Subject: [PATCH 601/628] Add LegacyForLoopUpdateExpression and test cases --- .../LegacyForStatementsShouldBeSimple.ql | 96 ++++++++++++++++++- cpp/misra/test/rules/RULE-9-5-1/test.cpp | 23 +++++ 2 files changed, 115 insertions(+), 4 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index a7054a3407..708b4eaf73 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -72,6 +72,60 @@ predicate variableModifiedInExpression(Expr expr, VariableAccess va) { valueToUpdate(va, _, expr) } +abstract class LegacyForLoopUpdateExpression extends Expr { + ForStmt forLoop; + + LegacyForLoopUpdateExpression() { this = forLoop.getUpdate().getAChild*() } + + abstract Expr getLoopStep(); +} + +class CrementLegacyForLoopUpdateExpression extends LegacyForLoopUpdateExpression { + CrementLegacyForLoopUpdateExpression() { this instanceof CrementOperation } + + override Expr getLoopStep() { none() } +} + +class AssignAddOrSubExpr extends LegacyForLoopUpdateExpression { + AssignAddOrSubExpr() { + this instanceof AssignAddExpr or + this instanceof AssignSubExpr + } + + override Expr getLoopStep() { + result = this.(AssignAddExpr).getRValue() or + result = this.(AssignSubExpr).getRValue() + } +} + +class AddOrSubThenAssignExpr extends LegacyForLoopUpdateExpression { + Expr assignRhs; + + AddOrSubThenAssignExpr() { + this.(AssignExpr).getRValue() = assignRhs and + ( + assignRhs instanceof AddExpr or + assignRhs instanceof SubExpr + ) + } + + override Expr getLoopStep() { + ( + result = assignRhs.(AddExpr).getAnOperand() or + result = assignRhs.(SubExpr).getAnOperand() + ) and + exists(VariableAccess iterationVariableAccess | + ( + iterationVariableAccess = assignRhs.(AddExpr).getAnOperand() + or + iterationVariableAccess = assignRhs.(SubExpr).getAnOperand() + ) and + iterationVariableAccess.getTarget() = forLoop.getAnIterationVariable() and + result != iterationVariableAccess + ) + } +} + /** * Gets the loop step of a legacy for loop. * @@ -81,8 +135,36 @@ predicate variableModifiedInExpression(Expr expr, VariableAccess va) { * predicate. */ Expr getLoopStepOfForStmt(ForStmt forLoop) { - result = forLoop.getUpdate().(AssignAddExpr).getRValue() or - result = forLoop.getUpdate().(AssignSubExpr).getRValue() + /* + * NOTE: We compute the transitive closure of `getAChild` on the update expression, + * since the update expression may be a compound one that embeds the four aforementioned + * expression types, such as a comma expression (e.g. `i += 1, E` where `E` is an + * arbitrary expression). + * + * This may be detrimental to performance, but we keep it for soundness. A possible + * alternative is an IR-based solution. + */ + + /* 1. Get the expression `E` when the update expression is `i += E` or `i -= E`. */ + result = forLoop.getUpdate().getAChild*().(AssignAddExpr).getRValue() + or + result = forLoop.getUpdate().getAChild*().(AssignSubExpr).getRValue() + or + /* 2. Get the expression `E` when the update expression is `i = i + E` or `i = i - E`. */ + ( + result = forLoop.getUpdate().getAChild*().(AssignExpr).getRValue().(AddExpr).getAnOperand() or + result = forLoop.getUpdate().getAChild*().(AssignExpr).getRValue().(SubExpr).getAnOperand() + ) and + exists(VariableAccess iterationVariableAccess | + ( + iterationVariableAccess = + forLoop.getUpdate().getAChild*().(AssignExpr).getRValue().(AddExpr).getAnOperand() or + iterationVariableAccess = + forLoop.getUpdate().getAChild*().(AssignExpr).getRValue().(SubExpr).getAnOperand() + ) and + iterationVariableAccess.getTarget() = forLoop.getAnIterationVariable() and + result != iterationVariableAccess + ) } /** @@ -184,9 +266,15 @@ private newtype TAlertType = condition = forLoop.getCondition() and not condition instanceof LegacyForLoopCondition } or - /* 3. The loop counter is mutated somewhere other than its update expression. */ + /* 3-1. The loop counter is mutated somewhere other than its update expression. */ TLoopCounterMutatedInLoopBody(ForStmt forLoop, Variable loopCounter) { - isIrregularLoopCounterModification(forLoop, loopCounter, loopCounter.getAnAccess()) + loopCounter = forLoop.getAnIterationVariable() and + variableModifiedInExpression(forLoop.getStmt().getChildStmt().getAChild*(), + loopCounter.getAnAccess()) + } or + /* 3-2. The loop counter is not updated using either of `++`, `--`, `+=`, or `-=`. */ + TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(ForStmt forLoop) { + none() // TODO } or /* 4. The type size of the loop counter is smaller than that of the loop bound. */ TLoopCounterSmallerThanLoopBound(ForStmt forLoop, LegacyForLoopCondition forLoopCondition) { diff --git a/cpp/misra/test/rules/RULE-9-5-1/test.cpp b/cpp/misra/test/rules/RULE-9-5-1/test.cpp index 718bc4d068..cb6905525e 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-1/test.cpp @@ -46,10 +46,33 @@ int main() { // the update expression } + for (int i = 20; i > 10; + --i) { // COMPLIANT: Pre-increment operator used as the update expression + } + + for (int i = 20; i > 10; i--) { // COMPLIANT: Post-increment operator used as + // the update expression + } + for (int i = 0; i < 10; i += 3) { // COMPLIANT: Add-and-assign operator used // as the update expression with loop step 3 } + for (int i = 20; i > 10; + i -= 3) { // COMPLIANT: Add-and-assign operator used + // as the update expression with loop step 3 + } + + for (int i = 0; i < 10; + i = i + + 3) { // COMPLIANT: Direct assignment with addition with loop step 3 + } + + for (int i = 20; i < 10; + i = i - + 3) { // COMPLIANT: Direct assignment with addition with loop step 3 + } + for (int i = 0; i < 10; i *= 2) { // NON_COMPLIANT: Mutiplication is not incrementing } From c8c0770d19aafe77ec70ff1c246cecd7d9766510 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 24 Sep 2025 14:10:29 -0400 Subject: [PATCH 602/628] Separate out helper classes into libraries --- cpp/common/src/codingstandards/cpp/Loops.qll | 31 ++++++ .../src/codingstandards/cpp/ast/Increment.qll | 57 +++++++++++ .../LegacyForStatementsShouldBeSimple.ql | 95 +------------------ 3 files changed, 91 insertions(+), 92 deletions(-) create mode 100644 cpp/common/src/codingstandards/cpp/ast/Increment.qll diff --git a/cpp/common/src/codingstandards/cpp/Loops.qll b/cpp/common/src/codingstandards/cpp/Loops.qll index aa3dc64ea5..ae5f6cf7f9 100644 --- a/cpp/common/src/codingstandards/cpp/Loops.qll +++ b/cpp/common/src/codingstandards/cpp/Loops.qll @@ -374,3 +374,34 @@ predicate isInvalidLoop(ForStmt forLoop, string reason, Locatable reasonLocation reason = "its $@ is not a boolean" and reasonLabel = "loop control variable" } + +/** + * A comparison expression that has the minimum qualification as being a valid termination + * condition of a legacy for-loop. It is characterized by a value read from a variable being + * compared to a value, which is supposed to be the loop bound. + */ +class LegacyForLoopCondition extends RelationalOperation { + /** + * The legacy for-loop this relational operation is a condition of. + */ + ForStmt forLoop; + VariableAccess loopCounter; + Expr loopBound; + + LegacyForLoopCondition() { + loopCounter = this.getAnOperand() and + loopBound = this.getAnOperand() and + loopCounter.getTarget() = getAnIterationVariable(forLoop) and + loopBound != loopCounter + } + + /** + * Gets the variable access to the loop counter variable, appearing in this loop condition. + */ + VariableAccess getLoopCounter() { result = loopCounter } + + /** + * Gets the variable access to the loop bound variable, appearing in this loop condition. + */ + Expr getLoopBound() { result = loopBound } +} diff --git a/cpp/common/src/codingstandards/cpp/ast/Increment.qll b/cpp/common/src/codingstandards/cpp/ast/Increment.qll new file mode 100644 index 0000000000..315748e067 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/ast/Increment.qll @@ -0,0 +1,57 @@ +import cpp + +abstract class LegacyForLoopUpdateExpression extends Expr { + ForStmt forLoop; + + LegacyForLoopUpdateExpression() { this = forLoop.getUpdate().getAChild*() } + + abstract Expr getLoopStep(); + /* TODO: Complete below and use it for 3-2 */ + // abstract VariableAccess getUpdatedVariable(); +} + +class CrementLegacyForLoopUpdateExpression extends LegacyForLoopUpdateExpression { + CrementLegacyForLoopUpdateExpression() { this instanceof CrementOperation } + + override Expr getLoopStep() { none() } +} + +class AssignAddOrSubExpr extends LegacyForLoopUpdateExpression { + AssignAddOrSubExpr() { + this instanceof AssignAddExpr or + this instanceof AssignSubExpr + } + + override Expr getLoopStep() { + result = this.(AssignAddExpr).getRValue() or + result = this.(AssignSubExpr).getRValue() + } +} + +class AddOrSubThenAssignExpr extends LegacyForLoopUpdateExpression { + Expr assignRhs; + + AddOrSubThenAssignExpr() { + this.(AssignExpr).getRValue() = assignRhs and + ( + assignRhs instanceof AddExpr or + assignRhs instanceof SubExpr + ) + } + + override Expr getLoopStep() { + ( + result = assignRhs.(AddExpr).getAnOperand() or + result = assignRhs.(SubExpr).getAnOperand() + ) and + exists(VariableAccess iterationVariableAccess | + ( + iterationVariableAccess = assignRhs.(AddExpr).getAnOperand() + or + iterationVariableAccess = assignRhs.(SubExpr).getAnOperand() + ) and + iterationVariableAccess.getTarget() = forLoop.getAnIterationVariable() and + result != iterationVariableAccess + ) + } +} \ No newline at end of file diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index 708b4eaf73..91212d2830 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -22,37 +22,6 @@ import codingstandards.cpp.Call import codingstandards.cpp.Loops import codingstandards.cpp.misra.BuiltInTypeRules::MisraCpp23BuiltInTypes -/** - * A comparison expression that has the minimum qualification as being a valid termination - * condition of a legacy for-loop. It is characterized by a value read from a variable being - * compared to a value, which is supposed to be the loop bound. - */ -class LegacyForLoopCondition extends RelationalOperation { - /** - * The legacy for-loop this relational operation is a condition of. - */ - ForStmt forLoop; - VariableAccess loopCounter; - Expr loopBound; - - LegacyForLoopCondition() { - loopCounter = this.getAnOperand() and - loopBound = this.getAnOperand() and - loopCounter.getTarget() = getAnIterationVariable(forLoop) and - loopBound != loopCounter - } - - /** - * Gets the variable access to the loop counter variable, embedded in this loop condition. - */ - VariableAccess getLoopCounter() { result = loopCounter } - - /** - * Gets the variable access to the loop bound variable, embedded in this loop condition. - */ - Expr getLoopBound() { result = loopBound } -} - /** * Holds if the given expression may mutate the variable. */ @@ -72,60 +41,6 @@ predicate variableModifiedInExpression(Expr expr, VariableAccess va) { valueToUpdate(va, _, expr) } -abstract class LegacyForLoopUpdateExpression extends Expr { - ForStmt forLoop; - - LegacyForLoopUpdateExpression() { this = forLoop.getUpdate().getAChild*() } - - abstract Expr getLoopStep(); -} - -class CrementLegacyForLoopUpdateExpression extends LegacyForLoopUpdateExpression { - CrementLegacyForLoopUpdateExpression() { this instanceof CrementOperation } - - override Expr getLoopStep() { none() } -} - -class AssignAddOrSubExpr extends LegacyForLoopUpdateExpression { - AssignAddOrSubExpr() { - this instanceof AssignAddExpr or - this instanceof AssignSubExpr - } - - override Expr getLoopStep() { - result = this.(AssignAddExpr).getRValue() or - result = this.(AssignSubExpr).getRValue() - } -} - -class AddOrSubThenAssignExpr extends LegacyForLoopUpdateExpression { - Expr assignRhs; - - AddOrSubThenAssignExpr() { - this.(AssignExpr).getRValue() = assignRhs and - ( - assignRhs instanceof AddExpr or - assignRhs instanceof SubExpr - ) - } - - override Expr getLoopStep() { - ( - result = assignRhs.(AddExpr).getAnOperand() or - result = assignRhs.(SubExpr).getAnOperand() - ) and - exists(VariableAccess iterationVariableAccess | - ( - iterationVariableAccess = assignRhs.(AddExpr).getAnOperand() - or - iterationVariableAccess = assignRhs.(SubExpr).getAnOperand() - ) and - iterationVariableAccess.getTarget() = forLoop.getAnIterationVariable() and - result != iterationVariableAccess - ) - } -} - /** * Gets the loop step of a legacy for loop. * @@ -146,9 +61,7 @@ Expr getLoopStepOfForStmt(ForStmt forLoop) { */ /* 1. Get the expression `E` when the update expression is `i += E` or `i -= E`. */ - result = forLoop.getUpdate().getAChild*().(AssignAddExpr).getRValue() - or - result = forLoop.getUpdate().getAChild*().(AssignSubExpr).getRValue() + result = forLoop.getUpdate().getAChild*().(AssignAddOrSubExpr).getLoopStep() or /* 2. Get the expression `E` when the update expression is `i = i + E` or `i = i - E`. */ ( @@ -175,13 +88,11 @@ Expr getLoopStepOfForStmt(ForStmt forLoop) { * 2. Another variable access of the same variable as the given variable access is assigned * to a non-const reference variable (thus constituting a `T` -> `&T` conversion.), i.e. * initialization and assignment. - */ -/* + * * Note that pass-by-reference is dealt with in a different predicate named * `loopVariablePassedAsArgumentToNonConstReferenceParameter`, due to implementation * limitations. */ - predicate loopVariableAssignedToNonConstPointerOrReferenceType( ForStmt forLoop, VariableAccess loopVariableAccessInCondition ) { @@ -199,7 +110,7 @@ predicate loopVariableAssignedToNonConstPointerOrReferenceType( assignmentRhs.(AddressOfExpr).getOperand() = loopVariableAccessInCondition.getTarget().getAnAccess() or - /* 2. The address is taken: A loop variable access */ + /* 2. A reference is taken: A loop variable access */ assignmentRhs = loopVariableAccessInCondition.getTarget().getAnAccess() ) ) From 2227255825358b3cec67478284b682037361ad54 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 24 Sep 2025 15:28:13 -0400 Subject: [PATCH 603/628] Finish draft of `LegacyForStatementsShouldBeSimple` --- .../LegacyForStatementsShouldBeSimple.ql | 47 ++++++++++++++----- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index 91212d2830..633aac3811 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -20,8 +20,13 @@ import semmle.code.cpp.dataflow.internal.AddressFlow import codingstandards.cpp.misra import codingstandards.cpp.Call import codingstandards.cpp.Loops +import codingstandards.cpp.ast.Increment import codingstandards.cpp.misra.BuiltInTypeRules::MisraCpp23BuiltInTypes +Variable getDeclaredVariableInForLoop(ForStmt forLoop) { + result = forLoop.getADeclaration().getADeclarationEntry().(VariableDeclarationEntry).getVariable() +} + /** * Holds if the given expression may mutate the variable. */ @@ -75,7 +80,7 @@ Expr getLoopStepOfForStmt(ForStmt forLoop) { iterationVariableAccess = forLoop.getUpdate().getAChild*().(AssignExpr).getRValue().(SubExpr).getAnOperand() ) and - iterationVariableAccess.getTarget() = forLoop.getAnIterationVariable() and + iterationVariableAccess.getTarget() = getDeclaredVariableInForLoop(forLoop) and result != iterationVariableAccess ) } @@ -159,9 +164,9 @@ predicate loopVariablePassedAsArgumentToNonConstReferenceParameter( private newtype TAlertType = /* 1. There is a counter variable that is not of an integer type. */ - TNonIntegerTypeCounterVariable(ForStmt forLoop, Variable iterationVariable) { - iterationVariable = forLoop.getAnIterationVariable() and - exists(Type type | type = iterationVariable.getType() | + TNonIntegerTypeCounterVariable(ForStmt forLoop, Variable loopCounter) { + loopCounter = getDeclaredVariableInForLoop(forLoop) and + exists(Type type | type = loopCounter.getType() | not ( type instanceof IntegralType or type instanceof FixedWidthIntegralType @@ -178,14 +183,18 @@ private newtype TAlertType = not condition instanceof LegacyForLoopCondition } or /* 3-1. The loop counter is mutated somewhere other than its update expression. */ - TLoopCounterMutatedInLoopBody(ForStmt forLoop, Variable loopCounter) { - loopCounter = forLoop.getAnIterationVariable() and + TLoopCounterMutatedInLoopBody(ForStmt forLoop, Variable loopCounterVariable) { + loopCounterVariable = getDeclaredVariableInForLoop(forLoop) and variableModifiedInExpression(forLoop.getStmt().getChildStmt().getAChild*(), - loopCounter.getAnAccess()) + loopCounterVariable.getAnAccess()) } or /* 3-2. The loop counter is not updated using either of `++`, `--`, `+=`, or `-=`. */ - TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(ForStmt forLoop) { - none() // TODO + TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr( + ForStmt forLoop, Variable loopCounterVariable, Expr updateExpr + ) { + loopCounterVariable = getDeclaredVariableInForLoop(forLoop) and + variableModifiedInExpression(updateExpr, loopCounterVariable.getAnAccess()) and + not updateExpr instanceof LegacyForLoopUpdateExpression } or /* 4. The type size of the loop counter is smaller than that of the loop bound. */ TLoopCounterSmallerThanLoopBound(ForStmt forLoop, LegacyForLoopCondition forLoopCondition) { @@ -281,6 +290,7 @@ class AlertType extends TAlertType { this = TNonIntegerTypeCounterVariable(result, _) or this = TNoRelationalOperatorInLoopCondition(result, _) or this = TLoopCounterMutatedInLoopBody(result, _) or + this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(result, _, _) or this = TLoopCounterSmallerThanLoopBound(result, _) or this = TLoopBoundIsMutatedVariableAccess(result, _, _) or this = TLoopBoundIsNonConstExpr(result, _) or @@ -301,6 +311,8 @@ class AlertType extends TAlertType { or this = TLoopCounterMutatedInLoopBody(_, result) or + this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, result, _) + or exists(LegacyForLoopCondition forLoopCondition | this = TLoopCounterSmallerThanLoopBound(_, forLoopCondition) and result = forLoopCondition.getLoopCounter() @@ -334,6 +346,9 @@ class AlertType extends TAlertType { this = TLoopCounterMutatedInLoopBody(_, _) and result = "counter variable" or + this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, _, _) and + result = "counter variable" + or this = TLoopCounterSmallerThanLoopBound(_, _) and result = "counter variable" or @@ -364,15 +379,18 @@ class AlertType extends TAlertType { */ string getMessage() { this = TNonIntegerTypeCounterVariable(_, _) and - result = "The $@ is not of an integer type." // Throwaway placeholder + result = "The $@ is not of an integer type." or this = TNoRelationalOperatorInLoopCondition(_, _) and result = - "The $@ does not compare the counter variable to an expression using a relational operator." // Throwaway placeholder + "The $@ does not compare the counter variable to an expression using a relational operator." or this = TLoopCounterMutatedInLoopBody(_, _) and result = "The $@ may be mutated in a location other than its update expression." or + this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, _, _) and + result = "The $@ is not updated with an $@ other than addition or subtraction." + or this = TLoopCounterSmallerThanLoopBound(_, _) and result = "The $@ has a smaller type than that of the $@." or @@ -403,7 +421,9 @@ class AlertType extends TAlertType { or this = TNoRelationalOperatorInLoopCondition(_, result) // Throwaway or - this = TLoopCounterMutatedInLoopBody(_, _) // Throwaway + this = TLoopCounterMutatedInLoopBody(_, result) // Throwaway + or + this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, _, result) or exists(LegacyForLoopCondition forLoopCondition | this = TLoopCounterSmallerThanLoopBound(_, forLoopCondition) and @@ -435,6 +455,9 @@ class AlertType extends TAlertType { this = TLoopCounterMutatedInLoopBody(_, _) and result = "N/A" // Throwaway or + this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, _, _) and + result = "expression" + or this = TLoopCounterSmallerThanLoopBound(_, _) and result = "loop bound" or From 38b5fbcaaa61b8860de5cc3619c89ff43294bf0e Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 24 Sep 2025 16:19:14 -0400 Subject: [PATCH 604/628] Decouple ForStmt from `Increment.qll` and rewrite `getLoopStepOfForStmt` --- .../src/codingstandards/cpp/ast/Increment.qll | 103 +++++++++++------- .../LegacyForStatementsShouldBeSimple.ql | 20 +--- 2 files changed, 63 insertions(+), 60 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/ast/Increment.qll b/cpp/common/src/codingstandards/cpp/ast/Increment.qll index 315748e067..00c893baae 100644 --- a/cpp/common/src/codingstandards/cpp/ast/Increment.qll +++ b/cpp/common/src/codingstandards/cpp/ast/Increment.qll @@ -1,57 +1,76 @@ -import cpp - -abstract class LegacyForLoopUpdateExpression extends Expr { - ForStmt forLoop; - - LegacyForLoopUpdateExpression() { this = forLoop.getUpdate().getAChild*() } - - abstract Expr getLoopStep(); - /* TODO: Complete below and use it for 3-2 */ - // abstract VariableAccess getUpdatedVariable(); -} +/** + * Provides a library for working with expressions that update the value + * of a numeric variable by incrementing or decrementing it by a certain + * amount. + */ -class CrementLegacyForLoopUpdateExpression extends LegacyForLoopUpdateExpression { - CrementLegacyForLoopUpdateExpression() { this instanceof CrementOperation } - - override Expr getLoopStep() { none() } -} +import cpp -class AssignAddOrSubExpr extends LegacyForLoopUpdateExpression { +private class AssignAddOrSubExpr extends AssignArithmeticOperation { AssignAddOrSubExpr() { this instanceof AssignAddExpr or this instanceof AssignSubExpr } +} - override Expr getLoopStep() { - result = this.(AssignAddExpr).getRValue() or - result = this.(AssignSubExpr).getRValue() +private class AddOrSubExpr extends BinaryArithmeticOperation { + AddOrSubExpr() { + this instanceof AddExpr or + this instanceof SubExpr } } -class AddOrSubThenAssignExpr extends LegacyForLoopUpdateExpression { - Expr assignRhs; +/** + * An expression that updates a numeric variable by adding to or subtracting + * from it a certain amount. + */ +abstract class StepCrementUpdateExpr extends Expr { + /** + * The expression in the abstract syntax tree that represents the amount of + * value by which the variable is updated. + */ + abstract Expr getAmountExpr(); +} + +/** + * An increment or decrement operator application, either postfix or prefix. + */ +class PostfixOrPrefixCrementExpr extends CrementOperation, StepCrementUpdateExpr { + override Expr getAmountExpr() { none() } +} + +/** + * An add-then-assign or subtract-then-assign expression in a shortened form, + * i.e. `+=` or `-=`. + */ +class AssignAddOrSubUpdateExpr extends AssignAddOrSubExpr, StepCrementUpdateExpr { + override Expr getAmountExpr() { result = this.getRValue() } +} + +/** + * An add-then-assign expression or a subtract-then-assign expression, i.e. + * `x = x + E` or `x = x - E`, where `x` is some variable and `E` an + * arbitrary expression. + */ +class AddOrSubThenAssignExpr extends AssignExpr, StepCrementUpdateExpr { + /** The `x` as in the left-hand side of `x = x + E`. */ + VariableAccess lvalueVariable; + /** The `x + E` as in `x = x + E`. */ + AddOrSubExpr addOrSubExpr; + /** The `E` as in `x = x + E`. */ + Expr amountExpr; AddOrSubThenAssignExpr() { - this.(AssignExpr).getRValue() = assignRhs and - ( - assignRhs instanceof AddExpr or - assignRhs instanceof SubExpr + this.getLValue() = lvalueVariable and + this.getRValue() = addOrSubExpr and + exists(VariableAccess lvalueVariableAsRvalue | + lvalueVariableAsRvalue = addOrSubExpr.getAnOperand() and + amountExpr = addOrSubExpr.getAnOperand() and + lvalueVariableAsRvalue != amountExpr + | + lvalueVariable.getTarget() = lvalueVariableAsRvalue.(VariableAccess).getTarget() ) } - override Expr getLoopStep() { - ( - result = assignRhs.(AddExpr).getAnOperand() or - result = assignRhs.(SubExpr).getAnOperand() - ) and - exists(VariableAccess iterationVariableAccess | - ( - iterationVariableAccess = assignRhs.(AddExpr).getAnOperand() - or - iterationVariableAccess = assignRhs.(SubExpr).getAnOperand() - ) and - iterationVariableAccess.getTarget() = forLoop.getAnIterationVariable() and - result != iterationVariableAccess - ) - } -} \ No newline at end of file + override Expr getAmountExpr() { result = amountExpr } +} diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index 633aac3811..458fbc4f91 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -66,23 +66,7 @@ Expr getLoopStepOfForStmt(ForStmt forLoop) { */ /* 1. Get the expression `E` when the update expression is `i += E` or `i -= E`. */ - result = forLoop.getUpdate().getAChild*().(AssignAddOrSubExpr).getLoopStep() - or - /* 2. Get the expression `E` when the update expression is `i = i + E` or `i = i - E`. */ - ( - result = forLoop.getUpdate().getAChild*().(AssignExpr).getRValue().(AddExpr).getAnOperand() or - result = forLoop.getUpdate().getAChild*().(AssignExpr).getRValue().(SubExpr).getAnOperand() - ) and - exists(VariableAccess iterationVariableAccess | - ( - iterationVariableAccess = - forLoop.getUpdate().getAChild*().(AssignExpr).getRValue().(AddExpr).getAnOperand() or - iterationVariableAccess = - forLoop.getUpdate().getAChild*().(AssignExpr).getRValue().(SubExpr).getAnOperand() - ) and - iterationVariableAccess.getTarget() = getDeclaredVariableInForLoop(forLoop) and - result != iterationVariableAccess - ) + result = forLoop.getUpdate().getAChild*().(StepCrementUpdateExpr).getAmountExpr() } /** @@ -194,7 +178,7 @@ private newtype TAlertType = ) { loopCounterVariable = getDeclaredVariableInForLoop(forLoop) and variableModifiedInExpression(updateExpr, loopCounterVariable.getAnAccess()) and - not updateExpr instanceof LegacyForLoopUpdateExpression + not updateExpr instanceof StepCrementUpdateExpr } or /* 4. The type size of the loop counter is smaller than that of the loop bound. */ TLoopCounterSmallerThanLoopBound(ForStmt forLoop, LegacyForLoopCondition forLoopCondition) { From 23aa711400340873fd8d580c08255b476535b934 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 29 Sep 2025 18:46:04 -0400 Subject: [PATCH 605/628] Update expected result of `RULE-9-5-1` --- ...LegacyForStatementsShouldBeSimple.expected | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected index 2ec1a0ac6c..1c85002d8c 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected +++ b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected @@ -1 +1,36 @@ -No expected results have yet been specified \ No newline at end of file +| test2.cpp:8:5:11:5 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test2.cpp:8:14:8:14 | i | counter variable | test2.cpp:9:9:9:9 | call to f | expression | +| test2.cpp:8:5:11:5 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test2.cpp:8:14:8:14 | i | counter variable | test2.cpp:8:14:8:14 | i | N/A | +| test.cpp:22:3:24:3 | for(...;...;...) ... | The $@ is not of an integer type. | test.cpp:22:14:22:14 | i | counter variable | test.cpp:22:14:22:14 | i | N/A | +| test.cpp:31:3:33:3 | for(...;...;...) ... | The $@ does not compare the counter variable to an expression using a relational operator. | test.cpp:31:19:31:25 | ... == ... | loop condition | test.cpp:31:19:31:25 | ... == ... | N/A | +| test.cpp:35:3:37:3 | for(...;...;...) ... | The $@ does not compare the counter variable to an expression using a relational operator. | test.cpp:35:19:35:24 | ... < ... | loop condition | test.cpp:35:19:35:24 | ... < ... | N/A | +| test.cpp:76:3:78:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:76:12:76:12 | i | counter variable | test.cpp:77:8:77:13 | ... *= ... | expression | +| test.cpp:90:3:93:3 | for(...;...;...) ... | The $@ has a smaller type than that of the $@. | test.cpp:90:19:90:19 | i | counter variable | test.cpp:90:23:90:27 | 10 | loop bound | +| test.cpp:115:3:118:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:116:13:116:13 | j | loop step | test.cpp:117:5:117:7 | ... ++ | mutated | +| test.cpp:120:3:122:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:121:13:121:13 | j | loop step | test.cpp:121:8:121:18 | ... , ... | mutated | +| test.cpp:120:3:122:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:121:13:121:13 | j | loop step | test.cpp:121:16:121:18 | ... ++ | mutated | +| test.cpp:120:3:122:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:120:12:120:12 | i | counter variable | test.cpp:121:8:121:18 | ... , ... | expression | +| test.cpp:132:3:135:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:132:23:132:23 | j | loop bound | test.cpp:134:5:134:7 | ... ++ | mutated | +| test.cpp:139:3:142:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:139:23:139:23 | k | loop bound | test.cpp:141:5:141:26 | ... += ... | mutated | +| test.cpp:144:3:147:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:145:13:145:13 | l | loop step | test.cpp:146:5:146:26 | ... += ... | mutated | +| test.cpp:149:3:151:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:149:23:149:24 | call to h1 | loop bound | test.cpp:149:23:149:24 | call to h1 | non-const expression | +| test.cpp:157:3:159:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:158:13:158:14 | call to h1 | loop step | test.cpp:158:13:158:14 | call to h1 | non-const expression | +| test.cpp:172:3:175:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:172:19:172:19 | i | loop counter | test.cpp:172:19:172:19 | i | N/A | +| test.cpp:177:3:180:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:177:19:177:19 | i | loop counter | test.cpp:177:19:177:19 | i | N/A | +| test.cpp:192:3:195:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:192:23:192:23 | k | loop bound | test.cpp:192:23:192:23 | k | N/A | +| test.cpp:197:3:200:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:197:23:197:23 | k | loop bound | test.cpp:197:23:197:23 | k | N/A | +| test.cpp:212:3:215:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:212:31:212:31 | l | loop step | test.cpp:212:31:212:31 | l | N/A | +| test.cpp:217:3:220:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:217:31:217:31 | l | loop step | test.cpp:217:31:217:31 | l | N/A | +| test.cpp:232:3:235:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:232:12:232:12 | i | counter variable | test.cpp:234:5:234:6 | call to f1 | expression | +| test.cpp:232:3:235:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:232:19:232:19 | i | loop counter | test.cpp:232:19:232:19 | i | N/A | +| test.cpp:232:3:235:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:232:12:232:12 | i | counter variable | test.cpp:232:12:232:12 | i | N/A | +| test.cpp:237:3:240:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:237:12:237:12 | i | counter variable | test.cpp:239:5:239:6 | call to g1 | expression | +| test.cpp:237:3:240:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:237:19:237:19 | i | loop counter | test.cpp:237:19:237:19 | i | N/A | +| test.cpp:237:3:240:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:237:12:237:12 | i | counter variable | test.cpp:237:12:237:12 | i | N/A | +| test.cpp:252:3:255:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:252:23:252:23 | k | loop bound | test.cpp:254:5:254:6 | call to f1 | mutated | +| test.cpp:252:3:255:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:252:23:252:23 | k | loop bound | test.cpp:252:23:252:23 | k | N/A | +| test.cpp:257:3:260:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:257:23:257:23 | k | loop bound | test.cpp:259:5:259:6 | call to g1 | mutated | +| test.cpp:257:3:260:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:257:23:257:23 | k | loop bound | test.cpp:257:23:257:23 | k | N/A | +| test.cpp:273:3:276:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:273:31:273:31 | l | loop step | test.cpp:275:5:275:6 | call to f1 | mutated | +| test.cpp:273:3:276:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:273:31:273:31 | l | loop step | test.cpp:273:31:273:31 | l | N/A | +| test.cpp:278:3:281:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:278:31:278:31 | l | loop step | test.cpp:280:5:280:6 | call to g1 | mutated | +| test.cpp:278:3:281:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:278:31:278:31 | l | loop step | test.cpp:278:31:278:31 | l | N/A | From f0b53e22affe1a8554fc58e05fa08a2d2642cbbf Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 29 Sep 2025 19:19:26 -0400 Subject: [PATCH 606/628] Update expected results of `RULE-9-5-2` --- .../ForRangeInitializerAtMostOneFunctionCall.ql | 9 +++++---- ...angeInitializerAtMostOneFunctionCall.expected | 16 ++++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql b/cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql index b78da2ad99..e6b8df9f87 100644 --- a/cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql +++ b/cpp/misra/src/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.ql @@ -19,9 +19,10 @@ import cpp import codingstandards.cpp.misra -from RangeBasedForStmt foreach, string message +from RangeBasedForStmt foreach, Expr initializer where not isExcluded(foreach, StatementsPackage::forRangeInitializerAtMostOneFunctionCallQuery()) and - count(Call call | call = foreach.getRange().getAChild*() | call) >= 2 and - message = "has nested call expression in its initializer" -select foreach, "Range-based for loop " + message + "." + initializer = foreach.getRange() and + count(Call call | call = initializer.getAChild*() | call) >= 2 +select foreach, "Range-based for loop has nested call expression in its $@.", initializer, + "initializer" diff --git a/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected b/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected index a8567ff48d..8b0fcb1d4e 100644 --- a/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected +++ b/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected @@ -1,8 +1,8 @@ -| test.cpp:48:3:49:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | -| test.cpp:56:3:59:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | -| test.cpp:71:3:73:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | -| test.cpp:95:3:97:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | -| test.cpp:99:3:101:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | -| test.cpp:103:3:107:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | -| test.cpp:116:3:119:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | -| test.cpp:121:3:124:3 | for(...:...) ... | Range-based for loop has nested call expression in its initializer. | +| test.cpp:48:3:49:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:48:17:48:27 | call to processData | initializer | +| test.cpp:56:3:59:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:57:8:57:32 | call to vector | initializer | +| test.cpp:71:3:73:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:71:17:72:21 | call to MyContainer | initializer | +| test.cpp:95:3:97:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:95:26:95:26 | call to operator+ | initializer | +| test.cpp:99:3:101:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:99:31:99:31 | call to operator+ | initializer | +| test.cpp:103:3:107:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:104:18:104:18 | call to operator+ | initializer | +| test.cpp:116:3:119:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:117:8:117:25 | call to convertToIntVector | initializer | +| test.cpp:121:3:124:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:122:8:122:25 | call to convertToIntVector | initializer | From 7d5f08b3e788afbe46fe865f4243205263eb3cd0 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 7 Oct 2025 15:23:40 -0400 Subject: [PATCH 607/628] Count in typedefs and cv-qualifiers We are interested if the underlying *data* can be mutated, not the pointer itself. Also, the surface type may be a typedef, so resolve that as well. --- .../LegacyForStatementsShouldBeSimple.ql | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index 458fbc4f91..ee8bf06361 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -85,9 +85,10 @@ Expr getLoopStepOfForStmt(ForStmt forLoop) { predicate loopVariableAssignedToNonConstPointerOrReferenceType( ForStmt forLoop, VariableAccess loopVariableAccessInCondition ) { - exists(Expr assignmentRhs, DerivedType targetType | + exists(Expr assignmentRhs, Type targetType, DerivedType strippedType | isAssignment(assignmentRhs, targetType, _) and - not targetType.getBaseType().isConst() and + strippedType = targetType.stripTopLevelSpecifiers() and + not strippedType.getBaseType().isConst() and ( targetType instanceof PointerType or targetType instanceof ReferenceType @@ -105,9 +106,14 @@ predicate loopVariableAssignedToNonConstPointerOrReferenceType( ) } -/* - * An adapted part of `BuiltinTypeRules::MisraCpp23BuiltInTypes::isPreConversionAssignment` - * that is only relevant to an argument passed to a parameter, seen as an assignment. +/** + * Holds if the given variable access has another variable access with the same target + * variable that is passed as reference to a non-const reference parameter of a function, + * constituting a `T` -> `&T` conversion. + * + * This is an adapted part of + * `BuiltinTypeRules::MisraCpp23BuiltInTypes::isPreConversionAssignment` that is only + * relevant to an argument passed to a parameter, seen as an assignment. * * This predicate adds two constraints to the target type, as compared to the original * portion of the predicate: @@ -117,20 +123,15 @@ predicate loopVariableAssignedToNonConstPointerOrReferenceType( * * Also, this predicate requires that the call is the body of the given for-loop. */ - -/** - * Holds if the given variable access has another variable access with the same target - * variable that is passed as reference to a non-const reference parameter of a function, - * constituting a `T` -> `&T` conversion. - */ predicate loopVariablePassedAsArgumentToNonConstReferenceParameter( ForStmt forLoop, VariableAccess loopVariableAccessInCondition ) { - exists(ReferenceType targetType | + exists(Type targetType, ReferenceType strippedReferenceType | exists(Call call, int i | call.getArgument(i) = loopVariableAccessInCondition.getTarget().getAnAccess() and call.getEnclosingStmt().getParent*() = forLoop.getStmt() and - not targetType.getBaseType().isConst() + strippedReferenceType = targetType.stripTopLevelSpecifiers() and + not strippedReferenceType.getBaseType().isConst() | /* A regular function call */ targetType = call.getTarget().getParameter(i).getType() From e135fe6c93ec6b0b0d6e0e9cbde2d58906a3376b Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 7 Oct 2025 15:25:26 -0400 Subject: [PATCH 608/628] Fix cross-join issue in `TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr` --- .../src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql | 1 + 1 file changed, 1 insertion(+) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index ee8bf06361..4ad3be0ef6 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -178,6 +178,7 @@ private newtype TAlertType = ForStmt forLoop, Variable loopCounterVariable, Expr updateExpr ) { loopCounterVariable = getDeclaredVariableInForLoop(forLoop) and + updateExpr = forLoop.getUpdate() and variableModifiedInExpression(updateExpr, loopCounterVariable.getAnAccess()) and not updateExpr instanceof StepCrementUpdateExpr } or From b13ffd2b48b7fff06dc74074021c56fec305d176 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 7 Oct 2025 15:26:00 -0400 Subject: [PATCH 609/628] Slightly change wording in the message Both `TLoopBoundIsMutatedVariableAccess` and `TLoopStepIsMutatedVariableAccess` transitively rely on `valueToUpdate`, which overapproximates by looking at the types alone. Therefore we'd like to drop the confidence slightly in reporting the expression where the expression *might* have been changed. --- .../src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index 4ad3be0ef6..4186f4149c 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -384,13 +384,13 @@ class AlertType extends TAlertType { result = "The $@ is a $@." or this = TLoopBoundIsMutatedVariableAccess(_, _, _) and - result = "The $@ is a non-const expression, or a variable that is $@ in the loop." + result = "The $@ is a non-const expression, or a variable that may be $@ in the loop." or this = TLoopStepIsNonConstExpr(_, _) and result = "The $@ is a $@." or this = TLoopStepIsMutatedVariableAccess(_, _, _) and - result = "The $@ is a non-const expression, or a variable that is $@ in the loop." + result = "The $@ is a non-const expression, or a variable that may be $@ in the loop." or this = TLoopCounterIsTakenNonConstAddress(_, _) and result = "The $@ is taken as a mutable reference or its address to a mutable pointer." From 82f9adc44785ad6f2c30747eb00fb2faac4eb12d Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 7 Oct 2025 16:55:10 -0400 Subject: [PATCH 610/628] Make the loop counter detection more relaxed --- cpp/common/src/codingstandards/cpp/Loops.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/common/src/codingstandards/cpp/Loops.qll b/cpp/common/src/codingstandards/cpp/Loops.qll index ae5f6cf7f9..f817ed6b5b 100644 --- a/cpp/common/src/codingstandards/cpp/Loops.qll +++ b/cpp/common/src/codingstandards/cpp/Loops.qll @@ -389,7 +389,7 @@ class LegacyForLoopCondition extends RelationalOperation { Expr loopBound; LegacyForLoopCondition() { - loopCounter = this.getAnOperand() and + loopCounter = this.getAnOperand().getAChild*() and loopBound = this.getAnOperand() and loopCounter.getTarget() = getAnIterationVariable(forLoop) and loopBound != loopCounter From 211640077b41a0091d5565b10a08515651c23a2a Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 8 Oct 2025 17:29:53 -0400 Subject: [PATCH 611/628] Refine `LegacyForLoopCondition` --- cpp/common/src/codingstandards/cpp/Loops.qll | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Loops.qll b/cpp/common/src/codingstandards/cpp/Loops.qll index f817ed6b5b..a18c8e34af 100644 --- a/cpp/common/src/codingstandards/cpp/Loops.qll +++ b/cpp/common/src/codingstandards/cpp/Loops.qll @@ -389,12 +389,21 @@ class LegacyForLoopCondition extends RelationalOperation { Expr loopBound; LegacyForLoopCondition() { - loopCounter = this.getAnOperand().getAChild*() and - loopBound = this.getAnOperand() and - loopCounter.getTarget() = getAnIterationVariable(forLoop) and - loopBound != loopCounter + this = forLoop.getCondition() and + exists(Expr loopCounterExpr | + loopCounterExpr = this.getAnOperand() and + loopBound = this.getAnOperand() and + loopCounter = loopCounterExpr.getAChild*() and + loopCounter.getTarget() = getAnIterationVariable(forLoop) and + loopBound != loopCounterExpr + ) } + /** + * Gets the for-loop this expression is a termination condition of. + */ + ForStmt getForLoop() { result = forLoop } + /** * Gets the variable access to the loop counter variable, appearing in this loop condition. */ From 1f8083a99752dd270e94d94e2655134a70cc0ffb Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 8 Oct 2025 17:30:18 -0400 Subject: [PATCH 612/628] Change phrasing of message from `TNoRelationalOperatorInLoopCondition` --- .../src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index 4186f4149c..8adfaf07a2 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -369,7 +369,7 @@ class AlertType extends TAlertType { or this = TNoRelationalOperatorInLoopCondition(_, _) and result = - "The $@ does not compare the counter variable to an expression using a relational operator." + "The $@ does not determine termination based only on a comparison against the value of the counter variable." or this = TLoopCounterMutatedInLoopBody(_, _) and result = "The $@ may be mutated in a location other than its update expression." From 1355effa734c50c900474c6d368bf98d89493e93 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 8 Oct 2025 18:52:24 -0400 Subject: [PATCH 613/628] Use `upperbound/0` and `getFullyConverted/0` to more precisely infer sizes --- .../RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index 8adfaf07a2..f34b8aec53 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -185,11 +185,10 @@ private newtype TAlertType = /* 4. The type size of the loop counter is smaller than that of the loop bound. */ TLoopCounterSmallerThanLoopBound(ForStmt forLoop, LegacyForLoopCondition forLoopCondition) { forLoopCondition = forLoop.getCondition() and - exists(Type loopCounterType, Type loopBoundType | - loopCounterType = forLoopCondition.getLoopCounter().getType() and - loopBoundType = forLoopCondition.getLoopBound().getType() - | - loopCounterType.getSize() < loopBoundType.getSize() + exists(Expr loopCounter, Expr loopBound | + loopCounter = forLoopCondition.getLoopCounter() and + loopBound = forLoopCondition.getLoopBound() and + upperBound(loopCounter.getFullyConverted()) < upperBound(loopBound.getFullyConverted()) ) } or /* 5-1-1. The loop bound is a variable that is mutated in the for loop. */ From 3ad5ef2ae7028d24b57a4899d30f6881c410416b Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 9 Oct 2025 14:41:10 -0400 Subject: [PATCH 614/628] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- cpp/misra/test/rules/RULE-9-5-2/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/misra/test/rules/RULE-9-5-2/test.cpp b/cpp/misra/test/rules/RULE-9-5-2/test.cpp index b9ec5a0574..c832f9735b 100644 --- a/cpp/misra/test/rules/RULE-9-5-2/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-2/test.cpp @@ -54,7 +54,7 @@ int main() { } for (auto x : - std::vector{1, 2, 3}) { // NON_COMPLIANT: 2 constructor call to + std::vector{1, 2, 3}) { // NON_COMPLIANT: 2 constructor calls to // `vector` and `initializer_list`, respectively } From fb2006513b29d87df34e13e1b9f44618f462215f Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 9 Oct 2025 14:41:27 -0400 Subject: [PATCH 615/628] Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .../rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql b/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql index f419834325..893ebfe735 100644 --- a/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql +++ b/cpp/misra/src/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.ql @@ -28,7 +28,7 @@ where exists(Stmt initializer | initializer = switch.getInitialization() | not initializer instanceof DeclStmt ) and - message = "contains a statement that that is not a simple declaration" + message = "contains a statement that is not a simple declaration" or /* 2. There is a switch case label that does not lead a branch (i.e. a switch case label is nested). */ exists(SwitchCase case | case = switch.getASwitchCase() | case instanceof NestedSwitchCase) and From bce38a04eb31b9288b1db6b4ec57bf905ca9e08b Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 9 Oct 2025 14:50:55 -0400 Subject: [PATCH 616/628] Reformat test cases of 9-4-2 and 9-5-2 --- cpp/misra/test/rules/RULE-9-4-2/test.cpp | 2 +- cpp/misra/test/rules/RULE-9-5-2/test.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/misra/test/rules/RULE-9-4-2/test.cpp b/cpp/misra/test/rules/RULE-9-4-2/test.cpp index 6bbb97e81b..0e8c2e2ec2 100644 --- a/cpp/misra/test/rules/RULE-9-4-2/test.cpp +++ b/cpp/misra/test/rules/RULE-9-4-2/test.cpp @@ -88,7 +88,7 @@ void testOtherLabelsInBranch(int expr) { void testLeadingNonCaseStatement(int expr) { switch (expr) { // NON_COMPLIANT: Non-case statement is the first statement in // the switch body - int x = 1; + int x = 1; case 1: i++; break; diff --git a/cpp/misra/test/rules/RULE-9-5-2/test.cpp b/cpp/misra/test/rules/RULE-9-5-2/test.cpp index b9ec5a0574..bc8c6c6acf 100644 --- a/cpp/misra/test/rules/RULE-9-5-2/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-2/test.cpp @@ -53,9 +53,9 @@ int main() { for (auto x : std::vector(3)) { // COMPLIANT: 1 constructor call only } - for (auto x : - std::vector{1, 2, 3}) { // NON_COMPLIANT: 2 constructor call to - // `vector` and `initializer_list`, respectively + for (auto x : std::vector{ + 1, 2, 3}) { // NON_COMPLIANT: 2 constructor call to + // `vector` and `initializer_list`, respectively } for (auto x : MyContainer()) { // COMPLIANT: 1 constructor call only From 59a40964aaab48d546a96756e13ca8137e5908e0 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 9 Oct 2025 15:57:50 -0400 Subject: [PATCH 617/628] Update expected results coming from change in message --- .../RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected | 2 +- .../ForRangeInitializerAtMostOneFunctionCall.expected | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected b/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected index ab8320ef8f..673e570631 100644 --- a/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected +++ b/cpp/misra/test/rules/RULE-9-4-2/AppropriateStructureOfSwitchStatement.expected @@ -1,4 +1,4 @@ -| test.cpp:28:3:37:3 | switch (...) ... | Switch statement contains a statement that that is not a simple declaration. | +| test.cpp:28:3:37:3 | switch (...) ... | Switch statement contains a statement that is not a simple declaration. | | test.cpp:51:3:60:3 | switch (...) ... | Switch statement contains a switch label that is not directly within the switch body. | | test.cpp:62:3:71:3 | switch (...) ... | Switch statement contains a switch label that is not directly within the switch body. | | test.cpp:75:3:85:3 | switch (...) ... | Switch statement contains a statement label that is not a case label. | diff --git a/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected b/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected index 8b0fcb1d4e..fdd088bf35 100644 --- a/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected +++ b/cpp/misra/test/rules/RULE-9-5-2/ForRangeInitializerAtMostOneFunctionCall.expected @@ -1,5 +1,5 @@ | test.cpp:48:3:49:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:48:17:48:27 | call to processData | initializer | -| test.cpp:56:3:59:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:57:8:57:32 | call to vector | initializer | +| test.cpp:56:3:59:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:56:17:57:19 | call to vector | initializer | | test.cpp:71:3:73:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:71:17:72:21 | call to MyContainer | initializer | | test.cpp:95:3:97:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:95:26:95:26 | call to operator+ | initializer | | test.cpp:99:3:101:3 | for(...:...) ... | Range-based for loop has nested call expression in its $@. | test.cpp:99:31:99:31 | call to operator+ | initializer | From d37bc70d1e653fe76b509595399a0bedf7453bea Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Thu, 9 Oct 2025 15:58:43 -0400 Subject: [PATCH 618/628] Use different range predicate and update tests --- .../LegacyForStatementsShouldBeSimple.ql | 5 +- ...LegacyForStatementsShouldBeSimple.expected | 68 +++++++++---------- cpp/misra/test/rules/RULE-9-5-1/test.cpp | 3 +- 3 files changed, 37 insertions(+), 39 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index f34b8aec53..d63e8b4890 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -187,8 +187,9 @@ private newtype TAlertType = forLoopCondition = forLoop.getCondition() and exists(Expr loopCounter, Expr loopBound | loopCounter = forLoopCondition.getLoopCounter() and - loopBound = forLoopCondition.getLoopBound() and - upperBound(loopCounter.getFullyConverted()) < upperBound(loopBound.getFullyConverted()) + loopBound = forLoopCondition.getLoopBound() + | + typeUpperBound(loopCounter.getType()) < upperBound(loopBound.getFullyConverted()) ) } or /* 5-1-1. The loop bound is a variable that is mutated in the for loop. */ diff --git a/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected index 1c85002d8c..d40663abf5 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected +++ b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected @@ -1,36 +1,32 @@ -| test2.cpp:8:5:11:5 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test2.cpp:8:14:8:14 | i | counter variable | test2.cpp:9:9:9:9 | call to f | expression | -| test2.cpp:8:5:11:5 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test2.cpp:8:14:8:14 | i | counter variable | test2.cpp:8:14:8:14 | i | N/A | -| test.cpp:22:3:24:3 | for(...;...;...) ... | The $@ is not of an integer type. | test.cpp:22:14:22:14 | i | counter variable | test.cpp:22:14:22:14 | i | N/A | -| test.cpp:31:3:33:3 | for(...;...;...) ... | The $@ does not compare the counter variable to an expression using a relational operator. | test.cpp:31:19:31:25 | ... == ... | loop condition | test.cpp:31:19:31:25 | ... == ... | N/A | -| test.cpp:35:3:37:3 | for(...;...;...) ... | The $@ does not compare the counter variable to an expression using a relational operator. | test.cpp:35:19:35:24 | ... < ... | loop condition | test.cpp:35:19:35:24 | ... < ... | N/A | -| test.cpp:76:3:78:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:76:12:76:12 | i | counter variable | test.cpp:77:8:77:13 | ... *= ... | expression | -| test.cpp:90:3:93:3 | for(...;...;...) ... | The $@ has a smaller type than that of the $@. | test.cpp:90:19:90:19 | i | counter variable | test.cpp:90:23:90:27 | 10 | loop bound | -| test.cpp:115:3:118:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:116:13:116:13 | j | loop step | test.cpp:117:5:117:7 | ... ++ | mutated | -| test.cpp:120:3:122:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:121:13:121:13 | j | loop step | test.cpp:121:8:121:18 | ... , ... | mutated | -| test.cpp:120:3:122:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:121:13:121:13 | j | loop step | test.cpp:121:16:121:18 | ... ++ | mutated | -| test.cpp:120:3:122:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:120:12:120:12 | i | counter variable | test.cpp:121:8:121:18 | ... , ... | expression | -| test.cpp:132:3:135:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:132:23:132:23 | j | loop bound | test.cpp:134:5:134:7 | ... ++ | mutated | -| test.cpp:139:3:142:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:139:23:139:23 | k | loop bound | test.cpp:141:5:141:26 | ... += ... | mutated | -| test.cpp:144:3:147:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:145:13:145:13 | l | loop step | test.cpp:146:5:146:26 | ... += ... | mutated | -| test.cpp:149:3:151:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:149:23:149:24 | call to h1 | loop bound | test.cpp:149:23:149:24 | call to h1 | non-const expression | -| test.cpp:157:3:159:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:158:13:158:14 | call to h1 | loop step | test.cpp:158:13:158:14 | call to h1 | non-const expression | -| test.cpp:172:3:175:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:172:19:172:19 | i | loop counter | test.cpp:172:19:172:19 | i | N/A | -| test.cpp:177:3:180:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:177:19:177:19 | i | loop counter | test.cpp:177:19:177:19 | i | N/A | -| test.cpp:192:3:195:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:192:23:192:23 | k | loop bound | test.cpp:192:23:192:23 | k | N/A | -| test.cpp:197:3:200:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:197:23:197:23 | k | loop bound | test.cpp:197:23:197:23 | k | N/A | -| test.cpp:212:3:215:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:212:31:212:31 | l | loop step | test.cpp:212:31:212:31 | l | N/A | -| test.cpp:217:3:220:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:217:31:217:31 | l | loop step | test.cpp:217:31:217:31 | l | N/A | -| test.cpp:232:3:235:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:232:12:232:12 | i | counter variable | test.cpp:234:5:234:6 | call to f1 | expression | -| test.cpp:232:3:235:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:232:19:232:19 | i | loop counter | test.cpp:232:19:232:19 | i | N/A | -| test.cpp:232:3:235:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:232:12:232:12 | i | counter variable | test.cpp:232:12:232:12 | i | N/A | -| test.cpp:237:3:240:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:237:12:237:12 | i | counter variable | test.cpp:239:5:239:6 | call to g1 | expression | -| test.cpp:237:3:240:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:237:19:237:19 | i | loop counter | test.cpp:237:19:237:19 | i | N/A | -| test.cpp:237:3:240:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:237:12:237:12 | i | counter variable | test.cpp:237:12:237:12 | i | N/A | -| test.cpp:252:3:255:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:252:23:252:23 | k | loop bound | test.cpp:254:5:254:6 | call to f1 | mutated | -| test.cpp:252:3:255:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:252:23:252:23 | k | loop bound | test.cpp:252:23:252:23 | k | N/A | -| test.cpp:257:3:260:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:257:23:257:23 | k | loop bound | test.cpp:259:5:259:6 | call to g1 | mutated | -| test.cpp:257:3:260:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:257:23:257:23 | k | loop bound | test.cpp:257:23:257:23 | k | N/A | -| test.cpp:273:3:276:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:273:31:273:31 | l | loop step | test.cpp:275:5:275:6 | call to f1 | mutated | -| test.cpp:273:3:276:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:273:31:273:31 | l | loop step | test.cpp:273:31:273:31 | l | N/A | -| test.cpp:278:3:281:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that is $@ in the loop. | test.cpp:278:31:278:31 | l | loop step | test.cpp:280:5:280:6 | call to g1 | mutated | -| test.cpp:278:3:281:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:278:31:278:31 | l | loop step | test.cpp:278:31:278:31 | l | N/A | +| test.cpp:23:3:25:3 | for(...;...;...) ... | The $@ is not of an integer type. | test.cpp:23:14:23:14 | i | counter variable | test.cpp:23:14:23:14 | i | N/A | +| test.cpp:32:3:34:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:32:19:32:25 | ... == ... | loop condition | test.cpp:32:19:32:25 | ... == ... | N/A | +| test.cpp:36:3:38:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:36:19:36:24 | ... < ... | loop condition | test.cpp:36:19:36:24 | ... < ... | N/A | +| test.cpp:77:3:79:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:77:12:77:12 | i | counter variable | test.cpp:78:8:78:13 | ... *= ... | expression | +| test.cpp:91:3:94:3 | for(...;...;...) ... | The $@ has a smaller type than that of the $@. | test.cpp:91:21:91:21 | i | counter variable | test.cpp:91:25:91:53 | call to max | loop bound | +| test.cpp:116:3:119:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:117:13:117:13 | j | loop step | test.cpp:118:5:118:7 | ... ++ | mutated | +| test.cpp:121:3:123:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:122:13:122:13 | j | loop step | test.cpp:122:8:122:18 | ... , ... | mutated | +| test.cpp:121:3:123:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:122:13:122:13 | j | loop step | test.cpp:122:16:122:18 | ... ++ | mutated | +| test.cpp:121:3:123:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:121:12:121:12 | i | counter variable | test.cpp:122:8:122:18 | ... , ... | expression | +| test.cpp:133:3:136:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:133:23:133:23 | j | loop bound | test.cpp:135:5:135:7 | ... ++ | mutated | +| test.cpp:140:3:143:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:140:23:140:23 | k | loop bound | test.cpp:142:5:142:26 | ... += ... | mutated | +| test.cpp:145:3:148:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:146:13:146:13 | l | loop step | test.cpp:147:5:147:26 | ... += ... | mutated | +| test.cpp:150:3:152:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:150:23:150:24 | call to h1 | loop bound | test.cpp:150:23:150:24 | call to h1 | non-const expression | +| test.cpp:158:3:160:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:159:13:159:14 | call to h1 | loop step | test.cpp:159:13:159:14 | call to h1 | non-const expression | +| test.cpp:173:3:176:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:173:19:173:19 | i | loop counter | test.cpp:173:19:173:19 | i | N/A | +| test.cpp:178:3:181:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:178:19:178:19 | i | loop counter | test.cpp:178:19:178:19 | i | N/A | +| test.cpp:193:3:196:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:193:23:193:23 | k | loop bound | test.cpp:193:23:193:23 | k | N/A | +| test.cpp:198:3:201:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:198:23:198:23 | k | loop bound | test.cpp:198:23:198:23 | k | N/A | +| test.cpp:213:3:216:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:213:31:213:31 | l | loop step | test.cpp:213:31:213:31 | l | N/A | +| test.cpp:218:3:221:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:218:31:218:31 | l | loop step | test.cpp:218:31:218:31 | l | N/A | +| test.cpp:233:3:236:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:233:19:233:19 | i | loop counter | test.cpp:233:19:233:19 | i | N/A | +| test.cpp:233:3:236:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:233:12:233:12 | i | counter variable | test.cpp:233:12:233:12 | i | N/A | +| test.cpp:238:3:241:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:238:19:238:19 | i | loop counter | test.cpp:238:19:238:19 | i | N/A | +| test.cpp:238:3:241:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:238:12:238:12 | i | counter variable | test.cpp:238:12:238:12 | i | N/A | +| test.cpp:253:3:256:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:253:23:253:23 | k | loop bound | test.cpp:255:5:255:6 | call to f1 | mutated | +| test.cpp:253:3:256:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:253:23:253:23 | k | loop bound | test.cpp:253:23:253:23 | k | N/A | +| test.cpp:258:3:261:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:258:23:258:23 | k | loop bound | test.cpp:260:5:260:6 | call to g1 | mutated | +| test.cpp:258:3:261:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:258:23:258:23 | k | loop bound | test.cpp:258:23:258:23 | k | N/A | +| test.cpp:274:3:277:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:274:31:274:31 | l | loop step | test.cpp:276:5:276:6 | call to f1 | mutated | +| test.cpp:274:3:277:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:274:31:274:31 | l | loop step | test.cpp:274:31:274:31 | l | N/A | +| test.cpp:279:3:282:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:279:31:279:31 | l | loop step | test.cpp:281:5:281:6 | call to g1 | mutated | +| test.cpp:279:3:282:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:279:31:279:31 | l | loop step | test.cpp:279:31:279:31 | l | N/A | diff --git a/cpp/misra/test/rules/RULE-9-5-1/test.cpp b/cpp/misra/test/rules/RULE-9-5-1/test.cpp index cb6905525e..6e7e09870b 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-1/test.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -87,7 +88,7 @@ int main() { // loop bound } - for (int i = 0; i < 10ull; + for (short i = 0; i < std::numeric_limits::max(); i++) { // NON_COMPLIANT: The type of the loop counter is not bigger // than that of the loop bound } From 25e29e48e4daf0bd97c3059dff85861784b6ef3c Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Fri, 10 Oct 2025 17:59:52 -0400 Subject: [PATCH 619/628] Refine `TLoopCounterMutatedInLoopBody` This refined definition can handle more cases than the previous one that only looked into the loop body, and better matches the description in the comment above. --- .../rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index d63e8b4890..e2d4e1d16e 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -170,8 +170,9 @@ private newtype TAlertType = /* 3-1. The loop counter is mutated somewhere other than its update expression. */ TLoopCounterMutatedInLoopBody(ForStmt forLoop, Variable loopCounterVariable) { loopCounterVariable = getDeclaredVariableInForLoop(forLoop) and - variableModifiedInExpression(forLoop.getStmt().getChildStmt().getAChild*(), - loopCounterVariable.getAnAccess()) + exists(Expr mutatingExpr | not mutatingExpr = forLoop.getUpdate().getAChild*() | + variableModifiedInExpression(mutatingExpr, loopCounterVariable.getAnAccess()) + ) } or /* 3-2. The loop counter is not updated using either of `++`, `--`, `+=`, or `-=`. */ TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr( From 01216fa1cdd0b4e8a01bedd09b8ab52e53453c61 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 13 Oct 2025 16:17:54 -0400 Subject: [PATCH 620/628] Add more candidate exprs and remove duplicate reportings on compound mutating exprs --- .../LegacyForStatementsShouldBeSimple.ql | 80 ++++++++++++------- 1 file changed, 53 insertions(+), 27 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index e2d4e1d16e..6de2d18de3 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -194,16 +194,28 @@ private newtype TAlertType = ) } or /* 5-1-1. The loop bound is a variable that is mutated in the for loop. */ - TLoopBoundIsMutatedVariableAccess(ForStmt forLoop, Expr loopBound, Expr mutatingExpr) { - loopBound = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and - ( - /* The mutating expression may be in the loop body. */ - mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() - or - /* The mutating expression may be in the loop updating expression. */ - mutatingExpr = forLoop.getUpdate().getAChild*() - ) and - variableModifiedInExpression(mutatingExpr, loopBound.(VariableAccess).getTarget().getAnAccess()) + TLoopBoundIsMutatedVariableAccess( + ForStmt forLoop, VariableAccess variableAccess, VariableAccess mutatedVariableAccess + ) { + exists(Expr loopBoundExpr, Expr mutatingExpr | + loopBoundExpr = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and + ( + /* 1. The mutating expression may be in the loop body. */ + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() + or + /* 2. The mutating expression may be in the loop updating expression. */ + mutatingExpr = forLoop.getUpdate().getAChild*() + or + /* 3. The mutating expression may be in the loop condition */ + mutatingExpr = forLoop.getCondition().getAChild*() + or + /* 4. The mutating expression may be in the loop initializer */ + mutatingExpr = forLoop.getInitialization().getAChild*() + ) and + variableAccess = loopBoundExpr.getAChild*() and + mutatedVariableAccess = variableAccess.getTarget().getAnAccess() and + variableModifiedInExpression(mutatingExpr, mutatedVariableAccess) + ) } or /* 5-1-2. The loop bound is not a variable access nor a constant expression. */ TLoopBoundIsNonConstExpr(ForStmt forLoop, Expr loopBound) { @@ -211,16 +223,28 @@ private newtype TAlertType = (not loopBound instanceof VariableAccess and not loopBound.isConstant()) } or /* 5-2-1. The loop step is a variable that is mutated in the for loop. */ - TLoopStepIsMutatedVariableAccess(ForStmt forLoop, Expr loopStep, Expr mutatingExpr) { - loopStep = getLoopStepOfForStmt(forLoop) and - ( - /* The mutating expression may be in the loop body. */ - mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() - or - /* The mutating expression may be in the loop updating expression. */ - mutatingExpr = forLoop.getUpdate().getAChild*() - ) and - variableModifiedInExpression(mutatingExpr, loopStep.(VariableAccess).getTarget().getAnAccess()) + TLoopStepIsMutatedVariableAccess( + ForStmt forLoop, VariableAccess variableAccess, VariableAccess mutatedVariableAccess + ) { + exists(Expr loopStepExpr, Expr mutatingExpr | + loopStepExpr = getLoopStepOfForStmt(forLoop) and + ( + /* 1. The mutating expression may be in the loop body. */ + mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*() + or + /* 2. The mutating expression may be in the loop updating expression. */ + mutatingExpr = forLoop.getUpdate().getAChild*() + or + /* 3. The mutating expression may be in the loop condition */ + mutatingExpr = forLoop.getCondition().getAChild*() + or + /* 4. The mutating expression may be in the loop initializer */ + mutatingExpr = forLoop.getInitialization().getAChild*() + ) and + variableAccess = loopStepExpr.getAChild*() and + mutatedVariableAccess = variableAccess.getTarget().getAnAccess() and + variableModifiedInExpression(mutatingExpr, mutatedVariableAccess) + ) } or /* 5-2-2. The loop step is not a variable access nor a constant expression. */ TLoopStepIsNonConstExpr(ForStmt forLoop, Expr loopStep) { @@ -244,13 +268,15 @@ private newtype TAlertType = * 6-2. The loop bound is taken as a mutable reference or its address to a mutable pointer. */ - TLoopBoundIsTakenNonConstAddress(ForStmt forLoop, Expr loopVariableAccessInCondition) { - loopVariableAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and - ( - loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, loopVariableAccessInCondition) - or - loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, - loopVariableAccessInCondition) + TLoopBoundIsTakenNonConstAddress(ForStmt forLoop, Expr loopBoundExpr) { + loopBoundExpr = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and + exists(VariableAccess variableAccess | + variableAccess = loopBoundExpr.getAChild*() and + ( + loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, variableAccess) + or + loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, variableAccess) + ) ) } or /* From 0f998ea7b1ec8087c12d001693c0d4cd34288f8c Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 13 Oct 2025 16:18:46 -0400 Subject: [PATCH 621/628] Add more test cases --- cpp/misra/test/rules/RULE-9-5-1/test.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cpp/misra/test/rules/RULE-9-5-1/test.cpp b/cpp/misra/test/rules/RULE-9-5-1/test.cpp index 6e7e09870b..11dfb51b38 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-1/test.cpp @@ -135,6 +135,14 @@ int main() { j++; } + for (int i = 0; i < j++; + i++) { // NON_COMPLIANT: The loop bound `j` is mutated in the loop + } + + for (int i = 0; i++ < j++; + i++) { // NON_COMPLIANT: The loop bound `j` is mutated in the loop + } + int n = 0; for (int i = 0; i < k; From 87a515886bfb3b414eb6020e402c3139d8d094ee Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 13 Oct 2025 17:17:15 -0400 Subject: [PATCH 622/628] Fix loop counter -> loop bound --- cpp/misra/test/rules/RULE-9-5-1/test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/misra/test/rules/RULE-9-5-1/test.cpp b/cpp/misra/test/rules/RULE-9-5-1/test.cpp index 11dfb51b38..81894406be 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-1/test.cpp @@ -208,12 +208,12 @@ int main() { int *m = &k; } - for (int i = j; i < k; i += l) { // COMPLIANT: The loop counter is taken + for (int i = j; i < k; i += l) { // COMPLIANT: The loop bound is taken // as a const reference const int &m = k; } - for (int i = j; i < k; i += l) { // COMPLIANT: The loop counter is taken + for (int i = j; i < k; i += l) { // COMPLIANT: The loop bound is taken // as a const pointer const int *m = &k; } From 2aed0f125fcc52d81a55285a8271c69fd82eaf74 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Mon, 13 Oct 2025 17:31:17 -0400 Subject: [PATCH 623/628] Add const-but-mutable pointer examples --- cpp/misra/test/rules/RULE-9-5-1/test.cpp | 31 ++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/cpp/misra/test/rules/RULE-9-5-1/test.cpp b/cpp/misra/test/rules/RULE-9-5-1/test.cpp index 81894406be..59f077c5bc 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-1/test.cpp @@ -6,6 +6,7 @@ void f1(int &x) {} // Function that takes a non-const integer reference void g1(int *x) {} // Function that takes a non-const integer pointer void f2(const int &x) {} // Function that takes a non-const integer reference void g2(const int *x) {} // Function that takes a non-const integer pointer +void f3(int *const x) {} int h1() { return 1; } constexpr int h2() { return 1; } @@ -198,6 +199,11 @@ int main() { const int *m = &i; } + for (int i = j; i < k; i += l) { // NON-COMPLIANT: The loop counter is taken + // as a const but mutable pointer + int *const m = &i; + } + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is taken as // a non-const reference int &m = k; @@ -218,6 +224,11 @@ int main() { const int *m = &k; } + for (int i = j; i < k; i += l) { // NON-COMPLIANT: The loop bound is taken as + // a const but mutable pointer + int *const m = &k; + } + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is taken as // a non-const reference int &m = l; @@ -238,6 +249,11 @@ int main() { const int *m = &l; } + for (int i = j; i < k; i += l) { // NON-COMPLIANT: The loop step is taken as + // a const but mutable pointer + int *const m = &l; + } + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed // to a non-const reference parameter f1(i); @@ -258,6 +274,11 @@ int main() { g2(&i); } + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed + // to a const but mutable pointer parameter + f3(&i); + } + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is passed to // a non-const reference parameter f1(k); @@ -279,6 +300,11 @@ int main() { g2(&k); } + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is passed to + // a const but mutable pointer parameter + f3(&k); + } + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to // a non-const reference parameter f1(l); @@ -298,4 +324,9 @@ int main() { // a const pointer parameter g2(&l); } + + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to + // a const but mutable pointer parameter + f3(&l); + } } \ No newline at end of file From 33222aef74c5fe67d70c7b685f3033cff04f8a21 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 14 Oct 2025 11:23:34 -0400 Subject: [PATCH 624/628] Debug loopVariableAssignedToNonConstPointOrReferenceType This is to cover the cases where the pointers are constant but the data behind it can be mutated through it. --- .../rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index 6de2d18de3..8d44c50bdf 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -90,8 +90,8 @@ predicate loopVariableAssignedToNonConstPointerOrReferenceType( strippedType = targetType.stripTopLevelSpecifiers() and not strippedType.getBaseType().isConst() and ( - targetType instanceof PointerType or - targetType instanceof ReferenceType + strippedType instanceof PointerType or + strippedType instanceof ReferenceType ) | assignmentRhs.getEnclosingStmt().getParent*() = forLoop.getStmt() and @@ -118,7 +118,7 @@ predicate loopVariableAssignedToNonConstPointerOrReferenceType( * This predicate adds two constraints to the target type, as compared to the original * portion of the predicate: * - * 1. This predicate adds type constraint that the target type is a `ReferenceType`. + * 1. This predicate adds a type constraint that the target type is a `ReferenceType`. * 2. This predicate adds the constraint that the target type is not `const`. * * Also, this predicate requires that the call is the body of the given for-loop. From 3dca053db68f77a0df9aee06bb1ddff441d251e1 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Tue, 14 Oct 2025 13:53:34 -0400 Subject: [PATCH 625/628] Update expected results of 9-5-1 --- ...LegacyForStatementsShouldBeSimple.expected | 77 +++++++++++-------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected index d40663abf5..a2b79b724d 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected +++ b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected @@ -1,32 +1,45 @@ -| test.cpp:23:3:25:3 | for(...;...;...) ... | The $@ is not of an integer type. | test.cpp:23:14:23:14 | i | counter variable | test.cpp:23:14:23:14 | i | N/A | -| test.cpp:32:3:34:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:32:19:32:25 | ... == ... | loop condition | test.cpp:32:19:32:25 | ... == ... | N/A | -| test.cpp:36:3:38:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:36:19:36:24 | ... < ... | loop condition | test.cpp:36:19:36:24 | ... < ... | N/A | -| test.cpp:77:3:79:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:77:12:77:12 | i | counter variable | test.cpp:78:8:78:13 | ... *= ... | expression | -| test.cpp:91:3:94:3 | for(...;...;...) ... | The $@ has a smaller type than that of the $@. | test.cpp:91:21:91:21 | i | counter variable | test.cpp:91:25:91:53 | call to max | loop bound | -| test.cpp:116:3:119:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:117:13:117:13 | j | loop step | test.cpp:118:5:118:7 | ... ++ | mutated | -| test.cpp:121:3:123:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:122:13:122:13 | j | loop step | test.cpp:122:8:122:18 | ... , ... | mutated | -| test.cpp:121:3:123:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:122:13:122:13 | j | loop step | test.cpp:122:16:122:18 | ... ++ | mutated | -| test.cpp:121:3:123:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:121:12:121:12 | i | counter variable | test.cpp:122:8:122:18 | ... , ... | expression | -| test.cpp:133:3:136:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:133:23:133:23 | j | loop bound | test.cpp:135:5:135:7 | ... ++ | mutated | -| test.cpp:140:3:143:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:140:23:140:23 | k | loop bound | test.cpp:142:5:142:26 | ... += ... | mutated | -| test.cpp:145:3:148:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:146:13:146:13 | l | loop step | test.cpp:147:5:147:26 | ... += ... | mutated | -| test.cpp:150:3:152:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:150:23:150:24 | call to h1 | loop bound | test.cpp:150:23:150:24 | call to h1 | non-const expression | -| test.cpp:158:3:160:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:159:13:159:14 | call to h1 | loop step | test.cpp:159:13:159:14 | call to h1 | non-const expression | -| test.cpp:173:3:176:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:173:19:173:19 | i | loop counter | test.cpp:173:19:173:19 | i | N/A | -| test.cpp:178:3:181:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:178:19:178:19 | i | loop counter | test.cpp:178:19:178:19 | i | N/A | -| test.cpp:193:3:196:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:193:23:193:23 | k | loop bound | test.cpp:193:23:193:23 | k | N/A | -| test.cpp:198:3:201:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:198:23:198:23 | k | loop bound | test.cpp:198:23:198:23 | k | N/A | -| test.cpp:213:3:216:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:213:31:213:31 | l | loop step | test.cpp:213:31:213:31 | l | N/A | -| test.cpp:218:3:221:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:218:31:218:31 | l | loop step | test.cpp:218:31:218:31 | l | N/A | -| test.cpp:233:3:236:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:233:19:233:19 | i | loop counter | test.cpp:233:19:233:19 | i | N/A | -| test.cpp:233:3:236:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:233:12:233:12 | i | counter variable | test.cpp:233:12:233:12 | i | N/A | -| test.cpp:238:3:241:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:238:19:238:19 | i | loop counter | test.cpp:238:19:238:19 | i | N/A | -| test.cpp:238:3:241:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:238:12:238:12 | i | counter variable | test.cpp:238:12:238:12 | i | N/A | -| test.cpp:253:3:256:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:253:23:253:23 | k | loop bound | test.cpp:255:5:255:6 | call to f1 | mutated | -| test.cpp:253:3:256:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:253:23:253:23 | k | loop bound | test.cpp:253:23:253:23 | k | N/A | -| test.cpp:258:3:261:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:258:23:258:23 | k | loop bound | test.cpp:260:5:260:6 | call to g1 | mutated | -| test.cpp:258:3:261:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:258:23:258:23 | k | loop bound | test.cpp:258:23:258:23 | k | N/A | -| test.cpp:274:3:277:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:274:31:274:31 | l | loop step | test.cpp:276:5:276:6 | call to f1 | mutated | -| test.cpp:274:3:277:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:274:31:274:31 | l | loop step | test.cpp:274:31:274:31 | l | N/A | -| test.cpp:279:3:282:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:279:31:279:31 | l | loop step | test.cpp:281:5:281:6 | call to g1 | mutated | -| test.cpp:279:3:282:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:279:31:279:31 | l | loop step | test.cpp:279:31:279:31 | l | N/A | +| test.cpp:24:3:26:3 | for(...;...;...) ... | The $@ is not of an integer type. | test.cpp:24:14:24:14 | i | counter variable | test.cpp:24:14:24:14 | i | N/A | +| test.cpp:33:3:35:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:33:19:33:25 | ... == ... | loop condition | test.cpp:33:19:33:25 | ... == ... | N/A | +| test.cpp:37:3:39:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:37:19:37:24 | ... < ... | loop condition | test.cpp:37:19:37:24 | ... < ... | N/A | +| test.cpp:78:3:80:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:78:12:78:12 | i | counter variable | test.cpp:79:8:79:13 | ... *= ... | expression | +| test.cpp:92:3:95:3 | for(...;...;...) ... | The $@ has a smaller type than that of the $@. | test.cpp:92:21:92:21 | i | counter variable | test.cpp:92:25:92:53 | call to max | loop bound | +| test.cpp:117:3:120:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:118:13:118:13 | j | loop step | test.cpp:119:5:119:5 | j | mutated | +| test.cpp:122:3:124:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:123:13:123:13 | j | loop step | test.cpp:123:16:123:16 | j | mutated | +| test.cpp:122:3:124:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:122:12:122:12 | i | counter variable | test.cpp:123:8:123:18 | ... , ... | expression | +| test.cpp:134:3:137:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:134:23:134:23 | j | loop bound | test.cpp:136:5:136:5 | j | mutated | +| test.cpp:139:3:141:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:139:23:139:25 | ... ++ | loop bound | test.cpp:139:23:139:25 | ... ++ | non-const expression | +| test.cpp:139:3:141:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:139:23:139:23 | j | loop bound | test.cpp:139:23:139:23 | j | mutated | +| test.cpp:143:3:145:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:143:25:143:27 | ... ++ | loop bound | test.cpp:143:25:143:27 | ... ++ | non-const expression | +| test.cpp:143:3:145:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:143:25:143:25 | j | loop bound | test.cpp:143:25:143:25 | j | mutated | +| test.cpp:143:3:145:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:143:12:143:12 | i | counter variable | test.cpp:143:12:143:12 | i | N/A | +| test.cpp:149:3:152:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:149:23:149:23 | k | loop bound | test.cpp:151:15:151:15 | k | mutated | +| test.cpp:154:3:157:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:155:13:155:13 | l | loop step | test.cpp:156:15:156:15 | l | mutated | +| test.cpp:159:3:161:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:159:23:159:24 | call to h1 | loop bound | test.cpp:159:23:159:24 | call to h1 | non-const expression | +| test.cpp:167:3:169:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:168:13:168:14 | call to h1 | loop step | test.cpp:168:13:168:14 | call to h1 | non-const expression | +| test.cpp:182:3:185:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:182:19:182:19 | i | loop counter | test.cpp:182:19:182:19 | i | N/A | +| test.cpp:187:3:190:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:187:19:187:19 | i | loop counter | test.cpp:187:19:187:19 | i | N/A | +| test.cpp:202:3:205:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:202:19:202:19 | i | loop counter | test.cpp:202:19:202:19 | i | N/A | +| test.cpp:207:3:210:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:207:23:207:23 | k | loop bound | test.cpp:207:23:207:23 | k | N/A | +| test.cpp:212:3:215:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:212:23:212:23 | k | loop bound | test.cpp:212:23:212:23 | k | N/A | +| test.cpp:227:3:230:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:227:23:227:23 | k | loop bound | test.cpp:227:23:227:23 | k | N/A | +| test.cpp:232:3:235:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:232:31:232:31 | l | loop step | test.cpp:232:31:232:31 | l | N/A | +| test.cpp:237:3:240:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:237:31:237:31 | l | loop step | test.cpp:237:31:237:31 | l | N/A | +| test.cpp:252:3:255:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:252:31:252:31 | l | loop step | test.cpp:252:31:252:31 | l | N/A | +| test.cpp:257:3:260:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:257:19:257:19 | i | loop counter | test.cpp:257:19:257:19 | i | N/A | +| test.cpp:257:3:260:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:257:12:257:12 | i | counter variable | test.cpp:257:12:257:12 | i | N/A | +| test.cpp:262:3:265:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:262:19:262:19 | i | loop counter | test.cpp:262:19:262:19 | i | N/A | +| test.cpp:262:3:265:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:262:12:262:12 | i | counter variable | test.cpp:262:12:262:12 | i | N/A | +| test.cpp:277:3:280:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:277:19:277:19 | i | loop counter | test.cpp:277:19:277:19 | i | N/A | +| test.cpp:277:3:280:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:277:12:277:12 | i | counter variable | test.cpp:277:12:277:12 | i | N/A | +| test.cpp:282:3:285:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:282:23:282:23 | k | loop bound | test.cpp:284:8:284:8 | k | mutated | +| test.cpp:282:3:285:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:282:23:282:23 | k | loop bound | test.cpp:282:23:282:23 | k | N/A | +| test.cpp:287:3:290:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:287:23:287:23 | k | loop bound | test.cpp:289:9:289:9 | k | mutated | +| test.cpp:287:3:290:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:287:23:287:23 | k | loop bound | test.cpp:287:23:287:23 | k | N/A | +| test.cpp:303:3:306:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:303:23:303:23 | k | loop bound | test.cpp:305:9:305:9 | k | mutated | +| test.cpp:303:3:306:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:303:23:303:23 | k | loop bound | test.cpp:303:23:303:23 | k | N/A | +| test.cpp:308:3:311:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:308:31:308:31 | l | loop step | test.cpp:310:8:310:8 | l | mutated | +| test.cpp:308:3:311:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:308:31:308:31 | l | loop step | test.cpp:308:31:308:31 | l | N/A | +| test.cpp:313:3:316:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:313:31:313:31 | l | loop step | test.cpp:315:9:315:9 | l | mutated | +| test.cpp:313:3:316:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:313:31:313:31 | l | loop step | test.cpp:313:31:313:31 | l | N/A | +| test.cpp:328:3:331:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:328:31:328:31 | l | loop step | test.cpp:330:9:330:9 | l | mutated | +| test.cpp:328:3:331:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:328:31:328:31 | l | loop step | test.cpp:328:31:328:31 | l | N/A | From ef71d7adbaba5282590e1655ee92e40b23775603 Mon Sep 17 00:00:00 2001 From: knewbury01 Date: Mon, 20 Oct 2025 21:10:32 +0000 Subject: [PATCH 626/628] Bump version to 2.52.0-dev --- c/cert/src/qlpack.yml | 2 +- c/cert/test/qlpack.yml | 2 +- c/common/src/qlpack.yml | 2 +- c/common/test/qlpack.yml | 2 +- c/misra/src/qlpack.yml | 2 +- c/misra/test/qlpack.yml | 2 +- cpp/autosar/src/qlpack.yml | 2 +- cpp/autosar/test/qlpack.yml | 2 +- cpp/cert/src/qlpack.yml | 2 +- cpp/cert/test/qlpack.yml | 2 +- cpp/common/src/qlpack.yml | 2 +- cpp/common/test/qlpack.yml | 2 +- cpp/misra/src/qlpack.yml | 2 +- cpp/misra/test/qlpack.yml | 2 +- cpp/report/src/qlpack.yml | 2 +- docs/user_manual.md | 12 ++++++------ 16 files changed, 21 insertions(+), 21 deletions(-) diff --git a/c/cert/src/qlpack.yml b/c/cert/src/qlpack.yml index 52f44f7370..ecf2a573e4 100644 --- a/c/cert/src/qlpack.yml +++ b/c/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards -version: 2.51.0-dev +version: 2.52.0-dev description: CERT C 2016 suites: codeql-suites license: MIT diff --git a/c/cert/test/qlpack.yml b/c/cert/test/qlpack.yml index 5588edec2a..80311bdd57 100644 --- a/c/cert/test/qlpack.yml +++ b/c/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-c-coding-standards-tests -version: 2.51.0-dev +version: 2.52.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/common/src/qlpack.yml b/c/common/src/qlpack.yml index 3dbcd1a492..d71ab0dd02 100644 --- a/c/common/src/qlpack.yml +++ b/c/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards -version: 2.51.0-dev +version: 2.52.0-dev license: MIT dependencies: codeql/common-cpp-coding-standards: '*' diff --git a/c/common/test/qlpack.yml b/c/common/test/qlpack.yml index 22772323b9..28785ce465 100644 --- a/c/common/test/qlpack.yml +++ b/c/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-c-coding-standards-tests -version: 2.51.0-dev +version: 2.52.0-dev extractor: cpp license: MIT dependencies: diff --git a/c/misra/src/qlpack.yml b/c/misra/src/qlpack.yml index ca5a163b4f..fad952166c 100644 --- a/c/misra/src/qlpack.yml +++ b/c/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards -version: 2.51.0-dev +version: 2.52.0-dev description: MISRA C 2012 suites: codeql-suites license: MIT diff --git a/c/misra/test/qlpack.yml b/c/misra/test/qlpack.yml index 7dec042c19..5f22b18e91 100644 --- a/c/misra/test/qlpack.yml +++ b/c/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-c-coding-standards-tests -version: 2.51.0-dev +version: 2.52.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/autosar/src/qlpack.yml b/cpp/autosar/src/qlpack.yml index 367a4a3f18..4382b97321 100644 --- a/cpp/autosar/src/qlpack.yml +++ b/cpp/autosar/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards -version: 2.51.0-dev +version: 2.52.0-dev description: AUTOSAR C++14 Guidelines R22-11, R21-11, R20-11, R19-11 and R19-03 suites: codeql-suites license: MIT diff --git a/cpp/autosar/test/qlpack.yml b/cpp/autosar/test/qlpack.yml index 07de7dd182..040c140538 100644 --- a/cpp/autosar/test/qlpack.yml +++ b/cpp/autosar/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/autosar-cpp-coding-standards-tests -version: 2.51.0-dev +version: 2.52.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/cert/src/qlpack.yml b/cpp/cert/src/qlpack.yml index 328c837fb6..08fdfc9746 100644 --- a/cpp/cert/src/qlpack.yml +++ b/cpp/cert/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards -version: 2.51.0-dev +version: 2.52.0-dev description: CERT C++ 2016 suites: codeql-suites license: MIT diff --git a/cpp/cert/test/qlpack.yml b/cpp/cert/test/qlpack.yml index c92c074dce..7dda15503a 100644 --- a/cpp/cert/test/qlpack.yml +++ b/cpp/cert/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/cert-cpp-coding-standards-tests -version: 2.51.0-dev +version: 2.52.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/common/src/qlpack.yml b/cpp/common/src/qlpack.yml index 0e220b7752..21663a5186 100644 --- a/cpp/common/src/qlpack.yml +++ b/cpp/common/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards -version: 2.51.0-dev +version: 2.52.0-dev license: MIT dependencies: codeql/cpp-all: 4.0.3 diff --git a/cpp/common/test/qlpack.yml b/cpp/common/test/qlpack.yml index f5dc77c16d..cdec8497fd 100644 --- a/cpp/common/test/qlpack.yml +++ b/cpp/common/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/common-cpp-coding-standards-tests -version: 2.51.0-dev +version: 2.52.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 1505587a55..89bb103b09 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards -version: 2.51.0-dev +version: 2.52.0-dev description: MISRA C++ 2023 default-suite: codeql-suites/misra-cpp-default.qls license: MIT diff --git a/cpp/misra/test/qlpack.yml b/cpp/misra/test/qlpack.yml index 080dcdebff..7f95987cd1 100644 --- a/cpp/misra/test/qlpack.yml +++ b/cpp/misra/test/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/misra-cpp-coding-standards-tests -version: 2.51.0-dev +version: 2.52.0-dev extractor: cpp license: MIT dependencies: diff --git a/cpp/report/src/qlpack.yml b/cpp/report/src/qlpack.yml index 7a0817da16..9f4064e4c6 100644 --- a/cpp/report/src/qlpack.yml +++ b/cpp/report/src/qlpack.yml @@ -1,5 +1,5 @@ name: codeql/report-cpp-coding-standards -version: 2.51.0-dev +version: 2.52.0-dev license: MIT dependencies: codeql/cpp-all: 4.0.3 diff --git a/docs/user_manual.md b/docs/user_manual.md index 14290aa8a4..201fb76ad5 100644 --- a/docs/user_manual.md +++ b/docs/user_manual.md @@ -36,14 +36,14 @@ ## Release information -This user manual documents release `2.51.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). +This user manual documents release `2.52.0-dev` of the coding standards located at [https://github.com/github/codeql-coding-standards](https://github.com/github/codeql-coding-standards). The release page documents the release notes and contains the following artifacts part of the release: - `coding-standards-codeql-packs-2.37.0-dev.zip`: CodeQL packs that can be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `code-scanning-cpp-query-pack-2.51.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. -- `supported_rules_list_2.51.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. -- `supported_rules_list_2.51.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. -- `user_manual_2.51.0-dev.md`: This user manual. +- `code-scanning-cpp-query-pack-2.52.0-dev.zip`: Legacy packaging for the queries and scripts to be used with GitHub Code Scanning or the CodeQL CLI as documented in the section _Operating manual_. +- `supported_rules_list_2.52.0-dev.csv`: A Comma Separated File (CSV) containing the supported rules per standard and the queries that implement the rule. +- `supported_rules_list_2.52.0-dev.md`: A Markdown formatted file with a table containing the supported rules per standard and the queries that implement the rule. +- `user_manual_2.52.0-dev.md`: This user manual. - `Source Code (zip)`: A zip archive containing the contents of https://github.com/github/codeql-coding-standards - `Source Code (tar.gz)`: A GZip compressed tar archive containing the contents of https://github.com/github/codeql-coding-standards - `checksums.txt`: A text file containing sha256 checksums for the aforementioned artifacts. @@ -670,7 +670,7 @@ This section describes known failure modes for "CodeQL Coding Standards" and des | | Out of space | Less output. Some files may be only be partially analyzed, or not analyzed at all. | Error reported on the command line. | Increase space. If it remains an issue report space consumption issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False positives | More output. Results are reported which are not violations of the guidelines. | All reported results must be reviewed. | Report false positive issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | | | False negatives | Less output. Violations of the guidelines are not reported. | Other validation and verification processes during software development should be used to complement the analysis performed by CodeQL Coding Standards. | Report false negative issues via the CodeQL Coding Standards [bug tracker](https://github.com/github/codeql-coding-standards/issues). | -| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.51.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | +| | Modifying coding standard suite | More or less output. If queries are added to the query set more result can be reported. If queries are removed less results might be reported. | All queries supported by the CodeQL Coding Standards are listed in the release artifacts `supported_rules_list_2.52.0-dev.csv` where VERSION is replaced with the used release. The rules in the resulting Sarif file must be cross-referenced with the expected rules in this list to determine the validity of the used CodeQL suite. | Ensure that the CodeQL Coding Standards are not modified in ways that are not documented as supported modifications. | | | Incorrect deviation record specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation records with a reason. Ensure that all deviation records are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Incorrect deviation permit specification | More output. Results are reported for guidelines for which a deviation is assigned. | Analysis integrity report lists all deviations and incorrectly specified deviation permits with a reason. Ensure that all deviation permits are correctly specified. | Ensure that the deviation record is specified according to the specification in the user manual. | | | Unapproved use of a deviation record | Less output. Results for guideline violations are not reported. | Validate that the deviation record use is approved by verifying the approved-by attribute of the deviation record specification. | Ensure that each raised deviation record is approved by an independent approver through an auditable process. | From 15be0109ebb4fa1721e7ba362359f9f56b8a306b Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 5 Nov 2025 15:02:39 -0500 Subject: [PATCH 627/628] Enforce loop counter to be variable access and add tests --- cpp/common/src/codingstandards/cpp/Loops.qll | 11 +- ...LegacyForStatementsShouldBeSimple.expected | 93 ++++++++-------- cpp/misra/test/rules/RULE-9-5-1/test.cpp | 104 +++++++++++++++++- 3 files changed, 152 insertions(+), 56 deletions(-) diff --git a/cpp/common/src/codingstandards/cpp/Loops.qll b/cpp/common/src/codingstandards/cpp/Loops.qll index a18c8e34af..1086355638 100644 --- a/cpp/common/src/codingstandards/cpp/Loops.qll +++ b/cpp/common/src/codingstandards/cpp/Loops.qll @@ -390,13 +390,10 @@ class LegacyForLoopCondition extends RelationalOperation { LegacyForLoopCondition() { this = forLoop.getCondition() and - exists(Expr loopCounterExpr | - loopCounterExpr = this.getAnOperand() and - loopBound = this.getAnOperand() and - loopCounter = loopCounterExpr.getAChild*() and - loopCounter.getTarget() = getAnIterationVariable(forLoop) and - loopBound != loopCounterExpr - ) + loopCounter = this.getAnOperand() and + loopBound = this.getAnOperand() and + loopCounter.getTarget() = getAnIterationVariable(forLoop) and + loopBound != loopCounter } /** diff --git a/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected index a2b79b724d..3469fcab47 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected +++ b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected @@ -1,45 +1,48 @@ -| test.cpp:24:3:26:3 | for(...;...;...) ... | The $@ is not of an integer type. | test.cpp:24:14:24:14 | i | counter variable | test.cpp:24:14:24:14 | i | N/A | -| test.cpp:33:3:35:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:33:19:33:25 | ... == ... | loop condition | test.cpp:33:19:33:25 | ... == ... | N/A | -| test.cpp:37:3:39:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:37:19:37:24 | ... < ... | loop condition | test.cpp:37:19:37:24 | ... < ... | N/A | -| test.cpp:78:3:80:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:78:12:78:12 | i | counter variable | test.cpp:79:8:79:13 | ... *= ... | expression | -| test.cpp:92:3:95:3 | for(...;...;...) ... | The $@ has a smaller type than that of the $@. | test.cpp:92:21:92:21 | i | counter variable | test.cpp:92:25:92:53 | call to max | loop bound | -| test.cpp:117:3:120:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:118:13:118:13 | j | loop step | test.cpp:119:5:119:5 | j | mutated | -| test.cpp:122:3:124:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:123:13:123:13 | j | loop step | test.cpp:123:16:123:16 | j | mutated | -| test.cpp:122:3:124:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:122:12:122:12 | i | counter variable | test.cpp:123:8:123:18 | ... , ... | expression | -| test.cpp:134:3:137:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:134:23:134:23 | j | loop bound | test.cpp:136:5:136:5 | j | mutated | -| test.cpp:139:3:141:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:139:23:139:25 | ... ++ | loop bound | test.cpp:139:23:139:25 | ... ++ | non-const expression | -| test.cpp:139:3:141:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:139:23:139:23 | j | loop bound | test.cpp:139:23:139:23 | j | mutated | -| test.cpp:143:3:145:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:143:25:143:27 | ... ++ | loop bound | test.cpp:143:25:143:27 | ... ++ | non-const expression | -| test.cpp:143:3:145:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:143:25:143:25 | j | loop bound | test.cpp:143:25:143:25 | j | mutated | -| test.cpp:143:3:145:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:143:12:143:12 | i | counter variable | test.cpp:143:12:143:12 | i | N/A | -| test.cpp:149:3:152:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:149:23:149:23 | k | loop bound | test.cpp:151:15:151:15 | k | mutated | -| test.cpp:154:3:157:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:155:13:155:13 | l | loop step | test.cpp:156:15:156:15 | l | mutated | -| test.cpp:159:3:161:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:159:23:159:24 | call to h1 | loop bound | test.cpp:159:23:159:24 | call to h1 | non-const expression | -| test.cpp:167:3:169:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:168:13:168:14 | call to h1 | loop step | test.cpp:168:13:168:14 | call to h1 | non-const expression | -| test.cpp:182:3:185:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:182:19:182:19 | i | loop counter | test.cpp:182:19:182:19 | i | N/A | -| test.cpp:187:3:190:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:187:19:187:19 | i | loop counter | test.cpp:187:19:187:19 | i | N/A | -| test.cpp:202:3:205:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:202:19:202:19 | i | loop counter | test.cpp:202:19:202:19 | i | N/A | -| test.cpp:207:3:210:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:207:23:207:23 | k | loop bound | test.cpp:207:23:207:23 | k | N/A | -| test.cpp:212:3:215:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:212:23:212:23 | k | loop bound | test.cpp:212:23:212:23 | k | N/A | -| test.cpp:227:3:230:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:227:23:227:23 | k | loop bound | test.cpp:227:23:227:23 | k | N/A | -| test.cpp:232:3:235:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:232:31:232:31 | l | loop step | test.cpp:232:31:232:31 | l | N/A | -| test.cpp:237:3:240:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:237:31:237:31 | l | loop step | test.cpp:237:31:237:31 | l | N/A | -| test.cpp:252:3:255:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:252:31:252:31 | l | loop step | test.cpp:252:31:252:31 | l | N/A | -| test.cpp:257:3:260:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:257:19:257:19 | i | loop counter | test.cpp:257:19:257:19 | i | N/A | -| test.cpp:257:3:260:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:257:12:257:12 | i | counter variable | test.cpp:257:12:257:12 | i | N/A | -| test.cpp:262:3:265:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:262:19:262:19 | i | loop counter | test.cpp:262:19:262:19 | i | N/A | -| test.cpp:262:3:265:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:262:12:262:12 | i | counter variable | test.cpp:262:12:262:12 | i | N/A | -| test.cpp:277:3:280:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:277:19:277:19 | i | loop counter | test.cpp:277:19:277:19 | i | N/A | -| test.cpp:277:3:280:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:277:12:277:12 | i | counter variable | test.cpp:277:12:277:12 | i | N/A | -| test.cpp:282:3:285:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:282:23:282:23 | k | loop bound | test.cpp:284:8:284:8 | k | mutated | -| test.cpp:282:3:285:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:282:23:282:23 | k | loop bound | test.cpp:282:23:282:23 | k | N/A | -| test.cpp:287:3:290:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:287:23:287:23 | k | loop bound | test.cpp:289:9:289:9 | k | mutated | -| test.cpp:287:3:290:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:287:23:287:23 | k | loop bound | test.cpp:287:23:287:23 | k | N/A | -| test.cpp:303:3:306:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:303:23:303:23 | k | loop bound | test.cpp:305:9:305:9 | k | mutated | -| test.cpp:303:3:306:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:303:23:303:23 | k | loop bound | test.cpp:303:23:303:23 | k | N/A | -| test.cpp:308:3:311:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:308:31:308:31 | l | loop step | test.cpp:310:8:310:8 | l | mutated | -| test.cpp:308:3:311:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:308:31:308:31 | l | loop step | test.cpp:308:31:308:31 | l | N/A | -| test.cpp:313:3:316:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:313:31:313:31 | l | loop step | test.cpp:315:9:315:9 | l | mutated | -| test.cpp:313:3:316:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:313:31:313:31 | l | loop step | test.cpp:313:31:313:31 | l | N/A | -| test.cpp:328:3:331:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:328:31:328:31 | l | loop step | test.cpp:330:9:330:9 | l | mutated | -| test.cpp:328:3:331:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:328:31:328:31 | l | loop step | test.cpp:328:31:328:31 | l | N/A | +| test.cpp:26:3:28:3 | for(...;...;...) ... | The $@ is not of an integer type. | test.cpp:26:14:26:14 | i | counter variable | test.cpp:26:14:26:14 | i | N/A | +| test.cpp:35:3:37:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:35:19:35:25 | ... == ... | loop condition | test.cpp:35:19:35:25 | ... == ... | N/A | +| test.cpp:39:3:41:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:39:19:39:24 | ... < ... | loop condition | test.cpp:39:19:39:24 | ... < ... | N/A | +| test.cpp:55:3:58:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:55:19:55:28 | ... < ... | loop condition | test.cpp:55:19:55:28 | ... < ... | N/A | +| test.cpp:60:3:63:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:60:19:60:27 | ... < ... | loop condition | test.cpp:60:19:60:27 | ... < ... | N/A | +| test.cpp:65:3:68:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:65:19:65:27 | ... < ... | loop condition | test.cpp:65:19:65:27 | ... < ... | N/A | +| test.cpp:65:3:68:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:65:12:65:12 | i | counter variable | test.cpp:65:12:65:12 | i | N/A | +| test.cpp:107:3:109:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:107:12:107:12 | i | counter variable | test.cpp:108:8:108:13 | ... *= ... | expression | +| test.cpp:121:3:124:3 | for(...;...;...) ... | The $@ has a smaller type than that of the $@. | test.cpp:121:21:121:21 | i | counter variable | test.cpp:121:25:121:53 | call to max | loop bound | +| test.cpp:146:3:149:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:147:13:147:13 | j | loop step | test.cpp:148:5:148:5 | j | mutated | +| test.cpp:151:3:153:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:152:13:152:13 | j | loop step | test.cpp:152:16:152:16 | j | mutated | +| test.cpp:151:3:153:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:151:12:151:12 | i | counter variable | test.cpp:152:8:152:18 | ... , ... | expression | +| test.cpp:163:3:166:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:163:23:163:23 | j | loop bound | test.cpp:165:5:165:5 | j | mutated | +| test.cpp:168:3:170:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:168:23:168:25 | ... ++ | loop bound | test.cpp:168:23:168:25 | ... ++ | non-const expression | +| test.cpp:168:3:170:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:168:23:168:23 | j | loop bound | test.cpp:168:23:168:23 | j | mutated | +| test.cpp:172:3:174:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:172:19:172:27 | ... < ... | loop condition | test.cpp:172:19:172:27 | ... < ... | N/A | +| test.cpp:172:3:174:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:172:12:172:12 | i | counter variable | test.cpp:172:12:172:12 | i | N/A | +| test.cpp:178:3:181:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:178:23:178:23 | k | loop bound | test.cpp:180:15:180:15 | k | mutated | +| test.cpp:183:3:186:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:184:13:184:13 | l | loop step | test.cpp:185:15:185:15 | l | mutated | +| test.cpp:188:3:190:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:188:23:188:24 | call to h1 | loop bound | test.cpp:188:23:188:24 | call to h1 | non-const expression | +| test.cpp:196:3:198:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:197:13:197:14 | call to h1 | loop step | test.cpp:197:13:197:14 | call to h1 | non-const expression | +| test.cpp:211:3:214:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:211:19:211:19 | i | loop counter | test.cpp:211:19:211:19 | i | N/A | +| test.cpp:216:3:219:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:216:19:216:19 | i | loop counter | test.cpp:216:19:216:19 | i | N/A | +| test.cpp:231:3:234:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:231:19:231:19 | i | loop counter | test.cpp:231:19:231:19 | i | N/A | +| test.cpp:236:3:239:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:236:23:236:23 | k | loop bound | test.cpp:236:23:236:23 | k | N/A | +| test.cpp:241:3:244:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:241:23:241:23 | k | loop bound | test.cpp:241:23:241:23 | k | N/A | +| test.cpp:256:3:259:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:256:23:256:23 | k | loop bound | test.cpp:256:23:256:23 | k | N/A | +| test.cpp:261:3:264:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:261:31:261:31 | l | loop step | test.cpp:261:31:261:31 | l | N/A | +| test.cpp:266:3:269:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:266:31:266:31 | l | loop step | test.cpp:266:31:266:31 | l | N/A | +| test.cpp:281:3:284:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:281:31:281:31 | l | loop step | test.cpp:281:31:281:31 | l | N/A | +| test.cpp:286:3:289:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:286:19:286:19 | i | loop counter | test.cpp:286:19:286:19 | i | N/A | +| test.cpp:286:3:289:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:286:12:286:12 | i | counter variable | test.cpp:286:12:286:12 | i | N/A | +| test.cpp:291:3:294:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:291:19:291:19 | i | loop counter | test.cpp:291:19:291:19 | i | N/A | +| test.cpp:291:3:294:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:291:12:291:12 | i | counter variable | test.cpp:291:12:291:12 | i | N/A | +| test.cpp:306:3:309:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:306:19:306:19 | i | loop counter | test.cpp:306:19:306:19 | i | N/A | +| test.cpp:306:3:309:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:306:12:306:12 | i | counter variable | test.cpp:306:12:306:12 | i | N/A | +| test.cpp:311:3:314:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:311:23:311:23 | k | loop bound | test.cpp:313:8:313:8 | k | mutated | +| test.cpp:311:3:314:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:311:23:311:23 | k | loop bound | test.cpp:311:23:311:23 | k | N/A | +| test.cpp:316:3:319:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:316:23:316:23 | k | loop bound | test.cpp:318:9:318:9 | k | mutated | +| test.cpp:316:3:319:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:316:23:316:23 | k | loop bound | test.cpp:316:23:316:23 | k | N/A | +| test.cpp:332:3:335:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:332:23:332:23 | k | loop bound | test.cpp:334:9:334:9 | k | mutated | +| test.cpp:332:3:335:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:332:23:332:23 | k | loop bound | test.cpp:332:23:332:23 | k | N/A | +| test.cpp:337:3:340:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:337:31:337:31 | l | loop step | test.cpp:339:8:339:8 | l | mutated | +| test.cpp:337:3:340:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:337:31:337:31 | l | loop step | test.cpp:337:31:337:31 | l | N/A | +| test.cpp:342:3:345:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:342:31:342:31 | l | loop step | test.cpp:344:9:344:9 | l | mutated | +| test.cpp:342:3:345:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:342:31:342:31 | l | loop step | test.cpp:342:31:342:31 | l | N/A | +| test.cpp:357:3:360:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:357:31:357:31 | l | loop step | test.cpp:359:9:359:9 | l | mutated | +| test.cpp:357:3:360:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:357:31:357:31 | l | loop step | test.cpp:357:31:357:31 | l | N/A | diff --git a/cpp/misra/test/rules/RULE-9-5-1/test.cpp b/cpp/misra/test/rules/RULE-9-5-1/test.cpp index 59f077c5bc..eaddd9644a 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/test.cpp +++ b/cpp/misra/test/rules/RULE-9-5-1/test.cpp @@ -7,10 +7,19 @@ void g1(int *x) {} // Function that takes a non-const integer pointer void f2(const int &x) {} // Function that takes a non-const integer reference void g2(const int *x) {} // Function that takes a non-const integer pointer void f3(int *const x) {} +void f4(int *x...) {} // Function that takes a non-const integer pointer +void g4(int &x...) {} // Function that takes a non-const integer pointer +void f5(const int *x...) {} // Function that takes a non-const integer pointer +void g5(const int &x...) {} // Function that takes a non-const integer pointer int h1() { return 1; } constexpr int h2() { return 1; } +int h3(int x) { return x; } + +void h4(int &args...) {} +void h5(const int &args...) {} + int main() { int j = 5; int k = 10; @@ -38,6 +47,33 @@ int main() { j++; } + /* + * The following test cases in this section document our stance on arithmetic + * operations on loop counters appearing as an operand of the loop condition. + * Our stance is that such conditions are non-compliant cases according to + * this part of the rule. + * + * Why we think they are non-compliant is as follows: We interpret the rule as + * having the loop counter be an index that are meant to be used directly as + * is, by their value. Therefore, performing arithmetic and comparing the + * result to a loop bound goes against the interpretation. + */ + + for (int i = 0; i + 10 < j; + ++i) { // NON_COMPLIANT: The loop condition does not directly compare + // loop counter `i` to the loop bound `j` + } + + for (int i = 0; h3(i) < j; + ++i) { // NON_COMPLIANT: The loop condition does not directly compare + // loop counter `i` to the loop bound `j` + } + + for (int i = 0; i++ < j++; + i++) { // NON_COMPLIANT: The loop condition does not directly compare + // loop counter `i` to the loop bound `j` + } + /* ========== 3. Updating expression ========== */ for (int i = 0; i < 10; @@ -199,7 +235,7 @@ int main() { const int *m = &i; } - for (int i = j; i < k; i += l) { // NON-COMPLIANT: The loop counter is taken + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is taken // as a const but mutable pointer int *const m = &i; } @@ -224,7 +260,7 @@ int main() { const int *m = &k; } - for (int i = j; i < k; i += l) { // NON-COMPLIANT: The loop bound is taken as + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is taken as // a const but mutable pointer int *const m = &k; } @@ -249,7 +285,7 @@ int main() { const int *m = &l; } - for (int i = j; i < k; i += l) { // NON-COMPLIANT: The loop step is taken as + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is taken as // a const but mutable pointer int *const m = &l; } @@ -279,6 +315,26 @@ int main() { f3(&i); } + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed + // to a non-const variadic reference argument + f4(&i); + } + + for (int i = j; i < k; i += l) { // COMPLIANT: The loop counter is passed to a + // const variadic reference argument + f5(&i); + } + + for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop counter is passed + // to a non-const variadic reference argument + g4(i); + } + + for (int i = 0; i < k; i += l) { // COMPLIANT: The loop counter is passed to a + // const variadic reference argument + g5(i); + } + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop bound is passed to // a non-const reference parameter f1(k); @@ -305,6 +361,26 @@ int main() { f3(&k); } + for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop bound is passed to + // a non-const variadic reference argument + f4(&k); + } + + for (int i = 0; i < k; i += l) { // COMPLIANT: The loop bound is passed to a + // const variadic reference argument + f5(&k); + } + + for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop bound is passed to + // a non-const variadic reference argument + g4(k); + } + + for (int i = 0; i < k; i += l) { // COMPLIANT: The loop bound is passed to a + // const variadic reference argument + g5(k); + } + for (int i = j; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to // a non-const reference parameter f1(l); @@ -329,4 +405,24 @@ int main() { // a const but mutable pointer parameter f3(&l); } -} \ No newline at end of file + + for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to + // a non-const variadic reference argument + f4(&l); + } + + for (int i = 0; i < k; i += l) { // COMPLIANT: The loop step is passed to a + // const variadic reference argument + f5(&l); + } + + for (int i = 0; i < k; i += l) { // NON_COMPLIANT: The loop step is passed to + // a non-const variadic reference argument + g4(l); + } + + for (int i = 0; i < k; i += l) { // COMPLIANT: The loop step is passed to a + // const variadic reference argument + g5(l); + } +} From 6ffd2296d662c4e27d885589e21d51892cec55b5 Mon Sep 17 00:00:00 2001 From: Jeongsoo Lee Date: Wed, 5 Nov 2025 15:23:00 -0500 Subject: [PATCH 628/628] Expose mutating / assignment rhs expressions --- .../LegacyForStatementsShouldBeSimple.ql | 109 +++++++++-------- ...LegacyForStatementsShouldBeSimple.expected | 110 ++++++++++-------- 2 files changed, 122 insertions(+), 97 deletions(-) diff --git a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql index 8d44c50bdf..9525d1f5f8 100644 --- a/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql +++ b/cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql @@ -83,9 +83,9 @@ Expr getLoopStepOfForStmt(ForStmt forLoop) { * limitations. */ predicate loopVariableAssignedToNonConstPointerOrReferenceType( - ForStmt forLoop, VariableAccess loopVariableAccessInCondition + ForStmt forLoop, VariableAccess loopVariableAccessInCondition, Expr assignmentRhs ) { - exists(Expr assignmentRhs, Type targetType, DerivedType strippedType | + exists(Type targetType, DerivedType strippedType | isAssignment(assignmentRhs, targetType, _) and strippedType = targetType.stripTopLevelSpecifiers() and not strippedType.getBaseType().isConst() and @@ -124,11 +124,12 @@ predicate loopVariableAssignedToNonConstPointerOrReferenceType( * Also, this predicate requires that the call is the body of the given for-loop. */ predicate loopVariablePassedAsArgumentToNonConstReferenceParameter( - ForStmt forLoop, VariableAccess loopVariableAccessInCondition + ForStmt forLoop, VariableAccess loopVariableAccessInCondition, Expr loopVariableArgument ) { exists(Type targetType, ReferenceType strippedReferenceType | exists(Call call, int i | - call.getArgument(i) = loopVariableAccessInCondition.getTarget().getAnAccess() and + loopVariableArgument = call.getArgument(i) and + loopVariableArgument = loopVariableAccessInCondition.getTarget().getAnAccess() and call.getEnclosingStmt().getParent*() = forLoop.getStmt() and strippedReferenceType = targetType.stripTopLevelSpecifiers() and not strippedReferenceType.getBaseType().isConst() @@ -168,11 +169,10 @@ private newtype TAlertType = not condition instanceof LegacyForLoopCondition } or /* 3-1. The loop counter is mutated somewhere other than its update expression. */ - TLoopCounterMutatedInLoopBody(ForStmt forLoop, Variable loopCounterVariable) { + TLoopCounterMutatedInLoopBody(ForStmt forLoop, Variable loopCounterVariable, Expr mutatingExpr) { loopCounterVariable = getDeclaredVariableInForLoop(forLoop) and - exists(Expr mutatingExpr | not mutatingExpr = forLoop.getUpdate().getAChild*() | - variableModifiedInExpression(mutatingExpr, loopCounterVariable.getAnAccess()) - ) + not mutatingExpr = forLoop.getUpdate().getAChild*() and + variableModifiedInExpression(mutatingExpr, loopCounterVariable.getAnAccess()) } or /* 3-2. The loop counter is not updated using either of `++`, `--`, `+=`, or `-=`. */ TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr( @@ -255,27 +255,35 @@ private newtype TAlertType = * 6-1. The loop counter is taken as a mutable reference or its address to a mutable pointer. */ - TLoopCounterIsTakenNonConstAddress(ForStmt forLoop, VariableAccess loopVariableAccessInCondition) { + TLoopCounterIsTakenNonConstAddress( + ForStmt forLoop, VariableAccess loopVariableAccessInCondition, + Expr loopVariableAccessInAssignment + ) { loopVariableAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter() and ( - loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, loopVariableAccessInCondition) + loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, loopVariableAccessInCondition, + loopVariableAccessInAssignment) or loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, - loopVariableAccessInCondition) + loopVariableAccessInCondition, loopVariableAccessInAssignment) ) } or /* * 6-2. The loop bound is taken as a mutable reference or its address to a mutable pointer. */ - TLoopBoundIsTakenNonConstAddress(ForStmt forLoop, Expr loopBoundExpr) { + TLoopBoundIsTakenNonConstAddress( + ForStmt forLoop, Expr loopBoundExpr, Expr loopVariableAccessInAssignment + ) { loopBoundExpr = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound() and exists(VariableAccess variableAccess | variableAccess = loopBoundExpr.getAChild*() and ( - loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, variableAccess) + loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, variableAccess, + loopVariableAccessInAssignment) or - loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, variableAccess) + loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, variableAccess, + loopVariableAccessInAssignment) ) ) } or @@ -283,13 +291,16 @@ private newtype TAlertType = * 6-3. The loop step is taken as a mutable reference or its address to a mutable pointer. */ - TLoopStepIsTakenNonConstAddress(ForStmt forLoop, Expr loopVariableAccessInCondition) { + TLoopStepIsTakenNonConstAddress( + ForStmt forLoop, Expr loopVariableAccessInCondition, Expr loopVariableAccessInAssignment + ) { loopVariableAccessInCondition = getLoopStepOfForStmt(forLoop) and ( - loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, loopVariableAccessInCondition) + loopVariableAssignedToNonConstPointerOrReferenceType(forLoop, loopVariableAccessInCondition, + loopVariableAccessInAssignment) or loopVariablePassedAsArgumentToNonConstReferenceParameter(forLoop, - loopVariableAccessInCondition) + loopVariableAccessInCondition, loopVariableAccessInAssignment) ) } @@ -302,16 +313,16 @@ class AlertType extends TAlertType { Element asElement() { this = TNonIntegerTypeCounterVariable(result, _) or this = TNoRelationalOperatorInLoopCondition(result, _) or - this = TLoopCounterMutatedInLoopBody(result, _) or + this = TLoopCounterMutatedInLoopBody(result, _, _) or this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(result, _, _) or this = TLoopCounterSmallerThanLoopBound(result, _) or this = TLoopBoundIsMutatedVariableAccess(result, _, _) or this = TLoopBoundIsNonConstExpr(result, _) or this = TLoopStepIsMutatedVariableAccess(result, _, _) or this = TLoopStepIsNonConstExpr(result, _) or - this = TLoopCounterIsTakenNonConstAddress(result, _) or - this = TLoopBoundIsTakenNonConstAddress(result, _) or - this = TLoopStepIsTakenNonConstAddress(result, _) + this = TLoopCounterIsTakenNonConstAddress(result, _, _) or + this = TLoopBoundIsTakenNonConstAddress(result, _, _) or + this = TLoopStepIsTakenNonConstAddress(result, _, _) } /** @@ -322,7 +333,7 @@ class AlertType extends TAlertType { or this = TNoRelationalOperatorInLoopCondition(_, result) or - this = TLoopCounterMutatedInLoopBody(_, result) + this = TLoopCounterMutatedInLoopBody(_, result, _) or this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, result, _) or @@ -339,11 +350,11 @@ class AlertType extends TAlertType { or this = TLoopStepIsMutatedVariableAccess(_, result, _) or - this = TLoopCounterIsTakenNonConstAddress(_, result) + this = TLoopCounterIsTakenNonConstAddress(_, result, _) or - this = TLoopBoundIsTakenNonConstAddress(_, result) + this = TLoopBoundIsTakenNonConstAddress(_, result, _) or - this = TLoopStepIsTakenNonConstAddress(_, result) + this = TLoopStepIsTakenNonConstAddress(_, result, _) } /** @@ -356,7 +367,7 @@ class AlertType extends TAlertType { this = TNoRelationalOperatorInLoopCondition(_, _) and result = "loop condition" or - this = TLoopCounterMutatedInLoopBody(_, _) and + this = TLoopCounterMutatedInLoopBody(_, _, _) and result = "counter variable" or this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, _, _) and @@ -377,13 +388,13 @@ class AlertType extends TAlertType { this = TLoopStepIsNonConstExpr(_, _) and result = "loop step" or - this = TLoopCounterIsTakenNonConstAddress(_, _) and + this = TLoopCounterIsTakenNonConstAddress(_, _, _) and result = "loop counter" or - this = TLoopBoundIsTakenNonConstAddress(_, _) and + this = TLoopBoundIsTakenNonConstAddress(_, _, _) and result = "loop bound" or - this = TLoopStepIsTakenNonConstAddress(_, _) and + this = TLoopStepIsTakenNonConstAddress(_, _, _) and result = "loop step" } @@ -398,8 +409,8 @@ class AlertType extends TAlertType { result = "The $@ does not determine termination based only on a comparison against the value of the counter variable." or - this = TLoopCounterMutatedInLoopBody(_, _) and - result = "The $@ may be mutated in a location other than its update expression." + this = TLoopCounterMutatedInLoopBody(_, _, _) and + result = "The $@ may be mutated in $@ other than its update expression." or this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, _, _) and result = "The $@ is not updated with an $@ other than addition or subtraction." @@ -419,14 +430,14 @@ class AlertType extends TAlertType { this = TLoopStepIsMutatedVariableAccess(_, _, _) and result = "The $@ is a non-const expression, or a variable that may be $@ in the loop." or - this = TLoopCounterIsTakenNonConstAddress(_, _) and - result = "The $@ is taken as a mutable reference or its address to a mutable pointer." + this = TLoopCounterIsTakenNonConstAddress(_, _, _) and + result = "The $@ is $@." or - this = TLoopBoundIsTakenNonConstAddress(_, _) and - result = "The $@ is taken as a mutable reference or its address to a mutable pointer." + this = TLoopBoundIsTakenNonConstAddress(_, _, _) and + result = "The $@ is $@." or - this = TLoopStepIsTakenNonConstAddress(_, _) and - result = "The $@ is taken as a mutable reference or its address to a mutable pointer." + this = TLoopStepIsTakenNonConstAddress(_, _, _) and + result = "The $@ is $@." } Locatable getLinkTarget2() { @@ -434,7 +445,7 @@ class AlertType extends TAlertType { or this = TNoRelationalOperatorInLoopCondition(_, result) // Throwaway or - this = TLoopCounterMutatedInLoopBody(_, result) // Throwaway + this = TLoopCounterMutatedInLoopBody(_, _, result) or this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, _, result) or @@ -451,11 +462,11 @@ class AlertType extends TAlertType { or this = TLoopStepIsMutatedVariableAccess(_, _, result) or - this = TLoopCounterIsTakenNonConstAddress(_, result) // Throwaway + this = TLoopCounterIsTakenNonConstAddress(_, _, result) or - this = TLoopBoundIsTakenNonConstAddress(_, result) // Throwaway + this = TLoopBoundIsTakenNonConstAddress(_, _, result) or - this = TLoopStepIsTakenNonConstAddress(_, result) // Throwaway + this = TLoopStepIsTakenNonConstAddress(_, _, result) } string getLinkText2() { @@ -465,8 +476,8 @@ class AlertType extends TAlertType { this = TNoRelationalOperatorInLoopCondition(_, _) and result = "N/A" // Throwaway or - this = TLoopCounterMutatedInLoopBody(_, _) and - result = "N/A" // Throwaway + this = TLoopCounterMutatedInLoopBody(_, _, _) and + result = "a location" or this = TLoopCounterUpdatedNotByCrementOrAddSubAssignmentExpr(_, _, _) and result = "expression" @@ -486,14 +497,14 @@ class AlertType extends TAlertType { this = TLoopStepIsMutatedVariableAccess(_, _, _) and result = "mutated" or - this = TLoopCounterIsTakenNonConstAddress(_, _) and - result = "N/A" // Throwaway + this = TLoopCounterIsTakenNonConstAddress(_, _, _) and + result = "taken as a mutable reference or its address to a mutable pointer" or - this = TLoopBoundIsTakenNonConstAddress(_, _) and - result = "N/A" // Throwaway + this = TLoopBoundIsTakenNonConstAddress(_, _, _) and + result = "taken as a mutable reference or its address to a mutable pointer" or - this = TLoopStepIsTakenNonConstAddress(_, _) and - result = "N/A" // Throwaway + this = TLoopStepIsTakenNonConstAddress(_, _, _) and + result = "taken as a mutable reference or its address to a mutable pointer" } string toString() { result = this.asElement().toString() } diff --git a/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected index 3469fcab47..16a43b6d49 100644 --- a/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected +++ b/cpp/misra/test/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.expected @@ -1,48 +1,62 @@ -| test.cpp:26:3:28:3 | for(...;...;...) ... | The $@ is not of an integer type. | test.cpp:26:14:26:14 | i | counter variable | test.cpp:26:14:26:14 | i | N/A | -| test.cpp:35:3:37:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:35:19:35:25 | ... == ... | loop condition | test.cpp:35:19:35:25 | ... == ... | N/A | -| test.cpp:39:3:41:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:39:19:39:24 | ... < ... | loop condition | test.cpp:39:19:39:24 | ... < ... | N/A | -| test.cpp:55:3:58:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:55:19:55:28 | ... < ... | loop condition | test.cpp:55:19:55:28 | ... < ... | N/A | -| test.cpp:60:3:63:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:60:19:60:27 | ... < ... | loop condition | test.cpp:60:19:60:27 | ... < ... | N/A | -| test.cpp:65:3:68:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:65:19:65:27 | ... < ... | loop condition | test.cpp:65:19:65:27 | ... < ... | N/A | -| test.cpp:65:3:68:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:65:12:65:12 | i | counter variable | test.cpp:65:12:65:12 | i | N/A | -| test.cpp:107:3:109:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:107:12:107:12 | i | counter variable | test.cpp:108:8:108:13 | ... *= ... | expression | -| test.cpp:121:3:124:3 | for(...;...;...) ... | The $@ has a smaller type than that of the $@. | test.cpp:121:21:121:21 | i | counter variable | test.cpp:121:25:121:53 | call to max | loop bound | -| test.cpp:146:3:149:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:147:13:147:13 | j | loop step | test.cpp:148:5:148:5 | j | mutated | -| test.cpp:151:3:153:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:152:13:152:13 | j | loop step | test.cpp:152:16:152:16 | j | mutated | -| test.cpp:151:3:153:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:151:12:151:12 | i | counter variable | test.cpp:152:8:152:18 | ... , ... | expression | -| test.cpp:163:3:166:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:163:23:163:23 | j | loop bound | test.cpp:165:5:165:5 | j | mutated | -| test.cpp:168:3:170:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:168:23:168:25 | ... ++ | loop bound | test.cpp:168:23:168:25 | ... ++ | non-const expression | -| test.cpp:168:3:170:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:168:23:168:23 | j | loop bound | test.cpp:168:23:168:23 | j | mutated | -| test.cpp:172:3:174:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:172:19:172:27 | ... < ... | loop condition | test.cpp:172:19:172:27 | ... < ... | N/A | -| test.cpp:172:3:174:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:172:12:172:12 | i | counter variable | test.cpp:172:12:172:12 | i | N/A | -| test.cpp:178:3:181:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:178:23:178:23 | k | loop bound | test.cpp:180:15:180:15 | k | mutated | -| test.cpp:183:3:186:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:184:13:184:13 | l | loop step | test.cpp:185:15:185:15 | l | mutated | -| test.cpp:188:3:190:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:188:23:188:24 | call to h1 | loop bound | test.cpp:188:23:188:24 | call to h1 | non-const expression | -| test.cpp:196:3:198:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:197:13:197:14 | call to h1 | loop step | test.cpp:197:13:197:14 | call to h1 | non-const expression | -| test.cpp:211:3:214:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:211:19:211:19 | i | loop counter | test.cpp:211:19:211:19 | i | N/A | -| test.cpp:216:3:219:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:216:19:216:19 | i | loop counter | test.cpp:216:19:216:19 | i | N/A | -| test.cpp:231:3:234:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:231:19:231:19 | i | loop counter | test.cpp:231:19:231:19 | i | N/A | -| test.cpp:236:3:239:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:236:23:236:23 | k | loop bound | test.cpp:236:23:236:23 | k | N/A | -| test.cpp:241:3:244:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:241:23:241:23 | k | loop bound | test.cpp:241:23:241:23 | k | N/A | -| test.cpp:256:3:259:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:256:23:256:23 | k | loop bound | test.cpp:256:23:256:23 | k | N/A | -| test.cpp:261:3:264:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:261:31:261:31 | l | loop step | test.cpp:261:31:261:31 | l | N/A | -| test.cpp:266:3:269:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:266:31:266:31 | l | loop step | test.cpp:266:31:266:31 | l | N/A | -| test.cpp:281:3:284:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:281:31:281:31 | l | loop step | test.cpp:281:31:281:31 | l | N/A | -| test.cpp:286:3:289:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:286:19:286:19 | i | loop counter | test.cpp:286:19:286:19 | i | N/A | -| test.cpp:286:3:289:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:286:12:286:12 | i | counter variable | test.cpp:286:12:286:12 | i | N/A | -| test.cpp:291:3:294:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:291:19:291:19 | i | loop counter | test.cpp:291:19:291:19 | i | N/A | -| test.cpp:291:3:294:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:291:12:291:12 | i | counter variable | test.cpp:291:12:291:12 | i | N/A | -| test.cpp:306:3:309:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:306:19:306:19 | i | loop counter | test.cpp:306:19:306:19 | i | N/A | -| test.cpp:306:3:309:3 | for(...;...;...) ... | The $@ may be mutated in a location other than its update expression. | test.cpp:306:12:306:12 | i | counter variable | test.cpp:306:12:306:12 | i | N/A | -| test.cpp:311:3:314:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:311:23:311:23 | k | loop bound | test.cpp:313:8:313:8 | k | mutated | -| test.cpp:311:3:314:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:311:23:311:23 | k | loop bound | test.cpp:311:23:311:23 | k | N/A | -| test.cpp:316:3:319:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:316:23:316:23 | k | loop bound | test.cpp:318:9:318:9 | k | mutated | -| test.cpp:316:3:319:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:316:23:316:23 | k | loop bound | test.cpp:316:23:316:23 | k | N/A | -| test.cpp:332:3:335:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:332:23:332:23 | k | loop bound | test.cpp:334:9:334:9 | k | mutated | -| test.cpp:332:3:335:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:332:23:332:23 | k | loop bound | test.cpp:332:23:332:23 | k | N/A | -| test.cpp:337:3:340:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:337:31:337:31 | l | loop step | test.cpp:339:8:339:8 | l | mutated | -| test.cpp:337:3:340:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:337:31:337:31 | l | loop step | test.cpp:337:31:337:31 | l | N/A | -| test.cpp:342:3:345:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:342:31:342:31 | l | loop step | test.cpp:344:9:344:9 | l | mutated | -| test.cpp:342:3:345:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:342:31:342:31 | l | loop step | test.cpp:342:31:342:31 | l | N/A | -| test.cpp:357:3:360:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:357:31:357:31 | l | loop step | test.cpp:359:9:359:9 | l | mutated | -| test.cpp:357:3:360:3 | for(...;...;...) ... | The $@ is taken as a mutable reference or its address to a mutable pointer. | test.cpp:357:31:357:31 | l | loop step | test.cpp:357:31:357:31 | l | N/A | +| test.cpp:33:3:35:3 | for(...;...;...) ... | The $@ is not of an integer type. | test.cpp:33:14:33:14 | i | counter variable | test.cpp:33:14:33:14 | i | N/A | +| test.cpp:42:3:44:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:42:19:42:25 | ... == ... | loop condition | test.cpp:42:19:42:25 | ... == ... | N/A | +| test.cpp:46:3:48:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:46:19:46:24 | ... < ... | loop condition | test.cpp:46:19:46:24 | ... < ... | N/A | +| test.cpp:62:3:65:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:62:19:62:28 | ... < ... | loop condition | test.cpp:62:19:62:28 | ... < ... | N/A | +| test.cpp:67:3:70:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:67:19:67:27 | ... < ... | loop condition | test.cpp:67:19:67:27 | ... < ... | N/A | +| test.cpp:72:3:75:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:72:19:72:27 | ... < ... | loop condition | test.cpp:72:19:72:27 | ... < ... | N/A | +| test.cpp:72:3:75:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:72:12:72:12 | i | counter variable | test.cpp:72:19:72:21 | ... ++ | a location | +| test.cpp:72:3:75:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:72:12:72:12 | i | counter variable | test.cpp:72:19:72:27 | ... < ... | a location | +| test.cpp:114:3:116:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:114:12:114:12 | i | counter variable | test.cpp:115:8:115:13 | ... *= ... | expression | +| test.cpp:128:3:131:3 | for(...;...;...) ... | The $@ has a smaller type than that of the $@. | test.cpp:128:21:128:21 | i | counter variable | test.cpp:128:25:128:53 | call to max | loop bound | +| test.cpp:153:3:156:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:154:13:154:13 | j | loop step | test.cpp:155:5:155:5 | j | mutated | +| test.cpp:158:3:160:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:159:13:159:13 | j | loop step | test.cpp:159:16:159:16 | j | mutated | +| test.cpp:158:3:160:3 | for(...;...;...) ... | The $@ is not updated with an $@ other than addition or subtraction. | test.cpp:158:12:158:12 | i | counter variable | test.cpp:159:8:159:18 | ... , ... | expression | +| test.cpp:170:3:173:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:170:23:170:23 | j | loop bound | test.cpp:172:5:172:5 | j | mutated | +| test.cpp:175:3:177:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:175:23:175:25 | ... ++ | loop bound | test.cpp:175:23:175:25 | ... ++ | non-const expression | +| test.cpp:175:3:177:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:175:23:175:23 | j | loop bound | test.cpp:175:23:175:23 | j | mutated | +| test.cpp:179:3:181:3 | for(...;...;...) ... | The $@ does not determine termination based only on a comparison against the value of the counter variable. | test.cpp:179:19:179:27 | ... < ... | loop condition | test.cpp:179:19:179:27 | ... < ... | N/A | +| test.cpp:179:3:181:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:179:12:179:12 | i | counter variable | test.cpp:179:19:179:21 | ... ++ | a location | +| test.cpp:179:3:181:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:179:12:179:12 | i | counter variable | test.cpp:179:19:179:27 | ... < ... | a location | +| test.cpp:185:3:188:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:185:23:185:23 | k | loop bound | test.cpp:187:15:187:15 | k | mutated | +| test.cpp:190:3:193:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:191:13:191:13 | l | loop step | test.cpp:192:15:192:15 | l | mutated | +| test.cpp:195:3:197:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:195:23:195:24 | call to h1 | loop bound | test.cpp:195:23:195:24 | call to h1 | non-const expression | +| test.cpp:203:3:205:3 | for(...;...;...) ... | The $@ is a $@. | test.cpp:204:13:204:14 | call to h1 | loop step | test.cpp:204:13:204:14 | call to h1 | non-const expression | +| test.cpp:218:3:221:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:218:19:218:19 | i | loop counter | test.cpp:220:14:220:14 | i | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:223:3:226:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:223:19:223:19 | i | loop counter | test.cpp:225:14:225:15 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:238:3:241:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:238:19:238:19 | i | loop counter | test.cpp:240:20:240:21 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:243:3:246:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:243:23:243:23 | k | loop bound | test.cpp:245:14:245:14 | k | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:248:3:251:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:248:23:248:23 | k | loop bound | test.cpp:250:14:250:15 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:263:3:266:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:263:23:263:23 | k | loop bound | test.cpp:265:20:265:21 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:268:3:271:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:268:31:268:31 | l | loop step | test.cpp:270:14:270:14 | l | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:273:3:276:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:273:31:273:31 | l | loop step | test.cpp:275:14:275:15 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:288:3:291:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:288:31:288:31 | l | loop step | test.cpp:290:20:290:21 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:293:3:296:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:293:19:293:19 | i | loop counter | test.cpp:295:8:295:8 | i | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:293:3:296:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:293:12:293:12 | i | counter variable | test.cpp:295:5:295:6 | call to f1 | a location | +| test.cpp:298:3:301:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:298:19:298:19 | i | loop counter | test.cpp:300:8:300:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:298:3:301:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:298:12:298:12 | i | counter variable | test.cpp:300:5:300:6 | call to g1 | a location | +| test.cpp:313:3:316:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:313:19:313:19 | i | loop counter | test.cpp:315:8:315:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:313:3:316:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:313:12:313:12 | i | counter variable | test.cpp:315:5:315:6 | call to f3 | a location | +| test.cpp:318:3:321:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:318:19:318:19 | i | loop counter | test.cpp:320:8:320:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:318:3:321:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:318:12:318:12 | i | counter variable | test.cpp:320:5:320:6 | call to f4 | a location | +| test.cpp:328:3:331:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:328:19:328:19 | i | loop counter | test.cpp:330:8:330:8 | i | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:328:3:331:3 | for(...;...;...) ... | The $@ may be mutated in $@ other than its update expression. | test.cpp:328:12:328:12 | i | counter variable | test.cpp:330:5:330:6 | call to g4 | a location | +| test.cpp:338:3:341:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:338:23:338:23 | k | loop bound | test.cpp:340:8:340:8 | k | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:338:3:341:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:338:23:338:23 | k | loop bound | test.cpp:340:8:340:8 | k | mutated | +| test.cpp:343:3:346:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:343:23:343:23 | k | loop bound | test.cpp:345:8:345:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:343:3:346:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:343:23:343:23 | k | loop bound | test.cpp:345:9:345:9 | k | mutated | +| test.cpp:359:3:362:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:359:23:359:23 | k | loop bound | test.cpp:361:8:361:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:359:3:362:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:359:23:359:23 | k | loop bound | test.cpp:361:9:361:9 | k | mutated | +| test.cpp:364:3:367:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:364:23:364:23 | k | loop bound | test.cpp:366:8:366:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:364:3:367:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:364:23:364:23 | k | loop bound | test.cpp:366:9:366:9 | k | mutated | +| test.cpp:374:3:377:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:374:23:374:23 | k | loop bound | test.cpp:376:8:376:8 | k | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:374:3:377:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:374:23:374:23 | k | loop bound | test.cpp:376:8:376:8 | k | mutated | +| test.cpp:384:3:387:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:384:31:384:31 | l | loop step | test.cpp:386:8:386:8 | l | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:384:3:387:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:384:31:384:31 | l | loop step | test.cpp:386:8:386:8 | l | mutated | +| test.cpp:389:3:392:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:389:31:389:31 | l | loop step | test.cpp:391:8:391:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:389:3:392:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:389:31:389:31 | l | loop step | test.cpp:391:9:391:9 | l | mutated | +| test.cpp:404:3:407:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:404:31:404:31 | l | loop step | test.cpp:406:8:406:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:404:3:407:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:404:31:404:31 | l | loop step | test.cpp:406:9:406:9 | l | mutated | +| test.cpp:409:3:412:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:409:31:409:31 | l | loop step | test.cpp:411:8:411:9 | & ... | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:409:3:412:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:409:31:409:31 | l | loop step | test.cpp:411:9:411:9 | l | mutated | +| test.cpp:419:3:422:3 | for(...;...;...) ... | The $@ is $@. | test.cpp:419:31:419:31 | l | loop step | test.cpp:421:8:421:8 | l | taken as a mutable reference or its address to a mutable pointer | +| test.cpp:419:3:422:3 | for(...;...;...) ... | The $@ is a non-const expression, or a variable that may be $@ in the loop. | test.cpp:419:31:419:31 | l | loop step | test.cpp:421:8:421:8 | l | mutated |