-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathField.qll
171 lines (155 loc) · 5.17 KB
/
Field.qll
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/**
* Provides classes representing C structure members and C++ non-static member variables.
*/
import semmle.code.cpp.Variable
import semmle.code.cpp.Enum
private predicate hasAFieldWithOffset(Class c, Field f, int offset) {
// Base case: `f` is a field in `c`.
f = c.getAField() and
offset = f.getByteOffset() and
not f.getUnspecifiedType().(Class).hasDefinition()
or
// Otherwise, we find the struct that is a field of `c` which then has
// the field `f` as a member.
exists(Field g |
g = c.getAField() and
// Find the field with the largest offset that's less than or equal to
// offset. That's the struct we need to search recursively.
g =
max(Field cand, int candOffset |
cand = c.getAField() and
candOffset = cand.getByteOffset() and
offset >= candOffset
|
cand order by candOffset
) and
hasAFieldWithOffset(g.getUnspecifiedType(), f, offset - g.getByteOffset())
)
}
/**
* 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())
)
}
/**
* Gets the offset (in bytes) of this field starting at `c`.
*
* For example, consider:
* ```cpp
* struct S1 {
* int a;
* void* b;
* };
*
* struct S2 {
* S1 s1;
* char c;
* };
* ```
* If `f` represents the field `s1` and `c` represents the class `S2` then
* `f.getOffsetInClass(S2) = 0` holds. Likewise, if `f` represents the
* field `a`, then `f.getOffsetInClass(c) = 0` holds.
*/
int getOffsetInClass(Class c) { hasAFieldWithOffset(c, this, result) }
}
/**
* 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()
}
}