diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2730f99e87..8cebadd0c3 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -236,6 +236,7 @@ "Lambdas", "Language1", "Language2", + "Language3", "Literals", "Loops", "Macros", diff --git a/c/common/src/codingstandards/c/Extensions.qll b/c/common/src/codingstandards/c/Extensions.qll new file mode 100644 index 0000000000..018359586e --- /dev/null +++ b/c/common/src/codingstandards/c/Extensions.qll @@ -0,0 +1,117 @@ +import cpp +import codingstandards.cpp.Extensions + +/** + * Common base class for modeling compiler extensions. + */ +abstract class CCompilerExtension extends CompilerExtension { } + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#Other-Builtins +abstract class CConditionalDefineExtension extends CCompilerExtension, PreprocessorIfdef { + 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")) + } +} + +// Reference: https://clang.llvm.org/docs/LanguageExtensions.html#builtin-macros +class CMacroBasedExtension extends CCompilerExtension, Macro { + CMacroBasedExtension() { + getBody() in [ + "__BASE_FILE__", "__FILE_NAME__", "__COUNTER__", "__INCLUDE_LEVEL__", "_TIMESTAMP__", + "__clang__", "__clang_major__", "__clang_minor__", "__clang_patchlevel__", + "__clang_version__", "__clang_literal_encoding__", "__clang_wide_literal_encoding__" + ] + } +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html#Variable-Attributes +class CAttributeExtension extends CCompilerExtension, Attribute { + CAttributeExtension() { + getName() in [ + "ext_vector_type", "vector_size", "access", "aligned", "deprecated", "cold", "unused", + "fallthrough", "read_only", "alias" + ] + } +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html#g_t_005f_005fsync-Builtins +class CFunctionExtension extends CCompilerExtension, FunctionCall { + CFunctionExtension() { + // these must be somewhat broad because of how they vary + // in implementation / naming + getTarget().getName().indexOf("__sync_fetch") = 0 or + getTarget().getName().indexOf("__sync_add") = 0 or + getTarget().getName().indexOf("__sync_sub") = 0 or + getTarget().getName().indexOf("__sync_or") = 0 or + getTarget().getName().indexOf("__sync_and") = 0 or + getTarget().getName().indexOf("__sync_xor") = 0 or + getTarget().getName().indexOf("__sync_nand") = 0 or + getTarget().getName().indexOf("__sync_bool") = 0 or + getTarget().getName().indexOf("__sync_val") = 0 or + getTarget().getName().indexOf("__sync_lock") = 0 or + // the built-in extensions + getTarget().getName().indexOf("__builtin_") = 0 + } +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Alignment.html#Alignment +class CFunctionLikeExtension extends CCompilerExtension, AlignofExprOperator { + CFunctionLikeExtension() { exists(getValueText().indexOf("__alignof__")) } +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs +class CStmtExprExtension extends CCompilerExtension, StmtExpr { } + +// 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() } +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html#g_t_005f_005fint128 +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Decimal-Float.html#Decimal-Float +class CRealTypeExtensionExtension extends CCompilerExtension, DeclarationEntry { + CRealTypeExtensionExtension() { + getType() instanceof Decimal128Type or + getType() instanceof Decimal32Type or + getType() instanceof Decimal64Type or + getType() instanceof Float128Type + } +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html#g_t_005f_005fint128 +class CIntegerTypeExtension extends CCompilerExtension, DeclarationEntry { + CIntegerTypeExtension() { getType() instanceof Int128Type } +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Long-Long.html#Long-Long +class CLongLongType extends CCompilerExtension, DeclarationEntry { + CLongLongType() { getType() instanceof LongLongType } +} + +class CZeroLengthArraysExtension extends CCompilerExtension, DeclarationEntry { + CZeroLengthArraysExtension() { getType().(ArrayType).getArraySize() = 0 } +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Empty-Structures.html#Empty-Structures +class CEmptyStructExtension extends CCompilerExtension, Struct { + CEmptyStructExtension() { not exists(getAMember(_)) } +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html#Variable-Length +class CVariableLengthArraysExtension extends CCompilerExtension, DeclarationEntry { + CVariableLengthArraysExtension() { + getType() instanceof ArrayType and + not getType().(ArrayType).hasArraySize() + } +} diff --git a/c/common/src/codingstandards/c/UndefinedBehavior.qll b/c/common/src/codingstandards/c/UndefinedBehavior.qll new file mode 100644 index 0000000000..49b1ee3e5e --- /dev/null +++ b/c/common/src/codingstandards/c/UndefinedBehavior.qll @@ -0,0 +1,28 @@ +import cpp +import codingstandards.cpp.UndefinedBehavior + +/** + * Library for modeling undefined behavior. + */ +abstract class CUndefinedBehavior extends UndefinedBehavior { } + +class C99MainFunction extends Function { + C99MainFunction() { + this.getNumberOfParameters() = 2 and + this.getType() instanceof IntType and + this.getParameter(0).getType() instanceof IntType and + this.getParameter(1).getType().(PointerType).getBaseType().(PointerType).getBaseType() + instanceof CharType + or + this.getNumberOfParameters() = 0 and + this.getType() instanceof VoidType + } +} + +class CUndefinedMainDefinition extends CUndefinedBehavior, Function { + CUndefinedMainDefinition() { + // for testing purposes, we use the prefix ____codeql_coding_standards` + (this.getName() = "main" or this.getName().indexOf("____codeql_coding_standards") = 0) and + not this instanceof C99MainFunction + } +} diff --git a/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql b/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql new file mode 100644 index 0000000000..f38e41a1b6 --- /dev/null +++ b/c/misra/src/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql @@ -0,0 +1,20 @@ +/** + * @id c/misra/language-extensions-should-not-be-used + * @name RULE-1-2: Language extensions should not be used + * @description Language extensions are not portable to other compilers and should not be used. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-1-2 + * maintainability + * readability + * external/misra/obligation/advisory + */ + +import cpp +import codingstandards.c.misra +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." diff --git a/c/misra/src/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.ql b/c/misra/src/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.ql new file mode 100644 index 0000000000..f6b295bd32 --- /dev/null +++ b/c/misra/src/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.ql @@ -0,0 +1,20 @@ +/** + * @id c/misra/occurrence-of-undefined-behavior + * @name RULE-1-3: There shall be no occurrence of undefined or critical unspecified behavior + * @description Relying on undefined or unspecified behavior can result in unreliable programs. + * @kind problem + * @precision high + * @problem.severity error + * @tags external/misra/id/rule-1-3 + * maintainability + * readability + * external/misra/obligation/required + */ + +import cpp +import codingstandards.c.misra +import codingstandards.c.UndefinedBehavior + +from CUndefinedBehavior c +where not isExcluded(c, Language3Package::occurrenceOfUndefinedBehaviorQuery()) +select c, "May result in undefined behavior." diff --git a/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected b/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected new file mode 100644 index 0000000000..f9f034c980 --- /dev/null +++ b/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.expected @@ -0,0 +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. | diff --git a/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.qlref b/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.qlref new file mode 100644 index 0000000000..965c95be2c --- /dev/null +++ b/c/misra/test/rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.qlref @@ -0,0 +1 @@ +rules/RULE-1-2/LanguageExtensionsShouldNotBeUsed.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-2/options b/c/misra/test/rules/RULE-1-2/options new file mode 100644 index 0000000000..ea7b68755d --- /dev/null +++ b/c/misra/test/rules/RULE-1-2/options @@ -0,0 +1 @@ +semmle-extractor-options:--clang -fhonor-infinity -std=c11 --edg --diag_error=implicit_func_decl -nostdinc -I../../../../common/test/includes/standard-library diff --git a/c/misra/test/rules/RULE-1-2/test.c b/c/misra/test/rules/RULE-1-2/test.c new file mode 100644 index 0000000000..367570f7e7 --- /dev/null +++ b/c/misra/test/rules/RULE-1-2/test.c @@ -0,0 +1,409 @@ +#include +#include +// Note: Clang aims to support both clang and gcc extensions. +// This test case has been designed using lists compiled from: +// - https://clang.llvm.org/docs/LanguageExtensions.html +// - https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#Other-Builtins +#ifdef __has_builtin // NON_COMPLIANT[FALSE_NEGATIVE] +#endif +#ifdef __has_constexpr_builtin // NON_COMPLIANT[FALSE_NEGATIVE] +#endif +#ifdef __has_feature // NON_COMPLIANT[FALSE_NEGATIVE] +#endif +#ifdef __has_extension // NON_COMPLIANT[FALSE_NEGATIVE] +#endif +#ifdef __has_c_attribute // NON_COMPLIANT[FALSE_NEGATIVE] +#endif +#ifdef __has_attribute // NON_COMPLIANT[FALSE_NEGATIVE] +#endif +#ifdef __has_declspec_attribute // NON_COMPLIANT[FALSE_NEGATIVE] +#endif +#ifdef __is_identifier // NON_COMPLIANT[FALSE_NEGATIVE] +#endif +#ifdef __has_include // NON_COMPLIANT[FALSE_NEGATIVE] +#endif +#ifdef __has_include_next // NON_COMPLIANT[FALSE_NEGATIVE] +#endif +#ifdef __has_warning // NON_COMPLIANT[FALSE_NEGATIVE] +#endif + +// Reference: https://clang.llvm.org/docs/LanguageExtensions.html#builtin-macros +#define A __BASE_FILE__ // NON_COMPLIANT +#define B __FILE_NAME__ // NON_COMPLIANT +#define C __COUNTER__ // NON_COMPLIANT +#define D __INCLUDE_LEVEL__ // NON_COMPLIANT +#define E__TIMESTAMP__ // NON_COMPLIANT +#define F __clang__ // NON_COMPLIANT +#define G __clang_major__ // NON_COMPLIANT +#define H __clang_minor__ // NON_COMPLIANT +#define I __clang_patchlevel__ // NON_COMPLIANT +#define J __clang_version__ // NON_COMPLIANT +#define K __clang_literal_encoding__ // NON_COMPLIANT +#define L __clang_wide_literal_encoding__ // NON_COMPLIANT + +// Requires additional compiler flags to change the architecture +// typedef __attribute__((neon_vector_type(8))) int8_t int8x8_t; +// typedef __attribute__((neon_polyvector_type(16))) poly8_t poly8x16_t; + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html#Variable-Attributes +typedef int int4 __attribute__((vector_size(4 * sizeof(int)))); // NON_COMPLIANT +typedef int v4si __attribute__((__vector_size__(16))); // NON_COMPLIANT +typedef float float4 __attribute__((ext_vector_type(4))); // NON_COMPLIANT +typedef float float2 __attribute__((ext_vector_type(2))); // NON_COMPLIANT + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs +void gf1() { + ({ // NON_COMPLIANT + int y = 1; + int z; + if (y > 0) + z = y; + else + z = -y; + z; + }); +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Local-Labels.html#Local-Labels +void gf2() { + // __label__ found; // NON_COMPLIANT[FALSE_NEGATIVE] -- local labels not + // supported by clang +} + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html#Labels-as-Values +void gf3() { + void *ptr; + // goto *ptr; // NON_COMPLIANT[FALSE_NEGATIVE] -- not supported in clang +} + +// Referfence: +// https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html#Nested-Functions +void gf4() { + // void gf4a(){ // NON_COMPLIANT[FALSE_NEGATIVE] -- not supported in clang + // + // } +} + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Nonlocal-Gotos.html#Nonlocal-Gotos +void gf5() { + __builtin_setjmp(0); // NON_COMPLIANT + __builtin_longjmp(0, 1); // NON_COMPLIANT +} + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Constructing-Calls.html#Constructing-Calls +void gf6() { + // not supported by clang + //__builtin_apply_args(); // NON_COMPLIANT[FALSE_NEGATIVE] + //__builtin_apply(0, 0, 0); // NON_COMPLIANT[FALSE_NEGATIVE] + //__builtin_return(0); // NON_COMPLIANT[FALSE_NEGATIVE] + //__builtin_va_arg_pack(); // NON_COMPLIANT[FALSE_NEGATIVE] + //__builtin_va_arg_pack_len(); // NON_COMPLIANT[FALSE_NEGATIVE] +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals +void gf7() { + int a = 0 ?: 0; // NON_COMPLIANT +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Typeof.html#Typeof +void gf8() { + typeof(int *); // NON_COMPLIANT[FALSE_NEGATIVE] +} + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/_005f_005fint128.html#g_t_005f_005fint128 +void gf9() { + __int128 a; // NON_COMPLIANT +} +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Long-Long.html#Long-Long +void gf10() { + long long int a; // NON_COMPLIANT +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Complex.html#Complex +void gf11() { + __real__(0); // NON_COMPLIANT[FALSE_NEGATIVE] + __imag__(0); // NON_COMPLIANT[FALSE_NEGATIVE] +} + +void gf12() {} + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Floating-Types.html#Floating-Types +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Decimal-Float.html#Decimal-Float +void gf13() { + // not supported on clang + //_Decimal32 a; // NON_COMPLIANT[FALSE_NEGATIVE] + //_Decimal64 b; // NON_COMPLIANT[FALSE_NEGATIVE] + //_Decimal128 c; // NON_COMPLIANT[FALSE_NEGATIVE] +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Complex.html#Complex +void gf14() { + // Do not work in clang + // typedef _Complex float __attribute__((mode(TC))) _Complex128; // + // NON_COMPLIANT[FALSE_NEGATIVE] typedef _Complex float + // __attribute__((mode(XC))) _Complex80; // NON_COMPLIANT[FALSE_NEGATIVE] +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Hex-Floats.html#Hex-Floats +void gf15() { + float f = 0x1.fp3; // NON_COMPLIANT[FALSE_NEGATIVE] +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html#Zero-Length +void gf16() { + char contents[0]; // NON_COMPLIANT +} + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Named-Address-Spaces.html#Named-Address-Spaces +void gf17() { + // const __flash char ** p; // NON_COMPLIANT[FALSE_NEGATIVE] -- not supported + // in clang +} + +void gf18() { + // not supported by extractor - checked by looking for flags. + + // short _Fract, _Fract; // NON_COMPLIANT[FALSE_NEGATIVE] - + // long _Fract; // NON_COMPLIANT[FALSE_NEGATIVE] +} + +struct gf19 {}; // NON_COMPLIANT + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html#Variable-Length +void gf20(int n) { + // struct S { int x[n]; }; // NON_COMPLIANT[FALSE_NEGATIVE] - will never be + // supported in clang +} +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Variadic-Macros.html#Variadic-Macros +#define gf21(format, args...) \ + printf(format, args) // NON_COMPLIANT[FALSE_NEGATIVE] -- note + // the issue here is explicitly naming the arguments. +#define gf21a(format, ...) printf(format, __VA_ARGS__) // COMPLIANT + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Escaped-Newlines.html#Escaped-Newlines +#define gf22 \ + "a" \ + \ +"b" // NON_COMPLIANT[FALSE_NEGATIVE] - additional spaces after a backslash -- + // stripped by extractor +#define gf22a \ + "a" \ + "b" // COMPLIANT + +void gf24(int f, int g) { + float beat_freqs[2] = {f - g, f + g}; // NON_COMPLIANT +} + +// 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 +} + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html#Compound-Literals +struct gf26t { + int a; + char b[2]; +} gf26v; +void gf26(int x, int y) { + gf26v = ((struct gf26t){ + x + y, 'z', 0}); // NON_COMPLIANT[FALSE_NEGATIVE] - compound literal +} +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html#Case-Ranges +void gf28() { + int a; + + // switch(a){ + // case: 0 ... 5: // NON_COMPLIANT[FALSE_NEGATIVE] - Not supported in + // clang. + // ;; + // break; + // default: + // ;; + // break; + // } +} + +union gf29u { + int i; + double j; +}; + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Cast-to-Union.html#Cast-to-Union +void gf29() { + int x; + int y; + union gf29u z; + z = (union gf29u)x; // NON_COMPLIANT[FALSE_NEGATIVE] + z = (union gf29u)y; // NON_COMPLIANT[FALSE_NEGATIVE] +} + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Variable-Attributes.html#Variable-Attributes +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html#Function-Attributes +__attribute__((access(read_only, 1))) int +gf30(const char *); // NON_COMPLIANT -- attributes are not portable. + +extern int __attribute__((alias("var_target"))) +gf31; // NON_COMPLIANT -- attributes are not portable. + +struct __attribute__((aligned(8))) gf32 { + short f[3]; +}; // NON_COMPLIANT -- attributes are not portable. + +void gf33() { +gf33l: + __attribute__((cold, unused)); // NON_COMPLIANT + return; +} + +enum gf34 { + oldval __attribute__((deprecated)), // NON_COMPLIANT + newval +}; + +void gf35() { + int x; + // __attribute__((assume(x == 42))); // NON_COMPLIANT[FALSE_NEGATIVE] - Not + // supported in clang + + switch (x) { + case 1: + printf(""); + __attribute__((fallthrough)); // NON_COMPLIANT + case 2: + break; + } +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Dollar-Signs.html#Dollar-Signs +void gf37() { + int a$1; // NON_COMPLIANT[FALSE_NEGATIVE] +} + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Character-Escapes.html#Character-Escapes +void gf38() { + const char *c = "test\e"; // NON_COMPLIANT[FALSE_NEGATIVE] +} + +struct gf39s { + int x; + char y; +} gf39v; + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Alignment.html#Alignment +void gf39() { + __alignof__(gf39v.x); // NON_COMPLIANT +} + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Incomplete-Enums.html#Incomplete-Enums +// enum gf40 {}; // NON_COMPLIANT[FALSE_NEGATIVE] - not supported in clang + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html#Function-Names +void gf41() { + printf("__FUNCTION__ = %s\n", __FUNCTION__); // NON_COMPLIANT[FALSE_NEGATIVE] + printf("__PRETTY_FUNCTION__ = %s\n", + __PRETTY_FUNCTION__); // NON_COMPLIANT[FALSE_NEGATIVE] +} + +// Reference: https://clang.llvm.org/docs/LanguageExtensions.html#builtin-macros +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#Other-Builtins +void gf42() { + __builtin_extract_return_addr(0); // NON_COMPLIANT + __builtin_frob_return_addr(0); // NON_COMPLIANT + __builtin_frame_address(0); // NON_COMPLIANT +} + +struct gf43s { + int x; + char y; +} gf43v; + +void gf43() { + __builtin_offsetof(struct gf43s, x); // NON_COMPLIANT +} + +struct gf44s { + int x; + char y; +} gf44v; + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html#g_t_005f_005fsync-Builtins +void gf44() { + int i; + __sync_fetch_and_add(&i, 0); // NON_COMPLIANT + __sync_fetch_and_sub(&i, 0); // NON_COMPLIANT + __sync_fetch_and_or(&i, 0); // NON_COMPLIANT + __sync_fetch_and_and(&i, 0); // NON_COMPLIANT + __sync_fetch_and_xor(&i, 0); // NON_COMPLIANT + __sync_fetch_and_nand(&i, 0); // NON_COMPLIANT + __sync_add_and_fetch(&i, 0); // NON_COMPLIANT + __sync_sub_and_fetch(&i, 0); // NON_COMPLIANT + __sync_or_and_fetch(&i, 0); // NON_COMPLIANT + __sync_and_and_fetch(&i, 0); // NON_COMPLIANT + __sync_xor_and_fetch(&i, 0); // NON_COMPLIANT + __sync_nand_and_fetch(&i, 0); // NON_COMPLIANT + + __sync_bool_compare_and_swap(&i, 0, 0); + __sync_val_compare_and_swap(&i, 0, 0); + __sync_lock_test_and_set(&i, 0, 0); + __sync_lock_release(&i, 0); +} + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Binary-constants.html#Binary-constants +void gf45() { + int i = 0b101010; // NON_COMPLIANT[FALSE_NEGATIVE] +} + +// Reference: https://gcc.gnu.org/onlinedocs/gcc/Thread-Local.html#Thread-Local +__thread int gf46; // NON_COMPLIANT[FALSE_NEGATIVE] + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields +void gf47() { // NON_COMPLIANT in versions < C11. + struct { + int a; + union { + int b; + float c; + }; + int d; + } f; +} + +// Reference: +// https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#Other-Builtins +void gf48() { + __builtin_alloca( + 0); // NON_COMPLIANT (all __builtin functions are non-compliant.) +} \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.expected b/c/misra/test/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.expected new file mode 100644 index 0000000000..68216d500f --- /dev/null +++ b/c/misra/test/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.expected @@ -0,0 +1,5 @@ +| test.c:8:6:8:35 | ____codeql_coding_standards_m2 | May result in undefined behavior. | +| test.c:11:5:11:34 | ____codeql_coding_standards_m3 | May result in undefined behavior. | +| test.c:15:5:15:34 | ____codeql_coding_standards_m4 | May result in undefined behavior. | +| test.c:19:5:19:34 | ____codeql_coding_standards_m5 | May result in undefined behavior. | +| test.c:23:5:23:34 | ____codeql_coding_standards_m6 | May result in undefined behavior. | diff --git a/c/misra/test/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.qlref b/c/misra/test/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.qlref new file mode 100644 index 0000000000..b579db05b1 --- /dev/null +++ b/c/misra/test/rules/RULE-1-3/OccurrenceOfUndefinedBehavior.qlref @@ -0,0 +1 @@ +rules/RULE-1-3/OccurrenceOfUndefinedBehavior.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-1-3/test.c b/c/misra/test/rules/RULE-1-3/test.c new file mode 100644 index 0000000000..190cff4000 --- /dev/null +++ b/c/misra/test/rules/RULE-1-3/test.c @@ -0,0 +1,25 @@ +void main(void) { // COMPLIANT +} + +int ____codeql_coding_standards_m1(int argc, char **argv) { // NON_COMPLIANT + return 0; +} + +void ____codeql_coding_standards_m2(char *argc, char **argv) { // NON_COMPLIANT +} + +int ____codeql_coding_standards_m3(int argc, char *argv) { // NON_COMPLIANT + return 0; +} + +int ____codeql_coding_standards_m4() { // NON_COMPLIANT + return 0; +} + +int ____codeql_coding_standards_m5(int argc, int *argv) { // NON_COMPLIANT + return 0; +} + +int ____codeql_coding_standards_m6(int argc, int **argv) { // NON_COMPLIANT + return 0; +} diff --git a/cpp/common/src/codingstandards/cpp/Extensions.qll b/cpp/common/src/codingstandards/cpp/Extensions.qll new file mode 100644 index 0000000000..5ca6cea4f6 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Extensions.qll @@ -0,0 +1,11 @@ +import cpp + +/** + * Common base class for modeling compiler extensions. + */ +abstract class CompilerExtension extends Locatable { } + +/** + * Common base class for modeling compiler extensions in CPP. + */ +abstract class CPPCompilerExtension extends CompilerExtension { } diff --git a/cpp/common/src/codingstandards/cpp/UndefinedBehavior.qll b/cpp/common/src/codingstandards/cpp/UndefinedBehavior.qll new file mode 100644 index 0000000000..85e2f64612 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/UndefinedBehavior.qll @@ -0,0 +1,8 @@ +import cpp + +/** + * Library for modeling undefined behavior. + */ +abstract class UndefinedBehavior extends Locatable { } + +abstract class CPPUndefinedBehavior extends UndefinedBehavior { } diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/Language3.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/Language3.qll new file mode 100644 index 0000000000..836f8f7010 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/Language3.qll @@ -0,0 +1,44 @@ +//** THIS FILE IS AUTOGENERATED, DO NOT MODIFY DIRECTLY. **/ +import cpp +import RuleMetadata +import codingstandards.cpp.exclusions.RuleMetadata + +newtype Language3Query = + TLanguageExtensionsShouldNotBeUsedQuery() or + TOccurrenceOfUndefinedBehaviorQuery() + +predicate isLanguage3QueryMetadata(Query query, string queryId, string ruleId, string category) { + query = + // `Query` instance for the `languageExtensionsShouldNotBeUsed` query + Language3Package::languageExtensionsShouldNotBeUsedQuery() and + queryId = + // `@id` for the `languageExtensionsShouldNotBeUsed` query + "c/misra/language-extensions-should-not-be-used" and + ruleId = "RULE-1-2" and + category = "advisory" + or + query = + // `Query` instance for the `occurrenceOfUndefinedBehavior` query + Language3Package::occurrenceOfUndefinedBehaviorQuery() and + queryId = + // `@id` for the `occurrenceOfUndefinedBehavior` query + "c/misra/occurrence-of-undefined-behavior" and + ruleId = "RULE-1-3" and + category = "required" +} + +module Language3Package { + Query languageExtensionsShouldNotBeUsedQuery() { + //autogenerate `Query` type + result = + // `Query` type for `languageExtensionsShouldNotBeUsed` query + TQueryC(TLanguage3PackageQuery(TLanguageExtensionsShouldNotBeUsedQuery())) + } + + Query occurrenceOfUndefinedBehaviorQuery() { + //autogenerate `Query` type + result = + // `Query` type for `occurrenceOfUndefinedBehavior` query + TQueryC(TLanguage3PackageQuery(TOccurrenceOfUndefinedBehaviorQuery())) + } +} diff --git a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll index 9dfb52fb84..4a25016843 100644 --- a/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll +++ b/cpp/common/src/codingstandards/cpp/exclusions/c/RuleMetadata.qll @@ -33,6 +33,7 @@ import IO4 import InvalidMemory1 import Language1 import Language2 +import Language3 import Memory1 import Misc import Pointers1 @@ -84,6 +85,7 @@ newtype TCQuery = TInvalidMemory1PackageQuery(InvalidMemory1Query q) or TLanguage1PackageQuery(Language1Query q) or TLanguage2PackageQuery(Language2Query q) or + TLanguage3PackageQuery(Language3Query q) or TMemory1PackageQuery(Memory1Query q) or TMiscPackageQuery(MiscQuery q) or TPointers1PackageQuery(Pointers1Query q) or @@ -135,6 +137,7 @@ predicate isQueryMetadata(Query query, string queryId, string ruleId, string cat isInvalidMemory1QueryMetadata(query, queryId, ruleId, category) or isLanguage1QueryMetadata(query, queryId, ruleId, category) or isLanguage2QueryMetadata(query, queryId, ruleId, category) or + isLanguage3QueryMetadata(query, queryId, ruleId, category) or isMemory1QueryMetadata(query, queryId, ruleId, category) or isMiscQueryMetadata(query, queryId, ruleId, category) or isPointers1QueryMetadata(query, queryId, ruleId, category) or diff --git a/rule_packages/c/Language3.json b/rule_packages/c/Language3.json new file mode 100644 index 0000000000..d48444a4ab --- /dev/null +++ b/rule_packages/c/Language3.json @@ -0,0 +1,50 @@ +{ + "MISRA-C-2012": { + "RULE-1-2": { + "properties": { + "obligation": "advisory" + }, + "queries": [ + { + "description": "Language extensions are not portable to other compilers and should not be used.", + "kind": "problem", + "name": "Language extensions should not be used", + "precision": "high", + "severity": "error", + "short_name": "LanguageExtensionsShouldNotBeUsed", + "tags": [ + "maintainability", + "readability" + ], + "implementation_scope": { + "description": "This implementation attempts to cover a broad section of the compiler specific extensions documented in: https://clang.llvm.org/docs/LanguageExtensions.html and https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html but is not comprehensive. The following topics are addressed in this query: Builtin macros, Variable Attributes, Function Attributes, Statement Expressions, Non-Local Gotos, Conditionals, Extended Integer / Numeric Types, Zero Length Structures, Zero Length Arrays, Variable Length Arrays, Case Attributes, Alignment, __sync and __fetch builtins. Other topics listed in the extension references are not covered by this query." + } + } + ], + "title": "Language extensions should not be used" + }, + "RULE-1-3": { + "properties": { + "obligation": "required" + }, + "queries": [ + { + "description": "Relying on undefined or unspecified behavior can result in unreliable programs.", + "kind": "problem", + "name": "There shall be no occurrence of undefined or critical unspecified behavior", + "precision": "high", + "severity": "error", + "short_name": "OccurrenceOfUndefinedBehavior", + "tags": [ + "maintainability", + "readability" + ], + "implementation_scope": { + "description": "This implementation only considers alternate forms of `main` and the undefined behavior that results. Note that the current version of CodeQL is not able to detect this issue if a function is named `main` since it will assume the return type and formal parameters. Additional cases from Appendix J of the C99 standard are not currently considered." + } + } + ], + "title": "There shall be no occurrence of undefined or critical unspecified behavior" + } + } +} \ No newline at end of file