From a6409e47d384c44019d780bb6ca683b5fed6ec8f Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 18 Sep 2024 22:52:51 +0100 Subject: [PATCH 1/6] Rule 1.2: Report specific extensions used Distinguish between the different types of extensions. --- c/common/src/codingstandards/c/Extensions.qll | 89 ++++++++++++--- .../LanguageExtensionsShouldNotBeUsed.ql | 2 +- ...LanguageExtensionsShouldNotBeUsed.expected | 102 +++++++++--------- 3 files changed, 129 insertions(+), 64 deletions(-) diff --git a/c/common/src/codingstandards/c/Extensions.qll b/c/common/src/codingstandards/c/Extensions.qll index 018359586e..a30f1ec45b 100644 --- a/c/common/src/codingstandards/c/Extensions.qll +++ b/c/common/src/codingstandards/c/Extensions.qll @@ -4,21 +4,28 @@ import codingstandards.cpp.Extensions /** * Common base class for modeling compiler extensions. */ -abstract class CCompilerExtension extends CompilerExtension { } +abstract class CCompilerExtension extends CompilerExtension { + abstract string getMessage(); +} // Reference: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#Other-Builtins abstract class CConditionalDefineExtension extends CCompilerExtension, PreprocessorIfdef { + string feature; + CConditionalDefineExtension() { - exists(toString().indexOf("__has_builtin")) or - exists(toString().indexOf("__has_constexpr_builtin")) or - exists(toString().indexOf("__has_feature")) or - exists(toString().indexOf("__has_extension")) or - exists(toString().indexOf("__has_attribute")) or - exists(toString().indexOf("__has_declspec_attribute")) or - exists(toString().indexOf("__is_identifier")) or - exists(toString().indexOf("__has_include")) or - exists(toString().indexOf("__has_include_next")) or - exists(toString().indexOf("__has_warning")) + feature = + [ + "__has_builtin", "__has_constexpr_builtin", "__has_feature", "__has_extension", + "__has_attribute", "__has_declspec_attribute", "__is_identifier", "__has_include", + "__has_include_next", "__has_warning" + ] and + exists(toString().indexOf(feature)) + } + + override string getMessage() { + result = + "Call to builtin function '" + feature + + "' is a compiler extension and is not portable to other compilers." } } @@ -31,6 +38,12 @@ class CMacroBasedExtension extends CCompilerExtension, Macro { "__clang_version__", "__clang_literal_encoding__", "__clang_wide_literal_encoding__" ] } + + override string getMessage() { + result = + "Use of builtin macro '" + getBody() + + "' is a compiler extension and is not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html#Variable-Attributes @@ -41,6 +54,12 @@ class CAttributeExtension extends CCompilerExtension, Attribute { "fallthrough", "read_only", "alias" ] } + + override string getMessage() { + result = + "Use of attribute '" + getName() + + "' is a compiler extension and is not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html#g_t_005f_005fsync-Builtins @@ -61,21 +80,41 @@ class CFunctionExtension extends CCompilerExtension, FunctionCall { // the built-in extensions getTarget().getName().indexOf("__builtin_") = 0 } + + override string getMessage() { + result = + "Call to builtin function '" + getTarget().getName() + + "' is a compiler extension and is not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/Alignment.html#Alignment class CFunctionLikeExtension extends CCompilerExtension, AlignofExprOperator { CFunctionLikeExtension() { exists(getValueText().indexOf("__alignof__")) } + + override string getMessage() { + result = "'__alignof__' is a compiler extension and is not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs -class CStmtExprExtension extends CCompilerExtension, StmtExpr { } +class CStmtExprExtension extends CCompilerExtension, StmtExpr { + override string getMessage() { + result = + "Statement expressions are a compiler extension and are not portable to other compilers." + } +} // Use of ternary like the following: `int a = 0 ?: 0;` where the // one of the branches is omitted // Reference: https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals class CTerseTernaryExtension extends CCompilerExtension, ConditionalExpr { CTerseTernaryExtension() { getCondition() = getElse() or getCondition() = getThen() } + + override string getMessage() { + result = + "Ternaries with omitted middle operands are a compiler extension and is not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html#g_t_005f_005fint128 @@ -87,25 +126,46 @@ class CRealTypeExtensionExtension extends CCompilerExtension, DeclarationEntry { getType() instanceof Decimal64Type or getType() instanceof Float128Type } + + override string getMessage() { + result = "Decimal floats are a compiler extension and are not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html#g_t_005f_005fint128 class CIntegerTypeExtension extends CCompilerExtension, DeclarationEntry { CIntegerTypeExtension() { getType() instanceof Int128Type } + + override string getMessage() { + result = "128-bit integers are a compiler extension and are not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/Long-Long.html#Long-Long class CLongLongType extends CCompilerExtension, DeclarationEntry { CLongLongType() { getType() instanceof LongLongType } + + override string getMessage() { + result = + "Double-Word integers are a compiler extension and are not portable to other compilers." + } } class CZeroLengthArraysExtension extends CCompilerExtension, DeclarationEntry { CZeroLengthArraysExtension() { getType().(ArrayType).getArraySize() = 0 } + + override string getMessage() { + result = "Zero length arrays are a compiler extension and are not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/Empty-Structures.html#Empty-Structures class CEmptyStructExtension extends CCompilerExtension, Struct { CEmptyStructExtension() { not exists(getAMember(_)) } + + override string getMessage() { + result = "Empty structures are a compiler extension and are not portable to other compilers." + } } // Reference: https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html#Variable-Length @@ -114,4 +174,9 @@ class CVariableLengthArraysExtension extends CCompilerExtension, DeclarationEntr getType() instanceof ArrayType and not getType().(ArrayType).hasArraySize() } + + override string getMessage() { + result = + "Variable length arrays are a compiler extension and are not portable to other compilers." + } } diff --git a/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql b/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql index f38e41a1b6..00a364a87e 100644 --- a/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql +++ b/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql @@ -17,4 +17,4 @@ import codingstandards.c.Extensions from CCompilerExtension e where not isExcluded(e, Language3Package::languageExtensionsShouldNotBeUsedQuery()) -select e, "Is a compiler extension and is not portable to other compilers." +select e, e.getMessage() diff --git a/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected b/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected index f9f034c980..d13141d7ac 100644 --- a/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected +++ b/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected @@ -1,51 +1,51 @@ -| test.c:34:1:34:23 | #define A __BASE_FILE__ | Is a compiler extension and is not portable to other compilers. | -| test.c:35:1:35:23 | #define B __FILE_NAME__ | Is a compiler extension and is not portable to other compilers. | -| test.c:36:1:36:21 | #define C __COUNTER__ | Is a compiler extension and is not portable to other compilers. | -| test.c:37:1:37:27 | #define D __INCLUDE_LEVEL__ | Is a compiler extension and is not portable to other compilers. | -| test.c:39:1:39:19 | #define F __clang__ | Is a compiler extension and is not portable to other compilers. | -| test.c:40:1:40:25 | #define G __clang_major__ | Is a compiler extension and is not portable to other compilers. | -| test.c:41:1:41:25 | #define H __clang_minor__ | Is a compiler extension and is not portable to other compilers. | -| test.c:42:1:42:30 | #define I __clang_patchlevel__ | Is a compiler extension and is not portable to other compilers. | -| test.c:43:1:43:27 | #define J __clang_version__ | Is a compiler extension and is not portable to other compilers. | -| test.c:44:1:44:36 | #define K __clang_literal_encoding__ | Is a compiler extension and is not portable to other compilers. | -| test.c:45:1:45:41 | #define L __clang_wide_literal_encoding__ | Is a compiler extension and is not portable to other compilers. | -| test.c:53:33:53:43 | vector_size | Is a compiler extension and is not portable to other compilers. | -| test.c:54:33:54:47 | vector_size | Is a compiler extension and is not portable to other compilers. | -| test.c:55:37:55:51 | ext_vector_type | Is a compiler extension and is not portable to other compilers. | -| test.c:56:37:56:51 | ext_vector_type | Is a compiler extension and is not portable to other compilers. | -| test.c:61:3:69:4 | (statement expression) | Is a compiler extension and is not portable to other compilers. | -| test.c:96:3:96:18 | call to __builtin_setjmp | Is a compiler extension and is not portable to other compilers. | -| test.c:97:3:97:19 | call to __builtin_longjmp | Is a compiler extension and is not portable to other compilers. | -| test.c:113:11:113:16 | ... ? ... : ... | Is a compiler extension and is not portable to other compilers. | -| test.c:124:12:124:12 | definition of a | Is a compiler extension and is not portable to other compilers. | -| test.c:128:17:128:17 | definition of a | Is a compiler extension and is not portable to other compilers. | -| test.c:165:8:165:15 | definition of contents | Is a compiler extension and is not portable to other compilers. | -| test.c:182:8:182:11 | gf19 | Is a compiler extension and is not portable to other compilers. | -| test.c:214:33:214:35 | declaration of out | Is a compiler extension and is not portable to other compilers. | -| test.c:215:25:215:26 | declaration of in | Is a compiler extension and is not portable to other compilers. | -| test.c:268:16:268:21 | access | Is a compiler extension and is not portable to other compilers. | -| test.c:271:27:271:31 | alias | Is a compiler extension and is not portable to other compilers. | -| test.c:274:23:274:29 | aligned | Is a compiler extension and is not portable to other compilers. | -| test.c:285:25:285:34 | deprecated | Is a compiler extension and is not portable to other compilers. | -| test.c:297:20:297:30 | fallthrough | Is a compiler extension and is not portable to other compilers. | -| test.c:321:3:321:22 | alignof() | Is a compiler extension and is not portable to other compilers. | -| test.c:340:3:340:31 | call to __builtin_extract_return_addr | Is a compiler extension and is not portable to other compilers. | -| test.c:341:3:341:28 | call to __builtin_frob_return_addr | Is a compiler extension and is not portable to other compilers. | -| test.c:342:3:342:25 | call to __builtin_frame_address | Is a compiler extension and is not portable to other compilers. | -| test.c:363:3:363:22 | call to __sync_fetch_and_add_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:364:3:364:22 | call to __sync_fetch_and_sub_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:365:3:365:21 | call to __sync_fetch_and_or_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:366:3:366:22 | call to __sync_fetch_and_and_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:367:3:367:22 | call to __sync_fetch_and_xor_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:368:3:368:23 | call to __sync_fetch_and_nand_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:369:3:369:22 | call to __sync_add_and_fetch_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:370:3:370:22 | call to __sync_sub_and_fetch_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:371:3:371:21 | call to __sync_or_and_fetch_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:372:3:372:22 | call to __sync_and_and_fetch_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:373:3:373:22 | call to __sync_xor_and_fetch_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:374:3:374:23 | call to __sync_nand_and_fetch_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:376:3:376:30 | call to __sync_bool_compare_and_swap_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:377:3:377:29 | call to __sync_val_compare_and_swap_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:378:3:378:26 | call to __sync_lock_test_and_set_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:379:3:379:21 | call to __sync_lock_release_4 | Is a compiler extension and is not portable to other compilers. | -| test.c:407:3:407:18 | call to __builtin_alloca | Is a compiler extension and is not portable to other compilers. | +| test.c:34:1:34:23 | #define A __BASE_FILE__ | Use of builtin macro '__BASE_FILE__' is a compiler extension and is not portable to other compilers. | +| test.c:35:1:35:23 | #define B __FILE_NAME__ | Use of builtin macro '__FILE_NAME__' is a compiler extension and is not portable to other compilers. | +| test.c:36:1:36:21 | #define C __COUNTER__ | Use of builtin macro '__COUNTER__' is a compiler extension and is not portable to other compilers. | +| test.c:37:1:37:27 | #define D __INCLUDE_LEVEL__ | Use of builtin macro '__INCLUDE_LEVEL__' is a compiler extension and is not portable to other compilers. | +| test.c:39:1:39:19 | #define F __clang__ | Use of builtin macro '__clang__' is a compiler extension and is not portable to other compilers. | +| test.c:40:1:40:25 | #define G __clang_major__ | Use of builtin macro '__clang_major__' is a compiler extension and is not portable to other compilers. | +| test.c:41:1:41:25 | #define H __clang_minor__ | Use of builtin macro '__clang_minor__' is a compiler extension and is not portable to other compilers. | +| test.c:42:1:42:30 | #define I __clang_patchlevel__ | Use of builtin macro '__clang_patchlevel__' is a compiler extension and is not portable to other compilers. | +| test.c:43:1:43:27 | #define J __clang_version__ | Use of builtin macro '__clang_version__' is a compiler extension and is not portable to other compilers. | +| test.c:44:1:44:36 | #define K __clang_literal_encoding__ | Use of builtin macro '__clang_literal_encoding__' is a compiler extension and is not portable to other compilers. | +| test.c:45:1:45:41 | #define L __clang_wide_literal_encoding__ | Use of builtin macro '__clang_wide_literal_encoding__' is a compiler extension and is not portable to other compilers. | +| test.c:53:33:53:43 | vector_size | Use of attribute 'vector_size' is a compiler extension and is not portable to other compilers. | +| test.c:54:33:54:47 | vector_size | Use of attribute 'vector_size' is a compiler extension and is not portable to other compilers. | +| test.c:55:37:55:51 | ext_vector_type | Use of attribute 'ext_vector_type' is a compiler extension and is not portable to other compilers. | +| test.c:56:37:56:51 | ext_vector_type | Use of attribute 'ext_vector_type' is a compiler extension and is not portable to other compilers. | +| test.c:61:3:69:4 | (statement expression) | Statement expressions are a compiler extension and are not portable to other compilers. | +| test.c:96:3:96:18 | call to __builtin_setjmp | Call to builtin function '__builtin_setjmp' is a compiler extension and is not portable to other compilers. | +| test.c:97:3:97:19 | call to __builtin_longjmp | Call to builtin function '__builtin_longjmp' is a compiler extension and is not portable to other compilers. | +| test.c:113:11:113:16 | ... ? ... : ... | Ternaries with omitted middle operands are a compiler extension and is not portable to other compilers. | +| test.c:124:12:124:12 | definition of a | 128-bit integers are a compiler extension and are not portable to other compilers. | +| test.c:128:17:128:17 | definition of a | Double-Word integers are a compiler extension and are not portable to other compilers. | +| test.c:165:8:165:15 | definition of contents | Zero length arrays are a compiler extension and are not portable to other compilers. | +| test.c:182:8:182:11 | gf19 | Empty structures are a compiler extension and are not portable to other compilers. | +| test.c:214:33:214:35 | declaration of out | Variable length arrays are a compiler extension and are not portable to other compilers. | +| test.c:215:25:215:26 | declaration of in | Variable length arrays are a compiler extension and are not portable to other compilers. | +| test.c:268:16:268:21 | access | Use of attribute 'access' is a compiler extension and is not portable to other compilers. | +| test.c:271:27:271:31 | alias | Use of attribute 'alias' is a compiler extension and is not portable to other compilers. | +| test.c:274:23:274:29 | aligned | Use of attribute 'aligned' is a compiler extension and is not portable to other compilers. | +| test.c:285:25:285:34 | deprecated | Use of attribute 'deprecated' is a compiler extension and is not portable to other compilers. | +| test.c:297:20:297:30 | fallthrough | Use of attribute 'fallthrough' is a compiler extension and is not portable to other compilers. | +| test.c:321:3:321:22 | alignof() | '__alignof__' is a compiler extension and is not portable to other compilers. | +| test.c:340:3:340:31 | call to __builtin_extract_return_addr | Call to builtin function '__builtin_extract_return_addr' is a compiler extension and is not portable to other compilers. | +| test.c:341:3:341:28 | call to __builtin_frob_return_addr | Call to builtin function '__builtin_frob_return_addr' is a compiler extension and is not portable to other compilers. | +| test.c:342:3:342:25 | call to __builtin_frame_address | Call to builtin function '__builtin_frame_address' is a compiler extension and is not portable to other compilers. | +| test.c:363:3:363:22 | call to __sync_fetch_and_add_4 | Call to builtin function '__sync_fetch_and_add_4' is a compiler extension and is not portable to other compilers. | +| test.c:364:3:364:22 | call to __sync_fetch_and_sub_4 | Call to builtin function '__sync_fetch_and_sub_4' is a compiler extension and is not portable to other compilers. | +| test.c:365:3:365:21 | call to __sync_fetch_and_or_4 | Call to builtin function '__sync_fetch_and_or_4' is a compiler extension and is not portable to other compilers. | +| test.c:366:3:366:22 | call to __sync_fetch_and_and_4 | Call to builtin function '__sync_fetch_and_and_4' is a compiler extension and is not portable to other compilers. | +| test.c:367:3:367:22 | call to __sync_fetch_and_xor_4 | Call to builtin function '__sync_fetch_and_xor_4' is a compiler extension and is not portable to other compilers. | +| test.c:368:3:368:23 | call to __sync_fetch_and_nand_4 | Call to builtin function '__sync_fetch_and_nand_4' is a compiler extension and is not portable to other compilers. | +| test.c:369:3:369:22 | call to __sync_add_and_fetch_4 | Call to builtin function '__sync_add_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:370:3:370:22 | call to __sync_sub_and_fetch_4 | Call to builtin function '__sync_sub_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:371:3:371:21 | call to __sync_or_and_fetch_4 | Call to builtin function '__sync_or_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:372:3:372:22 | call to __sync_and_and_fetch_4 | Call to builtin function '__sync_and_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:373:3:373:22 | call to __sync_xor_and_fetch_4 | Call to builtin function '__sync_xor_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:374:3:374:23 | call to __sync_nand_and_fetch_4 | Call to builtin function '__sync_nand_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:376:3:376:30 | call to __sync_bool_compare_and_swap_4 | Call to builtin function '__sync_bool_compare_and_swap_4' is a compiler extension and is not portable to other compilers. | +| test.c:377:3:377:29 | call to __sync_val_compare_and_swap_4 | Call to builtin function '__sync_val_compare_and_swap_4' is a compiler extension and is not portable to other compilers. | +| test.c:378:3:378:26 | call to __sync_lock_test_and_set_4 | Call to builtin function '__sync_lock_test_and_set_4' is a compiler extension and is not portable to other compilers. | +| test.c:379:3:379:21 | call to __sync_lock_release_4 | Call to builtin function '__sync_lock_release_4' is a compiler extension and is not portable to other compilers. | +| test.c:407:3:407:18 | call to __builtin_alloca | Call to builtin function '__builtin_alloca' is a compiler extension and is not portable to other compilers. | From 9605d7954cc7d04a61bbf28d0ecdb35ae0aff0c6 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Wed, 18 Sep 2024 23:13:39 +0100 Subject: [PATCH 2/6] Rule 1.2: Correct detection of variable length arrays --- c/common/src/codingstandards/c/Extensions.qll | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/c/common/src/codingstandards/c/Extensions.qll b/c/common/src/codingstandards/c/Extensions.qll index a30f1ec45b..4f16a1f09a 100644 --- a/c/common/src/codingstandards/c/Extensions.qll +++ b/c/common/src/codingstandards/c/Extensions.qll @@ -169,10 +169,16 @@ class CEmptyStructExtension extends CCompilerExtension, Struct { } // Reference: https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html#Variable-Length -class CVariableLengthArraysExtension extends CCompilerExtension, DeclarationEntry { +class CVariableLengthArraysExtension extends CCompilerExtension, Field { CVariableLengthArraysExtension() { getType() instanceof ArrayType and - not getType().(ArrayType).hasArraySize() + not getType().(ArrayType).hasArraySize() and + // Not the final member of the struct, which is allowed to be variably sized + not exists(int lastIndex, Class declaringStruct | + declaringStruct = getDeclaringType() and + lastIndex = count(declaringStruct.getACanonicalMember()) - 1 and + this = declaringStruct.getCanonicalMember(lastIndex) + ) } override string getMessage() { From 9139b8e21cb741cc56355ae7a19c68e04e572d58 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Sep 2024 10:00:05 +0100 Subject: [PATCH 3/6] Rule 1.2: Fix test for variable length arrays Only variable length struct fields are a gcc extension. --- ...LanguageExtensionsShouldNotBeUsed.expected | 55 +++++++++---------- c/misra/test/rules/RULE-1-2/test.c | 14 ++--- 2 files changed, 33 insertions(+), 36 deletions(-) diff --git a/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected b/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected index d13141d7ac..b82fa2bbc5 100644 --- a/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected +++ b/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected @@ -21,31 +21,30 @@ | test.c:128:17:128:17 | definition of a | Double-Word integers are a compiler extension and are not portable to other compilers. | | test.c:165:8:165:15 | definition of contents | Zero length arrays are a compiler extension and are not portable to other compilers. | | test.c:182:8:182:11 | gf19 | Empty structures are a compiler extension and are not portable to other compilers. | -| test.c:214:33:214:35 | declaration of out | Variable length arrays are a compiler extension and are not portable to other compilers. | -| test.c:215:25:215:26 | declaration of in | Variable length arrays are a compiler extension and are not portable to other compilers. | -| test.c:268:16:268:21 | access | Use of attribute 'access' is a compiler extension and is not portable to other compilers. | -| test.c:271:27:271:31 | alias | Use of attribute 'alias' is a compiler extension and is not portable to other compilers. | -| test.c:274:23:274:29 | aligned | Use of attribute 'aligned' is a compiler extension and is not portable to other compilers. | -| test.c:285:25:285:34 | deprecated | Use of attribute 'deprecated' is a compiler extension and is not portable to other compilers. | -| test.c:297:20:297:30 | fallthrough | Use of attribute 'fallthrough' is a compiler extension and is not portable to other compilers. | -| test.c:321:3:321:22 | alignof() | '__alignof__' is a compiler extension and is not portable to other compilers. | -| test.c:340:3:340:31 | call to __builtin_extract_return_addr | Call to builtin function '__builtin_extract_return_addr' is a compiler extension and is not portable to other compilers. | -| test.c:341:3:341:28 | call to __builtin_frob_return_addr | Call to builtin function '__builtin_frob_return_addr' is a compiler extension and is not portable to other compilers. | -| test.c:342:3:342:25 | call to __builtin_frame_address | Call to builtin function '__builtin_frame_address' is a compiler extension and is not portable to other compilers. | -| test.c:363:3:363:22 | call to __sync_fetch_and_add_4 | Call to builtin function '__sync_fetch_and_add_4' is a compiler extension and is not portable to other compilers. | -| test.c:364:3:364:22 | call to __sync_fetch_and_sub_4 | Call to builtin function '__sync_fetch_and_sub_4' is a compiler extension and is not portable to other compilers. | -| test.c:365:3:365:21 | call to __sync_fetch_and_or_4 | Call to builtin function '__sync_fetch_and_or_4' is a compiler extension and is not portable to other compilers. | -| test.c:366:3:366:22 | call to __sync_fetch_and_and_4 | Call to builtin function '__sync_fetch_and_and_4' is a compiler extension and is not portable to other compilers. | -| test.c:367:3:367:22 | call to __sync_fetch_and_xor_4 | Call to builtin function '__sync_fetch_and_xor_4' is a compiler extension and is not portable to other compilers. | -| test.c:368:3:368:23 | call to __sync_fetch_and_nand_4 | Call to builtin function '__sync_fetch_and_nand_4' is a compiler extension and is not portable to other compilers. | -| test.c:369:3:369:22 | call to __sync_add_and_fetch_4 | Call to builtin function '__sync_add_and_fetch_4' is a compiler extension and is not portable to other compilers. | -| test.c:370:3:370:22 | call to __sync_sub_and_fetch_4 | Call to builtin function '__sync_sub_and_fetch_4' is a compiler extension and is not portable to other compilers. | -| test.c:371:3:371:21 | call to __sync_or_and_fetch_4 | Call to builtin function '__sync_or_and_fetch_4' is a compiler extension and is not portable to other compilers. | -| test.c:372:3:372:22 | call to __sync_and_and_fetch_4 | Call to builtin function '__sync_and_and_fetch_4' is a compiler extension and is not portable to other compilers. | -| test.c:373:3:373:22 | call to __sync_xor_and_fetch_4 | Call to builtin function '__sync_xor_and_fetch_4' is a compiler extension and is not portable to other compilers. | -| test.c:374:3:374:23 | call to __sync_nand_and_fetch_4 | Call to builtin function '__sync_nand_and_fetch_4' is a compiler extension and is not portable to other compilers. | -| test.c:376:3:376:30 | call to __sync_bool_compare_and_swap_4 | Call to builtin function '__sync_bool_compare_and_swap_4' is a compiler extension and is not portable to other compilers. | -| test.c:377:3:377:29 | call to __sync_val_compare_and_swap_4 | Call to builtin function '__sync_val_compare_and_swap_4' is a compiler extension and is not portable to other compilers. | -| test.c:378:3:378:26 | call to __sync_lock_test_and_set_4 | Call to builtin function '__sync_lock_test_and_set_4' is a compiler extension and is not portable to other compilers. | -| test.c:379:3:379:21 | call to __sync_lock_release_4 | Call to builtin function '__sync_lock_release_4' is a compiler extension and is not portable to other compilers. | -| test.c:407:3:407:18 | call to __builtin_alloca | Call to builtin function '__builtin_alloca' is a compiler extension and is not portable to other compilers. | +| test.c:216:9:216:10 | definition of x1 | Zero length arrays are a compiler extension and are not portable to other compilers. | +| test.c:266:16:266:21 | access | Use of attribute 'access' is a compiler extension and is not portable to other compilers. | +| test.c:270:5:270:9 | alias | Use of attribute 'alias' is a compiler extension and is not portable to other compilers. | +| test.c:272:23:272:29 | aligned | Use of attribute 'aligned' is a compiler extension and is not portable to other compilers. | +| test.c:283:25:283:34 | deprecated | Use of attribute 'deprecated' is a compiler extension and is not portable to other compilers. | +| test.c:295:20:295:30 | fallthrough | Use of attribute 'fallthrough' is a compiler extension and is not portable to other compilers. | +| test.c:319:3:319:22 | alignof() | '__alignof__' is a compiler extension and is not portable to other compilers. | +| test.c:338:3:338:31 | call to __builtin_extract_return_addr | Call to builtin function '__builtin_extract_return_addr' is a compiler extension and is not portable to other compilers. | +| test.c:339:3:339:28 | call to __builtin_frob_return_addr | Call to builtin function '__builtin_frob_return_addr' is a compiler extension and is not portable to other compilers. | +| test.c:340:3:340:25 | call to __builtin_frame_address | Call to builtin function '__builtin_frame_address' is a compiler extension and is not portable to other compilers. | +| test.c:361:3:361:22 | call to __sync_fetch_and_add_4 | Call to builtin function '__sync_fetch_and_add_4' is a compiler extension and is not portable to other compilers. | +| test.c:362:3:362:22 | call to __sync_fetch_and_sub_4 | Call to builtin function '__sync_fetch_and_sub_4' is a compiler extension and is not portable to other compilers. | +| test.c:363:3:363:21 | call to __sync_fetch_and_or_4 | Call to builtin function '__sync_fetch_and_or_4' is a compiler extension and is not portable to other compilers. | +| test.c:364:3:364:22 | call to __sync_fetch_and_and_4 | Call to builtin function '__sync_fetch_and_and_4' is a compiler extension and is not portable to other compilers. | +| test.c:365:3:365:22 | call to __sync_fetch_and_xor_4 | Call to builtin function '__sync_fetch_and_xor_4' is a compiler extension and is not portable to other compilers. | +| test.c:366:3:366:23 | call to __sync_fetch_and_nand_4 | Call to builtin function '__sync_fetch_and_nand_4' is a compiler extension and is not portable to other compilers. | +| test.c:367:3:367:22 | call to __sync_add_and_fetch_4 | Call to builtin function '__sync_add_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:368:3:368:22 | call to __sync_sub_and_fetch_4 | Call to builtin function '__sync_sub_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:369:3:369:21 | call to __sync_or_and_fetch_4 | Call to builtin function '__sync_or_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:370:3:370:22 | call to __sync_and_and_fetch_4 | Call to builtin function '__sync_and_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:371:3:371:22 | call to __sync_xor_and_fetch_4 | Call to builtin function '__sync_xor_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:372:3:372:23 | call to __sync_nand_and_fetch_4 | Call to builtin function '__sync_nand_and_fetch_4' is a compiler extension and is not portable to other compilers. | +| test.c:374:3:374:30 | call to __sync_bool_compare_and_swap_4 | Call to builtin function '__sync_bool_compare_and_swap_4' is a compiler extension and is not portable to other compilers. | +| test.c:375:3:375:29 | call to __sync_val_compare_and_swap_4 | Call to builtin function '__sync_val_compare_and_swap_4' is a compiler extension and is not portable to other compilers. | +| test.c:376:3:376:26 | call to __sync_lock_test_and_set_4 | Call to builtin function '__sync_lock_test_and_set_4' is a compiler extension and is not portable to other compilers. | +| test.c:377:3:377:21 | call to __sync_lock_release_4 | Call to builtin function '__sync_lock_release_4' is a compiler extension and is not portable to other compilers. | +| test.c:405:3:405:18 | call to __builtin_alloca | Call to builtin function '__builtin_alloca' is a compiler extension and is not portable to other compilers. | diff --git a/c/misra/test/rules/RULE-1-2/test.c b/c/misra/test/rules/RULE-1-2/test.c index 86a3ae2f20..5a0759afba 100644 --- a/c/misra/test/rules/RULE-1-2/test.c +++ b/c/misra/test/rules/RULE-1-2/test.c @@ -211,14 +211,12 @@ void gf24(int f, int g) { // Reference: // https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html#Variable-Length -void gf25t(int N, int M, double out[M][N], // NON_COMPLIANT - const double in[N][M]); // NON_COMPLIANT -void gf25() { - double x[3][2]; - double y[2][3]; - gf25t(3, 2, y, - x); // in ISO C the const qualifier is formally attached - // to the element type of the array and not the array itself +void gf25(int n) { + struct S1 { + int x1[n]; // NON_COMPLIANT + int x2[5]; // COMPLIANT + int x3[]; // COMPLIANT + }; } // Reference: From ecf5e8beeba67957387fc2bdc8a6ff11b5b1d719 Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Sep 2024 10:57:50 +0100 Subject: [PATCH 4/6] Rule 1.2: Support aggregation of results at macro locations Add a new module/library for identifying the macro that generated an element as the primary location, and use it for Rule 1.2 to avoid overreporting. --- .../LanguageExtensionsShouldNotBeUsed.ql | 3 +- ...LanguageExtensionsShouldNotBeUsed.expected | 1 + c/misra/test/rules/RULE-1-2/test.c | 8 +++- .../codingstandards/cpp/AlertReporting.qll | 41 +++++++++++++++++++ 4 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 cpp/common/src/codingstandards/cpp/AlertReporting.qll diff --git a/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql b/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql index 00a364a87e..8017f58fb5 100644 --- a/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql +++ b/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql @@ -13,8 +13,9 @@ import cpp import codingstandards.c.misra +import codingstandards.cpp.AlertReporting import codingstandards.c.Extensions from CCompilerExtension e where not isExcluded(e, Language3Package::languageExtensionsShouldNotBeUsedQuery()) -select e, e.getMessage() +select MacroUnwrapper::unwrapElement(e), e.getMessage() diff --git a/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected b/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected index b82fa2bbc5..d0303f9a7f 100644 --- a/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected +++ b/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected @@ -48,3 +48,4 @@ | test.c:376:3:376:26 | call to __sync_lock_test_and_set_4 | Call to builtin function '__sync_lock_test_and_set_4' is a compiler extension and is not portable to other compilers. | | test.c:377:3:377:21 | call to __sync_lock_release_4 | Call to builtin function '__sync_lock_release_4' is a compiler extension and is not portable to other compilers. | | test.c:405:3:405:18 | call to __builtin_alloca | Call to builtin function '__builtin_alloca' is a compiler extension and is not portable to other compilers. | +| test.c:409:1:411:8 | #define BUILTIN __builtin_alloca( 0) | Call to builtin function '__builtin_alloca' is a compiler extension and is not portable to other compilers. | diff --git a/c/misra/test/rules/RULE-1-2/test.c b/c/misra/test/rules/RULE-1-2/test.c index 5a0759afba..439df3733c 100644 --- a/c/misra/test/rules/RULE-1-2/test.c +++ b/c/misra/test/rules/RULE-1-2/test.c @@ -404,4 +404,10 @@ void gf47() { // NON_COMPLIANT in versions < C11. void gf48() { __builtin_alloca( 0); // NON_COMPLIANT (all __builtin functions are non-compliant.) -} \ No newline at end of file +} + +#define BUILTIN \ + __builtin_alloca( \ + 0) // NON_COMPLIANT (all __builtin functions are non-compliant.) + +void gf49() { BUILTIN; } \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/AlertReporting.qll b/cpp/common/src/codingstandards/cpp/AlertReporting.qll new file mode 100644 index 0000000000..4259e1b67d --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/AlertReporting.qll @@ -0,0 +1,41 @@ +/** + * Provides a library for managing how alerts are reported. + */ + +import cpp + +signature class ResultType extends Element; + +/** + * A module for unwrapping results that occur in macro expansions. + */ +module MacroUnwrapper { + /** + * Gets a macro invocation that applies to the result element. + */ + private MacroInvocation getAMacroInvocation(ResultElement re) { + result.getAnExpandedElement() = re + } + + /** + * Gets the primary macro that generated the result element. + */ + Macro getPrimaryMacro(ResultElement re) { + exists(MacroInvocation mi | + mi = getAMacroInvocation(re) and + // No other more specific macro that expands to element + not exists(MacroInvocation otherMi | + otherMi = getAMacroInvocation(re) and otherMi.getParentInvocation() = mi + ) and + result = mi.getMacro() + ) + } + + /** + * If a result element is expanded from a macro invocation, then return the "primary" macro that + * generated the element, otherwise return the element itself. + */ + Element unwrapElement(ResultElement re) { + if exists(getPrimaryMacro(re)) then result = getPrimaryMacro(re) else result = re + } +} From 4318622161d534399d9cb4e2f531ebc9bf17dd0c Mon Sep 17 00:00:00 2001 From: Luke Cartey Date: Thu, 19 Sep 2024 11:38:15 +0100 Subject: [PATCH 5/6] Rule 1.2: Add change note --- change_notes/2024-09-19-c-extensions.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 change_notes/2024-09-19-c-extensions.md diff --git a/change_notes/2024-09-19-c-extensions.md b/change_notes/2024-09-19-c-extensions.md new file mode 100644 index 0000000000..2f78574679 --- /dev/null +++ b/change_notes/2024-09-19-c-extensions.md @@ -0,0 +1,4 @@ + - `RULE-1-2` - `LanguageExtensionsShouldNotBeUsed.ql`: + - Improve reporting by describing which language extensions are used. + - Improve reporting by aggregating results generated from a macro expansion at the generating macro location. + - Reduce false positives for the variable length array check by permitting those extensions which are included in the C99 standard. \ No newline at end of file From cbc63883d7b82c28b7166b7b106d3cfcc3c61563 Mon Sep 17 00:00:00 2001 From: Nicolas Will Date: Fri, 4 Oct 2024 13:29:03 +0200 Subject: [PATCH 6/6] Update c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected --- .../rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected b/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected index d0303f9a7f..0e2cbb26ee 100644 --- a/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected +++ b/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected @@ -23,7 +23,7 @@ | test.c:182:8:182:11 | gf19 | Empty structures are a compiler extension and are not portable to other compilers. | | test.c:216:9:216:10 | definition of x1 | Zero length arrays are a compiler extension and are not portable to other compilers. | | test.c:266:16:266:21 | access | Use of attribute 'access' is a compiler extension and is not portable to other compilers. | -| test.c:270:5:270:9 | alias | Use of attribute 'alias' is a compiler extension and is not portable to other compilers. | +| test.c:269:27:269:31 | alias | Use of attribute 'alias' is a compiler extension and is not portable to other compilers. | | test.c:272:23:272:29 | aligned | Use of attribute 'aligned' is a compiler extension and is not portable to other compilers. | | test.c:283:25:283:34 | deprecated | Use of attribute 'deprecated' is a compiler extension and is not portable to other compilers. | | test.c:295:20:295:30 | fallthrough | Use of attribute 'fallthrough' is a compiler extension and is not portable to other compilers. |