From 43f31379f9ca11db83c485765097ba824ecad127 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 31 Jan 2024 04:45:32 -0500 Subject: [PATCH 1/6] A16-0-1: exclusions for handling else and elif --- change_notes/2024-01-31-exclusion-a16-0-1.md | 2 ++ ...lOnlyBeUsedForCertainDirectivesPatterns.ql | 17 +++++++++++-- ...eUsedForCertainDirectivesPatterns.expected | 3 +++ cpp/autosar/test/rules/A16-0-1/test.cpp | 25 +++++++++++++++++++ 4 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 change_notes/2024-01-31-exclusion-a16-0-1.md diff --git a/change_notes/2024-01-31-exclusion-a16-0-1.md b/change_notes/2024-01-31-exclusion-a16-0-1.md new file mode 100644 index 0000000000..2d7dfe97ab --- /dev/null +++ b/change_notes/2024-01-31-exclusion-a16-0-1.md @@ -0,0 +1,2 @@ +`A16-0-1`: `cpp/autosar/pre-processor-shall-only-be-used-for-certain-directives-patterns` + - Exclude all preprocessor elses and also consider elifs separately (ie do not affect valid ifs) but not valid if not meeting the same criteria as an ifdef etc. \ No newline at end of file diff --git a/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql b/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql index a8e1e59839..bd8fe2da65 100644 --- a/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql +++ b/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql @@ -21,13 +21,26 @@ import cpp import codingstandards.cpp.autosar import codingstandards.cpp.FunctionLikeMacro +class PermittedInnerDirectiveType extends PreprocessorDirective { + PermittedInnerDirectiveType() { + //permissive listing for directives that can be used in a valid wrapper + this instanceof MacroWrapper or + this instanceof PreprocessorEndif or + this instanceof Include or + this instanceof PermittedMacro or + this instanceof PreprocessorElif or + this instanceof PreprocessorElse + } +} + class PermittedDirectiveType extends PreprocessorDirective { PermittedDirectiveType() { //permissive listing in case directive types modelled in ql ever expands (example non valid directives) this instanceof MacroWrapper or this instanceof PreprocessorEndif or this instanceof Include or - this instanceof PermittedMacro + this instanceof PermittedMacro or + this instanceof PreprocessorElse } } @@ -73,7 +86,7 @@ class MacroWrapper extends PreprocessorIfndef { class AcceptableWrapper extends PreprocessorBranch { AcceptableWrapper() { forall(Element inner | not inner instanceof Comment and this = getAGuard(inner) | - inner instanceof PermittedDirectiveType + inner instanceof PermittedInnerDirectiveType ) } } diff --git a/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected b/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected index 5f6114bea8..18ce57af8e 100644 --- a/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected +++ b/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected @@ -2,3 +2,6 @@ | test.cpp:9:1:9:26 | #define OBJECTLIKE_MACRO 1 | Preprocessor directive used for conditional compilation. | | test.cpp:10:1:10:35 | #define FUNCTIONLIKE_MACRO(X) X + 1 | Preprocessor directive used for conditional compilation. | | test.cpp:11:1:11:37 | #define FUNCTIONLIKE_MACROTWO() 1 + 1 | Preprocessor directive used for conditional compilation. | +| test.cpp:33:1:33:26 | #ifdef OBJECTLIKE_MACRO_NO | Preprocessor directive used for conditional compilation. | +| test.cpp:35:1:35:26 | #elif OBJECTLIKE_MACRO > 0 | Preprocessor directive used for conditional compilation. | +| test.cpp:39:1:39:23 | #ifdef OBJECTLIKE_MACRO | Preprocessor directive used for conditional compilation. | diff --git a/cpp/autosar/test/rules/A16-0-1/test.cpp b/cpp/autosar/test/rules/A16-0-1/test.cpp index b1ee540032..7233a015c1 100644 --- a/cpp/autosar/test/rules/A16-0-1/test.cpp +++ b/cpp/autosar/test/rules/A16-0-1/test.cpp @@ -17,3 +17,28 @@ int g; #ifndef TESTHEADER // COMPLIANT #include //COMPLIANT #endif // COMPLIANT + +#ifdef MACRO_ENABLED // COMPLIANT +#include // COMPLIANT +#else // COMPLIANT +#include // COMPLIANT +#endif // COMPLIANT + +#ifdef MACRO_ENABLED_NON // COMPLIANT +#include // COMPLIANT +#elif MACRO_ENABLED_OTHER // COMPLIANT +#include // COMPLIANT +#endif // COMPLIANT + +#ifdef OBJECTLIKE_MACRO_NO // NON_COMPLIANT +int x = 0; // not present +#elif OBJECTLIKE_MACRO > 0 // NON_COMPLIANT +int x = 1; // present +#endif // COMPLIANT + +#ifdef OBJECTLIKE_MACRO // NON_COMPLIANT +int x1 = 0; // present +#elif OBJECTLIKE_MACRO > \ + -1 // COMPLIANT - by technicality of conditional compilation +int x1 = 1; // not present +#endif // COMPLIANT \ No newline at end of file From bfcacf7f85859ba0a4b84cc6d882e34596f80287 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 7 Feb 2024 11:13:48 -0500 Subject: [PATCH 2/6] Update change_notes/2024-01-31-exclusion-a16-0-1.md Co-authored-by: Remco Vermeulen --- change_notes/2024-01-31-exclusion-a16-0-1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change_notes/2024-01-31-exclusion-a16-0-1.md b/change_notes/2024-01-31-exclusion-a16-0-1.md index 2d7dfe97ab..8ff06ba32d 100644 --- a/change_notes/2024-01-31-exclusion-a16-0-1.md +++ b/change_notes/2024-01-31-exclusion-a16-0-1.md @@ -1,2 +1,2 @@ -`A16-0-1`: `cpp/autosar/pre-processor-shall-only-be-used-for-certain-directives-patterns` +`A16-0-1` - `PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql`: - Exclude all preprocessor elses and also consider elifs separately (ie do not affect valid ifs) but not valid if not meeting the same criteria as an ifdef etc. \ No newline at end of file From 2193a22d076088da6f9f1bce74d33331d7d19472 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 7 Feb 2024 15:16:23 -0500 Subject: [PATCH 3/6] A16-0-1: improve range logic --- ...hallOnlyBeUsedForCertainDirectivesPatterns.ql | 16 ++++++++++++---- ...lyBeUsedForCertainDirectivesPatterns.expected | 1 - cpp/autosar/test/rules/A16-0-1/test.cpp | 6 +++--- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql b/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql index bd8fe2da65..74d132ad7c 100644 --- a/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql +++ b/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql @@ -53,10 +53,18 @@ pragma[noinline] predicate isPreprocConditionalRange( PreprocessorBranch pb, string filepath, int startLine, int endLine ) { - exists(PreprocessorEndif end | pb.getEndIf() = end | - isPreprocFileAndLine(pb, filepath, startLine) and - isPreprocFileAndLine(end, filepath, endLine) - ) + //the range of an if with an elif ends at the elif to avoid reporting things twice + if exists(PreprocessorElif elif | elif.getIf() = pb) + then + exists(PreprocessorElif end | end.getIf() = pb | + isPreprocFileAndLine(pb, filepath, startLine) and + isPreprocFileAndLine(end, filepath, endLine) + ) + else + exists(PreprocessorEndif end | pb.getEndIf() = end | + isPreprocFileAndLine(pb, filepath, startLine) and + isPreprocFileAndLine(end, filepath, endLine) + ) } /** diff --git a/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected b/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected index 18ce57af8e..9c96713ed4 100644 --- a/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected +++ b/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected @@ -2,6 +2,5 @@ | test.cpp:9:1:9:26 | #define OBJECTLIKE_MACRO 1 | Preprocessor directive used for conditional compilation. | | test.cpp:10:1:10:35 | #define FUNCTIONLIKE_MACRO(X) X + 1 | Preprocessor directive used for conditional compilation. | | test.cpp:11:1:11:37 | #define FUNCTIONLIKE_MACROTWO() 1 + 1 | Preprocessor directive used for conditional compilation. | -| test.cpp:33:1:33:26 | #ifdef OBJECTLIKE_MACRO_NO | Preprocessor directive used for conditional compilation. | | test.cpp:35:1:35:26 | #elif OBJECTLIKE_MACRO > 0 | Preprocessor directive used for conditional compilation. | | test.cpp:39:1:39:23 | #ifdef OBJECTLIKE_MACRO | Preprocessor directive used for conditional compilation. | diff --git a/cpp/autosar/test/rules/A16-0-1/test.cpp b/cpp/autosar/test/rules/A16-0-1/test.cpp index 7233a015c1..c843ccf8c6 100644 --- a/cpp/autosar/test/rules/A16-0-1/test.cpp +++ b/cpp/autosar/test/rules/A16-0-1/test.cpp @@ -30,10 +30,10 @@ int g; #include // COMPLIANT #endif // COMPLIANT -#ifdef OBJECTLIKE_MACRO_NO // NON_COMPLIANT -int x = 0; // not present +#ifdef OBJECTLIKE_MACRO_NO // COMPLIANT +int x0 = 0; // not present #elif OBJECTLIKE_MACRO > 0 // NON_COMPLIANT -int x = 1; // present +int x0 = 1; // present #endif // COMPLIANT #ifdef OBJECTLIKE_MACRO // NON_COMPLIANT From 18a297b513bd50a842359ba759e67c9c019d4e28 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Wed, 7 Feb 2024 21:22:38 -0500 Subject: [PATCH 4/6] A16-0-1: add extra testcases --- ...eUsedForCertainDirectivesPatterns.expected | 1 + cpp/autosar/test/rules/A16-0-1/options | 1 + cpp/autosar/test/rules/A16-0-1/test.cpp | 39 ++++++++++++++++--- 3 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 cpp/autosar/test/rules/A16-0-1/options diff --git a/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected b/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected index 9c96713ed4..8490570937 100644 --- a/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected +++ b/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected @@ -4,3 +4,4 @@ | test.cpp:11:1:11:37 | #define FUNCTIONLIKE_MACROTWO() 1 + 1 | Preprocessor directive used for conditional compilation. | | test.cpp:35:1:35:26 | #elif OBJECTLIKE_MACRO > 0 | Preprocessor directive used for conditional compilation. | | test.cpp:39:1:39:23 | #ifdef OBJECTLIKE_MACRO | Preprocessor directive used for conditional compilation. | +| test.cpp:56:1:56:27 | #elif MACRO_ENABLED_OTHER_1 | Preprocessor directive used for conditional compilation. | diff --git a/cpp/autosar/test/rules/A16-0-1/options b/cpp/autosar/test/rules/A16-0-1/options new file mode 100644 index 0000000000..9c0e6cf7b5 --- /dev/null +++ b/cpp/autosar/test/rules/A16-0-1/options @@ -0,0 +1 @@ +semmle-extractor-options:--clang -std=c++14 --edg --diag_error=implicit_func_decl -nostdinc -I../../../../../cpp/common/test/includes/standard-library -D MACRO_ENABLED_NON_1 -D MACRO_ENABLED_OTHER_1 diff --git a/cpp/autosar/test/rules/A16-0-1/test.cpp b/cpp/autosar/test/rules/A16-0-1/test.cpp index c843ccf8c6..d1d5314c59 100644 --- a/cpp/autosar/test/rules/A16-0-1/test.cpp +++ b/cpp/autosar/test/rules/A16-0-1/test.cpp @@ -36,9 +36,38 @@ int x0 = 0; // not present int x0 = 1; // present #endif // COMPLIANT -#ifdef OBJECTLIKE_MACRO // NON_COMPLIANT -int x1 = 0; // present -#elif OBJECTLIKE_MACRO > \ - -1 // COMPLIANT - by technicality of conditional compilation +#ifdef OBJECTLIKE_MACRO // NON_COMPLIANT +int x1 = 0; // present +#elif OBJECTLIKE_MACRO > -1 // NON_COMPLIANT[FALSE_NEGATIVE] - known due to + // database not containing elements int x1 = 1; // not present -#endif // COMPLIANT \ No newline at end of file +#endif // COMPLIANT + +// case 1 - first present only +#ifdef MACRO_ENABLED_NON_1 // COMPLIANT +#include //present +#elif MACRO_ENABLED_OTHER // NON_COMPLIANT[FALSE_NEGATIVE] +int x = 1; // not present +#endif + +// case 2 - second present only +#ifdef MACRO_ENABLED_NON // COMPLIANT +#include //not present +#elif MACRO_ENABLED_OTHER_1 // NON_COMPLIANT +int x = 1; // present +#endif + +// case 3 - neither present +#ifdef MACRO_ENABLED_NON // COMPLIANT +#include //not present +#elif MACRO_ENABLED_OTHER // NON_COMPLIANT[FALSE_NEGATIVE] +int x = 1; // not present +#endif + +// case 4 - both look present but the second still not bc the condition is not +// required to be evaluated +#ifdef MACRO_ENABLED_NON_1 // COMPLIANT +#include //present +#elif MACRO_ENABLED_OTHER_1 // NON_COMPLIANT[FALSE_NEGATIVE] +int x = 1; // not present +#endif \ No newline at end of file From 40d18f1e07d1d28d41df4d2cbd42d2c7dcff5293 Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Thu, 8 Feb 2024 16:55:06 -0500 Subject: [PATCH 5/6] A16-0-1: improve testcase and query logic --- ...allOnlyBeUsedForCertainDirectivesPatterns.ql | 17 ++++++----------- ...yBeUsedForCertainDirectivesPatterns.expected | 7 ++++--- cpp/autosar/test/rules/A16-0-1/test.cpp | 12 +++++++----- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql b/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql index 74d132ad7c..b026d3bba4 100644 --- a/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql +++ b/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql @@ -53,17 +53,12 @@ pragma[noinline] predicate isPreprocConditionalRange( PreprocessorBranch pb, string filepath, int startLine, int endLine ) { - //the range of an if with an elif ends at the elif to avoid reporting things twice - if exists(PreprocessorElif elif | elif.getIf() = pb) - then - exists(PreprocessorElif end | end.getIf() = pb | - isPreprocFileAndLine(pb, filepath, startLine) and - isPreprocFileAndLine(end, filepath, endLine) - ) - else - exists(PreprocessorEndif end | pb.getEndIf() = end | - isPreprocFileAndLine(pb, filepath, startLine) and - isPreprocFileAndLine(end, filepath, endLine) + isPreprocFileAndLine(pb, filepath, startLine) and + endLine = + min(int elifEndLine, PreprocessorDirective end | + pb.getNext() = end and isPreprocFileAndLine(end, filepath, elifEndLine) + | + elifEndLine ) } diff --git a/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected b/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected index 8490570937..44dd686b23 100644 --- a/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected +++ b/cpp/autosar/test/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.expected @@ -2,6 +2,7 @@ | test.cpp:9:1:9:26 | #define OBJECTLIKE_MACRO 1 | Preprocessor directive used for conditional compilation. | | test.cpp:10:1:10:35 | #define FUNCTIONLIKE_MACRO(X) X + 1 | Preprocessor directive used for conditional compilation. | | test.cpp:11:1:11:37 | #define FUNCTIONLIKE_MACROTWO() 1 + 1 | Preprocessor directive used for conditional compilation. | -| test.cpp:35:1:35:26 | #elif OBJECTLIKE_MACRO > 0 | Preprocessor directive used for conditional compilation. | -| test.cpp:39:1:39:23 | #ifdef OBJECTLIKE_MACRO | Preprocessor directive used for conditional compilation. | -| test.cpp:56:1:56:27 | #elif MACRO_ENABLED_OTHER_1 | Preprocessor directive used for conditional compilation. | +| test.cpp:31:1:31:26 | #elif OBJECTLIKE_MACRO > 0 | Preprocessor directive used for conditional compilation. | +| test.cpp:37:1:37:26 | #elif OBJECTLIKE_MACRO > 0 | Preprocessor directive used for conditional compilation. | +| test.cpp:41:1:41:23 | #ifdef OBJECTLIKE_MACRO | Preprocessor directive used for conditional compilation. | +| test.cpp:58:1:58:27 | #elif MACRO_ENABLED_OTHER_1 | Preprocessor directive used for conditional compilation. | diff --git a/cpp/autosar/test/rules/A16-0-1/test.cpp b/cpp/autosar/test/rules/A16-0-1/test.cpp index d1d5314c59..a8b83e40ec 100644 --- a/cpp/autosar/test/rules/A16-0-1/test.cpp +++ b/cpp/autosar/test/rules/A16-0-1/test.cpp @@ -24,11 +24,13 @@ int g; #include // COMPLIANT #endif // COMPLIANT -#ifdef MACRO_ENABLED_NON // COMPLIANT -#include // COMPLIANT -#elif MACRO_ENABLED_OTHER // COMPLIANT -#include // COMPLIANT -#endif // COMPLIANT +#ifdef MACRO_ENABLED_NON // COMPLIANT +#include // COMPLIANT +#elif MACRO_ENABLED_OTHER // COMPLIANT +#include // COMPLIANT +#elif OBJECTLIKE_MACRO > 0 // NON_COMPLIANT +int x00 = 1; // present +#endif // COMPLIANT #ifdef OBJECTLIKE_MACRO_NO // COMPLIANT int x0 = 0; // not present From 33509d53b876f68676adb929cbc5d82b07073c7d Mon Sep 17 00:00:00 2001 From: Kristen Newbury Date: Fri, 9 Feb 2024 09:34:21 -0500 Subject: [PATCH 6/6] A16-0-1: simplify query logic --- ...ocessorShallOnlyBeUsedForCertainDirectivesPatterns.ql | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql b/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql index b026d3bba4..6a4182d538 100644 --- a/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql +++ b/cpp/autosar/src/rules/A16-0-1/PreProcessorShallOnlyBeUsedForCertainDirectivesPatterns.ql @@ -54,12 +54,9 @@ predicate isPreprocConditionalRange( PreprocessorBranch pb, string filepath, int startLine, int endLine ) { isPreprocFileAndLine(pb, filepath, startLine) and - endLine = - min(int elifEndLine, PreprocessorDirective end | - pb.getNext() = end and isPreprocFileAndLine(end, filepath, elifEndLine) - | - elifEndLine - ) + exists(PreprocessorDirective end | + pb.getNext() = end and isPreprocFileAndLine(end, filepath, endLine) + ) } /**