diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/Preprocessor.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Preprocessor.qll new file mode 100644 index 000000000..569a20a22 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/Preprocessor.qll @@ -0,0 +1,78 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype PreprocessorQuery = + TUndefOfMacroNotDefinedInFileQuery() or + TInvalidTokenInDefinedOperatorQuery() or + TDefinedOperatorExpandedInIfDirectiveQuery() or + TNoValidIfdefGuardInHeaderQuery() + +predicate isPreprocessorQueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `undefOfMacroNotDefinedInFile` query + PreprocessorPackage::undefOfMacroNotDefinedInFileQuery() and + queryId = + // `@id` for the `undefOfMacroNotDefinedInFile` query + "cpp/misra/undef-of-macro-not-defined-in-file" and + ruleId = "RULE-19-0-4" and + category = "advisory" + or + query = + // `Query` instance for the `invalidTokenInDefinedOperator` query + PreprocessorPackage::invalidTokenInDefinedOperatorQuery() and + queryId = + // `@id` for the `invalidTokenInDefinedOperator` query + "cpp/misra/invalid-token-in-defined-operator" and + ruleId = "RULE-19-1-1" and + category = "required" + or + query = + // `Query` instance for the `definedOperatorExpandedInIfDirective` query + PreprocessorPackage::definedOperatorExpandedInIfDirectiveQuery() and + queryId = + // `@id` for the `definedOperatorExpandedInIfDirective` query + "cpp/misra/defined-operator-expanded-in-if-directive" and + ruleId = "RULE-19-1-1" and + category = "required" + or + query = + // `Query` instance for the `noValidIfdefGuardInHeader` query + PreprocessorPackage::noValidIfdefGuardInHeaderQuery() and + queryId = + // `@id` for the `noValidIfdefGuardInHeader` query + "cpp/misra/no-valid-ifdef-guard-in-header" and + ruleId = "RULE-19-2-1" and + category = "required" +} + +module PreprocessorPackage { + Query undefOfMacroNotDefinedInFileQuery() { + //autogenerate `Query` type + result = + // `Query` type for `undefOfMacroNotDefinedInFile` query + TQueryCPP(TPreprocessorPackageQuery(TUndefOfMacroNotDefinedInFileQuery())) + } + + Query invalidTokenInDefinedOperatorQuery() { + //autogenerate `Query` type + result = + // `Query` type for `invalidTokenInDefinedOperator` query + TQueryCPP(TPreprocessorPackageQuery(TInvalidTokenInDefinedOperatorQuery())) + } + + Query definedOperatorExpandedInIfDirectiveQuery() { + //autogenerate `Query` type + result = + // `Query` type for `definedOperatorExpandedInIfDirective` query + TQueryCPP(TPreprocessorPackageQuery(TDefinedOperatorExpandedInIfDirectiveQuery())) + } + + Query noValidIfdefGuardInHeaderQuery() { + //autogenerate `Query` type + result = + // `Query` type for `noValidIfdefGuardInHeader` query + TQueryCPP(TPreprocessorPackageQuery(TNoValidIfdefGuardInHeaderQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll index abd6aeff9..be4e882e0 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/cpp/RuleMetadata.qll @@ -41,6 +41,7 @@ import Operators import OrderOfEvaluation import OutOfBounds import Pointers +import Preprocessor import Representation import Scope import SideEffects1 @@ -96,6 +97,7 @@ newtype TCPPQuery = TOrderOfEvaluationPackageQuery(OrderOfEvaluationQuery q) or TOutOfBoundsPackageQuery(OutOfBoundsQuery q) or TPointersPackageQuery(PointersQuery q) or + TPreprocessorPackageQuery(PreprocessorQuery q) or TRepresentationPackageQuery(RepresentationQuery q) or TScopePackageQuery(ScopeQuery q) or TSideEffects1PackageQuery(SideEffects1Query q) or @@ -151,6 +153,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isOrderOfEvaluationQueryMetadata(query, queryId, ruleId, category) or isOutOfBoundsQueryMetadata(query, queryId, ruleId, category) or isPointersQueryMetadata(query, queryId, ruleId, category) or + isPreprocessorQueryMetadata(query, queryId, ruleId, category) or isRepresentationQueryMetadata(query, queryId, ruleId, category) or isScopeQueryMetadata(query, queryId, ruleId, category) or isSideEffects1QueryMetadata(query, queryId, ruleId, category) or diff --git a/cpp/misra/src/codeql-pack.lock.yml b/cpp/misra/src/codeql-pack.lock.yml index a45ea8f43..9a7d19bc0 100644 --- a/cpp/misra/src/codeql-pack.lock.yml +++ b/cpp/misra/src/codeql-pack.lock.yml @@ -1,6 +1,8 @@ --- lockVersion: 1.0.0 dependencies: + advanced-security/qtil: + version: 0.0.3 codeql/cpp-all: version: 4.0.3 codeql/dataflow: diff --git a/cpp/misra/src/qlpack.yml b/cpp/misra/src/qlpack.yml index 201291b13..ca2ccc5eb 100644 --- a/cpp/misra/src/qlpack.yml +++ b/cpp/misra/src/qlpack.yml @@ -6,3 +6,4 @@ license: MIT dependencies: codeql/common-cpp-coding-standards: '*' codeql/cpp-all: 4.0.3 + advanced-security/qtil: 0.0.3 diff --git a/cpp/misra/src/rules/RULE-19-0-4/UndefOfMacroNotDefinedInFile.ql b/cpp/misra/src/rules/RULE-19-0-4/UndefOfMacroNotDefinedInFile.ql new file mode 100644 index 000000000..45ff48f1c --- /dev/null +++ b/cpp/misra/src/rules/RULE-19-0-4/UndefOfMacroNotDefinedInFile.ql @@ -0,0 +1,57 @@ +/** + * @id cpp/misra/undef-of-macro-not-defined-in-file + * @name RULE-19-0-4: #undef should only be used for macros defined previously in the same file + * @description Using #undef to undefine a macro that is not defined in the same file can lead to + * confusion. + * @kind problem + * @precision very-high + * @problem.severity warning + * @tags external/misra/id/rule-19-0-4 + * scope/single-translation-unit + * readability + * maintainability + * external/misra/enforcement/decidable + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.cpp.misra +import qtil.Qtil + +class DefOrUndef extends PreprocessorDirective { + DefOrUndef() { this instanceof PreprocessorUndef or this instanceof Macro } + + string getName() { + result = this.(PreprocessorUndef).getName() or + result = this.(Macro).getName() + } +} + +predicate relevantNameAndFile(string name, File file) { + exists(DefOrUndef m | + m.getName() = name and + m.getFile() = file + ) +} + +class StringFilePair = Qtil::Pair::Pair; + +/** + * Defs and undefs ordered by location, grouped by name and file. + */ +class OrderedDefOrUndef extends Qtil::Ordered::GroupBy::Type { + override int getOrder() { result = getLocation().getStartLine() } + + override StringFilePair getGroup() { + result.getFirst() = getName() and result.getSecond() = getFile() + } +} + +from OrderedDefOrUndef defOrUndef +where + not isExcluded(defOrUndef, PreprocessorPackage::undefOfMacroNotDefinedInFileQuery()) and + // There exists an #undef for a given name and file + defOrUndef instanceof PreprocessorUndef and + // A previous def or undef of this name must exist in this file, and it must be a #define + not defOrUndef.getPrevious() instanceof Macro +select defOrUndef, "Undef of name '" + defOrUndef.getName() + "' not defined in the same file." diff --git a/cpp/misra/src/rules/RULE-19-1-1/DefinedOperatorExpandedInIfDirective.ql b/cpp/misra/src/rules/RULE-19-1-1/DefinedOperatorExpandedInIfDirective.ql new file mode 100644 index 000000000..cb79a5bbf --- /dev/null +++ b/cpp/misra/src/rules/RULE-19-1-1/DefinedOperatorExpandedInIfDirective.ql @@ -0,0 +1,27 @@ +/** + * @id cpp/misra/defined-operator-expanded-in-if-directive + * @name RULE-19-1-1: The defined preprocessor operator shall be used appropriately + * @description Macro expansions that produce the token 'defined' inside of an if directive result + * in undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-19-1-1 + * scope/single-translation-unit + * correctness + * maintainability + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +from PreprocessorIf ifDirective, MacroInvocation mi +where + not isExcluded(ifDirective, PreprocessorPackage::definedOperatorExpandedInIfDirectiveQuery()) and + ifDirective.getLocation().subsumes(mi.getLocation()) and + mi.getMacro().getBody().regexpMatch(".*defined.*") +select ifDirective, + "If directive contains macro expansion including the token 'defined' from macro $@, which results in undefined behavior.", + mi.getMacro(), mi.getMacroName() diff --git a/cpp/misra/src/rules/RULE-19-1-1/InvalidTokenInDefinedOperator.ql b/cpp/misra/src/rules/RULE-19-1-1/InvalidTokenInDefinedOperator.ql new file mode 100644 index 000000000..c405dcf54 --- /dev/null +++ b/cpp/misra/src/rules/RULE-19-1-1/InvalidTokenInDefinedOperator.ql @@ -0,0 +1,42 @@ +/** + * @id cpp/misra/invalid-token-in-defined-operator + * @name RULE-19-1-1: The defined preprocessor operator shall be used appropriately + * @description Using the defined operator without an immediately following optionally parenthesized + * identifier results in undefined behavior. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-19-1-1 + * scope/single-translation-unit + * correctness + * maintainability + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra + +string idRegex() { result = "[a-zA-Z_]([a-zA-Z_0-9]*)" } + +bindingset[body] +predicate hasInvalidDefinedOperator(string body) { + body.regexpMatch(".*\\bdefined" + + // Contains text "defined" at a word break + // Negative zero width lookahead: + "(?!(" + + // (group) optional whitespace followed by a valid identifier + "(\\s*" + idRegex() + ")" + + // or + "|" + + // (group) optional whitespace followed by parenthesis and valid identifier + "(\\s*\\(\\s*" + idRegex() + "\\s*\\))" + + // End negative zero width lookahead, match remaining text + ")).*") +} + +from PreprocessorIf ifDirective +where + not isExcluded(ifDirective, PreprocessorPackage::invalidTokenInDefinedOperatorQuery()) and + hasInvalidDefinedOperator(ifDirective.getHead()) +select ifDirective, "Invalid use of defined operator in if directive." diff --git a/cpp/misra/src/rules/RULE-19-2-1/NoValidIfdefGuardInHeader.ql b/cpp/misra/src/rules/RULE-19-2-1/NoValidIfdefGuardInHeader.ql new file mode 100644 index 000000000..902a356f7 --- /dev/null +++ b/cpp/misra/src/rules/RULE-19-2-1/NoValidIfdefGuardInHeader.ql @@ -0,0 +1,44 @@ +/** + * @id cpp/misra/no-valid-ifdef-guard-in-header + * @name RULE-19-2-1: Precautions shall be taken in order to prevent the contents of a header file being included more + * @description Precautions shall be taken in order to prevent the contents of a header file being + * included more than once. + * @kind problem + * @precision very-high + * @problem.severity error + * @tags external/misra/id/rule-19-2-1 + * scope/single-translation-unit + * maintainability + * correctness + * external/misra/enforcement/decidable + * external/misra/obligation/required + */ + +import cpp +import codingstandards.cpp.misra +import semmle.code.cpp.headers.MultipleInclusion + +predicate isOutside(CorrectIncludeGuard includeGuard, Location location) { + location.getFile() = includeGuard.getFile() and + ( + location.isBefore(includeGuard.getIfndef().getLocation()) + or + includeGuard.getEndif().getLocation().isBefore(location) + ) +} + +from File included +where + not isExcluded(included, PreprocessorPackage::noValidIfdefGuardInHeaderQuery()) and + included = any(Compilation c).getAFileCompiled().getAnIncludedFile+() and + not exists(CorrectIncludeGuard includeGuard | + includeGuard.getFile() = included and + // Stricter: define is before all other contents + not included + .getATopLevelDeclaration() + .getLocation() + .isBefore(includeGuard.getDefine().getLocation()) and + // Stricter: do not allow includes outside of the inclusion guard + not exists(Include include | isOutside(includeGuard, include.getLocation())) + ) +select included, "File does not have a well formatted include guard." diff --git a/cpp/misra/test/codeql-pack.lock.yml b/cpp/misra/test/codeql-pack.lock.yml index a45ea8f43..9a7d19bc0 100644 --- a/cpp/misra/test/codeql-pack.lock.yml +++ b/cpp/misra/test/codeql-pack.lock.yml @@ -1,6 +1,8 @@ --- lockVersion: 1.0.0 dependencies: + advanced-security/qtil: + version: 0.0.3 codeql/cpp-all: version: 4.0.3 codeql/dataflow: diff --git a/cpp/misra/test/rules/RULE-19-0-4/UndefOfMacroNotDefinedInFile.expected b/cpp/misra/test/rules/RULE-19-0-4/UndefOfMacroNotDefinedInFile.expected new file mode 100644 index 000000000..af0c0993e --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-0-4/UndefOfMacroNotDefinedInFile.expected @@ -0,0 +1,3 @@ +| test.cpp:3:1:3:9 | #undef M1 | Undef of name 'M1' not defined in the same file. | +| test.cpp:6:1:6:9 | #undef M1 | Undef of name 'M1' not defined in the same file. | +| test.cpp:7:1:7:9 | #undef M2 | Undef of name 'M2' not defined in the same file. | diff --git a/cpp/misra/test/rules/RULE-19-0-4/UndefOfMacroNotDefinedInFile.qlref b/cpp/misra/test/rules/RULE-19-0-4/UndefOfMacroNotDefinedInFile.qlref new file mode 100644 index 000000000..094c73c7f --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-0-4/UndefOfMacroNotDefinedInFile.qlref @@ -0,0 +1 @@ +rules/RULE-19-0-4/UndefOfMacroNotDefinedInFile.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-0-4/test.cpp b/cpp/misra/test/rules/RULE-19-0-4/test.cpp new file mode 100644 index 000000000..665d5b970 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-0-4/test.cpp @@ -0,0 +1,7 @@ +#define M1 +#undef M1 // COMPLIANT +#undef M1 // NON-COMPLIANT +#define M1 +#undef M1 // COMPLIANT +#undef M1 // NON-COMPLIANT +#undef M2 // NON-COMPLIANT \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-1-1/DefinedOperatorExpandedInIfDirective.expected b/cpp/misra/test/rules/RULE-19-1-1/DefinedOperatorExpandedInIfDirective.expected new file mode 100644 index 000000000..dbbbc5502 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-1-1/DefinedOperatorExpandedInIfDirective.expected @@ -0,0 +1,3 @@ +| test.cpp:39:1:39:6 | #if M1 | If directive contains macro expansion including the token 'defined' from macro $@, which results in undefined behavior. | test.cpp:34:1:34:18 | #define M1 defined | M1 | +| test.cpp:41:1:41:6 | #if M2 | If directive contains macro expansion including the token 'defined' from macro $@, which results in undefined behavior. | test.cpp:35:1:35:30 | #define M2 1 + 2 + defined + 3 | M2 | +| test.cpp:43:1:43:6 | #if M3 | If directive contains macro expansion including the token 'defined' from macro $@, which results in undefined behavior. | test.cpp:35:1:35:30 | #define M2 1 + 2 + defined + 3 | M2 | diff --git a/cpp/misra/test/rules/RULE-19-1-1/DefinedOperatorExpandedInIfDirective.qlref b/cpp/misra/test/rules/RULE-19-1-1/DefinedOperatorExpandedInIfDirective.qlref new file mode 100644 index 000000000..733221320 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-1-1/DefinedOperatorExpandedInIfDirective.qlref @@ -0,0 +1 @@ +rules/RULE-19-1-1/DefinedOperatorExpandedInIfDirective.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-1-1/InvalidTokenInDefinedOperator.expected b/cpp/misra/test/rules/RULE-19-1-1/InvalidTokenInDefinedOperator.expected new file mode 100644 index 000000000..7ccfd6fe8 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-1-1/InvalidTokenInDefinedOperator.expected @@ -0,0 +1,3 @@ +| test.cpp:11:1:11:11 | #if defined | Invalid use of defined operator in if directive. | +| test.cpp:13:1:13:26 | #if defined(M1) && defined | Invalid use of defined operator in if directive. | +| test.cpp:15:1:15:26 | #if defined && defined(M1) | Invalid use of defined operator in if directive. | diff --git a/cpp/misra/test/rules/RULE-19-1-1/InvalidTokenInDefinedOperator.qlref b/cpp/misra/test/rules/RULE-19-1-1/InvalidTokenInDefinedOperator.qlref new file mode 100644 index 000000000..4a0f690bf --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-1-1/InvalidTokenInDefinedOperator.qlref @@ -0,0 +1 @@ +rules/RULE-19-1-1/InvalidTokenInDefinedOperator.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-1-1/test.cpp b/cpp/misra/test/rules/RULE-19-1-1/test.cpp new file mode 100644 index 000000000..29a5843c1 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-1-1/test.cpp @@ -0,0 +1,48 @@ +#if defined M1 // COMPLIANT +#endif +#if defined(M1) // COMPLIANT +#endif +#if defined(M1) // COMPLIANT +#endif +#if defined M1 && defined M2 // COMPLIANT +#endif +#if defined(M1) && defined(M2) // COMPLIANT +#endif +#if defined // NON-COMPLIANT +#endif +#if defined(M1) && defined // NON-COMPLIANT +#endif +#if defined && defined(M1) // NON-COMPLIANT +#endif +// Compliant, there are no keywords in the context of the preprocessor, only +// identifiers. Therefore, 'new' is a valid identifier. +#if defined new // COMPLIANT +#endif +#if defined(new) // COMPLIANT +#endif + +// These cases don't compile in default tests, but may on other compilers +// #if defined 1 // NON-COMPLIANT +// #endif +// #if defined ( 1 ) // NON-COMPLIANT +// #endif +// #if defined + // NON-COMPLIANT +// #endif +// #if defined ( + ) // NON-COMPLIANT +// #endif + +#define M1 defined +#define M2 1 + 2 + defined + 3 +#define M3 M2 +#define M4 1 + 2 + 3 +#define M5 M4 +#if M1 // NON-COMPLIANT +#endif +#if M2 // NON-COMPLIANT +#endif +#if M3 // NON-COMPLIANT +#endif +#if M4 // COMPLIANT +#endif +#if M5 // COMPLIANT +#endif diff --git a/cpp/misra/test/rules/RULE-19-2-1/NoValidIfdefGuardInHeader.expected b/cpp/misra/test/rules/RULE-19-2-1/NoValidIfdefGuardInHeader.expected new file mode 100644 index 000000000..73ce7d7a5 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/NoValidIfdefGuardInHeader.expected @@ -0,0 +1,9 @@ +| invalid1.h:0:0:0:0 | invalid1.h | File does not have a well formatted include guard. | +| invalid2.h:0:0:0:0 | invalid2.h | File does not have a well formatted include guard. | +| invalid3.h:0:0:0:0 | invalid3.h | File does not have a well formatted include guard. | +| invalid4.h:0:0:0:0 | invalid4.h | File does not have a well formatted include guard. | +| invalid5_file2.h:0:0:0:0 | invalid5_file2.h | File does not have a well formatted include guard. | +| invalid6_b.h:0:0:0:0 | invalid6_b.h | File does not have a well formatted include guard. | +| invalid7.h:0:0:0:0 | invalid7.h | File does not have a well formatted include guard. | +| invalid8.h:0:0:0:0 | invalid8.h | File does not have a well formatted include guard. | +| invalid9.h:0:0:0:0 | invalid9.h | File does not have a well formatted include guard. | diff --git a/cpp/misra/test/rules/RULE-19-2-1/NoValidIfdefGuardInHeader.qlref b/cpp/misra/test/rules/RULE-19-2-1/NoValidIfdefGuardInHeader.qlref new file mode 100644 index 000000000..2857bfe31 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/NoValidIfdefGuardInHeader.qlref @@ -0,0 +1 @@ +rules/RULE-19-2-1/NoValidIfdefGuardInHeader.ql \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-2-1/invalid1.h b/cpp/misra/test/rules/RULE-19-2-1/invalid1.h new file mode 100644 index 000000000..ed9b55508 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/invalid1.h @@ -0,0 +1,6 @@ +#ifndef MISSPELLED +#define MISPELED + +void invalid1_f1(); + +#endif \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-2-1/invalid2.h b/cpp/misra/test/rules/RULE-19-2-1/invalid2.h new file mode 100644 index 000000000..c2ebad359 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/invalid2.h @@ -0,0 +1,7 @@ +#ifdef INVALID2_H +#define INVALID2_H + +void invalid2_f1(); +// invalid: uses ifdef, not ifndef + +#endif \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-2-1/invalid3.h b/cpp/misra/test/rules/RULE-19-2-1/invalid3.h new file mode 100644 index 000000000..cfac97ead --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/invalid3.h @@ -0,0 +1,6 @@ +#ifndef INVALID3_H +#define INVALID3_H + +#endif + +void invalid3_f1(); // NON-COMPLIANT -- outside of guard condition \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-2-1/invalid4.h b/cpp/misra/test/rules/RULE-19-2-1/invalid4.h new file mode 100644 index 000000000..002e4308b --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/invalid4.h @@ -0,0 +1,14 @@ +#ifndef INVALID4_H1 +#define INVALID4_H1 + +void invalid4_f1(); + +#endif + +#ifndef INVALID4_H2 +#define INVALID4_H2 + +// NON-COMPLIANT -- There should not be two inclusion guards in one file. +void invalid4_f1(); + +#endif \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-2-1/invalid5.h b/cpp/misra/test/rules/RULE-19-2-1/invalid5.h new file mode 100644 index 000000000..79d7aaf83 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/invalid5.h @@ -0,0 +1,6 @@ +#ifndef INVALID5_H +#define INVALID5_H + +#include "invalid5_file2.h" + +#endif \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-2-1/invalid5_file2.h b/cpp/misra/test/rules/RULE-19-2-1/invalid5_file2.h new file mode 100644 index 000000000..ef548fb87 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/invalid5_file2.h @@ -0,0 +1,2 @@ +void invalid5_f1(); // NON-COMPLIANT -- guarded from invalid5.h but not in + // current file \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-2-1/invalid6_a.h b/cpp/misra/test/rules/RULE-19-2-1/invalid6_a.h new file mode 100644 index 000000000..97aba7e3e --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/invalid6_a.h @@ -0,0 +1,7 @@ +// NON-COMPLIANT -- same inclusion guard identifier as invalid6_b.h +#ifndef INVALID6_H +#define INVALID6_H + +void invalid6_f1(); + +#endif \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-2-1/invalid6_b.h b/cpp/misra/test/rules/RULE-19-2-1/invalid6_b.h new file mode 100644 index 000000000..43bf77217 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/invalid6_b.h @@ -0,0 +1,7 @@ +// NON-COMPLIANT -- same inclusion guard identifier as invalid6_a.h +#ifndef INVALID6_H +#define INVALID6_H + +void invalid6_f2(); + +#endif \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-2-1/invalid7.h b/cpp/misra/test/rules/RULE-19-2-1/invalid7.h new file mode 100644 index 000000000..e45f13886 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/invalid7.h @@ -0,0 +1,2 @@ +// Empty file +// NON-COMPLIANT -- no inclusion guard \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-2-1/invalid8.h b/cpp/misra/test/rules/RULE-19-2-1/invalid8.h new file mode 100644 index 000000000..2dc25f09c --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/invalid8.h @@ -0,0 +1,8 @@ +#include "valid1.h" // NON-COMPLIANT -- contents not in inclusion guard + +#ifndef INVALID8_H +#define INVALID8_H + +void invalid8_f1(); + +#endif diff --git a/cpp/misra/test/rules/RULE-19-2-1/invalid9.h b/cpp/misra/test/rules/RULE-19-2-1/invalid9.h new file mode 100644 index 000000000..50d89c22b --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/invalid9.h @@ -0,0 +1,7 @@ +#ifndef INVALID9_H + +void invalid9_f1(); + +// NON-COMPLIANT -- define is not at top of inclusion guard +#define INVALID9_H +#endif diff --git a/cpp/misra/test/rules/RULE-19-2-1/test.cpp b/cpp/misra/test/rules/RULE-19-2-1/test.cpp new file mode 100644 index 000000000..d80bc8949 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/test.cpp @@ -0,0 +1,14 @@ +#include "invalid1.h" +#include "invalid2.h" +#include "invalid3.h" +#include "invalid4.h" +#include "invalid5.h" +#include "invalid6_a.h" +#include "invalid6_b.h" +#include "invalid7.h" +#include "invalid8.h" +#include "invalid9.h" +#include "valid1.h" +#include "valid2.h" + +void f() {} // COMPLIANT -- not in header, no inclusion guard necessary \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-2-1/valid1.h b/cpp/misra/test/rules/RULE-19-2-1/valid1.h new file mode 100644 index 000000000..e924cac32 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/valid1.h @@ -0,0 +1,8 @@ +// COMPLIANT + +#ifndef VALID1_H +#define VALID1_H + +void valid1_f1(); + +#endif \ No newline at end of file diff --git a/cpp/misra/test/rules/RULE-19-2-1/valid2.h b/cpp/misra/test/rules/RULE-19-2-1/valid2.h new file mode 100644 index 000000000..653ec0c24 --- /dev/null +++ b/cpp/misra/test/rules/RULE-19-2-1/valid2.h @@ -0,0 +1,8 @@ +// COMPLIANT + +#if !defined(VALID2_H) +#define VALID2_H + +void valid2_f1(); + +#endif \ No newline at end of file diff --git a/rule_packages/cpp/Preprocessor.json b/rule_packages/cpp/Preprocessor.json new file mode 100644 index 000000000..b379af2ff --- /dev/null +++ b/rule_packages/cpp/Preprocessor.json @@ -0,0 +1,83 @@ +{ + "MISRA-C++-2023": { + "RULE-19-0-4": { + "properties": { + "enforcement": "decidable", + "obligation": "advisory" + }, + "queries": [ + { + "description": "Using #undef to undefine a macro that is not defined in the same file can lead to confusion.", + "kind": "problem", + "name": "#undef should only be used for macros defined previously in the same file", + "precision": "very-high", + "severity": "warning", + "short_name": "UndefOfMacroNotDefinedInFile", + "tags": [ + "scope/single-translation-unit", + "readability", + "maintainability" + ] + } + ], + "title": "#undef should only be used for macros defined previously in the same file" + }, + "RULE-19-1-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Using the defined operator without an immediately following optionally parenthesized identifier results in undefined behavior.", + "kind": "problem", + "name": "The defined preprocessor operator shall be used appropriately", + "precision": "very-high", + "severity": "error", + "short_name": "InvalidTokenInDefinedOperator", + "tags": [ + "scope/single-translation-unit", + "correctness", + "maintainability" + ] + }, + { + "description": "Macro expansions that produce the token 'defined' inside of an if directive result in undefined behavior.", + "kind": "problem", + "name": "The defined preprocessor operator shall be used appropriately", + "precision": "very-high", + "severity": "error", + "short_name": "DefinedOperatorExpandedInIfDirective", + "tags": [ + "scope/single-translation-unit", + "correctness", + "maintainability" + ] + } + ], + "title": "The defined preprocessor operator shall be used appropriately" + }, + "RULE-19-2-1": { + "properties": { + "enforcement": "decidable", + "obligation": "required" + }, + "queries": [ + { + "description": "Precautions shall be taken in order to prevent the contents of a header file being included more than once.", + "kind": "problem", + "name": "Precautions shall be taken in order to prevent the contents of a header file being included more", + "precision": "very-high", + "severity": "error", + "short_name": "NoValidIfdefGuardInHeader", + "tags": [ + "scope/single-translation-unit", + "maintainability", + "correctness" + ] + } + ], + "title": "Precautions shall be taken in order to prevent the contents of a header file being included more than once" + } + } +} \ No newline at end of file diff --git a/rules.csv b/rules.csv index 68049625e..ec2253398 100644 --- a/rules.csv +++ b/rules.csv @@ -966,14 +966,14 @@ cpp,MISRA-C++-2023,RULE-19-1-1,Yes,Required,Decidable,Single Translation Unit,Th cpp,MISRA-C++-2023,RULE-19-1-2,No,Required,Decidable,Single Translation Unit,"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,,, cpp,MISRA-C++-2023,RULE-19-1-3,Yes,Required,Decidable,Single Translation Unit,All identifiers used in the controlling expression of #if or #elif preprocessing directives shall be defined prior to evaluation,M16-0-7,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-19-2-1,Yes,Required,Decidable,Single Translation Unit,Precautions shall be taken in order to prevent the contents of a header file being included more than once,M16-2-3,Preprocessor,Easy, -cpp,MISRA-C++-2023,RULE-19-2-2,Yes,Required,Decidable,Single Translation Unit,"The #include directive shall be followed by either a or ""filename"" sequence",,Preprocessor,Easy, +cpp,MISRA-C++-2023,RULE-19-2-2,Yes,Required,Decidable,Single Translation Unit,"The #include directive shall be followed by either a or ""filename"" sequence",,Preprocessor2,Easy, cpp,MISRA-C++-2023,RULE-19-2-3,Yes,Required,Decidable,Single Translation Unit,"The ' or "" or \ characters and the /* or // character sequences shall not occur in a header file name",A16-2-1,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-19-3-1,Yes,Advisory,Decidable,Single Translation Unit,The # and ## preprocessor operators should not be used,M16-3-2,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-19-3-2,Yes,Required,Decidable,Single Translation Unit,A macro parameter immediately following a # operator shall not be immediately followed by a ## operator,RULE-20-11,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-19-3-3,Yes,Required,Decidable,Single Translation Unit,The argument to a mixed-use macro parameter shall not be subject to further expansion,RULE-20-12,ImportMisra23,Import, -cpp,MISRA-C++-2023,RULE-19-3-4,Yes,Required,Decidable,Single Translation Unit,Parentheses shall be used to ensure macro arguments are expanded appropriately,M16-0-6,Preprocessor,Medium, +cpp,MISRA-C++-2023,RULE-19-3-4,Yes,Required,Decidable,Single Translation Unit,Parentheses shall be used to ensure macro arguments are expanded appropriately,M16-0-6,Preprocessor2,Medium, cpp,MISRA-C++-2023,RULE-19-3-5,Yes,Required,Decidable,Single Translation Unit,Tokens that look like a preprocessing directive shall not occur within a macro argument,RULE-20-6,ImportMisra23,Import, -cpp,MISRA-C++-2023,RULE-19-6-1,Yes,Advisory,Decidable,Single Translation Unit,The #pragma directive and the _Pragma operator should not be used,A16-7-1,Preprocessor,Easy, +cpp,MISRA-C++-2023,RULE-19-6-1,Yes,Advisory,Decidable,Single Translation Unit,The #pragma directive and the _Pragma operator should not be used,A16-7-1,Preprocessor2,Easy, cpp,MISRA-C++-2023,RULE-21-2-1,Yes,Required,Decidable,Single Translation Unit,"The library functions atof, atoi, atol and atoll from shall not be used",RULE-21-7,ImportMisra23,Import, cpp,MISRA-C++-2023,RULE-21-2-2,Yes,Required,Decidable,Single Translation Unit,"The string handling functions from , , and shall not be used",M18-0-5,BannedAPIs,Easy, cpp,MISRA-C++-2023,RULE-21-2-3,Yes,Required,Decidable,Single Translation Unit,The library function system from shall not be used,M18-0-3,BannedAPIs,Easy,