Skip to content

Commit 941ad87

Browse files
committed
C++: Move 'hasAFieldWithOffset' to 'Field'.
1 parent 3591f84 commit 941ad87

File tree

2 files changed

+48
-45
lines changed

2 files changed

+48
-45
lines changed

cpp/ql/lib/semmle/code/cpp/Field.qll

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,30 @@
55
import semmle.code.cpp.Variable
66
import semmle.code.cpp.Enum
77

8+
private predicate hasAFieldWithOffset(Class c, Field f, int offset) {
9+
// Base case: `f` is a field in `c`.
10+
f = c.getAField() and
11+
offset = f.getByteOffset() and
12+
not f.getUnspecifiedType().(Class).hasDefinition()
13+
or
14+
// Otherwise, we find the struct that is a field of `c` which then has
15+
// the field `f` as a member.
16+
exists(Field g |
17+
g = c.getAField() and
18+
// Find the field with the largest offset that's less than or equal to
19+
// offset. That's the struct we need to search recursively.
20+
g =
21+
max(Field cand, int candOffset |
22+
cand = c.getAField() and
23+
candOffset = cand.getByteOffset() and
24+
offset >= candOffset
25+
|
26+
cand order by candOffset
27+
) and
28+
hasAFieldWithOffset(g.getUnspecifiedType(), f, offset - g.getByteOffset())
29+
)
30+
}
31+
832
/**
933
* A C structure member or C++ non-static member variable. For example the
1034
* member variable `m` in the following code (but not `s`):
@@ -76,6 +100,27 @@ class Field extends MemberVariable {
76100
rank[result + 1](int index | cls.getCanonicalMember(index).(Field).isInitializable())
77101
)
78102
}
103+
104+
/**
105+
* Gets the offset (in bytes) of this field starting at `c`.
106+
*
107+
* For example, consider:
108+
* ```cpp
109+
* struct S1 {
110+
* int a;
111+
* void* b;
112+
* };
113+
*
114+
* struct S2 {
115+
* S1 s1;
116+
* char c;
117+
* };
118+
* ```
119+
* If `f` represents the field `s1` and `c` represents the class `S2` then
120+
* `f.getOffsetInClass(S2) = 0` holds. Likewise, if `f` represents the
121+
* field `a`, then `f.getOffsetInClass(c) = 0` holds.
122+
*/
123+
int getOffsetInClass(Class c) { hasAFieldWithOffset(c, this, result) }
79124
}
80125

81126
/**

cpp/ql/src/Security/CWE/CWE-843/TypeConfusion.ql

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -14,48 +14,6 @@ import cpp
1414
import semmle.code.cpp.dataflow.new.DataFlow
1515
import Flow::PathGraph
1616

17-
/**
18-
* Holds if `f` is a field located at byte offset `offset` in `c`.
19-
*
20-
* Note that predicate is recursive, so that given the following:
21-
* ```cpp
22-
* struct S1 {
23-
* int a;
24-
* void* b;
25-
* };
26-
*
27-
* struct S2 {
28-
* S1 s1;
29-
* char c;
30-
* };
31-
* ```
32-
* both `hasAFieldWithOffset(S2, s1, 0)` and `hasAFieldWithOffset(S2, a, 0)`
33-
* holds.
34-
*/
35-
predicate hasAFieldWithOffset(Class c, Field f, int offset) {
36-
// Base case: `f` is a field in `c`.
37-
f = c.getAField() and
38-
offset = f.getByteOffset() and
39-
not f.getUnspecifiedType().(Class).hasDefinition()
40-
or
41-
// Otherwise, we find the struct that is a field of `c` which then has
42-
// the field `f` as a member.
43-
exists(Field g |
44-
g = c.getAField() and
45-
// Find the field with the largest offset that's less than or equal to
46-
// offset. That's the struct we need to search recursively.
47-
g =
48-
max(Field cand, int candOffset |
49-
cand = c.getAField() and
50-
candOffset = cand.getByteOffset() and
51-
offset >= candOffset
52-
|
53-
cand order by candOffset
54-
) and
55-
hasAFieldWithOffset(g.getUnspecifiedType(), f, offset - g.getByteOffset())
56-
)
57-
}
58-
5917
/** Holds if `f` is the last field of its declaring class. */
6018
predicate lastField(Field f) {
6119
exists(Class c | c = f.getDeclaringType() |
@@ -75,7 +33,7 @@ predicate lastField(Field f) {
7533
bindingset[f1, offset, c2]
7634
pragma[inline_late]
7735
predicate hasCompatibleFieldAtOffset(Field f1, int offset, Class c2) {
78-
exists(Field f2 | hasAFieldWithOffset(c2, f2, offset) |
36+
exists(Field f2 | offset = f2.getOffsetInClass(c2) |
7937
// Let's not deal with bit-fields for now.
8038
f2 instanceof BitField
8139
or
@@ -100,15 +58,15 @@ predicate prefix(Class c1, Class c2) {
10058
exists(Field f1, int offset |
10159
// Let's not deal with bit-fields for now.
10260
not f1 instanceof BitField and
103-
hasAFieldWithOffset(c1, f1, offset)
61+
offset = f1.getOffsetInClass(c1)
10462
|
10563
hasCompatibleFieldAtOffset(f1, offset, c2)
10664
)
10765
else
10866
forall(Field f1, int offset |
10967
// Let's not deal with bit-fields for now.
11068
not f1 instanceof BitField and
111-
hasAFieldWithOffset(c1, f1, offset)
69+
offset = f1.getOffsetInClass(c1)
11270
|
11371
hasCompatibleFieldAtOffset(f1, offset, c2)
11472
)

0 commit comments

Comments
 (0)