From 16af63403063a887e22c9597c48f44ba5defb101 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Mon, 12 Sep 2022 17:16:24 -0400 Subject: [PATCH 1/9] Declarations2: add pkg to vscode tasks file --- .vscode/tasks.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 170479d5ca..83420bb65b 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -202,6 +202,7 @@ "DeadCode", "Declarations", "Declarations1", + "Declarations2", "Exceptions1", "Exceptions2", "Expressions", From 36a4e3f3518bcfe0112b4db37617a6a97705ebbb Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Tue, 13 Sep 2022 12:17:17 -0400 Subject: [PATCH 2/9] Declarations2: add rule DCL41-C --- .../DCL41-C/VariablesInsideSwitchStatement.md | 109 ++++++++++++++++++ .../DCL41-C/VariablesInsideSwitchStatement.ql | 32 +++++ .../VariablesInsideSwitchStatement.expected | 1 + .../VariablesInsideSwitchStatement.qlref | 1 + c/cert/test/rules/DCL41-C/test.c | 32 +++++ .../cpp/exclusions/c/Declarations2.qll | 25 ++++ .../cpp/exclusions/c/RuleMetadata.qll | 3 + rule_packages/c/Declarations2.json | 25 ++++ rules.csv | 2 +- 9 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.md create mode 100644 c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.ql create mode 100644 c/cert/test/rules/DCL41-C/VariablesInsideSwitchStatement.expected create mode 100644 c/cert/test/rules/DCL41-C/VariablesInsideSwitchStatement.qlref create mode 100644 c/cert/test/rules/DCL41-C/test.c create mode 100644 cpp/common/src/codingstandards/cpp/exclusions/c/Declarations2.qll create mode 100644 rule_packages/c/Declarations2.json diff --git a/c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.md b/c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.md new file mode 100644 index 0000000000..20d033f6b3 --- /dev/null +++ b/c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.md @@ -0,0 +1,109 @@ +# DCL41-C: Do not declare variables inside a switch statement before the first case label + +This query implements the CERT-C rule DCL41-C: + +> Do not declare variables inside a switch statement before the first case label + + +## Description + +According to the C Standard, 6.8.4.2, paragraph 4 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], + +> A switch statement causes control to jump to, into, or past the statement that is the switch body, depending on the value of a controlling expression, and on the presence of a default label and the values of any case labels on or in the switch body. + + +If a programmer declares variables, initializes them before the first case statement, and then tries to use them inside any of the case statements, those variables will have scope inside the `switch` block but will not be initialized and will consequently contain indeterminate values. Reading such values also violates [EXP33-C. Do not read uninitialized memory](https://wiki.sei.cmu.edu/confluence/display/c/EXP33-C.+Do+not+read+uninitialized+memory). + +## Noncompliant Code Example + +This noncompliant code example declares variables and contains executable statements before the first case label within the `switch` statement: + +```cpp +#include + +extern void f(int i); + +void func(int expr) { + switch (expr) { + int i = 4; + f(i); + case 0: + i = 17; + /* Falls through into default code */ + default: + printf("%d\n", i); + } +} + +``` +**Implementation Details** + +When the preceding example is executed on GCC 4.8.1, the variable `i` is instantiated with automatic storage duration within the block, but it is not initialized. Consequently, if the controlling expression `expr` has a nonzero value, the call to `printf()` will access an indeterminate value of `i`. Similarly, the call to `f()` is not executed. + +
Value of expr Output
0 17
Nonzero Indeterminate
+ + +## Compliant Solution + +In this compliant solution, the statements before the first case label occur before the `switch` statement: + +```cpp +#include + +extern void f(int i); + +int func(int expr) { + /* + * Move the code outside the switch block; now the statements + * will get executed. + */ + int i = 4; + f(i); + + switch (expr) { + case 0: + i = 17; + /* Falls through into default code */ + default: + printf("%d\n", i); + } + return 0; +} + +``` + +## Risk Assessment + +Using test conditions or initializing variables before the first case statement in a `switch` block can result in [unexpected behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior) and [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). + +
Rule Severity Likelihood Remediation Cost Priority Level
DCL41-C Medium Unlikely Medium P4 L3
+ + +## Automated Detection + +
Tool Version Checker Description
Astrée 22.04 switch-skipped-code Fully checked
Axivion Bauhaus Suite 7.2.0 CertC-DCL41 Fully implemented
Clang 3.9 -Wsometimes-uninitialized
CodeSonar 7.1p0 LANG.STRUCT.SW.BAD Malformed switch Statement
Coverity 2017.07 MISRA C 2004 Rule 15.0 MISRA C 2012 Rule 16.1 Implemented
Helix QAC 2022.2 C2008, C2882, C3234
Klocwork 2022.2 CERT.DCL.SWITCH.VAR_BEFORE_CASE
LDRA tool suite 9.7.1 385 S Fully implemented
Parasoft C/C++test 2022.1 CERT_C-DCL41-a A switch statement shall only contain switch labels and switch clauses, and no other code
PC-lint Plus 1.4 527 Assistance provided
Polyspace Bug Finder R2022a CERT C: Rule DCL41-C Checks for ill-formed switch statements (rule partially covered)
PRQA QA-C 9.7 3234 2008 2882 Partially implemented
PVS-Studio 7.20 V622
RuleChecker 22.04 switch-skipped-code Fully checked
TrustInSoft Analyzer 1.38 initialisation Exhaustively detects undefined behavior (see the compliant and the non-compliant example ).
+ + +## 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+DCL41-C). + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
Taxonomy Taxonomy item Relationship
MISRA C:2012 Rule 16.1 (required) Prior to 2018-01-12: CERT: Unspecified Relationship
+ + +## Bibliography + +
\[ ISO/IEC 9899:2011 \] 6.8.4.2, "The switch Statement"
+ + +## Implementation notes + +None + +## References + +* CERT-C: [DCL41-C: Do not declare variables inside a switch statement before the first case label](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.ql b/c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.ql new file mode 100644 index 0000000000..db42f7102c --- /dev/null +++ b/c/cert/src/rules/DCL41-C/VariablesInsideSwitchStatement.ql @@ -0,0 +1,32 @@ +/** + * @id c/cert/variables-inside-switch-statement + * @name DCL41-C: Do not declare variables inside a switch statement before the first case label + * @description Declaring a variable in a switch statement before the first case label can result in + * reading uninitialized memory which is undefined behaviour. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/dcl41-c + * correctness + * maintainability + * readability + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert + +from SwitchCase case, SwitchStmt stmt, VariableDeclarationEntry d +where + not isExcluded(d, Declarations2Package::variablesInsideSwitchStatementQuery()) and + case.getSwitchStmt() = stmt and + //first case + not exists(case.getPreviousSwitchCase()) and + exists(string filepath, int declarationLine, int caseLine, int stmtLine | + d.getLocation().hasLocationInfo(filepath, declarationLine, _, _, _) and + stmt.getLocation().hasLocationInfo(filepath, stmtLine, _, _, _) and + case.getLocation().hasLocationInfo(filepath, caseLine, _, _, _) and + declarationLine > stmtLine and + declarationLine < caseLine + ) +select d, "Declaration is located in switch $@.", stmt, "statement" diff --git a/c/cert/test/rules/DCL41-C/VariablesInsideSwitchStatement.expected b/c/cert/test/rules/DCL41-C/VariablesInsideSwitchStatement.expected new file mode 100644 index 0000000000..6515fa8bc1 --- /dev/null +++ b/c/cert/test/rules/DCL41-C/VariablesInsideSwitchStatement.expected @@ -0,0 +1 @@ +| test.c:5:9:5:9 | definition of i | Declaration is located in switch $@. | test.c:4:3:10:3 | switch (...) ... | statement | diff --git a/c/cert/test/rules/DCL41-C/VariablesInsideSwitchStatement.qlref b/c/cert/test/rules/DCL41-C/VariablesInsideSwitchStatement.qlref new file mode 100644 index 0000000000..cbb2d1f791 --- /dev/null +++ b/c/cert/test/rules/DCL41-C/VariablesInsideSwitchStatement.qlref @@ -0,0 +1 @@ +rules/DCL41-C/VariablesInsideSwitchStatement.ql \ No newline at end of file diff --git a/c/cert/test/rules/DCL41-C/test.c b/c/cert/test/rules/DCL41-C/test.c new file mode 100644 index 0000000000..2500c982f3 --- /dev/null +++ b/c/cert/test/rules/DCL41-C/test.c @@ -0,0 +1,32 @@ +#include + +void f(int expr) { + switch (expr) { + int i = 4; // NON_COMPLIANT + case 0: + i = 17; + default: + printf("%d\n", i); + } +} + +void f1(int expr) { + int i = 4; // COMPLIANT + switch (expr) { + case 0: + i = 17; + default: + printf("%d\n", i); + } +} + +void f2(int expr) { + switch (expr) { + case 0: + int i = 4; // COMPLIANT + case 1: + i = 6; // COMPLIANT + default: + printf("%d\n", i); + } +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations2.qll new file mode 100644 index 0000000000..869db31097 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations2.qll @@ -0,0 +1,25 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Declarations2Query = TVariablesInsideSwitchStatementQuery() + +predicate isDeclarations2QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `variablesInsideSwitchStatement` query + Declarations2Package::variablesInsideSwitchStatementQuery() and + queryId = + // `@id` for the `variablesInsideSwitchStatement` query + "c/cert/variables-inside-switch-statement" and + ruleId = "DCL41-C" +} + +module Declarations2Package { + Query variablesInsideSwitchStatementQuery() { + //autogenerate `Query` type + result = + // `Query` type for `variablesInsideSwitchStatement` query + TQueryC(TDeclarations2PackageQuery(TVariablesInsideSwitchStatementQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index c271b218dc..d00f1a65cf 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -8,6 +8,7 @@ import Concurrency2 import Concurrency3 import Contracts1 import Declarations1 +import Declarations2 import Expressions import IO1 import IO2 @@ -36,6 +37,7 @@ newtype TCQuery = TConcurrency3PackageQuery(Concurrency3Query q) or TContracts1PackageQuery(Contracts1Query q) or TDeclarations1PackageQuery(Declarations1Query q) or + TDeclarations2PackageQuery(Declarations2Query q) or TExpressionsPackageQuery(ExpressionsQuery q) or TIO1PackageQuery(IO1Query q) or TIO2PackageQuery(IO2Query q) or @@ -64,6 +66,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId) { isConcurrency3QueryMetadata(query, queryId, ruleId) or isContracts1QueryMetadata(query, queryId, ruleId) or isDeclarations1QueryMetadata(query, queryId, ruleId) or + isDeclarations2QueryMetadata(query, queryId, ruleId) or isExpressionsQueryMetadata(query, queryId, ruleId) or isIO1QueryMetadata(query, queryId, ruleId) or isIO2QueryMetadata(query, queryId, ruleId) or diff --git a/rule_packages/c/Declarations2.json b/rule_packages/c/Declarations2.json new file mode 100644 index 0000000000..d7ed583f7c --- /dev/null +++ b/rule_packages/c/Declarations2.json @@ -0,0 +1,25 @@ +{ + "CERT-C": { + "DCL41-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Declaring a variable in a switch statement before the first case label can result in reading uninitialized memory which is undefined behaviour.", + "kind": "problem", + "name": "Do not declare variables inside a switch statement before the first case label", + "precision": "very-high", + "severity": "error", + "short_name": "VariablesInsideSwitchStatement", + "tags": [ + "correctness", + "maintainability", + "readability" + ] + } + ], + "title": "Do not declare variables inside a switch statement before the first case label" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index 02191e5626..fe3a9aca3d 100755 --- a/rules.csv +++ b/rules.csv @@ -505,7 +505,7 @@ c,CERT-C,DCL37-C,Yes,Rule,,,Do not declare or define a reserved identifier,,Decl c,CERT-C,DCL38-C,Yes,Rule,,,Use the correct syntax when declaring a flexible array member,,Declarations,Easy, c,CERT-C,DCL39-C,Yes,Rule,,,Avoid information leakage when passing a structure across a trust boundary,,Declarations,Hard, c,CERT-C,DCL40-C,Yes,Rule,,,Do not create incompatible declarations of the same function or object,,Declarations,Hard, -c,CERT-C,DCL41-C,Yes,Rule,,,Do not declare variables inside a switch statement before the first case label,,Declarations,Medium, +c,CERT-C,DCL41-C,Yes,Rule,,,Do not declare variables inside a switch statement before the first case label,,Declarations2,Medium, c,CERT-C,ENV30-C,Yes,Rule,,,Do not modify the object referenced by the return value of certain functions,RULE-21-19,Contracts1,Medium, c,CERT-C,ENV31-C,Yes,Rule,,,Do not rely on an environment pointer following an operation that may invalidate it,RULE-21-20,Contracts1,Hard, c,CERT-C,ENV32-C,Yes,Rule,,,All exit handlers must return normally,,Contracts,Medium, From 59d9565acab52d512a1f9a3d74c660b1e50109df Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 14 Sep 2022 15:05:47 -0400 Subject: [PATCH 3/9] Declarations2: add rule DCL38-C and omit RULE-17-6 from csv --- .../DCL38-C/DeclaringAFlexibleArrayMember.md | 130 ++++++++++++++++++ .../DCL38-C/DeclaringAFlexibleArrayMember.ql | 43 ++++++ .../DeclaringAFlexibleArrayMember.expected | 1 + .../DeclaringAFlexibleArrayMember.qlref | 1 + c/cert/test/rules/DCL38-C/test.c | 20 +++ .../cpp/exclusions/c/Declarations2.qll | 19 ++- rule_packages/c/Declarations2.json | 21 +++ rules.csv | 4 +- 8 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.md create mode 100644 c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.ql create mode 100644 c/cert/test/rules/DCL38-C/DeclaringAFlexibleArrayMember.expected create mode 100644 c/cert/test/rules/DCL38-C/DeclaringAFlexibleArrayMember.qlref create mode 100644 c/cert/test/rules/DCL38-C/test.c diff --git a/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.md b/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.md new file mode 100644 index 0000000000..9bd57a0686 --- /dev/null +++ b/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.md @@ -0,0 +1,130 @@ +# DCL38-C: Use the correct syntax when declaring a flexible array member + +This query implements the CERT-C rule DCL38-C: + +> Use the correct syntax when declaring a flexible array member + + + +## Description + +Flexible array members are a special type of array in which the last element of a structure with more than one named member has an incomplete array type; that is, the size of the array is not specified explicitly within the structure. This "struct hack" was widely used in practice and supported by a variety of compilers. Consequently, a variety of different syntaxes have been used for declaring flexible array members. For conforming C implementations, use the syntax guaranteed to be valid by the C Standard. + +Flexible array members are defined in the C Standard, 6.7.2.1, paragraph 18 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], as follows: + +> As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a *flexible array member*. In most situations, the flexible array member is ignored. In particular, the size of the structure is as if the flexible array member were omitted except that it may have more trailing padding than the omission would imply. However, when a `**.**`(or `**->**`) operator has a left operand that is (a pointer to) a structure with a flexible array member and the right operand names that member, it behaves as if that member were replaced with the longest array (with the same element type) that would not make the structure larger than the object being accessed; the offset of the array shall remain that of the flexible array member, even if this would differ from that of the replacement array. If this array would have no elements, it behaves as if it had one element but the behavior is undefined if any attempt is made to access that element or to generate a pointer one past it. + + +Structures with a flexible array member can be used to produce code with defined behavior. However, some restrictions apply: + +1. The incomplete array type *must* be the last element within the structure. +1. There cannot be an array of structures that contain a flexible array member. +1. Structures that contain a flexible array member cannot be used as a member of another structure. +1. The structure must contain at least one named member in addition to the flexible array member. + +## Noncompliant Code Example + +Before the introduction of flexible array members in the C Standard, structures with a one-element array as the final member were used to achieve similar functionality. This noncompliant code example illustrates how `struct flexArrayStruct` is declared in this case. + +This noncompliant code example attempts to allocate a flexible array-like member with a one-element array as the final member. When the structure is instantiated, the size computed for `malloc()` is modified to account for the actual size of the dynamic array. + +```cpp +#include + +struct flexArrayStruct { + int num; + int data[1]; +}; + +void func(size_t array_size) { + /* Space is allocated for the struct */ + struct flexArrayStruct *structP + = (struct flexArrayStruct *) + malloc(sizeof(struct flexArrayStruct) + + sizeof(int) * (array_size - 1)); + if (structP == NULL) { + /* Handle malloc failure */ + } + + structP->num = array_size; + + /* + * Access data[] as if it had been allocated + * as data[array_size]. + */ + for (size_t i = 0; i < array_size; ++i) { + structP->data[i] = 1; + } +} +``` +This example has [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) when accessing any element other than the first element of the `data` array. (See the C Standard, 6.5.6.) Consequently, the compiler can generate code that does not return the expected value when accessing the second element of data. + +This approach may be the only alternative for compilers that do not yet implement the standard C syntax. + +## Compliant Solution + +This compliant solution uses a flexible array member to achieve a dynamically sized structure: + +```cpp +#include + +struct flexArrayStruct{ + int num; + int data[]; +}; + +void func(size_t array_size) { + /* Space is allocated for the struct */ + struct flexArrayStruct *structP + = (struct flexArrayStruct *) + malloc(sizeof(struct flexArrayStruct) + + sizeof(int) * array_size); + if (structP == NULL) { + /* Handle malloc failure */ + } + + structP->num = array_size; + + /* + * Access data[] as if it had been allocated + * as data[array_size]. + */ + for (size_t i = 0; i < array_size; ++i) { + structP->data[i] = 1; + } +} +``` +This compliant solution allows the structure to be treated as if its member `data[]` was declared to be `data[array_size]` in a manner that conforms to the C Standard. + +## Risk Assessment + +Failing to use the correct syntax when declaring a flexible array member can result in [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior), although the incorrect syntax will work on most implementations. + +
Rule Severity Likelihood Remediation Cost Priority Level
DCL38-C Low Unlikely Low P3 L3
+ + +## Automated Detection + +
Tool Version Checker Description
Astrée 22.04 array_out_of_bounds Supported Astrée reports all out-of-bounds array access.
Axivion Bauhaus Suite 7.2.0 CertC-DCL38 Detects if the final member of struct which is declared as an array of small bound, is used as a flexible array member.
Compass/ROSE Can detect some violations of this rule. In particular, it warns if the last element of a struct is an array with a small index (0 or 1)
Helix QAC 2022.2 C1037, C1039
Klocwork 2022.2 CERT.STRUCT.FLEXIBLE_ARRAY_MEMBER
LDRA tool suite 9.7.1 648 S Fully implemented
Parasoft C/C++test 2022.1 CERT_C-DCL38-a The final member of a structure should not be an array of size '0' or '1'
PC-lint Plus 1.4 9040 Fully supported
Polyspace Bug Finder R2022a CERT C: Rule DCL38-C Checks for incorrect syntax of flexible array member size (rule fully covered)
PRQA QA-C 9.7 1037 1039
TrustInSoft Analyzer 1.38 index_bound Exhaustively detects out-of-bounds array access (see the compliant and the non-compliant example ).
+ + +## 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+DCL38-C). + +## Related Guidelines + +This rule supplements [MEM33-C. Allocate and copy structures containing a flexible array member dynamically](https://wiki.sei.cmu.edu/confluence/display/c/MEM33-C.++Allocate+and+copy+structures+containing+a+flexible+array+member+dynamically) + +## Bibliography + +
\[ ISO/IEC 9899:2011 \] 6.5.6, "Additive Operators" 6.7.2.1, "Structure and Union Specifiers"
\[ McCluskey 2001 \] " Flexible Array Members and Designators in C9X "
+ + +## Implementation notes + +None + +## References + +* CERT-C: [DCL38-C: Use the correct syntax when declaring a flexible array member](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.ql b/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.ql new file mode 100644 index 0000000000..b5f7087ab0 --- /dev/null +++ b/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.ql @@ -0,0 +1,43 @@ +/** + * @id c/cert/declaring-a-flexible-array-member + * @name DCL38-C: Use the correct syntax when declaring a flexible array member + * @description Structures with flexible array members can be declared in ways that will lead to + * undefined behaviour. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/dcl38-c + * correctness + * maintainability + * readability + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert + +/** + * A member with the type array that is last in a struct + * includes any sized array (either specified or not) + */ +class FlexibleArrayMember extends MemberVariable { + Struct s; + + FlexibleArrayMember() { + this.getType() instanceof ArrayType and + this.getDeclaringType() = s and + not exists(int i, int j | + s.getAMember(i) = this and + exists(s.getAMember(j)) and + j > i + ) + } +} + +from VariableDeclarationEntry m, ArrayType a +where + not isExcluded(m, Declarations2Package::declaringAFlexibleArrayMemberQuery()) and + m.getType() = a and + m.getVariable() instanceof FlexibleArrayMember and + a.getArraySize() = 1 +select m, "Incorrect syntax used for declaring this flexible array member." diff --git a/c/cert/test/rules/DCL38-C/DeclaringAFlexibleArrayMember.expected b/c/cert/test/rules/DCL38-C/DeclaringAFlexibleArrayMember.expected new file mode 100644 index 0000000000..a195c79bc5 --- /dev/null +++ b/c/cert/test/rules/DCL38-C/DeclaringAFlexibleArrayMember.expected @@ -0,0 +1 @@ +| test.c:3:7:3:7 | definition of b | Incorrect syntax used for declaring this flexible array member. | diff --git a/c/cert/test/rules/DCL38-C/DeclaringAFlexibleArrayMember.qlref b/c/cert/test/rules/DCL38-C/DeclaringAFlexibleArrayMember.qlref new file mode 100644 index 0000000000..0e4621c1e6 --- /dev/null +++ b/c/cert/test/rules/DCL38-C/DeclaringAFlexibleArrayMember.qlref @@ -0,0 +1 @@ +rules/DCL38-C/DeclaringAFlexibleArrayMember.ql \ No newline at end of file diff --git a/c/cert/test/rules/DCL38-C/test.c b/c/cert/test/rules/DCL38-C/test.c new file mode 100644 index 0000000000..9b23e2e9dd --- /dev/null +++ b/c/cert/test/rules/DCL38-C/test.c @@ -0,0 +1,20 @@ +struct s { + int a; + int b[1]; // NON_COMPLIANT +}; + +struct s1 { + int a; + int b[]; // COMPLIANT +}; + +struct s2 { + int a; + int b[2]; // COMPLIANT +}; + +struct s3 { + int a; + int b[1]; // COMPLIANT + int a1; +}; \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations2.qll index 869db31097..4357de3a60 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations2.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations2.qll @@ -3,9 +3,19 @@ import cpp import RuleMetadata import codingstandards.cpp.exclusions.RuleMetadata -newtype Declarations2Query = TVariablesInsideSwitchStatementQuery() +newtype Declarations2Query = + TDeclaringAFlexibleArrayMemberQuery() or + TVariablesInsideSwitchStatementQuery() predicate isDeclarations2QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `declaringAFlexibleArrayMember` query + Declarations2Package::declaringAFlexibleArrayMemberQuery() and + queryId = + // `@id` for the `declaringAFlexibleArrayMember` query + "c/cert/declaring-a-flexible-array-member" and + ruleId = "DCL38-C" + or query = // `Query` instance for the `variablesInsideSwitchStatement` query Declarations2Package::variablesInsideSwitchStatementQuery() and @@ -16,6 +26,13 @@ predicate isDeclarations2QueryMetadata(Query query, string queryId, string ruleI } module Declarations2Package { + Query declaringAFlexibleArrayMemberQuery() { + //autogenerate `Query` type + result = + // `Query` type for `declaringAFlexibleArrayMember` query + TQueryC(TDeclarations2PackageQuery(TDeclaringAFlexibleArrayMemberQuery())) + } + Query variablesInsideSwitchStatementQuery() { //autogenerate `Query` type result = diff --git a/rule_packages/c/Declarations2.json b/rule_packages/c/Declarations2.json index d7ed583f7c..7549a08e5d 100644 --- a/rule_packages/c/Declarations2.json +++ b/rule_packages/c/Declarations2.json @@ -1,5 +1,26 @@ { "CERT-C": { + "DCL38-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Structures with flexible array members can be declared in ways that will lead to undefined behaviour.", + "kind": "problem", + "name": "Use the correct syntax when declaring a flexible array member", + "precision": "very-high", + "severity": "error", + "short_name": "DeclaringAFlexibleArrayMember", + "tags": [ + "correctness", + "maintainability", + "readability" + ] + } + ], + "title": "Use the correct syntax when declaring a flexible array member" + }, "DCL41-C": { "properties": { "obligation": "rule" diff --git a/rules.csv b/rules.csv index fe3a9aca3d..edae0dca72 100755 --- a/rules.csv +++ b/rules.csv @@ -502,7 +502,7 @@ c,CERT-C,DCL30-C,Yes,Rule,,,Declare objects with appropriate storage durations,, c,CERT-C,DCL31-C,Yes,Rule,,,Declare identifiers before using them,,Declarations1,Medium, c,CERT-C,DCL36-C,Yes,Rule,,,Do not declare an identifier with conflicting linkage classifications,,Declarations,Medium, c,CERT-C,DCL37-C,Yes,Rule,,,Do not declare or define a reserved identifier,,Declarations1,Easy, -c,CERT-C,DCL38-C,Yes,Rule,,,Use the correct syntax when declaring a flexible array member,,Declarations,Easy, +c,CERT-C,DCL38-C,Yes,Rule,,,Use the correct syntax when declaring a flexible array member,,Declarations2,Easy, c,CERT-C,DCL39-C,Yes,Rule,,,Avoid information leakage when passing a structure across a trust boundary,,Declarations,Hard, c,CERT-C,DCL40-C,Yes,Rule,,,Do not create incompatible declarations of the same function or object,,Declarations,Hard, c,CERT-C,DCL41-C,Yes,Rule,,,Do not declare variables inside a switch statement before the first case label,,Declarations2,Medium, @@ -716,7 +716,7 @@ c,MISRA-C-2012,RULE-17-2,Yes,Required,,,"Functions shall not call themselves, ei c,MISRA-C-2012,RULE-17-3,Yes,Mandatory,,,A function shall not be declared implicitly,,Declarations,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,Statements,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,,Contracts,Hard, -c,MISRA-C-2012,RULE-17-6,Yes,Mandatory,,,The declaration of an array parameter shall not contain the static keyword between the [ ],,Declarations,Easy, +c,MISRA-C-2012,RULE-17-6,No,Mandatory,,,The declaration of an array parameter shall not contain the static keyword between the [ ],,,, 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,Contracts,Import, c,MISRA-C-2012,RULE-17-8,Yes,Advisory,,,A function parameter should not be modified,,SideEffects2,Medium, c,MISRA-C-2012,RULE-18-1,Yes,Required,,,A pointer resulting from arithmetic on a pointer operand shall address an element of the same array as that pointer operand,M5-0-16,Pointers1,Import, From 2555c70bc27922a8d8ff586f5910d98cd77ea9cd Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 14 Sep 2022 15:07:52 -0400 Subject: [PATCH 4/9] Declarations2: fix help file syntax rule DCL38-C --- c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.md | 1 - 1 file changed, 1 deletion(-) diff --git a/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.md b/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.md index 9bd57a0686..d6030b99eb 100644 --- a/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.md +++ b/c/cert/src/rules/DCL38-C/DeclaringAFlexibleArrayMember.md @@ -5,7 +5,6 @@ This query implements the CERT-C rule DCL38-C: > Use the correct syntax when declaring a flexible array member - ## Description Flexible array members are a special type of array in which the last element of a structure with more than one named member has an incomplete array type; that is, the size of the array is not specified explicitly within the structure. This "struct hack" was widely used in practice and supported by a variety of compilers. Consequently, a variety of different syntaxes have been used for declaring flexible array members. For conforming C implementations, use the syntax guaranteed to be valid by the C Standard. From dda49f7167732e518b602526c6dad61a218657e8 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Tue, 20 Sep 2022 17:01:02 -0400 Subject: [PATCH 5/9] Declarations2: add rule DCL40-C --- ...ExcessLengthNamesIdentifiersNotDistinct.md | 18 +++ ...ExcessLengthNamesIdentifiersNotDistinct.ql | 23 ++++ .../src/rules/DCL40-C/ExternalIdentifiers.qll | 15 +++ .../IncompatibleFunctionDeclarations.md | 16 +++ .../IncompatibleFunctionDeclarations.ql | 45 +++++++ .../DCL40-C/IncompatibleObjectDeclarations.md | 18 +++ .../DCL40-C/IncompatibleObjectDeclarations.ql | 30 +++++ ...sLengthNamesIdentifiersNotDistinct.testref | 1 + .../IncompatibleFunctionDeclarations.expected | 4 + .../IncompatibleFunctionDeclarations.qlref | 1 + .../IncompatibleObjectDeclarations.expected | 2 + .../IncompatibleObjectDeclarations.qlref | 1 + c/cert/test/rules/DCL40-C/test.c | 10 ++ c/cert/test/rules/DCL40-C/test1.c | 7 ++ .../NotDistinctIdentifier.expected} | 0 .../NotDistinctIdentifier.ql | 2 + .../test/rules/notdistinctidentifier}/test.c | 0 .../ExternalIdentifiersNotDistinct.qlref | 1 - .../ExternalIdentifiersNotDistinct.testref | 1 + .../cpp/exclusions/c/Declarations2.qll | 48 +++++++ .../NotDistinctIdentifier.qll | 15 +++ rule_packages/c/Declarations1.json | 1 + rule_packages/c/Declarations2.json | 118 +++++++++++++----- rules.csv | 2 +- 24 files changed, 344 insertions(+), 35 deletions(-) create mode 100644 c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.md create mode 100644 c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.ql create mode 100644 c/cert/src/rules/DCL40-C/ExternalIdentifiers.qll create mode 100644 c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.md create mode 100644 c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql create mode 100644 c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.md create mode 100644 c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql create mode 100644 c/cert/test/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.testref create mode 100644 c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.expected create mode 100644 c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.qlref create mode 100644 c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.expected create mode 100644 c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.qlref create mode 100644 c/cert/test/rules/DCL40-C/test.c create mode 100644 c/cert/test/rules/DCL40-C/test1.c rename c/{misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.expected => common/test/rules/notdistinctidentifier/NotDistinctIdentifier.expected} (100%) create mode 100644 c/common/test/rules/notdistinctidentifier/NotDistinctIdentifier.ql rename c/{misra/test/rules/RULE-5-1 => common/test/rules/notdistinctidentifier}/test.c (100%) delete mode 100644 c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.qlref create mode 100644 c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.testref create mode 100644 cpp/common/src/codingstandards/cpp/rules/notdistinctidentifier/NotDistinctIdentifier.qll diff --git a/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.md b/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.md new file mode 100644 index 0000000000..78a724f136 --- /dev/null +++ b/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.md @@ -0,0 +1,18 @@ +# DCL40-C: External identifiers shall be distinct + +This query implements the CERT-C rule DCL40-C: + +> Do not create incompatible declarations of the same function or object + + +## CERT + +** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` ** + +## Implementation notes + +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. + +## References + +* CERT-C: [DCL40-C: Do not create incompatible declarations of the same function or object](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.ql b/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.ql new file mode 100644 index 0000000000..ba2cc5c23f --- /dev/null +++ b/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.ql @@ -0,0 +1,23 @@ +/** + * @id c/cert/excess-length-names-identifiers-not-distinct + * @name DCL40-C: External identifiers shall be distinct + * @description Using nondistinct external identifiers results in undefined behaviour. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/cert/id/dcl40-c + * correctness + * maintainability + * readability + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.rules.notdistinctidentifier.NotDistinctIdentifier + +class ExcessLengthNamesIdentifiersNotDistinctQuery extends NotDistinctIdentifierSharedQuery { + ExcessLengthNamesIdentifiersNotDistinctQuery() { + this = Declarations2Package::excessLengthNamesIdentifiersNotDistinctQuery() + } +} diff --git a/c/cert/src/rules/DCL40-C/ExternalIdentifiers.qll b/c/cert/src/rules/DCL40-C/ExternalIdentifiers.qll new file mode 100644 index 0000000000..ae63dac5be --- /dev/null +++ b/c/cert/src/rules/DCL40-C/ExternalIdentifiers.qll @@ -0,0 +1,15 @@ +import cpp +import codingstandards.cpp.Linkage + +class ExternalIdentifiers extends Declaration { + ExternalIdentifiers() { + hasExternalLinkage(this) and + getNamespace() instanceof GlobalNamespace and + not this.isFromTemplateInstantiation(_) and + not this.isFromUninstantiatedTemplate(_) and + not this.hasDeclaringType() and + not this instanceof UserType and + not this instanceof Operator and + not this.hasName("main") + } +} diff --git a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.md b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.md new file mode 100644 index 0000000000..6257b1ad11 --- /dev/null +++ b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.md @@ -0,0 +1,16 @@ +# DCL40-C: Do not create incompatible declarations of the same function or object + +This query implements the CERT-C rule DCL40-C: + +> Do not create incompatible declarations of the same function or object +## CERT + +** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` ** + +## Implementation notes + +None + +## References + +* CERT-C: [DCL40-C: Do not create incompatible declarations of the same function or object](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql new file mode 100644 index 0000000000..4660e69b68 --- /dev/null +++ b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.ql @@ -0,0 +1,45 @@ +/** + * @id c/cert/incompatible-function-declarations + * @name DCL40-C: Do not create incompatible declarations of the same function or object + * @description Declaring incompatible functions, in other words same named function of different + * return types or with different numbers of parameters or parameter types, then + * accessing those functions can lead to undefined behaviour. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/cert/id/dcl40-c + * correctness + * maintainability + * readability + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import ExternalIdentifiers + +//checks if they are incompatible based on return type, number of parameters and parameter types +predicate checkMatchingFunction(FunctionDeclarationEntry d, FunctionDeclarationEntry d2) { + not d.getType() = d2.getType() + or + not d.getNumberOfParameters() = d2.getNumberOfParameters() + or + exists(ParameterDeclarationEntry p, ParameterDeclarationEntry p2, int i | + d.getParameterDeclarationEntry(i) = p and + d2.getParameterDeclarationEntry(i) = p2 and + not p.getType() = p2.getType() + ) +} + +from ExternalIdentifiers d, FunctionDeclarationEntry f1, FunctionDeclarationEntry f2 +where + not isExcluded(f1, Declarations2Package::incompatibleFunctionDeclarationsQuery()) and + not isExcluded(f2, Declarations2Package::incompatibleFunctionDeclarationsQuery()) and + f1 = d.getADeclarationEntry() and + f2 = d.getADeclarationEntry() and + not f1 = f2 and + f1.getLocation().getStartLine() >= f2.getLocation().getStartLine() and + f1.getName() = f2.getName() and + checkMatchingFunction(f1, f2) +select f1, "The object $@ is not compatible with re-declaration $@", f1, f1.getName(), f2, + f2.getName() diff --git a/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.md b/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.md new file mode 100644 index 0000000000..90ff4b8550 --- /dev/null +++ b/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.md @@ -0,0 +1,18 @@ +# DCL40-C: Do not create incompatible declarations of the same function or object + +This query implements the CERT-C rule DCL40-C: + +> Do not create incompatible declarations of the same function or object + + +## CERT + +** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` ** + +## Implementation notes + +None + +## References + +* CERT-C: [DCL40-C: Do not create incompatible declarations of the same function or object](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql b/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql new file mode 100644 index 0000000000..151d33db5c --- /dev/null +++ b/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.ql @@ -0,0 +1,30 @@ +/** + * @id c/cert/incompatible-object-declarations + * @name DCL40-C: Do not create incompatible declarations of the same function or object + * @description Declaring incompatible objects, in other words same named objects of different + * types, then accessing those objects can lead to undefined behaviour. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/cert/id/dcl40-c + * correctness + * maintainability + * readability + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import ExternalIdentifiers + +from VariableDeclarationEntry decl1, VariableDeclarationEntry decl2 +where + not isExcluded(decl1, Declarations2Package::incompatibleObjectDeclarationsQuery()) and + not isExcluded(decl2, Declarations2Package::incompatibleObjectDeclarationsQuery()) and + not decl1.getUnspecifiedType() = decl2.getUnspecifiedType() and + decl1.getDeclaration() instanceof ExternalIdentifiers and + decl2.getDeclaration() instanceof ExternalIdentifiers and + decl1.getLocation().getStartLine() >= decl2.getLocation().getStartLine() and + decl1.getVariable().getName() = decl2.getVariable().getName() +select decl1, "The object $@ is not compatible with re-declaration $@", decl1, decl1.getName(), + decl2, decl2.getName() diff --git a/c/cert/test/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.testref b/c/cert/test/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.testref new file mode 100644 index 0000000000..1d98a97af8 --- /dev/null +++ b/c/cert/test/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.testref @@ -0,0 +1 @@ +c/common/test/rules/notdistinctidentifier/NotDistinctIdentifier.ql \ No newline at end of file diff --git a/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.expected b/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.expected new file mode 100644 index 0000000000..f6e330d697 --- /dev/null +++ b/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.expected @@ -0,0 +1,4 @@ +| test1.c:4:12:4:12 | declaration of f | The object $@ is not compatible with re-declaration $@ | test1.c:4:12:4:12 | declaration of f | f | test.c:4:6:4:6 | definition of f | f | +| test.c:4:6:4:6 | definition of f | The object $@ is not compatible with re-declaration $@ | test.c:4:6:4:6 | definition of f | f | test1.c:4:12:4:12 | declaration of f | f | +| test.c:8:6:8:7 | declaration of f1 | The object $@ is not compatible with re-declaration $@ | test.c:8:6:8:7 | declaration of f1 | f1 | test1.c:5:13:5:14 | declaration of f1 | f1 | +| test.c:9:6:9:7 | definition of f2 | The object $@ is not compatible with re-declaration $@ | test.c:9:6:9:7 | definition of f2 | f2 | test1.c:6:6:6:7 | definition of f2 | f2 | diff --git a/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.qlref b/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.qlref new file mode 100644 index 0000000000..39e98a0f82 --- /dev/null +++ b/c/cert/test/rules/DCL40-C/IncompatibleFunctionDeclarations.qlref @@ -0,0 +1 @@ +rules/DCL40-C/IncompatibleFunctionDeclarations.ql \ No newline at end of file diff --git a/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.expected b/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.expected new file mode 100644 index 0000000000..30eaf1a416 --- /dev/null +++ b/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.expected @@ -0,0 +1,2 @@ +| test1.c:2:12:2:12 | declaration of i | The object $@ is not compatible with re-declaration $@ | test1.c:2:12:2:12 | declaration of i | i | test.c:1:7:1:7 | definition of i | i | +| test.c:2:5:2:5 | definition of a | The object $@ is not compatible with re-declaration $@ | test.c:2:5:2:5 | definition of a | a | test1.c:1:13:1:13 | declaration of a | a | diff --git a/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.qlref b/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.qlref new file mode 100644 index 0000000000..6648409686 --- /dev/null +++ b/c/cert/test/rules/DCL40-C/IncompatibleObjectDeclarations.qlref @@ -0,0 +1 @@ +rules/DCL40-C/IncompatibleObjectDeclarations.ql \ No newline at end of file diff --git a/c/cert/test/rules/DCL40-C/test.c b/c/cert/test/rules/DCL40-C/test.c new file mode 100644 index 0000000000..53ea630187 --- /dev/null +++ b/c/cert/test/rules/DCL40-C/test.c @@ -0,0 +1,10 @@ +short i; // NON_COMPLIANT +int a[] = {1, 2, 3, 4}; // NON_COMPLIANT + +long f(int a) { // NON_COMPLIANT + return a * 2; +} + +void f1(long a); // NON_COMPLIANT +void f2() {} // NON_COMPLIANT +int f3(); // COMPLIANT \ No newline at end of file diff --git a/c/cert/test/rules/DCL40-C/test1.c b/c/cert/test/rules/DCL40-C/test1.c new file mode 100644 index 0000000000..60178e1439 --- /dev/null +++ b/c/cert/test/rules/DCL40-C/test1.c @@ -0,0 +1,7 @@ +extern int *a; // NON_COMPLIANT +extern int i; // NON_COMPLIANT + +extern int f(int a); // NON_COMPLIANT +extern void f1(int a); // NON_COMPLIANT +void f2(int a, ...) {} // NON_COMPLIANT +int f3(); // COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.expected b/c/common/test/rules/notdistinctidentifier/NotDistinctIdentifier.expected similarity index 100% rename from c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.expected rename to c/common/test/rules/notdistinctidentifier/NotDistinctIdentifier.expected diff --git a/c/common/test/rules/notdistinctidentifier/NotDistinctIdentifier.ql b/c/common/test/rules/notdistinctidentifier/NotDistinctIdentifier.ql new file mode 100644 index 0000000000..82ea80b775 --- /dev/null +++ b/c/common/test/rules/notdistinctidentifier/NotDistinctIdentifier.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.notdistinctidentifier.NotDistinctIdentifier diff --git a/c/misra/test/rules/RULE-5-1/test.c b/c/common/test/rules/notdistinctidentifier/test.c similarity index 100% rename from c/misra/test/rules/RULE-5-1/test.c rename to c/common/test/rules/notdistinctidentifier/test.c diff --git a/c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.qlref b/c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.qlref deleted file mode 100644 index 965e5c3298..0000000000 --- a/c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.qlref +++ /dev/null @@ -1 +0,0 @@ -rules/RULE-5-1/ExternalIdentifiersNotDistinct.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.testref b/c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.testref new file mode 100644 index 0000000000..1d98a97af8 --- /dev/null +++ b/c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.testref @@ -0,0 +1 @@ +c/common/test/rules/notdistinctidentifier/NotDistinctIdentifier.ql \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations2.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations2.qll index 4357de3a60..5314ebc400 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations2.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations2.qll @@ -5,6 +5,9 @@ import codingstandards.cpp.exclusions.RuleMetadata newtype Declarations2Query = TDeclaringAFlexibleArrayMemberQuery() or + TExcessLengthNamesIdentifiersNotDistinctQuery() or + TIncompatibleObjectDeclarationsQuery() or + TIncompatibleFunctionDeclarationsQuery() or TVariablesInsideSwitchStatementQuery() predicate isDeclarations2QueryMetadata(Query query, string queryId, string ruleId) { @@ -16,6 +19,30 @@ predicate isDeclarations2QueryMetadata(Query query, string queryId, string ruleI "c/cert/declaring-a-flexible-array-member" and ruleId = "DCL38-C" or + query = + // `Query` instance for the `excessLengthNamesIdentifiersNotDistinct` query + Declarations2Package::excessLengthNamesIdentifiersNotDistinctQuery() and + queryId = + // `@id` for the `excessLengthNamesIdentifiersNotDistinct` query + "c/cert/excess-length-names-identifiers-not-distinct" and + ruleId = "DCL40-C" + or + query = + // `Query` instance for the `incompatibleObjectDeclarations` query + Declarations2Package::incompatibleObjectDeclarationsQuery() and + queryId = + // `@id` for the `incompatibleObjectDeclarations` query + "c/cert/incompatible-object-declarations" and + ruleId = "DCL40-C" + or + query = + // `Query` instance for the `incompatibleFunctionDeclarations` query + Declarations2Package::incompatibleFunctionDeclarationsQuery() and + queryId = + // `@id` for the `incompatibleFunctionDeclarations` query + "c/cert/incompatible-function-declarations" and + ruleId = "DCL40-C" + or query = // `Query` instance for the `variablesInsideSwitchStatement` query Declarations2Package::variablesInsideSwitchStatementQuery() and @@ -33,6 +60,27 @@ module Declarations2Package { TQueryC(TDeclarations2PackageQuery(TDeclaringAFlexibleArrayMemberQuery())) } + Query excessLengthNamesIdentifiersNotDistinctQuery() { + //autogenerate `Query` type + result = + // `Query` type for `excessLengthNamesIdentifiersNotDistinct` query + TQueryC(TDeclarations2PackageQuery(TExcessLengthNamesIdentifiersNotDistinctQuery())) + } + + Query incompatibleObjectDeclarationsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `incompatibleObjectDeclarations` query + TQueryC(TDeclarations2PackageQuery(TIncompatibleObjectDeclarationsQuery())) + } + + Query incompatibleFunctionDeclarationsQuery() { + //autogenerate `Query` type + result = + // `Query` type for `incompatibleFunctionDeclarations` query + TQueryC(TDeclarations2PackageQuery(TIncompatibleFunctionDeclarationsQuery())) + } + Query variablesInsideSwitchStatementQuery() { //autogenerate `Query` type result = diff --git a/cpp/common/src/codingstandards/cpp/rules/notdistinctidentifier/NotDistinctIdentifier.qll b/cpp/common/src/codingstandards/cpp/rules/notdistinctidentifier/NotDistinctIdentifier.qll new file mode 100644 index 0000000000..cba5c020e2 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/notdistinctidentifier/NotDistinctIdentifier.qll @@ -0,0 +1,15 @@ +/** + * Provides a library which includes a `problems` predicate for reporting.... + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions + +abstract class NotDistinctIdentifierSharedQuery extends Query { } + +Query getQuery() { result instanceof NotDistinctIdentifierSharedQuery } + +query predicate problems(Element e, string message) { +not isExcluded(e, getQuery()) and message = "" +} \ No newline at end of file diff --git a/rule_packages/c/Declarations1.json b/rule_packages/c/Declarations1.json index 49635a47ae..417d6f1f84 100644 --- a/rule_packages/c/Declarations1.json +++ b/rule_packages/c/Declarations1.json @@ -86,6 +86,7 @@ "precision": "very-high", "severity": "warning", "short_name": "ExternalIdentifiersNotDistinct", + "shared_implementation_short_name": "NotDistinctIdentifier", "tags": [ "correctness", "maintainability", diff --git a/rule_packages/c/Declarations2.json b/rule_packages/c/Declarations2.json index 7549a08e5d..303965b6b6 100644 --- a/rule_packages/c/Declarations2.json +++ b/rule_packages/c/Declarations2.json @@ -1,46 +1,98 @@ { "CERT-C": { "DCL38-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Structures with flexible array members can be declared in ways that will lead to undefined behaviour.", + "kind": "problem", + "name": "Use the correct syntax when declaring a flexible array member", + "precision": "very-high", + "severity": "error", + "short_name": "DeclaringAFlexibleArrayMember", + "tags": [ + "correctness", + "maintainability", + "readability" + ] + } + ], + "title": "Use the correct syntax when declaring a flexible array member" + }, + "DCL40-C": { "properties": { "obligation": "rule" }, "queries": [ { - "description": "Structures with flexible array members can be declared in ways that will lead to undefined behaviour.", - "kind": "problem", - "name": "Use the correct syntax when declaring a flexible array member", - "precision": "very-high", - "severity": "error", - "short_name": "DeclaringAFlexibleArrayMember", - "tags": [ - "correctness", - "maintainability", - "readability" - ] - } + "description": "Using nondistinct external identifiers results in undefined behaviour.", + "kind": "problem", + "name": "External identifiers shall be distinct", + "precision": "very-high", + "severity": "warning", + "short_name": "ExcessLengthNamesIdentifiersNotDistinct", + "shared_implementation_short_name": "NotDistinctIdentifier", + "tags": [ + "correctness", + "maintainability", + "readability" + ], + "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.", + "items": [] + } + }, + { + "description": "Declaring incompatible objects, in other words same named objects of different types, then accessing those objects can lead to undefined behaviour.", + "kind": "problem", + "name": "Do not create incompatible declarations of the same function or object", + "precision": "high", + "severity": "error", + "short_name": "IncompatibleObjectDeclarations", + "tags": [ + "correctness", + "maintainability", + "readability" + ] + }, + { + "description": "Declaring incompatible functions, in other words same named function of different return types or with different numbers of parameters or parameter types, then accessing those functions can lead to undefined behaviour.", + "kind": "problem", + "name": "Do not create incompatible declarations of the same function or object", + "precision": "high", + "severity": "error", + "short_name": "IncompatibleFunctionDeclarations", + "tags": [ + "correctness", + "maintainability", + "readability" + ] + } ], - "title": "Use the correct syntax when declaring a flexible array member" + "title": "Do not create incompatible declarations of the same function or object" }, "DCL41-C": { - "properties": { - "obligation": "rule" - }, - "queries": [ - { - "description": "Declaring a variable in a switch statement before the first case label can result in reading uninitialized memory which is undefined behaviour.", - "kind": "problem", - "name": "Do not declare variables inside a switch statement before the first case label", - "precision": "very-high", - "severity": "error", - "short_name": "VariablesInsideSwitchStatement", - "tags": [ - "correctness", - "maintainability", - "readability" - ] - } - ], - "title": "Do not declare variables inside a switch statement before the first case label" - } + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Declaring a variable in a switch statement before the first case label can result in reading uninitialized memory which is undefined behaviour.", + "kind": "problem", + "name": "Do not declare variables inside a switch statement before the first case label", + "precision": "very-high", + "severity": "error", + "short_name": "VariablesInsideSwitchStatement", + "tags": [ + "correctness", + "maintainability", + "readability" + ] + } + ], + "title": "Do not declare variables inside a switch statement before the first case label" + } } } \ No newline at end of file diff --git a/rules.csv b/rules.csv index edae0dca72..673f116f19 100755 --- a/rules.csv +++ b/rules.csv @@ -504,7 +504,7 @@ c,CERT-C,DCL36-C,Yes,Rule,,,Do not declare an identifier with conflicting linkag c,CERT-C,DCL37-C,Yes,Rule,,,Do not declare or define a reserved identifier,,Declarations1,Easy, c,CERT-C,DCL38-C,Yes,Rule,,,Use the correct syntax when declaring a flexible array member,,Declarations2,Easy, c,CERT-C,DCL39-C,Yes,Rule,,,Avoid information leakage when passing a structure across a trust boundary,,Declarations,Hard, -c,CERT-C,DCL40-C,Yes,Rule,,,Do not create incompatible declarations of the same function or object,,Declarations,Hard, +c,CERT-C,DCL40-C,Yes,Rule,,,Do not create incompatible declarations of the same function or object,,Declarations2,Hard, c,CERT-C,DCL41-C,Yes,Rule,,,Do not declare variables inside a switch statement before the first case label,,Declarations2,Medium, c,CERT-C,ENV30-C,Yes,Rule,,,Do not modify the object referenced by the return value of certain functions,RULE-21-19,Contracts1,Medium, c,CERT-C,ENV31-C,Yes,Rule,,,Do not rely on an environment pointer following an operation that may invalidate it,RULE-21-20,Contracts1,Hard, From 235ea7fb1af58276bfc69ab0100cbe888dfb8e8f Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Tue, 20 Sep 2022 17:03:43 -0400 Subject: [PATCH 6/9] Declarations2: add missing help files DCL40-C --- ...ExcessLengthNamesIdentifiersNotDistinct.md | 213 ++++++++++++++++- .../IncompatibleFunctionDeclarations.md | 214 +++++++++++++++++- .../DCL40-C/IncompatibleObjectDeclarations.md | 213 ++++++++++++++++- 3 files changed, 634 insertions(+), 6 deletions(-) diff --git a/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.md b/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.md index 78a724f136..a687948e8e 100644 --- a/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.md +++ b/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.md @@ -5,9 +5,218 @@ This query implements the CERT-C rule DCL40-C: > Do not create incompatible declarations of the same function or object -## CERT -** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` ** +## Description + +Two or more incompatible declarations of the same function or object must not appear in the same program because they result in [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). The C Standard, 6.2.7, mentions that two types may be distinct yet compatible and addresses precisely when two distinct types are compatible. + +The C Standard identifies four situations in which [undefined behavior (UB)](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) may arise as a result of incompatible declarations of the same function or object: + +
UB Description Code
15 Two declarations of the same object or function specify types that are not compatible (6.2.7). All noncompliant code in this guideline
31 Two identifiers differ only in nonsignificant characters (6.4.2.1). Excessively Long Identifiers
37 An object has its stored value accessed other than by an lvalue of an allowable type (6.5). Incompatible Object Declarations Incompatible Array Declarations
41 A function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function (6.5.2.2). Incompatible Function Declarations Excessively Long Identifiers
+Although the effect of two incompatible declarations simply appearing in the same program may be benign on most [implementations](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation), the effects of invoking a function through an expression whose type is incompatible with the function definition are typically catastrophic. Similarly, the effects of accessing an object using an [lvalue](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-lvalue) of a type that is incompatible with the object definition may range from unintended information exposure to memory overwrite to a hardware trap. + + +## Noncompliant Code Example (Incompatible Object Declarations) + +In this noncompliant code example, the variable `i` is declared to have type `int` in file `a.c` but defined to be of type `short` in file `b.c`. The declarations are incompatible, resulting in [undefined behavior 15](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_15). Furthermore, accessing the object using an [lvalue](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-lvalue) of an incompatible type, as shown in function `f()`, is [undefined behavior 37](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_37) with possible observable results ranging from unintended information exposure to memory overwrite to a hardware trap. + +```cpp +/* In a.c */ +extern int i; /* UB 15 */ + +int f(void) { + return ++i; /* UB 37 */ +} + +/* In b.c */ +short i; /* UB 15 */ + +``` + +## Compliant Solution (Incompatible Object Declarations) + +This compliant solution has compatible declarations of the variable `i`: + +```cpp +/* In a.c */ +extern int i; + +int f(void) { + return ++i; +} + +/* In b.c */ +int i; +``` + +## Noncompliant Code Example (Incompatible Array Declarations) + +In this noncompliant code example, the variable `a` is declared to have a pointer type in file `a.c` but defined to have an array type in file `b.c`. The two declarations are incompatible, resulting in [undefined behavior 15](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_15). As before, accessing the object in function `f()` is [undefined behavior 37](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_37) with the typical effect of triggering a hardware trap. + +```cpp +/* In a.c */ +extern int *a; /* UB 15 */ + +int f(unsigned int i, int x) { + int tmp = a[i]; /* UB 37: read access */ + a[i] = x; /* UB 37: write access */ + return tmp; +} + +/* In b.c */ +int a[] = { 1, 2, 3, 4 }; /* UB 15 */ + +``` + +## Compliant Solution (Incompatible Array Declarations) + +This compliant solution declares `a` as an array in `a.c` and `b.c`: + +```cpp +/* In a.c */ +extern int a[]; + +int f(unsigned int i, int x) { + int tmp = a[i]; + a[i] = x; + return tmp; +} + +/* In b.c */ +int a[] = { 1, 2, 3, 4 }; +``` + +## Noncompliant Code Example (Incompatible Function Declarations) + +In this noncompliant code example, the function `f()` is declared in file `a.c` with one prototype but defined in file `b.c` with another. The two prototypes are incompatible, resulting in [undefined behavior 15](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_15). Furthermore, invoking the function is [undefined behavior 41](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_41) and typically has catastrophic consequences. + +```cpp +/* In a.c */ +extern int f(int a); /* UB 15 */ + +int g(int a) { + return f(a); /* UB 41 */ +} + +/* In b.c */ +long f(long a) { /* UB 15 */ + return a * 2; +} + +``` + +## Compliant Solution (Incompatible Function Declarations) + +This compliant solution has compatible prototypes for the function `f()`: + +```cpp +/* In a.c */ +extern int f(int a); + +int g(int a) { + return f(a); +} + +/* In b.c */ +int f(int a) { + return a * 2; +} +``` + +## Noncompliant Code Example (Incompatible Variadic Function Declarations) + +In this noncompliant code example, the function `buginf()` is defined to take a variable number of arguments and expects them all to be signed integers with a sentinel value of `-1`: + +```cpp +/* In a.c */ +void buginf(const char *fmt, ...) { + /* ... */ +} + +/* In b.c */ +void buginf(); +``` +Although this code appears to be well defined because of the prototype-less declaration of `buginf()`, it exhibits [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) in accordance with the C Standard, 6.7.6.3, paragraph 15 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], + +> For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions. + + +## Compliant Solution (Incompatible Variadic Function Declarations) + +In this compliant solution, the prototype for the function `buginf()` is included in the scope in the source file where it will be used: + +```cpp +/* In a.c */ +void buginf(const char *fmt, ...) { + /* ... */ +} + +/* In b.c */ +void buginf(const char *fmt, ...); +``` + +## Noncompliant Code Example (Excessively Long Identifiers) + +In this noncompliant code example, the length of the identifier declaring the function pointer `bash_groupname_completion_function()` in the file `bashline.h` exceeds by 3 the minimum implementation limit of 31 significant initial characters in an external identifier. This introduces the possibility of colliding with the `bash_groupname_completion_funct` integer variable defined in file `b.c`, which is exactly 31 characters long. On an implementation that exactly meets this limit, this is [undefined behavior 31](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_31). It results in two incompatible declarations of the same function. (See [undefined behavior 15](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_15).) In addition, invoking the function leads to [undefined behavior 41](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_41) with typically catastrophic effects. + +```cpp +/* In bashline.h */ +/* UB 15, UB 31 */ +extern char * bash_groupname_completion_function(const char *, int); + +/* In a.c */ +#include "bashline.h" + +void f(const char *s, int i) { + bash_groupname_completion_function(s, i); /* UB 41 */ +} + +/* In b.c */ +int bash_groupname_completion_funct; /* UB 15, UB 31 */ + +``` +NOTE: The identifier `bash_groupname_completion_function` referenced here was taken from GNU [Bash](http://www.gnu.org/software/bash/), version 3.2. + +## Compliant Solution (Excessively Long Identifiers) + +In this compliant solution, the length of the identifier declaring the function pointer `bash_groupname_completion()` in `bashline.h` is less than 32 characters. Consequently, it cannot clash with `bash_groupname_completion_funct` on any compliant platform. + +```cpp +/* In bashline.h */ +extern char * bash_groupname_completion(const char *, int); + +/* In a.c */ +#include "bashline.h" + +void f(const char *s, int i) { + bash_groupname_completion(s, i); +} + +/* In b.c */ +int bash_groupname_completion_funct; +``` + +## Risk Assessment + +
Rule Severity Likelihood Remediation Cost Priority Level
DCL40-C Low Unlikely Medium P2 L3
+ + +## Automated Detection + +
Tool Version Checker Description
Astrée 22.04 type-compatibility type-compatibility-link distinct-extern Fully checked
Axivion Bauhaus Suite 7.2.0 CertC-DCL40 Fully implemented
CodeSonar 7.1p0 LANG.STRUCT.DECL.IFLANG.STRUCT.DECL.IO Inconsistent function declarations Inconsistent object declarations
Coverity 2017.07 MISRA C 2012 Rule 8.4 Implemented
Helix QAC 2022.2 C0776, C0778, C0779, C0789, C1510 C++1510
Klocwork 2022.2 MISRA.FUNC.NOPROT.DEF.2012 MISRA.FUNC.PARAMS.IDENT
LDRA tool suite 8.5.4 1 X, 17 D Partially implemented
Parasoft C/C++test 2022.1 CERT_C-DCL40-a CERT_C-DCL40-b All declarations of an object or function shall have compatible types If objects or functions are declared more than once their types shall be compatible
Parasoft Insure++ Runtime analysis
PC-lint Plus 1.4 18, 621, 793, 4376 Fully supported
Polyspace Bug Finder R2022a CERT C: Rule DCL40-C Checks for declaration mismatch (rule fully covered)
PRQA QA-C 9.7 0776, 0778, 0779, 0789, 1510 Fully implemented
PRQA QA-C++ 4.4 1510
RuleChecker 22.04 type-compatibility type-compatibility-link distinct-extern Fully checked
TrustInSoft Analyzer 1.38 incompatible declaration Exhaustively verified.
+ + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
Taxonomy Taxonomy item Relationship
ISO/IEC TS 17961 Declaring the same function or object in incompatible ways \[funcdecl\] Prior to 2018-01-12: CERT: Unspecified Relationship
MISRA C:2012 Rule 8.4 (required) Prior to 2018-01-12: CERT: Unspecified Relationship
+ + +## Bibliography + +
\[ Hatton 1995 \] Section 2.8.3
\[ ISO/IEC 9899:2011 \] 6.7.6.3, "Function Declarators (including Prototypes)" J.2, "Undefined Behavior"
+ ## Implementation notes diff --git a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.md b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.md index 6257b1ad11..99b8a6de42 100644 --- a/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.md +++ b/c/cert/src/rules/DCL40-C/IncompatibleFunctionDeclarations.md @@ -3,9 +3,219 @@ This query implements the CERT-C rule DCL40-C: > Do not create incompatible declarations of the same function or object -## CERT -** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` ** + +## Description + +Two or more incompatible declarations of the same function or object must not appear in the same program because they result in [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). The C Standard, 6.2.7, mentions that two types may be distinct yet compatible and addresses precisely when two distinct types are compatible. + +The C Standard identifies four situations in which [undefined behavior (UB)](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) may arise as a result of incompatible declarations of the same function or object: + +
UB Description Code
15 Two declarations of the same object or function specify types that are not compatible (6.2.7). All noncompliant code in this guideline
31 Two identifiers differ only in nonsignificant characters (6.4.2.1). Excessively Long Identifiers
37 An object has its stored value accessed other than by an lvalue of an allowable type (6.5). Incompatible Object Declarations Incompatible Array Declarations
41 A function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function (6.5.2.2). Incompatible Function Declarations Excessively Long Identifiers
+Although the effect of two incompatible declarations simply appearing in the same program may be benign on most [implementations](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation), the effects of invoking a function through an expression whose type is incompatible with the function definition are typically catastrophic. Similarly, the effects of accessing an object using an [lvalue](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-lvalue) of a type that is incompatible with the object definition may range from unintended information exposure to memory overwrite to a hardware trap. + + +## Noncompliant Code Example (Incompatible Object Declarations) + +In this noncompliant code example, the variable `i` is declared to have type `int` in file `a.c` but defined to be of type `short` in file `b.c`. The declarations are incompatible, resulting in [undefined behavior 15](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_15). Furthermore, accessing the object using an [lvalue](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-lvalue) of an incompatible type, as shown in function `f()`, is [undefined behavior 37](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_37) with possible observable results ranging from unintended information exposure to memory overwrite to a hardware trap. + +```cpp +/* In a.c */ +extern int i; /* UB 15 */ + +int f(void) { + return ++i; /* UB 37 */ +} + +/* In b.c */ +short i; /* UB 15 */ + +``` + +## Compliant Solution (Incompatible Object Declarations) + +This compliant solution has compatible declarations of the variable `i`: + +```cpp +/* In a.c */ +extern int i; + +int f(void) { + return ++i; +} + +/* In b.c */ +int i; +``` + +## Noncompliant Code Example (Incompatible Array Declarations) + +In this noncompliant code example, the variable `a` is declared to have a pointer type in file `a.c` but defined to have an array type in file `b.c`. The two declarations are incompatible, resulting in [undefined behavior 15](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_15). As before, accessing the object in function `f()` is [undefined behavior 37](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_37) with the typical effect of triggering a hardware trap. + +```cpp +/* In a.c */ +extern int *a; /* UB 15 */ + +int f(unsigned int i, int x) { + int tmp = a[i]; /* UB 37: read access */ + a[i] = x; /* UB 37: write access */ + return tmp; +} + +/* In b.c */ +int a[] = { 1, 2, 3, 4 }; /* UB 15 */ + +``` + +## Compliant Solution (Incompatible Array Declarations) + +This compliant solution declares `a` as an array in `a.c` and `b.c`: + +```cpp +/* In a.c */ +extern int a[]; + +int f(unsigned int i, int x) { + int tmp = a[i]; + a[i] = x; + return tmp; +} + +/* In b.c */ +int a[] = { 1, 2, 3, 4 }; +``` + +## Noncompliant Code Example (Incompatible Function Declarations) + +In this noncompliant code example, the function `f()` is declared in file `a.c` with one prototype but defined in file `b.c` with another. The two prototypes are incompatible, resulting in [undefined behavior 15](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_15). Furthermore, invoking the function is [undefined behavior 41](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_41) and typically has catastrophic consequences. + +```cpp +/* In a.c */ +extern int f(int a); /* UB 15 */ + +int g(int a) { + return f(a); /* UB 41 */ +} + +/* In b.c */ +long f(long a) { /* UB 15 */ + return a * 2; +} + +``` + +## Compliant Solution (Incompatible Function Declarations) + +This compliant solution has compatible prototypes for the function `f()`: + +```cpp +/* In a.c */ +extern int f(int a); + +int g(int a) { + return f(a); +} + +/* In b.c */ +int f(int a) { + return a * 2; +} +``` + +## Noncompliant Code Example (Incompatible Variadic Function Declarations) + +In this noncompliant code example, the function `buginf()` is defined to take a variable number of arguments and expects them all to be signed integers with a sentinel value of `-1`: + +```cpp +/* In a.c */ +void buginf(const char *fmt, ...) { + /* ... */ +} + +/* In b.c */ +void buginf(); +``` +Although this code appears to be well defined because of the prototype-less declaration of `buginf()`, it exhibits [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) in accordance with the C Standard, 6.7.6.3, paragraph 15 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], + +> For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions. + + +## Compliant Solution (Incompatible Variadic Function Declarations) + +In this compliant solution, the prototype for the function `buginf()` is included in the scope in the source file where it will be used: + +```cpp +/* In a.c */ +void buginf(const char *fmt, ...) { + /* ... */ +} + +/* In b.c */ +void buginf(const char *fmt, ...); +``` + +## Noncompliant Code Example (Excessively Long Identifiers) + +In this noncompliant code example, the length of the identifier declaring the function pointer `bash_groupname_completion_function()` in the file `bashline.h` exceeds by 3 the minimum implementation limit of 31 significant initial characters in an external identifier. This introduces the possibility of colliding with the `bash_groupname_completion_funct` integer variable defined in file `b.c`, which is exactly 31 characters long. On an implementation that exactly meets this limit, this is [undefined behavior 31](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_31). It results in two incompatible declarations of the same function. (See [undefined behavior 15](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_15).) In addition, invoking the function leads to [undefined behavior 41](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_41) with typically catastrophic effects. + +```cpp +/* In bashline.h */ +/* UB 15, UB 31 */ +extern char * bash_groupname_completion_function(const char *, int); + +/* In a.c */ +#include "bashline.h" + +void f(const char *s, int i) { + bash_groupname_completion_function(s, i); /* UB 41 */ +} + +/* In b.c */ +int bash_groupname_completion_funct; /* UB 15, UB 31 */ + +``` +NOTE: The identifier `bash_groupname_completion_function` referenced here was taken from GNU [Bash](http://www.gnu.org/software/bash/), version 3.2. + +## Compliant Solution (Excessively Long Identifiers) + +In this compliant solution, the length of the identifier declaring the function pointer `bash_groupname_completion()` in `bashline.h` is less than 32 characters. Consequently, it cannot clash with `bash_groupname_completion_funct` on any compliant platform. + +```cpp +/* In bashline.h */ +extern char * bash_groupname_completion(const char *, int); + +/* In a.c */ +#include "bashline.h" + +void f(const char *s, int i) { + bash_groupname_completion(s, i); +} + +/* In b.c */ +int bash_groupname_completion_funct; +``` + +## Risk Assessment + +
Rule Severity Likelihood Remediation Cost Priority Level
DCL40-C Low Unlikely Medium P2 L3
+ + +## Automated Detection + +
Tool Version Checker Description
Astrée 22.04 type-compatibility type-compatibility-link distinct-extern Fully checked
Axivion Bauhaus Suite 7.2.0 CertC-DCL40 Fully implemented
CodeSonar 7.1p0 LANG.STRUCT.DECL.IFLANG.STRUCT.DECL.IO Inconsistent function declarations Inconsistent object declarations
Coverity 2017.07 MISRA C 2012 Rule 8.4 Implemented
Helix QAC 2022.2 C0776, C0778, C0779, C0789, C1510 C++1510
Klocwork 2022.2 MISRA.FUNC.NOPROT.DEF.2012 MISRA.FUNC.PARAMS.IDENT
LDRA tool suite 8.5.4 1 X, 17 D Partially implemented
Parasoft C/C++test 2022.1 CERT_C-DCL40-a CERT_C-DCL40-b All declarations of an object or function shall have compatible types If objects or functions are declared more than once their types shall be compatible
Parasoft Insure++ Runtime analysis
PC-lint Plus 1.4 18, 621, 793, 4376 Fully supported
Polyspace Bug Finder R2022a CERT C: Rule DCL40-C Checks for declaration mismatch (rule fully covered)
PRQA QA-C 9.7 0776, 0778, 0779, 0789, 1510 Fully implemented
PRQA QA-C++ 4.4 1510
RuleChecker 22.04 type-compatibility type-compatibility-link distinct-extern Fully checked
TrustInSoft Analyzer 1.38 incompatible declaration Exhaustively verified.
+ + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
Taxonomy Taxonomy item Relationship
ISO/IEC TS 17961 Declaring the same function or object in incompatible ways \[funcdecl\] Prior to 2018-01-12: CERT: Unspecified Relationship
MISRA C:2012 Rule 8.4 (required) Prior to 2018-01-12: CERT: Unspecified Relationship
+ + +## Bibliography + +
\[ Hatton 1995 \] Section 2.8.3
\[ ISO/IEC 9899:2011 \] 6.7.6.3, "Function Declarators (including Prototypes)" J.2, "Undefined Behavior"
+ ## Implementation notes diff --git a/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.md b/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.md index 90ff4b8550..9e5a36ed1f 100644 --- a/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.md +++ b/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.md @@ -5,9 +5,218 @@ This query implements the CERT-C rule DCL40-C: > Do not create incompatible declarations of the same function or object -## CERT -** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` ** +## Description + +Two or more incompatible declarations of the same function or object must not appear in the same program because they result in [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). The C Standard, 6.2.7, mentions that two types may be distinct yet compatible and addresses precisely when two distinct types are compatible. + +The C Standard identifies four situations in which [undefined behavior (UB)](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) may arise as a result of incompatible declarations of the same function or object: + +
UB Description Code
15 Two declarations of the same object or function specify types that are not compatible (6.2.7). All noncompliant code in this guideline
31 Two identifiers differ only in nonsignificant characters (6.4.2.1). Excessively Long Identifiers
37 An object has its stored value accessed other than by an lvalue of an allowable type (6.5). Incompatible Object Declarations Incompatible Array Declarations
41 A function is defined with a type that is not compatible with the type (of the expression) pointed to by the expression that denotes the called function (6.5.2.2). Incompatible Function Declarations Excessively Long Identifiers
+Although the effect of two incompatible declarations simply appearing in the same program may be benign on most [implementations](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation), the effects of invoking a function through an expression whose type is incompatible with the function definition are typically catastrophic. Similarly, the effects of accessing an object using an [lvalue](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-lvalue) of a type that is incompatible with the object definition may range from unintended information exposure to memory overwrite to a hardware trap. + + +## Noncompliant Code Example (Incompatible Object Declarations) + +In this noncompliant code example, the variable `i` is declared to have type `int` in file `a.c` but defined to be of type `short` in file `b.c`. The declarations are incompatible, resulting in [undefined behavior 15](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_15). Furthermore, accessing the object using an [lvalue](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-lvalue) of an incompatible type, as shown in function `f()`, is [undefined behavior 37](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_37) with possible observable results ranging from unintended information exposure to memory overwrite to a hardware trap. + +```cpp +/* In a.c */ +extern int i; /* UB 15 */ + +int f(void) { + return ++i; /* UB 37 */ +} + +/* In b.c */ +short i; /* UB 15 */ + +``` + +## Compliant Solution (Incompatible Object Declarations) + +This compliant solution has compatible declarations of the variable `i`: + +```cpp +/* In a.c */ +extern int i; + +int f(void) { + return ++i; +} + +/* In b.c */ +int i; +``` + +## Noncompliant Code Example (Incompatible Array Declarations) + +In this noncompliant code example, the variable `a` is declared to have a pointer type in file `a.c` but defined to have an array type in file `b.c`. The two declarations are incompatible, resulting in [undefined behavior 15](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_15). As before, accessing the object in function `f()` is [undefined behavior 37](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_37) with the typical effect of triggering a hardware trap. + +```cpp +/* In a.c */ +extern int *a; /* UB 15 */ + +int f(unsigned int i, int x) { + int tmp = a[i]; /* UB 37: read access */ + a[i] = x; /* UB 37: write access */ + return tmp; +} + +/* In b.c */ +int a[] = { 1, 2, 3, 4 }; /* UB 15 */ + +``` + +## Compliant Solution (Incompatible Array Declarations) + +This compliant solution declares `a` as an array in `a.c` and `b.c`: + +```cpp +/* In a.c */ +extern int a[]; + +int f(unsigned int i, int x) { + int tmp = a[i]; + a[i] = x; + return tmp; +} + +/* In b.c */ +int a[] = { 1, 2, 3, 4 }; +``` + +## Noncompliant Code Example (Incompatible Function Declarations) + +In this noncompliant code example, the function `f()` is declared in file `a.c` with one prototype but defined in file `b.c` with another. The two prototypes are incompatible, resulting in [undefined behavior 15](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_15). Furthermore, invoking the function is [undefined behavior 41](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_41) and typically has catastrophic consequences. + +```cpp +/* In a.c */ +extern int f(int a); /* UB 15 */ + +int g(int a) { + return f(a); /* UB 41 */ +} + +/* In b.c */ +long f(long a) { /* UB 15 */ + return a * 2; +} + +``` + +## Compliant Solution (Incompatible Function Declarations) + +This compliant solution has compatible prototypes for the function `f()`: + +```cpp +/* In a.c */ +extern int f(int a); + +int g(int a) { + return f(a); +} + +/* In b.c */ +int f(int a) { + return a * 2; +} +``` + +## Noncompliant Code Example (Incompatible Variadic Function Declarations) + +In this noncompliant code example, the function `buginf()` is defined to take a variable number of arguments and expects them all to be signed integers with a sentinel value of `-1`: + +```cpp +/* In a.c */ +void buginf(const char *fmt, ...) { + /* ... */ +} + +/* In b.c */ +void buginf(); +``` +Although this code appears to be well defined because of the prototype-less declaration of `buginf()`, it exhibits [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) in accordance with the C Standard, 6.7.6.3, paragraph 15 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], + +> For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types. If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions. + + +## Compliant Solution (Incompatible Variadic Function Declarations) + +In this compliant solution, the prototype for the function `buginf()` is included in the scope in the source file where it will be used: + +```cpp +/* In a.c */ +void buginf(const char *fmt, ...) { + /* ... */ +} + +/* In b.c */ +void buginf(const char *fmt, ...); +``` + +## Noncompliant Code Example (Excessively Long Identifiers) + +In this noncompliant code example, the length of the identifier declaring the function pointer `bash_groupname_completion_function()` in the file `bashline.h` exceeds by 3 the minimum implementation limit of 31 significant initial characters in an external identifier. This introduces the possibility of colliding with the `bash_groupname_completion_funct` integer variable defined in file `b.c`, which is exactly 31 characters long. On an implementation that exactly meets this limit, this is [undefined behavior 31](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_31). It results in two incompatible declarations of the same function. (See [undefined behavior 15](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_15).) In addition, invoking the function leads to [undefined behavior 41](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_41) with typically catastrophic effects. + +```cpp +/* In bashline.h */ +/* UB 15, UB 31 */ +extern char * bash_groupname_completion_function(const char *, int); + +/* In a.c */ +#include "bashline.h" + +void f(const char *s, int i) { + bash_groupname_completion_function(s, i); /* UB 41 */ +} + +/* In b.c */ +int bash_groupname_completion_funct; /* UB 15, UB 31 */ + +``` +NOTE: The identifier `bash_groupname_completion_function` referenced here was taken from GNU [Bash](http://www.gnu.org/software/bash/), version 3.2. + +## Compliant Solution (Excessively Long Identifiers) + +In this compliant solution, the length of the identifier declaring the function pointer `bash_groupname_completion()` in `bashline.h` is less than 32 characters. Consequently, it cannot clash with `bash_groupname_completion_funct` on any compliant platform. + +```cpp +/* In bashline.h */ +extern char * bash_groupname_completion(const char *, int); + +/* In a.c */ +#include "bashline.h" + +void f(const char *s, int i) { + bash_groupname_completion(s, i); +} + +/* In b.c */ +int bash_groupname_completion_funct; +``` + +## Risk Assessment + +
Rule Severity Likelihood Remediation Cost Priority Level
DCL40-C Low Unlikely Medium P2 L3
+ + +## Automated Detection + +
Tool Version Checker Description
Astrée 22.04 type-compatibility type-compatibility-link distinct-extern Fully checked
Axivion Bauhaus Suite 7.2.0 CertC-DCL40 Fully implemented
CodeSonar 7.1p0 LANG.STRUCT.DECL.IFLANG.STRUCT.DECL.IO Inconsistent function declarations Inconsistent object declarations
Coverity 2017.07 MISRA C 2012 Rule 8.4 Implemented
Helix QAC 2022.2 C0776, C0778, C0779, C0789, C1510 C++1510
Klocwork 2022.2 MISRA.FUNC.NOPROT.DEF.2012 MISRA.FUNC.PARAMS.IDENT
LDRA tool suite 8.5.4 1 X, 17 D Partially implemented
Parasoft C/C++test 2022.1 CERT_C-DCL40-a CERT_C-DCL40-b All declarations of an object or function shall have compatible types If objects or functions are declared more than once their types shall be compatible
Parasoft Insure++ Runtime analysis
PC-lint Plus 1.4 18, 621, 793, 4376 Fully supported
Polyspace Bug Finder R2022a CERT C: Rule DCL40-C Checks for declaration mismatch (rule fully covered)
PRQA QA-C 9.7 0776, 0778, 0779, 0789, 1510 Fully implemented
PRQA QA-C++ 4.4 1510
RuleChecker 22.04 type-compatibility type-compatibility-link distinct-extern Fully checked
TrustInSoft Analyzer 1.38 incompatible declaration Exhaustively verified.
+ + +## Related Guidelines + +[Key here](https://wiki.sei.cmu.edu/confluence/display/c/How+this+Coding+Standard+is+Organized#HowthisCodingStandardisOrganized-RelatedGuidelines) (explains table format and definitions) + +
Taxonomy Taxonomy item Relationship
ISO/IEC TS 17961 Declaring the same function or object in incompatible ways \[funcdecl\] Prior to 2018-01-12: CERT: Unspecified Relationship
MISRA C:2012 Rule 8.4 (required) Prior to 2018-01-12: CERT: Unspecified Relationship
+ + +## Bibliography + +
\[ Hatton 1995 \] Section 2.8.3
\[ ISO/IEC 9899:2011 \] 6.7.6.3, "Function Declarators (including Prototypes)" J.2, "Undefined Behavior"
+ ## Implementation notes From 282eb99c860653ddfb66026ac8f38540b303934e Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Tue, 20 Sep 2022 17:06:10 -0400 Subject: [PATCH 7/9] Declarations2: fix help file format DCL40-C --- .../src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.md | 1 - c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.md | 1 - 2 files changed, 2 deletions(-) diff --git a/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.md b/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.md index a687948e8e..b99b621736 100644 --- a/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.md +++ b/c/cert/src/rules/DCL40-C/ExcessLengthNamesIdentifiersNotDistinct.md @@ -5,7 +5,6 @@ This query implements the CERT-C rule DCL40-C: > Do not create incompatible declarations of the same function or object - ## Description Two or more incompatible declarations of the same function or object must not appear in the same program because they result in [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). The C Standard, 6.2.7, mentions that two types may be distinct yet compatible and addresses precisely when two distinct types are compatible. diff --git a/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.md b/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.md index 9e5a36ed1f..99b8a6de42 100644 --- a/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.md +++ b/c/cert/src/rules/DCL40-C/IncompatibleObjectDeclarations.md @@ -5,7 +5,6 @@ This query implements the CERT-C rule DCL40-C: > Do not create incompatible declarations of the same function or object - ## Description Two or more incompatible declarations of the same function or object must not appear in the same program because they result in [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). The C Standard, 6.2.7, mentions that two types may be distinct yet compatible and addresses precisely when two distinct types are compatible. From 25ef99662e2c2ae01770ef29310b99e2b32ebff7 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 21 Sep 2022 11:45:29 -0400 Subject: [PATCH 8/9] Declarations2: fix shared rule DCL40-C --- .../ExternalIdentifiersNotDistinct.ql | 36 +++---------------- .../NotDistinctIdentifier.qll | 36 +++++++++++++++++-- 2 files changed, 38 insertions(+), 34 deletions(-) diff --git a/c/misra/src/rules/RULE-5-1/ExternalIdentifiersNotDistinct.ql b/c/misra/src/rules/RULE-5-1/ExternalIdentifiersNotDistinct.ql index 9dac244b3a..774bc97663 100644 --- a/c/misra/src/rules/RULE-5-1/ExternalIdentifiersNotDistinct.ql +++ b/c/misra/src/rules/RULE-5-1/ExternalIdentifiersNotDistinct.ql @@ -14,36 +14,10 @@ import cpp import codingstandards.c.misra -import codingstandards.cpp.Linkage +import codingstandards.cpp.rules.notdistinctidentifier.NotDistinctIdentifier -class ExternalIdentifiers extends Declaration { - ExternalIdentifiers() { - this.getName().length() >= 31 and - hasExternalLinkage(this) and - getNamespace() instanceof GlobalNamespace and - not this.isFromTemplateInstantiation(_) and - not this.isFromUninstantiatedTemplate(_) and - not this.hasDeclaringType() and - not this instanceof UserType and - not this instanceof Operator and - not this.hasName("main") +class ExternalIdentifiersNotDistinct extends NotDistinctIdentifierSharedQuery { + ExternalIdentifiersNotDistinct() { + this = Declarations1Package::externalIdentifiersNotDistinctQuery() } - - string getSignificantName() { - //C99 states the first 31 characters of external identifiers are significant - //C90 states the first 6 characters of external identifiers are significant and case is not required to be significant - //C90 is not currently considered by this rule - result = this.getName().prefix(31) - } -} - -from ExternalIdentifiers d, ExternalIdentifiers d2 -where - not isExcluded(d, Declarations1Package::externalIdentifiersNotDistinctQuery()) and - not d = d2 and - d.getLocation().getStartLine() >= d2.getLocation().getStartLine() and - d.getSignificantName() = d2.getSignificantName() and - not d.getName() = d2.getName() -select d, - "External identifer " + d.getName() + - " is nondistinct in characters at or over 31 limit, compared to $@.", d2, d2.getName() +} \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/rules/notdistinctidentifier/NotDistinctIdentifier.qll b/cpp/common/src/codingstandards/cpp/rules/notdistinctidentifier/NotDistinctIdentifier.qll index cba5c020e2..8e58cbac07 100644 --- a/cpp/common/src/codingstandards/cpp/rules/notdistinctidentifier/NotDistinctIdentifier.qll +++ b/cpp/common/src/codingstandards/cpp/rules/notdistinctidentifier/NotDistinctIdentifier.qll @@ -5,11 +5,41 @@ import cpp import codingstandards.cpp.Customizations import codingstandards.cpp.Exclusions +import codingstandards.cpp.Linkage + +class ExternalIdentifiers extends Declaration { + ExternalIdentifiers() { + this.getName().length() >= 31 and + hasExternalLinkage(this) and + getNamespace() instanceof GlobalNamespace and + not this.isFromTemplateInstantiation(_) and + not this.isFromUninstantiatedTemplate(_) and + not this.hasDeclaringType() and + not this instanceof UserType and + not this instanceof Operator and + not this.hasName("main") + } + + string getSignificantName() { + //C99 states the first 31 characters of external identifiers are significant + //C90 states the first 6 characters of external identifiers are significant and case is not required to be significant + //C90 is not currently considered by this rule + result = this.getName().prefix(31) + } +} abstract class NotDistinctIdentifierSharedQuery extends Query { } Query getQuery() { result instanceof NotDistinctIdentifierSharedQuery } -query predicate problems(Element e, string message) { -not isExcluded(e, getQuery()) and message = "" -} \ No newline at end of file +query predicate problems(ExternalIdentifiers d, ExternalIdentifiers d2, string message) { + not isExcluded(d, getQuery()) and + not isExcluded(d, getQuery()) and + not d = d2 and + d.getLocation().getStartLine() >= d2.getLocation().getStartLine() and + d.getSignificantName() = d2.getSignificantName() and + not d.getName() = d2.getName() and + message = + "External identifer " + d.getName() + + " is nondistinct in characters at or over 31 limit, compared to " + d2.getName() +} From b2ef73e6780e1e71346e4cbfeaf5e74d4a8ba230 Mon Sep 17 00:00:00 2001 From: Mauro Baluda Date: Thu, 22 Sep 2022 15:55:30 +0200 Subject: [PATCH 9/9] Fix expected file --- .../notdistinctidentifier/NotDistinctIdentifier.expected | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/c/common/test/rules/notdistinctidentifier/NotDistinctIdentifier.expected b/c/common/test/rules/notdistinctidentifier/NotDistinctIdentifier.expected index 1e7d80876e..4a0178ec23 100644 --- a/c/common/test/rules/notdistinctidentifier/NotDistinctIdentifier.expected +++ b/c/common/test/rules/notdistinctidentifier/NotDistinctIdentifier.expected @@ -1,4 +1,4 @@ -| test.c:2:5:2:36 | iltiqzxgfqsgigwfuyntzghvzltueeeB | External identifer iltiqzxgfqsgigwfuyntzghvzltueeeB is nondistinct in characters at or over 31 limit, compared to $@. | test.c:1:5:1:36 | iltiqzxgfqsgigwfuyntzghvzltueeeA | iltiqzxgfqsgigwfuyntzghvzltueeeA | -| test.c:5:5:5:35 | iltiqzxgfqsgigwfuyntzghvzltueea | External identifer iltiqzxgfqsgigwfuyntzghvzltueea is nondistinct in characters at or over 31 limit, compared to $@. | test.c:4:5:4:36 | iltiqzxgfqsgigwfuyntzghvzltueeaZ | iltiqzxgfqsgigwfuyntzghvzltueeaZ | -| test.c:8:5:8:35 | iltiqzxgfqsgigwfuyntzghvzltueee | External identifer iltiqzxgfqsgigwfuyntzghvzltueee is nondistinct in characters at or over 31 limit, compared to $@. | test.c:1:5:1:36 | iltiqzxgfqsgigwfuyntzghvzltueeeA | iltiqzxgfqsgigwfuyntzghvzltueeeA | -| test.c:8:5:8:35 | iltiqzxgfqsgigwfuyntzghvzltueee | External identifer iltiqzxgfqsgigwfuyntzghvzltueee is nondistinct in characters at or over 31 limit, compared to $@. | test.c:2:5:2:36 | iltiqzxgfqsgigwfuyntzghvzltueeeB | iltiqzxgfqsgigwfuyntzghvzltueeeB | +| test.c:2:5:2:36 | iltiqzxgfqsgigwfuyntzghvzltueeeB | test.c:1:5:1:36 | iltiqzxgfqsgigwfuyntzghvzltueeeA | External identifer iltiqzxgfqsgigwfuyntzghvzltueeeB is nondistinct in characters at or over 31 limit, compared to iltiqzxgfqsgigwfuyntzghvzltueeeA | +| test.c:5:5:5:35 | iltiqzxgfqsgigwfuyntzghvzltueea | test.c:4:5:4:36 | iltiqzxgfqsgigwfuyntzghvzltueeaZ | External identifer iltiqzxgfqsgigwfuyntzghvzltueea is nondistinct in characters at or over 31 limit, compared to iltiqzxgfqsgigwfuyntzghvzltueeaZ | +| test.c:8:5:8:35 | iltiqzxgfqsgigwfuyntzghvzltueee | test.c:1:5:1:36 | iltiqzxgfqsgigwfuyntzghvzltueeeA | External identifer iltiqzxgfqsgigwfuyntzghvzltueee is nondistinct in characters at or over 31 limit, compared to iltiqzxgfqsgigwfuyntzghvzltueeeA | +| test.c:8:5:8:35 | iltiqzxgfqsgigwfuyntzghvzltueee | test.c:2:5:2:36 | iltiqzxgfqsgigwfuyntzghvzltueeeB | External identifer iltiqzxgfqsgigwfuyntzghvzltueee is nondistinct in characters at or over 31 limit, compared to iltiqzxgfqsgigwfuyntzghvzltueeeB |