diff --git a/c/misra/src/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.ql b/c/misra/src/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.ql index 81c7fb69a3..fce1d9ad1a 100644 --- a/c/misra/src/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.ql +++ b/c/misra/src/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.ql @@ -12,16 +12,26 @@ import cpp import codingstandards.c.misra +import codingstandards.cpp.Compiler -predicate isAppropriatePrimitive(Type type) { - /* An appropriate primitive types to which a bit-field can be declared. */ - type instanceof IntType and +Type getSupportedBitFieldType(Compiler compiler) { + compiler instanceof UnsupportedCompiler and ( - type.(IntegralType).isExplicitlySigned() or - type.(IntegralType).isExplicitlyUnsigned() + result instanceof IntType and + ( + result.(IntegralType).isExplicitlySigned() or + result.(IntegralType).isExplicitlyUnsigned() + ) + or + result instanceof BoolType ) or - type instanceof BoolType + (compiler instanceof Gcc or compiler instanceof Clang) and + ( + result instanceof IntegralOrEnumType + or + result instanceof BoolType + ) } from BitField bitField @@ -29,5 +39,6 @@ where not isExcluded(bitField, BitfieldTypesPackage::bitFieldsShallOnlyBeDeclaredWithAnAppropriateTypeQuery()) and /* A violation would neither be an appropriate primitive type nor an appropriate typedef. */ - not isAppropriatePrimitive(bitField.getType().resolveTypedefs()) -select bitField, "Bit-field " + bitField + " is declared on type " + bitField.getType() + "." + not getSupportedBitFieldType(getCompiler(bitField.getFile())) = + bitField.getType().resolveTypedefs() +select bitField, "Bit-field '" + bitField + "' is declared on type '" + bitField.getType() + "'." diff --git a/c/misra/test/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.expected b/c/misra/test/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.expected index aaba0ee30c..4ff4c2aaa1 100644 --- a/c/misra/test/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.expected +++ b/c/misra/test/rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.expected @@ -1,4 +1,4 @@ -| test.c:6:7:6:8 | x1 | Bit-field x1 is declared on type int. | -| test.c:10:15:10:16 | x5 | Bit-field x5 is declared on type signed long. | -| test.c:12:15:12:16 | x6 | Bit-field x6 is declared on type signed char. | -| test.c:14:14:14:15 | x7 | Bit-field x7 is declared on type Color. | +| test.c:6:7:6:8 | x1 | Bit-field 'x1' is declared on type 'int'. | +| test.c:10:15:10:16 | x5 | Bit-field 'x5' is declared on type 'signed long'. | +| test.c:12:15:12:16 | x6 | Bit-field 'x6' is declared on type 'signed char'. | +| test.c:14:14:14:15 | x7 | Bit-field 'x7' is declared on type 'Color'. | diff --git a/c/misra/test/rules/RULE-6-1/clang/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.expected b/c/misra/test/rules/RULE-6-1/clang/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.expected new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/test/rules/RULE-6-1/clang/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.qlref b/c/misra/test/rules/RULE-6-1/clang/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.qlref new file mode 100644 index 0000000000..7000f50ab1 --- /dev/null +++ b/c/misra/test/rules/RULE-6-1/clang/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.qlref @@ -0,0 +1 @@ +rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-6-1/clang/options b/c/misra/test/rules/RULE-6-1/clang/options new file mode 100644 index 0000000000..d37493684d --- /dev/null +++ b/c/misra/test/rules/RULE-6-1/clang/options @@ -0,0 +1 @@ +semmle-extractor-options:--mimic clang --std=c11 --edg --diag_error=implicit_func_decl -nostdinc -I../../../../common/test/includes/standard-library \ No newline at end of file diff --git a/c/misra/test/rules/RULE-6-1/clang/test.c b/c/misra/test/rules/RULE-6-1/clang/test.c new file mode 100644 index 0000000000..c8b377b0fd --- /dev/null +++ b/c/misra/test/rules/RULE-6-1/clang/test.c @@ -0,0 +1,15 @@ +typedef unsigned int UINT16; + +enum Color { R, G, B }; + +struct SampleStruct { + int x1 : 2; // COMPLIANT + unsigned int x2 : 2; // COMPLIANT - explicitly unsigned + signed int x3 : 2; // COMPLIANT - explicitly signed + UINT16 x4 : 2; // COMPLIANT - type alias resolves to a compliant type + signed long x5 : 2; // COMPLIANT + signed char x6 : 2; // COMPLIANT + enum Color x7 : 3; // COMPLIANT + //_Atomic(int) x8 : 2; // NON_COMPLIANT[COMPILER_CHECKED] - atomic types are + // not permitted for bit-fields. +} sample_struct; diff --git a/c/misra/test/rules/RULE-6-1/gcc/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.expected b/c/misra/test/rules/RULE-6-1/gcc/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.expected new file mode 100644 index 0000000000..e69de29bb2 diff --git a/c/misra/test/rules/RULE-6-1/gcc/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.qlref b/c/misra/test/rules/RULE-6-1/gcc/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.qlref new file mode 100644 index 0000000000..7000f50ab1 --- /dev/null +++ b/c/misra/test/rules/RULE-6-1/gcc/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.qlref @@ -0,0 +1 @@ +rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.ql \ No newline at end of file diff --git a/c/misra/test/rules/RULE-6-1/gcc/options b/c/misra/test/rules/RULE-6-1/gcc/options new file mode 100644 index 0000000000..b2d1a92f7a --- /dev/null +++ b/c/misra/test/rules/RULE-6-1/gcc/options @@ -0,0 +1 @@ +semmle-extractor-options:--mimic gcc --std=c11 --edg --diag_error=implicit_func_decl -nostdinc -I../../../../common/test/includes/standard-library \ No newline at end of file diff --git a/c/misra/test/rules/RULE-6-1/gcc/test.c b/c/misra/test/rules/RULE-6-1/gcc/test.c new file mode 100644 index 0000000000..c8b377b0fd --- /dev/null +++ b/c/misra/test/rules/RULE-6-1/gcc/test.c @@ -0,0 +1,15 @@ +typedef unsigned int UINT16; + +enum Color { R, G, B }; + +struct SampleStruct { + int x1 : 2; // COMPLIANT + unsigned int x2 : 2; // COMPLIANT - explicitly unsigned + signed int x3 : 2; // COMPLIANT - explicitly signed + UINT16 x4 : 2; // COMPLIANT - type alias resolves to a compliant type + signed long x5 : 2; // COMPLIANT + signed char x6 : 2; // COMPLIANT + enum Color x7 : 3; // COMPLIANT + //_Atomic(int) x8 : 2; // NON_COMPLIANT[COMPILER_CHECKED] - atomic types are + // not permitted for bit-fields. +} sample_struct; diff --git a/c/misra/test/rules/RULE-6-1/options b/c/misra/test/rules/RULE-6-1/options new file mode 100644 index 0000000000..52175e51f9 --- /dev/null +++ b/c/misra/test/rules/RULE-6-1/options @@ -0,0 +1 @@ +semmle-extractor-options:--no-clang --std=c11 --edg --diag_error=implicit_func_decl -nostdinc -I../../../../common/test/includes/standard-library \ No newline at end of file diff --git a/change_notes/2024-04-26-fix-fp-rule-6-1.md b/change_notes/2024-04-26-fix-fp-rule-6-1.md new file mode 100644 index 0000000000..856c15623f --- /dev/null +++ b/change_notes/2024-04-26-fix-fp-rule-6-1.md @@ -0,0 +1,2 @@ +- `RULE-6-1` - `BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.ql`: + - Address FP reported in #318. Add support for implementation specific bitfield types for Clang and Gcc. \ No newline at end of file diff --git a/cpp/common/src/codingstandards/cpp/Compiler.qll b/cpp/common/src/codingstandards/cpp/Compiler.qll new file mode 100644 index 0000000000..20aade5827 --- /dev/null +++ b/cpp/common/src/codingstandards/cpp/Compiler.qll @@ -0,0 +1,39 @@ +/** A module to reason about the compiler used to compile translation units. */ + +import cpp +import codingstandards.cpp.Scope + +newtype Compiler = + Gcc() or + Clang() or + UnsupportedCompiler() + +/** Get the match pattern to detect the compiler being mimicked by the extractor to determine the compiler used to compile a file. */ +string getMimicMatch(Compiler compiler) { + result = ["%gcc", "%g++"] and compiler instanceof Gcc + or + result = ["%clang", "%clang++"] and compiler instanceof Clang +} + +/** Get the compiler used to compile the translation unit the file `f` is part of. */ +Compiler getCompiler(File f) { + exists(Compilation compilation, TranslationUnit translationUnit | + compilation.getAFileCompiled() = translationUnit and + (f = translationUnit or f = translationUnit.getAUserFile()) + | + if exists(int mimicIndex | compilation.getArgument(mimicIndex) = "--mimic") + then + exists(int mimicIndex | + compilation.getArgument(mimicIndex) = "--mimic" and + ( + compilation.getArgument(mimicIndex + 1).matches(getMimicMatch(result)) + or + forall(string match | match = getMimicMatch(_) | + not compilation.getArgument(mimicIndex + 1).matches(match) + ) and + result = UnsupportedCompiler() + ) + ) + else result = UnsupportedCompiler() + ) +}