Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for implementation specific bitfield types #564

Merged
merged 6 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
knewbury01 marked this conversation as resolved.
Show resolved Hide resolved
(
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;
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;
rvermeulen marked this conversation as resolved.
Show resolved Hide resolved
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()
)
}
Loading