Files
codeql/cpp/ql/lib/semmle/code/cpp/Field.qll
2023-05-09 15:35:54 +02:00

127 lines
3.9 KiB
Plaintext

/**
* Provides classes representing C structure members and C++ non-static member variables.
*/
import semmle.code.cpp.Variable
import semmle.code.cpp.Enum
/**
* A C structure member or C++ non-static member variable. For example the
* member variable `m` in the following code (but not `s`):
* ```
* class MyClass {
* public:
* int m;
* static int s;
* };
* ```
*
* This does not include static member variables in C++. To include static member
* variables, use `MemberVariable` instead of `Field`.
*/
class Field extends MemberVariable {
Field() { fieldoffsets(underlyingElement(this), _, _) }
override string getAPrimaryQlClass() { result = "Field" }
/**
* Gets the offset of this field in bytes from the start of its declaring
* type (on the machine where facts were extracted).
*/
int getByteOffset() { fieldoffsets(underlyingElement(this), result, _) }
/**
* Gets the byte offset within `mostDerivedClass` of each occurrence of this
* field within `mostDerivedClass` itself or a base class subobject of
* `mostDerivedClass`.
* Note that for fields of virtual base classes, and non-virtual base classes
* thereof, this predicate assumes that `mostDerivedClass` is the type of the
* complete most-derived object.
*/
int getAByteOffsetIn(Class mostDerivedClass) {
result =
mostDerivedClass.getABaseClassByteOffset(this.getDeclaringType()) + this.getByteOffset()
}
/**
* Holds if the field can be initialized as part of an initializer list. For
* example, in:
* ```
* struct S {
* unsigned int a : 5;
* unsigned int : 5;
* unsigned int b : 5;
* };
* ```
*
* Fields `a` and `b` are initializable, but the unnamed bitfield is not.
*/
predicate isInitializable() {
// All non-bitfield fields are initializable. This predicate is overridden
// in `BitField` to handle the anonymous bitfield case.
any()
}
/**
* Gets the zero-based index of the specified field within its enclosing
* class, counting only fields that can be initialized. This is the order in
* which the field will be initialized, whether by an initializer list or in a
* constructor.
*/
pragma[nomagic]
final int getInitializationOrder() {
exists(Class cls, int memberIndex |
this = cls.getCanonicalMember(memberIndex) and
memberIndex =
rank[result + 1](int index | cls.getCanonicalMember(index).(Field).isInitializable())
)
}
}
/**
* A C structure member or C++ member variable declared with an explicit size
* in bits. For example the member variable `x` in the following code:
* ```
* struct MyStruct {
* int x : 3;
* };
* ```
*/
class BitField extends Field {
BitField() { bitfield(underlyingElement(this), _, _) }
override string getAPrimaryQlClass() { result = "BitField" }
/**
* Gets the size of this bitfield in bits (on the machine where facts
* were extracted).
*/
int getNumBits() { bitfield(underlyingElement(this), result, _) }
/**
* Gets the value which appeared after the colon in the bitfield
* declaration.
*
* In most cases, this will give the same value as `getNumBits`. It will
* only differ when the value after the colon is larger than the size of
* the variable's type. For example, given `int32_t x : 1234`,
* `getNumBits` will give 32, whereas `getDeclaredNumBits` will give
* 1234.
*/
int getDeclaredNumBits() { bitfield(underlyingElement(this), _, result) }
/**
* Gets the offset of this bitfield in bits from the byte identified by
* getByteOffset (on the machine where facts were extracted).
*/
int getBitOffset() { fieldoffsets(underlyingElement(this), _, result) }
/** Holds if this bitfield is anonymous. */
predicate isAnonymous() { this.hasName("(unnamed bitfield)") }
override predicate isInitializable() {
// Anonymous bitfields are not initializable.
not this.isAnonymous()
}
}