1 : // Copyright 2015 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : // A set of classes to experiment with object layout wrt vftables. To obtain
16 : // Visual Studio's object layout use /d1reportAllClassLayout or
17 : // /d1reportSingleClassLayout, eg:
18 : // cl /c /d1reportSingleClassLayoutNoVirtualMethodUDT test_vtables.cc
19 :
20 : #include <cstdint>
21 :
22 : #include "syzygy/refinery/types/alias.h"
23 :
24 m : namespace testing {
25 :
26 : // Note: we declare different functions (return different integers) to avoid
27 : // the possibility of vtables overlapping.
28 :
29 : // Visual Studio expectation
30 : // class NoVirtualMethodUDT size(4):
31 : // +---
32 : // 0 | a
33 : // +---
34 m : struct NoVirtualMethodUDT {
35 m : int a;
36 m : int f();
37 m : };
38 :
39 : // class NoVirtualMethodChildUDT size(12):
40 : // +---
41 : // 0 | {vfptr}
42 : // | +--- (base class NoVirtualMethodUDT)
43 : // 4 | | a
44 : // | +---
45 : // 8 | a
46 : // +---
47 m : struct NoVirtualMethodChildUDT : public NoVirtualMethodUDT {
48 m : int a;
49 m : int f();
50 m : virtual int g() { return 0; }
51 m : };
52 :
53 : // Visual Studio expectation: a vftable pointer at offset 0.
54 : // class VirtualMethodUDT size(8):
55 : // +---
56 : // 0 | {vfptr}
57 : // 4 | a
58 : // +---
59 m : struct VirtualMethodUDT {
60 m : int a;
61 m : virtual int f() { return 1; }
62 m : };
63 :
64 : // Visual Studio expectation: a vftable pointer at offset 0.
65 : // class ChildUDT size(12):
66 : // +---
67 : // | +--- (base class VirtualMethodUDT)
68 : // 0 | | {vfptr}
69 : // 4 | | a
70 : // | +---
71 : // 8 | b
72 : // +---
73 m : struct ChildUDT : public VirtualMethodUDT {
74 m : int b;
75 m : int f() override { return 2; }
76 m : };
77 :
78 : // Visual Studio expectation: a class that has virtual functions (possibly
79 : // through inheritance) always has a vftable pointer at offset 0 unless it only
80 : // has these due to virtual bases.
81 :
82 : // class VirtualChildUDT size(16):
83 : // +---
84 : // 0 | {vbptr}
85 : // 4 | b
86 : // +---
87 : // +--- (virtual base VirtualMethodUDT)
88 : // 8 | {vfptr}
89 : // 12 | a
90 : // +---
91 m : struct VirtualChildUDT : virtual VirtualMethodUDT {
92 m : int b;
93 m : int f() override { return 3; }
94 m : };
95 :
96 : // class VirtualChildWithVirtualMethodUDT size(20):
97 : // +---
98 : // 0 | {vfptr}
99 : // 4 | {vbptr}
100 : // 8 | b
101 : // +---
102 : // +--- (virtual base VirtualMethodUDT)
103 : // 12 | {vfptr}
104 : // 16 | a
105 : // +---
106 m : struct VirtualChildWithVirtualMethodUDT : virtual VirtualMethodUDT {
107 m : int b;
108 m : int f() override { return 4; }
109 m : virtual int g() { return 5; }
110 m : };
111 :
112 : // class ComposedUDT size(16):
113 : // +---
114 : // 0 | {vfptr}
115 : // 4 | a
116 : // 8 | VirtualMethodUDT udt
117 : // +---
118 m : struct ComposedUDT {
119 m : int a;
120 m : VirtualMethodUDT udt;
121 m : virtual int f() { return 6; }
122 m : };
123 :
124 : // Interface implementation case.
125 : // class InterfaceImplUDT size(16):
126 : // +---
127 : // | +--- (base class IA)
128 : // 0 | | {vfptr}
129 : // | +---
130 : // | +--- (base class IB)
131 : // 4 | | {vfptr}
132 : // | +---
133 : // | +--- (base class SimpleBase)
134 : // 8 | | member
135 : // | +---
136 : // 12 | bar
137 : // +---
138 m : struct IA { virtual int one() = 0; };
139 m : struct IB { virtual int two() = 0; };
140 m : struct SimpleBase { int member; };
141 m : struct InterfaceImplUDT : public SimpleBase, public IA, public IB {
142 m : int bar;
143 m : int one() override { return 7; }
144 m : int two() override { return 8; }
145 m : };
146 :
147 m : void AliasTypes() {
148 m : NoVirtualMethodUDT no_virtual_method_udt = {};
149 m : Alias(&no_virtual_method_udt);
150 m : }
151 :
152 : // Gets the expected vftable virtual addresses.
153 : // @param buffer_size size of @p vftable_vas
154 : // @param vftable_vas on success, contains the expected vftable virtual
155 : // addresses.
156 : // @param count on success, the count of returned vftable virtual addresses.
157 : // @returns true on success, false otherwise.
158 m : extern "C" bool GetExpectedVftableVAs(unsigned buffer_size,
159 m : uint64_t* vftable_vas,
160 m : unsigned* count) {
161 m : if (!vftable_vas || !count)
162 m : return false;
163 : // Validate pointer size.
164 m : if (sizeof(unsigned) != sizeof(unsigned*))
165 m : return false;
166 m : if (buffer_size < 3U)
167 m : return false;
168 :
169 m : unsigned cnt = 0U;
170 :
171 m : {
172 m : VirtualMethodUDT udt;
173 m : vftable_vas[cnt] =
174 m : static_cast<uint64_t>(*reinterpret_cast<uintptr_t*>(&udt));
175 m : cnt++;
176 m : }
177 :
178 m : {
179 m : ComposedUDT udt;
180 m : vftable_vas[cnt] =
181 m : static_cast<uint64_t>(*reinterpret_cast<uintptr_t*>(&udt));
182 m : cnt++;
183 m : }
184 :
185 m : {
186 m : VirtualChildWithVirtualMethodUDT udt;
187 m : vftable_vas[cnt] =
188 m : static_cast<uint64_t>(*reinterpret_cast<uintptr_t*>(&udt));
189 m : cnt++;
190 m : }
191 :
192 : // TODO(manzagop): handle the other cases.
193 :
194 m : *count = cnt;
195 m : return true;
196 m : }
197 :
198 m : } // namespace testing
|