diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 9f4a58d9fb..b7e907a3bc 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -203,6 +203,7 @@ "Const", "DeadCode", "Declarations", + "Declarations1", "Exceptions1", "Exceptions2", "Expressions", diff --git a/c/cert/src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.md b/c/cert/src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.md new file mode 100644 index 0000000000..677e3fcb03 --- /dev/null +++ b/c/cert/src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.md @@ -0,0 +1,160 @@ +# DCL31-C: Declare identifiers before using them + +This query implements the CERT-C rule DCL31-C: + +> Declare identifiers before using them + + +## Description + +The C11 Standard requires type specifiers and forbids implicit function declarations. The C90 Standard allows implicit typing of variables and functions. Consequently, some existing legacy code uses implicit typing. Some C compilers still support legacy code by allowing implicit typing, but it should not be used for new code. Such an [implementation](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation) may choose to assume an implicit declaration and continue translation to support existing programs that used this feature. + +## Noncompliant Code Example (Implicit int) + +C no longer allows the absence of type specifiers in a declaration. The C Standard, 6.7.2 \[ [ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011) \], states + +> At least one type specifier shall be given in the declaration specifiers in each declaration, and in the specifier-qualifier list in each `struct` declaration and type name. + + +This noncompliant code example omits the type specifier: + +```cpp +extern foo; + +``` +Some C [implementations](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation) do not issue a diagnostic for the violation of this constraint. These nonconforming C translators continue to treat such declarations as implying the type `int`. + +## Compliant Solution (Implicit int) + +This compliant solution explicitly includes a type specifier: + +```cpp +extern int foo; + +``` + +## Noncompliant Code Example (Implicit Function Declaration) + +Implicit declaration of functions is not allowed; every function must be explicitly declared before it can be called. In C90, if a function is called without an explicit prototype, the compiler provides an implicit declaration. + +The C90 Standard \[[ISO/IEC 9899:1990](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-1990)\] includes this requirement: + +> If the expression that precedes the parenthesized argument list in a function call consists solely of an identifier, and if no declaration is visible for this identifier, the identifier is implicitly declared exactly as if, in the innermost block containing the function call, the declaration `extern int identifier();` appeared. + + +If a function declaration is not visible at the point at which a call to the function is made, C90-compliant platforms assume an implicit declaration of `extern int identifier();`. + +This declaration implies that the function may take any number and type of arguments and return an `int`. However, to conform to the current C Standard, programmers must explicitly prototype every function before invoking it. An implementation that conforms to the C Standard may or may not perform implicit function declarations, but C does require a conforming implementation to issue a diagnostic if it encounters an undeclared function being used. + +In this noncompliant code example, if `malloc()` is not declared, either explicitly or by including `stdlib.h`, a compiler that conforms only to C90 may implicitly declare `malloc()` as `int malloc()`. If the platform's size of `int` is 32 bits, but the size of pointers is 64 bits, the resulting pointer would likely be truncated as a result of the implicit declaration of `malloc()`, returning a 32-bit integer. + +```cpp +#include +/* #include is missing */ + +int main(void) { + for (size_t i = 0; i < 100; ++i) { + /* int malloc() assumed */ + char *ptr = (char *)malloc(0x10000000); + *ptr = 'a'; + } + return 0; +} +``` +**Implementation Details** + +When compiled with Microsoft Visual Studio 2013 for a 64-bit platform, this noncompliant code example will eventually cause an access violation when dereferencing `ptr` in the loop. + +## Compliant Solution (Implicit Function Declaration) + +This compliant solution declares `malloc()` by including the appropriate header file: + +```cpp +#include + +int main(void) { + for (size_t i = 0; i < 100; ++i) { + char *ptr = (char *)malloc(0x10000000); + *ptr = 'a'; + } + return 0; +} +``` +For more information on function declarations, see [DCL07-C. Include the appropriate type information in function declarators](https://wiki.sei.cmu.edu/confluence/display/c/DCL07-C.+Include+the+appropriate+type+information+in+function+declarators). + +## Noncompliant Code Example (Implicit Return Type) + +Do not declare a function with an implicit return type. For example, if a function returns a meaningful integer value, declare it as returning `int`. If it returns no meaningful value, declare it as returning `void`. + +```cpp +#include +#include + +foo(void) { + return UINT_MAX; +} + +int main(void) { + long long int c = foo(); + printf("%lld\n", c); + return 0; +} + +``` +Because the compiler assumes that `foo()` returns a value of type `int` for this noncompliant code example, `UINT_MAX` is incorrectly converted to `−1`. + +## Compliant Solution (Implicit Return Type) + +This compliant solution explicitly defines the return type of `foo()` as `unsigned int`. As a result, the function correctly returns ` `UINT_MAX` `. + +```cpp +#include +#include + +unsigned int foo(void) { + return UINT_MAX; +} + +int main(void) { + long long int c = foo(); + printf("%lld\n", c); + return 0; +} + +``` + +## Risk Assessment + +Because implicit declarations lead to less stringent type checking, they can introduce [unexpected](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-unexpectedbehavior) and erroneous behavior. Occurrences of an omitted type specifier in existing code are rare, and the consequences are generally minor, perhaps resulting in [abnormal program termination](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-abnormaltermination). + +
Rule Severity Likelihood Remediation Cost Priority Level
DCL31-C Low Unlikely Low P3 L3
+ + +## Automated Detection + +
Tool Version Checker Description
Astrée 22.04 type-specifier function-return-type implicit-function-declaration undeclared-parameter Fully checked
Axivion Bauhaus Suite 7.2.0 CertC-DCL31 Fully implemented
Clang 3.9 -Wimplicit-int
Compass/ROSE
Coverity 2017.07 MISRA C 2012 Rule 8.1 Implemented
ECLAIR 1.2 CC2.DCL31 Fully implemented
GCC 4.3.5 Can detect violations of this rule when the -Wimplicit and -Wreturn-type flags are used
Helix QAC 2022.2 C0434, C2050, C2051, C3335
Klocwork 2022.2 CWARN.IMPLICITINT MISRA.DECL.NO_TYPE MISRA.FUNC.NOPROT.CALL RETVOID.IMPLICIT
LDRA tool suite 9.7.1 24 D, 41 D, 20 S, 326 S, 496 S Fully implemented
Parasoft C/C++test 2022.1 CERT_C-DCL31-a All functions shall be declared before use
PC-lint Plus 1.4 601, 718, 746, 808 Fully supported
Polyspace Bug Finder R2022a CERT C: Rule DCL31-C Checks for: Types not explicitly specifiedypes not explicitly specified, implicit function declarationmplicit function declaration. Rule fully covered.
PRQA QA-C 9.7 0434 (C)205020513335 Fully implemented
PVS-Studio 7.20 V1031
SonarQube C/C++ Plugin 3.11 S819, S820 Partially implemented; implicit return type not covered.
RuleChecker 22.04 type-specifier function-return-type implicit-function-declaration undeclared-parameter Fully checked
TrustInSoft Analyzer 1.38 type specifier missing Partially verified (exhaustively detects undefined behavior).
+ + +## 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+DCL31-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
CERT C Secure Coding Standard DCL07-C. Include the appropriate type information in function declarators Prior to 2018-01-12: CERT: Unspecified Relationship
ISO/IEC TR 24772:2013 Subprogram Signature Mismatch \[OTR\] Prior to 2018-01-12: CERT: Unspecified Relationship
MISRA C:2012 Rule 8.1 (required) Prior to 2018-01-12: CERT: Unspecified Relationship
+ + +## Bibliography + +
\[ ISO/IEC 9899:1990 \]
\[ ISO/IEC 9899:2011 \] Subclause 6.7.2, "Type Specifiers"
\[ Jones 2008 \]
+ + +## Implementation notes + +This query does not check for implicit function declarations as this is partially compiler checked. + +## References + +* CERT-C: [DCL31-C: Declare identifiers before using them](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.ql b/c/cert/src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.ql new file mode 100644 index 0000000000..0d2e241957 --- /dev/null +++ b/c/cert/src/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.ql @@ -0,0 +1,28 @@ +/** + * @id c/cert/declare-identifiers-before-using-them + * @name DCL31-C: Declare identifiers before using them + * @description Omission of type specifiers may not be supported by some compilers. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/cert/id/dcl31-c + * correctness + * readability + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert + +from Declaration d +where + not isExcluded(d, Declarations1Package::declareIdentifiersBeforeUsingThemQuery()) and + d.hasSpecifier("implicit_int") and + exists(Type t | + (d.(Variable).getType() = t or d.(Function).getType() = t) and + // Exclude "short" or "long", as opposed to "short int" or "long int". + t instanceof IntType and + // Exclude "signed" or "unsigned", as opposed to "signed int" or "unsigned int". + not exists(IntegralType it | it = t | it.isExplicitlySigned() or it.isExplicitlyUnsigned()) + ) +select d, "Declaration " + d.getName() + " is missing a type specifier." diff --git a/c/cert/src/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.md b/c/cert/src/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.md new file mode 100644 index 0000000000..bdf9294d23 --- /dev/null +++ b/c/cert/src/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.md @@ -0,0 +1,286 @@ +# DCL37-C: Do not declare or define a reserved identifier + +This query implements the CERT-C rule DCL37-C: + +> Do not declare or define a reserved identifier + + +## Description + +According to the C Standard, 7.1.3 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], + +> All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use. + + +All identifiers that begin with an underscore are always reserved for use as identifiers with file scope in both the ordinary and tag name spaces. + +Each macro name in any of the following subclauses (including the future library directions) is reserved for use as specified if any of its associated headers is included, unless explicitly stated otherwise. + +All identifiers with external linkage (including future library directions) and `errno` are always reserved for use as identifiers with external linkage. + +Each identifier with file scope listed in any of the following subclauses (including the future library directions) is reserved for use as a macro name and as an identifier with file scope in the same name space if any of its associated headers is included. + +Additionally, subclause 7.31 defines many other reserved identifiers for future library directions. + +No other identifiers are reserved. (The POSIX standard extends the set of identifiers reserved by the C Standard to include an open-ended set of its own. See *Portable Operating System Interface \[POSIX®\], Base Specifications, Issue 7*, [Section 2.2](http://www.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html#tag_15_02), "The Compilation Environment" \[[IEEE Std 1003.1-2013](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-IEEEStd1003.1-2013)\].) The behavior of a program that declares or defines an identifier in a context in which it is reserved or that defines a reserved identifier as a macro name is undefined. (See [undefined behavior 106](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_106).) + +## Noncompliant Code Example (Include Guard) + +A common, but noncompliant, practice is to choose a reserved name for a macro used in a preprocessor conditional guarding against multiple inclusions of a header file. (See also [PRE06-C. Enclose header files in an include guard](https://wiki.sei.cmu.edu/confluence/display/c/PRE06-C.+Enclose+header+files+in+an+include+guard).) The name may clash with reserved names defined by the implementation of the C standard library in its headers or with reserved names implicitly predefined by the compiler even when no C standard library header is included. + +```cpp +#ifndef _MY_HEADER_H_ +#define _MY_HEADER_H_ + +/* Contents of */ + +#endif /* _MY_HEADER_H_ */ + +``` + +## Compliant Solution (Include Guard) + +This compliant solution avoids using leading underscores in the macro name of the include guard: + +```cpp +#ifndef MY_HEADER_H +#define MY_HEADER_H + +/* Contents of */ + +#endif /* MY_HEADER_H */ + +``` + +## Noncompliant Code Example (File Scope Objects) + +In this noncompliant code example, the names of the file scope objects `_max_limit` and `_limit` both begin with an underscore. Because `_max_limit` is static, this declaration might seem to be impervious to clashes with names defined by the implementation. However, because the header `` is included to define `size_t`, a potential for a name clash exists. (Note, however, that a [conforming](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-conformingprogram) compiler may implicitly declare reserved names regardless of whether any C standard library header is explicitly included.) + +In addition, because `_limit` has external linkage, it may clash with a symbol of the same name defined in the language runtime library even if such a symbol is not declared in any header. Consequently, it is not safe to start the name of any file scope identifier with an underscore even if its linkage limits its visibility to a single translation unit. + +```cpp +#include + +static const size_t _max_limit = 1024; +size_t _limit = 100; + +unsigned int getValue(unsigned int count) { + return count < _limit ? count : _limit; +} + +``` + +## Compliant Solution (File Scope Objects) + +In this compliant solution, names of file scope objects do not begin with an underscore: + +```cpp +#include + +static const size_t max_limit = 1024; +size_t limit = 100; + +unsigned int getValue(unsigned int count) { + return count < limit ? count : limit; +} + +``` + +## Noncompliant Code Example (Reserved Macros) + +In this noncompliant code example, because the C standard library header `` is specified to include ``, the name `SIZE_MAX` conflicts with a standard macro of the same name, which is used to denote the upper limit of `size_t`. In addition, although the name `INTFAST16_LIMIT_MAX` is not defined by the C standard library, it is a reserved identifier because it begins with the `INT` prefix and ends with the `_MAX` suffix. (See the C Standard, 7.31.10.) + +```cpp +#include +#include + +static const int_fast16_t INTFAST16_LIMIT_MAX = 12000; + +void print_fast16(int_fast16_t val) { + enum { SIZE_MAX = 80 }; + char buf[SIZE_MAX]; + if (INTFAST16_LIMIT_MAX < val) { + sprintf(buf, "The value is too large"); + } else { + snprintf(buf, SIZE_MAX, "The value is %" PRIdFAST16, val); + } +} + +``` + +## Compliant Solution (Reserved Macros) + +This compliant solution avoids redefining reserved names or using reserved prefixes and suffixes: + +```cpp +#include +#include + +static const int_fast16_t MY_INTFAST16_UPPER_LIMIT = 12000; + +void print_fast16(int_fast16_t val) { + enum { BUFSIZE = 80 }; + char buf[BUFSIZE]; + if (MY_INTFAST16_UPPER_LIMIT < val) { + sprintf(buf, "The value is too large"); + } else { + snprintf(buf, BUFSIZE, "The value is %" PRIdFAST16, val); + } +} + +``` + +## Noncompliant Code Example (Identifiers with External Linkage) + +This noncompliant example provides definitions for the C standard library functions `malloc()` and `free()`. Although this practice is permitted by many traditional implementations of UNIX (for example, the [Dmalloc ](http://dmalloc.com/) library), it is [undefined behavior](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) according to the C Standard. Even on systems that allow replacing `malloc()`, doing so without also replacing `aligned_alloc()`, `calloc()`, and `realloc()` is likely to cause problems. + +```cpp +#include + +void *malloc(size_t nbytes) { + void *ptr; + /* Allocate storage from own pool and set ptr */ + return ptr; +} + +void free(void *ptr) { + /* Return storage to own pool */ +} + +``` + +## Compliant Solution (Identifiers with External Linkage) + +The compliant, portable solution avoids redefining any C standard library identifiers with external linkage. In addition, it provides definitions for all memory allocation functions: + +```cpp +#include + +void *my_malloc(size_t nbytes) { + void *ptr; + /* Allocate storage from own pool and set ptr */ + return ptr; +} + +void *my_aligned_alloc(size_t alignment, size_t size) { + void *ptr; + /* Allocate storage from own pool, align properly, set ptr */ + return ptr; +} + +void *my_calloc(size_t nelems, size_t elsize) { + void *ptr; + /* Allocate storage from own pool, zero memory, and set ptr */ + return ptr; +} + +void *my_realloc(void *ptr, size_t nbytes) { + /* Reallocate storage from own pool and set ptr */ + return ptr; +} + +void my_free(void *ptr) { + /* Return storage to own pool */ +} + +``` + +## Noncompliant Code Example (errno) + +In addition to symbols defined as functions in each C standard library header, identifiers with external linkage include `errno` and `math_errhandling`. According to the C Standard, 7.5, paragraph 2 \[[ISO/IEC 9899:2011](https://wiki.sei.cmu.edu/confluence/display/c/AA.+Bibliography#AA.Bibliography-ISO-IEC9899-2011)\], the behavior of a program is [undefined](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior) when + +> A macro definition of `errno` is suppressed in order to access an actual object, or the program defines an identifier with the name `errno`. + + +See [undefined behavior 114](https://wiki.sei.cmu.edu/confluence/display/c/CC.+Undefined+Behavior#CC.UndefinedBehavior-ub_114). + +The `errno` identifier expands to a modifiable [lvalue](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-lvalue) that has type `int` but is not necessarily the identifier of an object. It might expand to a modifiable lvalue resulting from a function call, such as `*errno()`. It is unspecified whether `errno` is a macro or an identifier declared with external linkage. If a macro definition is suppressed to access an actual object, or if a program defines an identifier with the name `errno`, the behavior is [undefined](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-undefinedbehavior). + +Legacy code is apt to include an incorrect declaration, such as the following: + +```cpp +extern int errno; + +``` + +## Compliant Solution (errno) + +The correct way to declare `errno` is to include the header ``: + +```cpp +#include + +``` +[Implementations](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-implementation) [conforming](https://wiki.sei.cmu.edu/confluence/display/c/BB.+Definitions#BB.Definitions-conformingprogram) to C are required to declare `errno` in ``, although some historic implementations failed to do so. + +## Exceptions + +**DCL37-C-EX1:** Provided that a library function can be declared without reference to any type defined in a header, it is permissible to declare that function without including its header provided that declaration is compatible with the standard declaration. + +```cpp +/* Not including stdlib.h */ +void free(void *); + +void func(void *ptr) { + free(ptr); +} +``` +Such code is compliant because the declaration matches what `stdlib.h` would provide and does not redefine the reserved identifier. However, it would not be acceptable to provide a definition for the `free()` function in this example. + +**DCL37-C-EX2:** For compatibility with other compiler vendors or language standard modes, it is acceptable to create a macro identifier that is the same as a reserved identifier so long as the behavior is idempotent, as in this example: + +```cpp +/* Sometimes generated by configuration tools such as autoconf */ +#define const const + +/* Allowed compilers with semantically equivalent extension behavior */ +#define inline __inline +``` +**DCL37-C-EX3:** As a compiler vendor or standard library developer, it is acceptable to use identifiers reserved for your implementation. Reserved identifiers may be defined by the compiler, in standard library headers or headers included by a standard library header, as in this example declaration from the glibc standard C library implementation: + +```cpp +/* + The following declarations of reserved identifiers exist in the glibc implementation of + . The original source code may be found at: + https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=include/stdio.h;hb=HEAD +*/ + +# define __need_size_t +# include +/* Generate a unique file name (and possibly open it). */ +extern int __path_search (char *__tmpl, size_t __tmpl_len, + const char *__dir, const char *__pfx, + int __try_tempdir); +``` + +## Risk Assessment + +Using reserved identifiers can lead to incorrect program operation. + +
Rule Severity Likelihood Remediation Cost Priority Level
DCL37-C Low Unlikely Low P3 L3
+ + +## Automated Detection + +
Tool Version Checker Description
Astrée 22.04 future-library-use language-override language-override-c99 reserved-declaration reserved-declaration-c99 reserved-identifier Partially checked
Axivion Bauhaus Suite 7.2.0 CertC-DCL37 Fully implemented. Reserved identifiers, as in DCL37-C-EX3 , are configurable.
CodeSonar 7.0p0 LANG.STRUCT.DECL.RESERVED Declaration of reserved name
Compass/ROSE
Coverity 2017.07 MISRA C 2004 Rule 20.1 MISRA C 2004 Rule 20.2 MISRA C 2012 Rule 21.1 MISRA C 2012 Rule 21.2 Implemented
ECLAIR 1.2 CC2.DCL37 Fully implemented
Helix QAC 2022.2 C0602, C0603, C4600, C4601, C4602, C4603, C4604, C4605, C4606, C4607, C4608, C4620, C4621, C4622, C4623, C4624, C4640, C4641, C4642, C4643, C4644, C4645
Klocwork 2022.2 MISRA.DEFINE.WRONGNAME.UNDERSCORE MISRA.STDLIB.WRONGNAME.UNDERSCORE MISRA.STDLIB.WRONGNAME
LDRA tool suite 9.7.1 86 S, 218 S, 219 S, 580 S, 626 S Fully Implemented
Parasoft C/C++test 2022.1 CERT_C-DCL37-a Do not \#define or \#undef identifiers with names which start with underscore
PC-lint Plus 1.4 978, 9071, 9093 Partially supported
Polyspace Bug Finder R2022a CERT C: Rule DCL37-C Checks for: Defining and undefining reserved identifiers or macrosefining and undefining reserved identifiers or macros, declaring a reserved identifier or macro nameeclaring a reserved identifier or macro name. Rule partially covered
PRQA QA-C 9.7 0602, 0603, 4600, 4601, 4602, 4603, 4604, 4605, 4606, 4607, 4608, 4620, 4621, 4622, 4623, 4624, 4640, 4641, 4642, 4643, 4644, 4645
PVS-Studio 7.19 V677
SonarQube C/C++ Plugin 3.11 S978
RuleChecker 22.04 future-library-use language-override language-override-c99 reserved-declaration reserved-declaration-c99 reserved-identifier Partially checked
+ + +## 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
CERT C Secure Coding Standard PRE00-C. Prefer inline or static functions to function-like macros Prior to 2018-01-12: CERT: Unspecified Relationship
CERT C Secure Coding Standard PRE06-C. Enclose header files in an include guard Prior to 2018-01-12: CERT: Unspecified Relationship
CERT C Secure Coding Standard PRE31-C. Avoid side effects in arguments to unsafe macros Prior to 2018-01-12: CERT: Unspecified Relationship
CERT C DCL51-CPP. Do not declare or define a reserved identifier Prior to 2018-01-12: CERT: Unspecified Relationship
ISO/IEC TS 17961 Using identifiers that are reserved for the implementation \[resident\] Prior to 2018-01-12: CERT: Unspecified Relationship
MISRA C:2012 Rule 21.1 (required) Prior to 2018-01-12: CERT: Unspecified Relationship
MISRA C:2012 Rule 21.2 (required) Prior to 2018-01-12: CERT: Unspecified Relationship
+ + +## Bibliography + +
\[ IEEE Std 1003.1-2013 \] Section 2.2, "The Compilation Environment"
\[ ISO/IEC 9899:2011 \] 7.1.3, "Reserved Identifiers" 7.31.10, "Integer Types <stdint.h> "
+ + +## Implementation notes + +This query does not consider identifiers described in the future library directions section of the standard. This query also checks for any reserved identifier as declared regardless of whether its header file is included or not. + +## References + +* CERT-C: [DCL37-C: Do not declare or define a reserved identifier](https://wiki.sei.cmu.edu/confluence/display/c) diff --git a/c/cert/src/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.ql b/c/cert/src/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.ql new file mode 100644 index 0000000000..99c5a9708b --- /dev/null +++ b/c/cert/src/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.ql @@ -0,0 +1,23 @@ +/** + * @id c/cert/do-not-declare-or-define-a-reserved-identifier + * @name DCL37-C: Do not declare or define a reserved identifier + * @description Declaring a reserved identifier can lead to undefined behaviour. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/cert/id/dcl37-c + * correctness + * maintainability + * readability + * external/cert/obligation/rule + */ + +import cpp +import codingstandards.c.cert +import codingstandards.cpp.rules.declaredareservedidentifier.DeclaredAReservedIdentifier + +class DoNotDeclareAReservedIdentifierQuery extends DeclaredAReservedIdentifierSharedQuery { + DoNotDeclareAReservedIdentifierQuery() { + this = Declarations1Package::doNotDeclareOrDefineAReservedIdentifierQuery() + } +} diff --git a/c/cert/test/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.expected b/c/cert/test/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.expected new file mode 100644 index 0000000000..b10efab02c --- /dev/null +++ b/c/cert/test/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.expected @@ -0,0 +1,2 @@ +| test.c:1:8:1:8 | g | Declaration g is missing a type specifier. | +| test.c:5:1:5:1 | f | Declaration f is missing a type specifier. | diff --git a/c/cert/test/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.qlref b/c/cert/test/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.qlref new file mode 100644 index 0000000000..f51571a4fe --- /dev/null +++ b/c/cert/test/rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.qlref @@ -0,0 +1 @@ +rules/DCL31-C/DeclareIdentifiersBeforeUsingThem.ql \ No newline at end of file diff --git a/c/cert/test/rules/DCL31-C/test.c b/c/cert/test/rules/DCL31-C/test.c new file mode 100644 index 0000000000..7442adb246 --- /dev/null +++ b/c/cert/test/rules/DCL31-C/test.c @@ -0,0 +1,15 @@ +extern g; // NON_COMPLIANT + +extern int g1; // COMPLIANT + +f(void) { // NON_COMPLIANT + return 1; +} + +int f1(void) { // COMPLIANT + return 1; +} + +short g2; // COMPLIANT +long g3; // COMPLIANT +signed g4() { return 1; } // COMPLIANT diff --git a/c/cert/test/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.testref b/c/cert/test/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.testref new file mode 100644 index 0000000000..32b1b02bf4 --- /dev/null +++ b/c/cert/test/rules/DCL37-C/DoNotDeclareOrDefineAReservedIdentifier.testref @@ -0,0 +1 @@ +c/common/test/rules/declaredareservedidentifier/DeclaredAReservedIdentifier.ql \ No newline at end of file diff --git a/c/common/test/rules/declaredareservedidentifier/DeclaredAReservedIdentifier.expected b/c/common/test/rules/declaredareservedidentifier/DeclaredAReservedIdentifier.expected new file mode 100644 index 0000000000..08e1688eb1 --- /dev/null +++ b/c/common/test/rules/declaredareservedidentifier/DeclaredAReservedIdentifier.expected @@ -0,0 +1,6 @@ +| file://:0:0:0:0 | __va_list_tag | Reserved identifier '__va_list_tag' is declared. | +| test.c:2:1:2:23 | #define _RESERVED_MACRO | Reserved identifier '_RESERVED_MACRO' is declared. | +| test.c:11:8:11:9 | _s | Reserved identifier '_s' is declared. | +| test.c:15:6:15:7 | _f | Reserved identifier '_f' is declared. | +| test.c:19:7:19:12 | malloc | Reserved identifier 'malloc' is declared. | +| test.c:24:12:24:16 | errno | Reserved identifier 'errno' is declared. | diff --git a/c/common/test/rules/declaredareservedidentifier/DeclaredAReservedIdentifier.ql b/c/common/test/rules/declaredareservedidentifier/DeclaredAReservedIdentifier.ql new file mode 100644 index 0000000000..c53a7c44b2 --- /dev/null +++ b/c/common/test/rules/declaredareservedidentifier/DeclaredAReservedIdentifier.ql @@ -0,0 +1,2 @@ +// GENERATED FILE - DO NOT MODIFY +import codingstandards.cpp.rules.declaredareservedidentifier.DeclaredAReservedIdentifier diff --git a/c/common/test/rules/declaredareservedidentifier/test.c b/c/common/test/rules/declaredareservedidentifier/test.c new file mode 100644 index 0000000000..1580dfc6d7 --- /dev/null +++ b/c/common/test/rules/declaredareservedidentifier/test.c @@ -0,0 +1,24 @@ +#ifndef _RESERVED_MACRO +#define _RESERVED_MACRO // NON_COMPLIANT +#endif /* _RESERVED_MACRO */ + +#ifndef _not_reserved_MACRO +#define _not_reserved_MACRO // COMPLIANT +#endif /* _not_reserved_MACRO */ + +static const int INT_LIMIT_MAX = 12000; // COMPLIANT future library directions + +struct _s { // NON_COMPLIANT + struct _s *_next; // COMPLIANT not file scope +}; + +void _f() { // NON_COMPLIANT + int _p; // COMPLIANT not file scope +} + +void *malloc(int bytes) { // NON_COMPLIANT + void *ptr; + return ptr; +} + +extern int errno; // NON_COMPLIANT \ No newline at end of file diff --git a/c/misra/src/rules/RULE-20-4/MacroDefinedWithTheSameNameAsKeyword.ql b/c/misra/src/rules/RULE-20-4/MacroDefinedWithTheSameNameAsKeyword.ql index 5ec14f4df1..6b9ae71120 100644 --- a/c/misra/src/rules/RULE-20-4/MacroDefinedWithTheSameNameAsKeyword.ql +++ b/c/misra/src/rules/RULE-20-4/MacroDefinedWithTheSameNameAsKeyword.ql @@ -16,7 +16,7 @@ import cpp import codingstandards.c.misra -import codingstandards.c.Keywords +import codingstandards.cpp.CKeywords from Macro m, string name where diff --git a/c/misra/src/rules/RULE-21-2/DoNotDeclareAReservedIdentifier.ql b/c/misra/src/rules/RULE-21-2/DoNotDeclareAReservedIdentifier.ql new file mode 100644 index 0000000000..89140222da --- /dev/null +++ b/c/misra/src/rules/RULE-21-2/DoNotDeclareAReservedIdentifier.ql @@ -0,0 +1,23 @@ +/** + * @id c/misra/do-not-declare-a-reserved-identifier + * @name RULE-21-2: A reserved identifier or reserved macro name shall not be declared + * @description Declaring a reserved identifier can lead to undefined behaviour. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-21-2 + * correctness + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.rules.declaredareservedidentifier.DeclaredAReservedIdentifier + +class DoNotDeclareAReservedIdentifierQuery extends DeclaredAReservedIdentifierSharedQuery { + DoNotDeclareAReservedIdentifierQuery() { + this = Declarations1Package::doNotDeclareAReservedIdentifierQuery() + } +} diff --git a/c/misra/src/rules/RULE-5-1/ExternalIdentifiersNotDistinct.ql b/c/misra/src/rules/RULE-5-1/ExternalIdentifiersNotDistinct.ql new file mode 100644 index 0000000000..9dac244b3a --- /dev/null +++ b/c/misra/src/rules/RULE-5-1/ExternalIdentifiersNotDistinct.ql @@ -0,0 +1,49 @@ +/** + * @id c/misra/external-identifiers-not-distinct + * @name RULE-5-1: External identifiers shall be distinct + * @description Using nondistinct external identifiers results in undefined behaviour. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-5-1 + * correctness + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +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) + } +} + +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() diff --git a/c/misra/src/rules/RULE-5-4/MacroIdentifierNotDistinctFromParameter.ql b/c/misra/src/rules/RULE-5-4/MacroIdentifierNotDistinctFromParameter.ql new file mode 100644 index 0000000000..886e05f0ea --- /dev/null +++ b/c/misra/src/rules/RULE-5-4/MacroIdentifierNotDistinctFromParameter.ql @@ -0,0 +1,22 @@ +/** + * @id c/misra/macro-identifier-not-distinct-from-parameter + * @name RULE-5-4: Macro identifiers shall be distinct from paramters + * @description Macros with the same name as their parameters are less readable. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-5-4 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.cpp.FunctionLikeMacro + +from FunctionLikeMacro m +where + not isExcluded(m, Declarations1Package::macroIdentifierNotDistinctFromParameterQuery()) and + exists(string p | p = m.(FunctionLikeMacro).getAParameter() and p = m.getName()) +select m, "Macro name matches parameter " + m.getName() + " ." diff --git a/c/misra/src/rules/RULE-5-4/MacroIdentifiersNotDistinct.ql b/c/misra/src/rules/RULE-5-4/MacroIdentifiersNotDistinct.ql new file mode 100644 index 0000000000..1dd0fe196e --- /dev/null +++ b/c/misra/src/rules/RULE-5-4/MacroIdentifiersNotDistinct.ql @@ -0,0 +1,33 @@ +/** + * @id c/misra/macro-identifiers-not-distinct + * @name RULE-5-4: Macro identifiers shall be distinct + * @description Declaring multiple macros with the same name leads to undefined behaviour. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-5-4 + * correctness + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra + +from Macro m, Macro m2 +where + not isExcluded(m, Declarations1Package::macroIdentifiersNotDistinctQuery()) and + not m = m2 and + ( + //C99 states the first 63 characters of macro identifiers are significant + //C90 states the first 31 characters of macro identifiers are significant and is not currently considered by this rule + //ie an identifier differing on the 32nd character would be indistinct for C90 but distinct for C99 + //and is currently not reported by this rule + if m.getName().length() >= 64 + then m.getName().prefix(63) = m2.getName().prefix(63) + else m.getName() = m2.getName() + ) and + //reduce double report since both macros are in alert, arbitrary ordering + m.getLocation().getStartLine() >= m2.getLocation().getStartLine() +select m, "Macro identifer " + m.getName() + " is nondistinct in first 63 characters, compared to $@.", m2, m2.getName() diff --git a/c/misra/test/rules/RULE-21-2/DoNotDeclareAReservedIdentifier.testref b/c/misra/test/rules/RULE-21-2/DoNotDeclareAReservedIdentifier.testref new file mode 100644 index 0000000000..32b1b02bf4 --- /dev/null +++ b/c/misra/test/rules/RULE-21-2/DoNotDeclareAReservedIdentifier.testref @@ -0,0 +1 @@ +c/common/test/rules/declaredareservedidentifier/DeclaredAReservedIdentifier.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.expected b/c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.expected new file mode 100644 index 0000000000..1e7d80876e --- /dev/null +++ b/c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.expected @@ -0,0 +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 | diff --git a/c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.qlref b/c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.qlref new file mode 100644 index 0000000000..965e5c3298 --- /dev/null +++ b/c/misra/test/rules/RULE-5-1/ExternalIdentifiersNotDistinct.qlref @@ -0,0 +1 @@ +rules/RULE-5-1/ExternalIdentifiersNotDistinct.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-5-1/test.c b/c/misra/test/rules/RULE-5-1/test.c new file mode 100644 index 0000000000..b0e2be532d --- /dev/null +++ b/c/misra/test/rules/RULE-5-1/test.c @@ -0,0 +1,14 @@ +int iltiqzxgfqsgigwfuyntzghvzltueeeA; // NON_COMPLIANT - length 32 +int iltiqzxgfqsgigwfuyntzghvzltueeeB; // NON_COMPLIANT + +int iltiqzxgfqsgigwfuyntzghvzltueeaZ; // NON_COMPLIANT - length 32 +int iltiqzxgfqsgigwfuyntzghvzltueea; // NON_COMPLIANT - length 31 + +int iltiqzxgfqsgigwfuyntzghvzltueee; // NON_COMPLIANT - length 31 +int iltiqzxgfqsgigwfuyntzghvzltueee; // NON_COMPLIANT + +int iltiqzxgfqsgigwfuyntzghvzltuee; // COMPLIANT - length 30 +int iltiqzxgfqsgigwfuyntzghvzltuee; // COMPLIANT + +int var1; // COMPLIANT +int var2; // COMPLIANT \ No newline at end of file diff --git a/c/misra/test/rules/RULE-5-4/MacroIdentifierNotDistinctFromParameter.expected b/c/misra/test/rules/RULE-5-4/MacroIdentifierNotDistinctFromParameter.expected new file mode 100644 index 0000000000..df55a62ed3 --- /dev/null +++ b/c/misra/test/rules/RULE-5-4/MacroIdentifierNotDistinctFromParameter.expected @@ -0,0 +1 @@ +| test.c:7:1:7:57 | #define FUNCTION_MACRO(FUNCTION_MACRO) FUNCTION_MACRO + 1 | Macro name matches parameter FUNCTION_MACRO . | diff --git a/c/misra/test/rules/RULE-5-4/MacroIdentifierNotDistinctFromParameter.qlref b/c/misra/test/rules/RULE-5-4/MacroIdentifierNotDistinctFromParameter.qlref new file mode 100644 index 0000000000..961df59e11 --- /dev/null +++ b/c/misra/test/rules/RULE-5-4/MacroIdentifierNotDistinctFromParameter.qlref @@ -0,0 +1 @@ +rules/RULE-5-4/MacroIdentifierNotDistinctFromParameter.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-5-4/MacroIdentifiersNotDistinct.expected b/c/misra/test/rules/RULE-5-4/MacroIdentifiersNotDistinct.expected new file mode 100644 index 0000000000..12507b2d3f --- /dev/null +++ b/c/misra/test/rules/RULE-5-4/MacroIdentifiersNotDistinct.expected @@ -0,0 +1,2 @@ +| test.c:2:1:2:72 | #define iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyB | Macro identifer iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyB is nondistinct in first 63 characters, compared to $@. | test.c:1:1:1:72 | #define iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyA | iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyA | +| test.c:8:1:8:31 | #define FUNCTION_MACRO(X) X + 1 | Macro identifer FUNCTION_MACRO is nondistinct in first 63 characters, compared to $@. | test.c:7:1:7:57 | #define FUNCTION_MACRO(FUNCTION_MACRO) FUNCTION_MACRO + 1 | FUNCTION_MACRO | diff --git a/c/misra/test/rules/RULE-5-4/MacroIdentifiersNotDistinct.qlref b/c/misra/test/rules/RULE-5-4/MacroIdentifiersNotDistinct.qlref new file mode 100644 index 0000000000..76762609f3 --- /dev/null +++ b/c/misra/test/rules/RULE-5-4/MacroIdentifiersNotDistinct.qlref @@ -0,0 +1 @@ +rules/RULE-5-4/MacroIdentifiersNotDistinct.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-5-4/test.c b/c/misra/test/rules/RULE-5-4/test.c new file mode 100644 index 0000000000..3ff498a2e7 --- /dev/null +++ b/c/misra/test/rules/RULE-5-4/test.c @@ -0,0 +1,9 @@ +#define iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyA // NON_COMPLIANT +#define iltiqzxgfqsgigwfuyntzghvzltueatcxqnqofnnvjyszmcsylyohvqaosjbqyyB // NON_COMPLIANT + +#define MACRO1 // COMPLIANT +#define MACRO2 // COMPLIANT + +#define FUNCTION_MACRO(FUNCTION_MACRO) FUNCTION_MACRO + 1 // NON_COMPLIANT +#define FUNCTION_MACRO(X) X + 1 // NON_COMPLIANT +#define FUNCTION_MACRO2(X) X + 1 // COMPLIANT \ No newline at end of file diff --git a/c/common/src/codingstandards/c/Keywords.qll b/cpp/common/src/codingstandards/cpp/CKeywords.qll similarity index 100% rename from c/common/src/codingstandards/c/Keywords.qll rename to cpp/common/src/codingstandards/cpp/CKeywords.qll diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations1.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations1.qll new file mode 100644 index 0000000000..c52cd567c8 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Declarations1.qll @@ -0,0 +1,106 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Declarations1Query = + TDeclareIdentifiersBeforeUsingThemQuery() or + TDoNotDeclareOrDefineAReservedIdentifierQuery() or + TDoNotDeclareAReservedIdentifierQuery() or + TExternalIdentifiersNotDistinctQuery() or + TMacroIdentifiersNotDistinctQuery() or + TMacroIdentifierNotDistinctFromParameterQuery() + +predicate isDeclarations1QueryMetadata(Query query, string queryId, string ruleId) { + query = + // `Query` instance for the `declareIdentifiersBeforeUsingThem` query + Declarations1Package::declareIdentifiersBeforeUsingThemQuery() and + queryId = + // `@id` for the `declareIdentifiersBeforeUsingThem` query + "c/cert/declare-identifiers-before-using-them" and + ruleId = "DCL31-C" + or + query = + // `Query` instance for the `doNotDeclareOrDefineAReservedIdentifier` query + Declarations1Package::doNotDeclareOrDefineAReservedIdentifierQuery() and + queryId = + // `@id` for the `doNotDeclareOrDefineAReservedIdentifier` query + "c/cert/do-not-declare-or-define-a-reserved-identifier" and + ruleId = "DCL37-C" + or + query = + // `Query` instance for the `doNotDeclareAReservedIdentifier` query + Declarations1Package::doNotDeclareAReservedIdentifierQuery() and + queryId = + // `@id` for the `doNotDeclareAReservedIdentifier` query + "c/misra/do-not-declare-a-reserved-identifier" and + ruleId = "RULE-21-2" + or + query = + // `Query` instance for the `externalIdentifiersNotDistinct` query + Declarations1Package::externalIdentifiersNotDistinctQuery() and + queryId = + // `@id` for the `externalIdentifiersNotDistinct` query + "c/misra/external-identifiers-not-distinct" and + ruleId = "RULE-5-1" + or + query = + // `Query` instance for the `macroIdentifiersNotDistinct` query + Declarations1Package::macroIdentifiersNotDistinctQuery() and + queryId = + // `@id` for the `macroIdentifiersNotDistinct` query + "c/misra/macro-identifiers-not-distinct" and + ruleId = "RULE-5-4" + or + query = + // `Query` instance for the `macroIdentifierNotDistinctFromParameter` query + Declarations1Package::macroIdentifierNotDistinctFromParameterQuery() and + queryId = + // `@id` for the `macroIdentifierNotDistinctFromParameter` query + "c/misra/macro-identifier-not-distinct-from-parameter" and + ruleId = "RULE-5-4" +} + +module Declarations1Package { + Query declareIdentifiersBeforeUsingThemQuery() { + //autogenerate `Query` type + result = + // `Query` type for `declareIdentifiersBeforeUsingThem` query + TQueryC(TDeclarations1PackageQuery(TDeclareIdentifiersBeforeUsingThemQuery())) + } + + Query doNotDeclareOrDefineAReservedIdentifierQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotDeclareOrDefineAReservedIdentifier` query + TQueryC(TDeclarations1PackageQuery(TDoNotDeclareOrDefineAReservedIdentifierQuery())) + } + + Query doNotDeclareAReservedIdentifierQuery() { + //autogenerate `Query` type + result = + // `Query` type for `doNotDeclareAReservedIdentifier` query + TQueryC(TDeclarations1PackageQuery(TDoNotDeclareAReservedIdentifierQuery())) + } + + Query externalIdentifiersNotDistinctQuery() { + //autogenerate `Query` type + result = + // `Query` type for `externalIdentifiersNotDistinct` query + TQueryC(TDeclarations1PackageQuery(TExternalIdentifiersNotDistinctQuery())) + } + + Query macroIdentifiersNotDistinctQuery() { + //autogenerate `Query` type + result = + // `Query` type for `macroIdentifiersNotDistinct` query + TQueryC(TDeclarations1PackageQuery(TMacroIdentifiersNotDistinctQuery())) + } + + Query macroIdentifierNotDistinctFromParameterQuery() { + //autogenerate `Query` type + result = + // `Query` type for `macroIdentifierNotDistinctFromParameter` query + TQueryC(TDeclarations1PackageQuery(TMacroIdentifierNotDistinctFromParameterQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index bd0e3021ec..6b6915ad3b 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -7,6 +7,7 @@ import Concurrency1 import Concurrency2 import Concurrency3 import Contracts1 +import Declarations1 import IO1 import IO2 import IO3 @@ -31,6 +32,7 @@ newtype TCQuery = TConcurrency2PackageQuery(Concurrency2Query q) or TConcurrency3PackageQuery(Concurrency3Query q) or TContracts1PackageQuery(Contracts1Query q) or + TDeclarations1PackageQuery(Declarations1Query q) or TIO1PackageQuery(IO1Query q) or TIO2PackageQuery(IO2Query q) or TIO3PackageQuery(IO3Query q) or @@ -55,6 +57,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId) { isConcurrency2QueryMetadata(query, queryId, ruleId) or isConcurrency3QueryMetadata(query, queryId, ruleId) or isContracts1QueryMetadata(query, queryId, ruleId) or + isDeclarations1QueryMetadata(query, queryId, ruleId) or isIO1QueryMetadata(query, queryId, ruleId) or isIO2QueryMetadata(query, queryId, ruleId) or isIO3QueryMetadata(query, queryId, ruleId) or diff --git a/cpp/common/src/codingstandards/cpp/rules/declaredareservedidentifier/DeclaredAReservedIdentifier.qll b/cpp/common/src/codingstandards/cpp/rules/declaredareservedidentifier/DeclaredAReservedIdentifier.qll new file mode 100644 index 0000000000..f1fdf06862 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/rules/declaredareservedidentifier/DeclaredAReservedIdentifier.qll @@ -0,0 +1,37 @@ +/** + * Provides a library which includes a `problems` predicate for reporting declarations of reserved identifiers. + */ + +import cpp +import codingstandards.cpp.Customizations +import codingstandards.cpp.Exclusions +import codingstandards.cpp.Naming +import codingstandards.cpp.CKeywords + +abstract class DeclaredAReservedIdentifierSharedQuery extends Query { } + +Query getQuery() { result instanceof DeclaredAReservedIdentifierSharedQuery } + +query predicate problems(Element m, string message) { + not isExcluded(m, getQuery()) and + exists(string name | + ( + m.(Macro).hasName(name) or + m.(Declaration).hasGlobalName(name) + ) and + ( + Naming::Cpp14::hasStandardLibraryMacroName(name) + or + Naming::Cpp14::hasStandardLibraryObjectName(name) + or + Naming::Cpp14::hasStandardLibraryFunctionName(name) + or + name.regexpMatch("_[A-Z_].*") + or + name.regexpMatch("_.*") and m.(Declaration).hasGlobalName(name) + or + Keywords::isKeyword(name) + ) and + message = "Reserved identifier '" + name + "' is declared." + ) +} diff --git a/rule_packages/c/Declarations1.json b/rule_packages/c/Declarations1.json new file mode 100644 index 0000000000..49635a47ae --- /dev/null +++ b/rule_packages/c/Declarations1.json @@ -0,0 +1,140 @@ +{ + "CERT-C": { + "DCL31-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Omission of type specifiers may not be supported by some compilers.", + "kind": "problem", + "name": "Declare identifiers before using them", + "precision": "very-high", + "severity": "error", + "short_name": "DeclareIdentifiersBeforeUsingThem", + "tags": [ + "correctness", + "readability" + ], + "implementation_scope": { + "description": "This query does not check for implicit function declarations as this is partially compiler checked.", + "items": [] + } + } + ], + "title": "Declare identifiers before using them" + }, + "DCL37-C": { + "properties": { + "obligation": "rule" + }, + "queries": [ + { + "description": "Declaring a reserved identifier can lead to undefined behaviour.", + "kind": "problem", + "name": "Do not declare or define a reserved identifier", + "precision": "very-high", + "severity": "warning", + "short_name": "DoNotDeclareOrDefineAReservedIdentifier", + "shared_implementation_short_name": "DeclaredAReservedIdentifier", + "tags": [ + "correctness", + "maintainability", + "readability" + ], + "implementation_scope": { + "description": "This query does not consider identifiers described in the future library directions section of the standard. This query also checks for any reserved identifier as declared regardless of whether its header file is included or not.", + "items": [] + } + } + ], + "title": "Do not declare or define a reserved identifier" + } + }, + "MISRA-C-2012": { + "RULE-21-2": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Declaring a reserved identifier can lead to undefined behaviour.", + "kind": "problem", + "name": "A reserved identifier or reserved macro name shall not be declared", + "precision": "very-high", + "severity": "warning", + "short_name": "DoNotDeclareAReservedIdentifier", + "shared_implementation_short_name": "DeclaredAReservedIdentifier", + "tags": [ + "correctness", + "maintainability", + "readability" + ] + } + ], + "title": "A reserved identifier or reserved macro name shall not be declared" + }, + "RULE-5-1": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Using nondistinct external identifiers results in undefined behaviour.", + "kind": "problem", + "name": "External identifiers shall be distinct", + "precision": "very-high", + "severity": "warning", + "short_name": "ExternalIdentifiersNotDistinct", + "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": [] + } + } + ], + "title": "External identifiers shall be distinct" + }, + "RULE-5-4": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Declaring multiple macros with the same name leads to undefined behaviour.", + "kind": "problem", + "name": "Macro identifiers shall be distinct", + "precision": "very-high", + "severity": "warning", + "short_name": "MacroIdentifiersNotDistinct", + "tags": [ + "correctness", + "maintainability", + "readability" + ], + "implementation_scope": { + "description": "This query checks the first 63 characters of macro identifiers as significant, as per C99. Distinctness of parameters within the same function like macro are checked by compiler and therefore not checked by this rule.", + "items": [] + } + }, + { + "description": "Macros with the same name as their parameters are less readable.", + "kind": "problem", + "name": "Macro identifiers shall be distinct from paramters", + "precision": "very-high", + "severity": "warning", + "short_name": "MacroIdentifierNotDistinctFromParameter", + "tags": [ + "maintainability", + "readability" + ] + } + ], + "title": "Macro identifiers shall be distinct" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index 7aaac01d5f..cbec139e7a 100755 --- a/rules.csv +++ b/rules.csv @@ -499,9 +499,9 @@ c,CERT-C,CON40-C,Yes,Rule,,,Do not refer to an atomic variable twice in an expre c,CERT-C,CON41-C,Yes,Rule,,,Wrap functions that can fail spuriously in a loop,CON53-CPP,Concurrency3,Medium, c,CERT-C,CON43-C,OutOfScope,Rule,,,Do not allow data races in multithreaded code,,,, c,CERT-C,DCL30-C,Yes,Rule,,,Declare objects with appropriate storage durations,,Declarations,Hard, -c,CERT-C,DCL31-C,Yes,Rule,,,Declare identifiers before using them,,Declarations,Medium, +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,,Declarations,Easy, +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,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, @@ -631,10 +631,10 @@ c,MISRA-C-2012,RULE-3-1,Yes,Required,,,The character sequences /* and // shall n c,MISRA-C-2012,RULE-3-2,Yes,Required,,,Line-splicing shall not be used in // comments,,Syntax,Easy, c,MISRA-C-2012,RULE-4-1,Yes,Required,,,Octal and hexadecimal escape sequences shall be terminated,A2-13-1 M2-13-2,Syntax,Medium, c,MISRA-C-2012,RULE-4-2,No,Advisory,,,Trigraphs should not be used,A2-5-1,,Import, -c,MISRA-C-2012,RULE-5-1,Yes,Required,,,External identifiers shall be distinct,,Declarations,Medium, +c,MISRA-C-2012,RULE-5-1,Yes,Required,,,External identifiers shall be distinct,,Declarations1,Medium, c,MISRA-C-2012,RULE-5-2,Yes,Required,,,Identifiers declared in the same scope and name space shall be distinct,,Declarations,Medium, c,MISRA-C-2012,RULE-5-3,Yes,Required,,,An identifier declared in an inner scope shall not hide an identifier declared in an outer scope,A2-10-1,Declarations,Import, -c,MISRA-C-2012,RULE-5-4,Yes,Required,,,Macro identifiers shall be distinct,,Declarations,Easy, +c,MISRA-C-2012,RULE-5-4,Yes,Required,,,Macro identifiers shall be distinct,,Declarations1,Easy, c,MISRA-C-2012,RULE-5-5,Yes,Required,,,Identifiers shall be distinct from macro names,,Declarations,Easy, c,MISRA-C-2012,RULE-5-6,Yes,Required,,,A typedef name shall be a unique identifier,,Declarations,Easy, c,MISRA-C-2012,RULE-5-7,Yes,Required,,,A tag name shall be a unique identifier,,Declarations,Easy, @@ -744,7 +744,7 @@ c,MISRA-C-2012,RULE-20-12,Yes,Required,,,"A macro parameter used as an operand t c,MISRA-C-2012,RULE-20-13,No,Required,,,A line whose first token is # shall be a valid preprocessing directive,M16-0-8,,,This is verified by the compiler in the cases where the token is not within an ifdef branch that's never taken c,MISRA-C-2012,RULE-20-14,No,Required,,,"All #else, #elif and #endif preprocessor directives shall reside in the same file as the #if, #ifdef or #ifndef directive to which they are related",M16-1-2,,,Compilers already prohibit this case c,MISRA-C-2012,RULE-21-1,Yes,Required,,,#define and #undef shall not be used on a reserved identifier or reserved macro name,,Preprocessor4,Hard, -c,MISRA-C-2012,RULE-21-2,Yes,Required,,,A reserved identifier or reserved macro name shall not be declared,,Declarations,Hard, +c,MISRA-C-2012,RULE-21-2,Yes,Required,,,A reserved identifier or reserved macro name shall not be declared,,Declarations1,Hard, c,MISRA-C-2012,RULE-21-3,Yes,Required,,,The memory allocation and deallocation functions of shall not be used,,Banned,Medium, c,MISRA-C-2012,RULE-21-4,Yes,Required,,,The standard header file shall not be used ,,Banned,Easy, c,MISRA-C-2012,RULE-21-5,Yes,Required,,,The standard header file shall not be used ,,Banned,Easy,