Skip to content

Commit

Permalink
Merge pull request #564 from rvermeulen/rvermeulen/fix-rule-6-1
Browse files Browse the repository at this point in the history
Add support for implementation specific bitfield types
  • Loading branch information
rvermeulen authored Apr 4, 2024
2 parents b31377d + 570dd80 commit 177293e
Show file tree
Hide file tree
Showing 13 changed files with 99 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,33 @@

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
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() + "'."
Original file line number Diff line number Diff line change
@@ -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'. |
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.ql
1 change: 1 addition & 0 deletions c/misra/test/rules/RULE-6-1/clang/options
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
semmle-extractor-options:--mimic clang --std=c11 --edg --diag_error=implicit_func_decl -nostdinc -I../../../../common/test/includes/standard-library
15 changes: 15 additions & 0 deletions c/misra/test/rules/RULE-6-1/clang/test.c
Original file line number Diff line number Diff line change
@@ -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;
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rules/RULE-6-1/BitFieldsShallOnlyBeDeclaredWithAnAppropriateType.ql
1 change: 1 addition & 0 deletions c/misra/test/rules/RULE-6-1/gcc/options
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
semmle-extractor-options:--mimic gcc --std=c11 --edg --diag_error=implicit_func_decl -nostdinc -I../../../../common/test/includes/standard-library
15 changes: 15 additions & 0 deletions c/misra/test/rules/RULE-6-1/gcc/test.c
Original file line number Diff line number Diff line change
@@ -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;
1 change: 1 addition & 0 deletions c/misra/test/rules/RULE-6-1/options
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
semmle-extractor-options:--no-clang --std=c11 --edg --diag_error=implicit_func_decl -nostdinc -I../../../../common/test/includes/standard-library
2 changes: 2 additions & 0 deletions change_notes/2024-04-26-fix-fp-rule-6-1.md
Original file line number Diff line number Diff line change
@@ -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.
39 changes: 39 additions & 0 deletions cpp/common/src/codingstandards/cpp/Compiler.qll
Original file line number Diff line number Diff line change
@@ -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()
)
}

0 comments on commit 177293e

Please sign in to comment.