forked from dotnet/runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathVerifyLayouts.inc
More file actions
351 lines (310 loc) · 15.5 KB
/
Copy pathVerifyLayouts.inc
File metadata and controls
351 lines (310 loc) · 15.5 KB
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// This file provides an explicit check of field layouts using some macro magic
// in VerifyLayouts.h. The goal is that if any field changes offset or type changes
// size then a build time assert should trigger. DO NOT change these definitions without
// reading the comments in VerifyLayouts.h and understanding what other code you need
// to change at the same time.
//
//
// AN EXAMPLE:
// You want to validate the fields in type CDerived
//
// class CFoo
// {
// void* m_ptrField;
// }
//
// struct BigStruct
// {
// DWORD m_one;
// DWORD m_two;
// DWORD m_three;
// }
//
// CDerived : CFoo
// {
// DWORD m_cRef;
// SomeOtherType* m_otherType;
// #ifdef _SOME_DEFINE
// BigStruct m_struct;
// #endif //_SOME_DEFINE
// }
//
//
// and the layout validation is written as:
//
// BEGIN_TYPE(CDerived, sizeof(CFoo)) // a) The first field starts at sizeof(CFoo) to account for base class data
// // b) Beware of vtable pointers, they take up space before the data fields too
// // c) Beware of using sizeof(some_other_type) unless you also explicitly verify
// // the layout of that type here. Changing the base type would change the derived types
// // layout and won't be caught unless the base type is explicitly verified.
// // d) sizeof(<primitive_type>) is fine - they never change over time and we know how
// // to deal with platform pointer size differences
// FIELD(CDerived, m_cRef, 4)
// FIELD(CDerived, m_otherType, sizeof(void*))
// #ifdef _SOME_DEFINE_
// ALIGN_FIELD(CDerived, m_struct, sizeof(BigStruct), 4) // We need to use the ALIGN_FIELD macro because the alignment isn't the same as
// // the field size. The alignment of a structure is typically the max alignment
// // of any member. The alignment of a primitive type is typically the size of the type.
// #endif _SOME_DEFINE_
// END_TYPE(CDerived, sizeof(void*)
//
//
// BEGIN_TYPE(CFoo, 0) // We must verify this type because we used it to define the starting offset of CDerived
// FIELD(CFoo, m_ptrField, sizeof(void*))
// END_TYPE(CFoo, sizeof(void*))
//
//
// BEGIN_TYPE(BigStruct, 0) // We must verify this type because we used sizeof(BigStruct) to define the size of
// // CDerived::m_struct field
// FIELD(BigStruct, m_one, 4)
// FIELD(BigStruct, m_two, 4)
// FIELD(BigStruct, m_thee, 4)
// END_TYPE(BigStruct, 4)
//
//
//
//
// OTHER CONSIDERATIONS:
//
// 1) if the type layout is conditional on a define, just include the same define here in the layout verification
// Make sure that the define is registered in the list of defines and the debugger reading code knows how to dynamically
// adjust for it (See VerifyLayouts.h comment item (b) and (c))
//
// 2) If your type names use characters that aren't valid identifiers (such as the '<' and '>' chars in templates)
// then you need to provide an escaped name. There are variations of the macros above to do that:
// BEGIN_TYPE_ESCAPED(typeName, escaptedTypeName, firstFieldOffset)
// FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize)
// ALIGN_FIELD_ESCAPED(typeName, escapedTypeName, fieldName, fieldSize, fieldAlign)
// END_TYPE_ESCAPED(typeName, escapedTypeName, typeAlignment)
//
// If CFoo above had instead been CFoo<ULONG> we would write:
// BEGIN_TYPE_ESCAPED(CFoo<ULONG>, CFoo__ULONG__, 0)
// FIELD_ESCAPED(CFoo<ULONG>, CFoo__ULONG__, m_ptrField, sizeof(void*))
// END_TYPE_ESCAPED(CFoo<ULONG>, CFoo__ULONG__, sizeof(void*))
//
// The escapedTypeName is relatively arbitrary, but convention is to replace the illegal characters with double underscore
// The name does show up in build error messages, so it should close to the real name for people to understand
//
// 3) If your type name has commas in it (such as in a list of template arguments) the macros could interpret it as seperate
// arguments (no good). To fix this use the IGNORE_COMMAS() macro to escape any typeNames with commas. If CFoo above had
// been CFoo<ULONG,INT> you could rewrite the defines as:
// BEGIN_TYPE_ESCAPED(IGNORE_COMMAS(CFoo<ULONG,INT>), CFoo__ULONG__INT__, 0)
// FIELD_ESCAPED(IGNORE_COMMAS(CFoo<ULONG,INT>), CFoo__ULONG__INT__, m_ptrField, sizeof(void*))
// END_TYPE_ESCAPED(IGNORE_COMMAS(CFoo<ULONG,INT>), CFoo__ULONG__INT__, sizeof(void*))
//
// 4) If you have a bitfield in your type, the offsetof macro can't be used which will break the static asserts.
// There is a special BITFIELD macro that can work around it:
// BITFIELD(typeName, fieldName, expectedFieldOffset, fieldSize, fieldAlign)
//
// The macro is just like FIELD execpt you must provide the offset yourself. Since you can't use offsetof on the field directly
// the convention is to use the offset of the previous field and then add the size and alignment requirements. For example if your
// type had this:
// CMiniMdRW
// {
// ULONG m_cbSaveSize;
// int m_fIsReadOnly : 1;
// int m_bPreSaveDone : 1;
// int m_bSaveCompressed : 1;
// int m_bPostGSSMod : 1;
// }
//
// You could write
// FIELD(CMiniMdRW, m_cbSaveSize, 4)
// BITFIELD(CMiniMdRW, m_fIsReadOnly, offsetof(CMiniMdRW, m_cbSaveSize)+4, 4)
//
// Don't include al the fields in the bitfield, just pick one as the canonical field name
//
//
//
// HOW DO I DEBUG THIS STUFF WHEN THE BUILD DOESN'T WORK?
//
// One way that has been effective for me is to write a few static_assert_no_msg entries manually in VerifyLayouts.h
// You can use those to verify your assumptions such as:
// static_assert_no_msg(sizeof(Foo) == 24)
// static_assert_no_msg(offset(Foo, m_lastField) == 20)
// static_assert_no_msg(offset_of_field_affter_Foo_m_lastField == 24)
// Then rebuild and find out where the compiler disagress with you.
//
// Another option is to run the source through the preprocessor
//
//
//
BEGIN_TYPE(MDInternalRW, 2*sizeof(void*))
FIELD(MDInternalRW, m_pStgdb, sizeof(void*))
FIELD(MDInternalRW, m_tdModule, 4)
FIELD(MDInternalRW, m_cRefs, 4)
FIELD(MDInternalRW, m_fOwnStgdb, 4)
FIELD(MDInternalRW, m_pUnk, sizeof(void*))
FIELD(MDInternalRW, m_pUserUnk, sizeof(void*))
FIELD(MDInternalRW, m_pIMetaDataHelper, sizeof(void*))
FIELD(MDInternalRW, m_pSemReadWrite, sizeof(void*))
FIELD(MDInternalRW, m_fOwnSem, 4)
END_TYPE(MDInternalRW, sizeof(void*))
BEGIN_TYPE(CLiteWeightStgdbRW, sizeof(CLiteWeightStgdb<CMiniMdRW>))
FIELD(CLiteWeightStgdbRW, m_cbSaveSize, 4)
FIELD(CLiteWeightStgdbRW, m_bSaveCompressed, 4)
FIELD(CLiteWeightStgdbRW, m_pImage, sizeof(void*))
FIELD(CLiteWeightStgdbRW, m_dwImageSize, 4)
FIELD(CLiteWeightStgdbRW, m_dwPEKind, 4)
FIELD(CLiteWeightStgdbRW, m_dwMachine, 4)
FIELD(CLiteWeightStgdbRW, m_pStreamList, sizeof(void*))
FIELD(CLiteWeightStgdbRW, m_pNextStgdb, sizeof(void*))
FIELD(CLiteWeightStgdbRW, m_eFileType, 4)
FIELD(CLiteWeightStgdbRW, m_wszFileName, sizeof(void*))
FIELD(CLiteWeightStgdbRW, m_dwDatabaseLFT, 4)
FIELD(CLiteWeightStgdbRW, m_dwDatabaseLFS, 4)
FIELD(CLiteWeightStgdbRW, m_pStgIO, sizeof(void*))
END_TYPE(CLiteWeightStgdbRW, 8)
BEGIN_TYPE_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, 0)
ALIGN_FIELD_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, m_MiniMd, sizeof(CMiniMdRW), sizeof(void*))
FIELD_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, m_pvMd, sizeof(void*))
FIELD_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, m_cbMd, 4)
END_TYPE_ESCAPED(CLiteWeightStgdb<CMiniMdRW>, CLiteWeightStgdb__CMiniMdRW__, sizeof(void*))
BEGIN_TYPE(CMiniMdRW, sizeof(CMiniMdTemplate<CMiniMdRW>))
FIELD(CMiniMdRW, m_pMemberRefHash, sizeof(void*))
FIELD(CMiniMdRW, m_pMemberDefHash, sizeof(void*))
ALIGN_FIELD(CMiniMdRW, m_pLookUpHashs, sizeof(void*)*TBL_COUNT, sizeof(void*))
ALIGN_FIELD(CMiniMdRW, m_StringPoolOffsetHash, sizeof(MapSHash<UINT32, UINT32>), 4)
FIELD(CMiniMdRW, m_pNamedItemHash, sizeof(void*))
FIELD(CMiniMdRW, m_maxRid, 4)
FIELD(CMiniMdRW, m_limRid, 4)
FIELD(CMiniMdRW, m_maxIx, 4)
FIELD(CMiniMdRW, m_limIx, 4)
FIELD(CMiniMdRW, m_eGrow, 4)
ALIGN_FIELD(CMiniMdRW, m_Tables, sizeof(RecordPool)*TBL_COUNT, sizeof(void*))
ALIGN_FIELD(CMiniMdRW, m_pVS, sizeof(void*)*TBL_COUNT, sizeof(void*))
ALIGN_FIELD(CMiniMdRW, m_StringHeap, sizeof(StgStringPool), sizeof(void*))
ALIGN_FIELD(CMiniMdRW, m_BlobHeap, sizeof(StgBlobPool), sizeof(void*))
ALIGN_FIELD(CMiniMdRW, m_UserStringHeap, sizeof(StgBlobPool), sizeof(void*))
ALIGN_FIELD(CMiniMdRW, m_GuidHeap, sizeof(StgGuidPool), sizeof(void*))
FIELD(CMiniMdRW, m_pHandler, sizeof(void*))
FIELD(CMiniMdRW, m_cbSaveSize, 4)
BITFIELD(CMiniMdRW, m_fIsReadOnly, offsetof(CMiniMdRW, m_cbSaveSize)+4, 4)
FIELD(CMiniMdRW, m_pMethodMap, sizeof(void*))
FIELD(CMiniMdRW, m_pFieldMap, sizeof(void*))
FIELD(CMiniMdRW, m_pPropertyMap, sizeof(void*))
FIELD(CMiniMdRW, m_pEventMap, sizeof(void*))
FIELD(CMiniMdRW, m_pParamMap, sizeof(void*))
FIELD(CMiniMdRW, m_pFilterTable, sizeof(void*))
FIELD(CMiniMdRW, m_pHostFilter, sizeof(void*))
FIELD(CMiniMdRW, m_pTokenRemapManager, sizeof(void*))
ALIGN_FIELD(CMiniMdRW, m_OptionValue, sizeof(OptionValue), 4)
ALIGN_FIELD(CMiniMdRW, m_StartupSchema, sizeof(CMiniMdSchema), 8)
ALIGN_FIELD(CMiniMdRW, m_bSortable, sizeof(BYTE)*TBL_COUNT, sizeof(BYTE))
#ifdef _DEBUG
FIELD(CMiniMdRW, dbg_m_pLock, sizeof(void*))
#endif
FIELD(CMiniMdRW, m_fMinimalDelta, 4)
FIELD(CMiniMdRW, m_rENCRecs, sizeof(void*))
END_TYPE(CMiniMdRW, 8)
BEGIN_TYPE(OptionValue, 0)
FIELD(OptionValue, m_DupCheck, 4)
FIELD(OptionValue, m_RefToDefCheck, 4)
FIELD(OptionValue, m_NotifyRemap, 4)
FIELD(OptionValue, m_UpdateMode, 4)
FIELD(OptionValue, m_ErrorIfEmitOutOfOrder, 4)
FIELD(OptionValue, m_ThreadSafetyOptions, 4)
FIELD(OptionValue, m_ImportOption, 4)
FIELD(OptionValue, m_LinkerOption, 4)
FIELD(OptionValue, m_GenerateTCEAdapters, 4)
FIELD(OptionValue, m_RuntimeVersion, sizeof(void*))
FIELD(OptionValue, m_MetadataVersion, 4)
FIELD(OptionValue, m_MergeOptions, 4)
FIELD(OptionValue, m_InitialSize, 4)
FIELD(OptionValue, m_LocalRefPreservation, 4)
END_TYPE(OptionValue, sizeof(void*))
BEGIN_TYPE(StgBlobPool, sizeof(StgPool))
ALIGN_FIELD(StgBlobPool, m_Hash, sizeof(CBlobPoolHash), sizeof(void*))
END_TYPE(StgBlobPool, sizeof(void*))
BEGIN_TYPE(StgStringPool, sizeof(StgPool))
ALIGN_FIELD(StgStringPool, m_Hash, sizeof(CStringPoolHash), sizeof(void*))
FIELD(StgStringPool, m_bHash, sizeof(BOOL))
END_TYPE(StgStringPool, sizeof(void*))
BEGIN_TYPE(StgGuidPool, sizeof(StgPool))
ALIGN_FIELD(StgGuidPool, m_Hash, sizeof(CGuidPoolHash), sizeof(void*))
FIELD(StgGuidPool, m_bHash, sizeof(BOOL))
END_TYPE(StgGuidPool, sizeof(void*))
BEGIN_TYPE(RecordPool, sizeof(StgPool))
FIELD(RecordPool, m_cbRec, 4)
END_TYPE(RecordPool, sizeof(void*))
BEGIN_TYPE(StgPool, sizeof(StgPoolReadOnly))
FIELD(StgPool, m_ulGrowInc, 4)
FIELD(StgPool, m_pCurSeg, sizeof(void*))
FIELD(StgPool, m_cbCurSegOffset, 4)
BITFIELD(StgPool, m_bFree, offsetof(StgPool, m_cbCurSegOffset)+4, 4) // can't take offsetof on a bitfield so we have to provide the offset another way
FIELD(StgPool, m_nVariableAlignmentMask, 4)
FIELD(StgPool, m_cbStartOffsetOfEdit, 4)
FIELD(StgPool, m_fValidOffsetOfEdit, 4)
END_TYPE(StgPool, sizeof(void*))
BEGIN_TYPE(CStringPoolHash, sizeof(CChainedHash<STRINGHASH>))
FIELD(CStringPoolHash, m_Pool, sizeof(void*))
END_TYPE(CStringPoolHash, sizeof(void*))
BEGIN_TYPE(CBlobPoolHash, sizeof(CChainedHash<STRINGHASH>))
FIELD(CBlobPoolHash, m_Pool, sizeof(void*))
END_TYPE(CStringPoolHash, sizeof(void*))
BEGIN_TYPE(CGuidPoolHash, sizeof(CChainedHash<GUIDHASH>))
FIELD(CGuidPoolHash, m_Pool, sizeof(void*))
END_TYPE(CGuidPoolHash, sizeof(void*))
BEGIN_TYPE_ESCAPED(MetaData::HotHeap, MetaData__HotHeap, 0)
FIELD_ESCAPED(MetaData::HotHeap, MetaData__HotHeap, m_pHotHeapHeader, sizeof(void*))
END_TYPE_ESCAPED(MetaData::HotHeap, MetaData__HotHeap, sizeof(void*))
BEGIN_TYPE(StgPoolReadOnly, sizeof(StgPoolSeg) + sizeof(void*)) //vtable pointer
ALIGN_FIELD(StgPoolReadOnly, m_HotHeap, sizeof(MetaData::HotHeap), sizeof(void*))
END_TYPE(StgPoolReadOnly, sizeof(void*))
BEGIN_TYPE_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, sizeof(void*))
FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_table, sizeof(void*))
FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_tableSize, 4)
FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_tableCount, 4)
FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_tableOccupied, 4)
FIELD_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, m_tableMax, 4)
END_TYPE_ESCAPED(IGNORE_COMMAS(MapSHash<ULONG, ULONG>), MapSHash__ULONG__ULONG, sizeof(void*))
BEGIN_TYPE(StgPoolSeg, 0)
FIELD(StgPoolSeg, m_pSegData, sizeof(void*))
FIELD(StgPoolSeg, m_pNextSeg, sizeof(void*))
FIELD(StgPoolSeg, m_cbSegSize, 4)
FIELD(StgPoolSeg, m_cbSegNext, 4)
END_TYPE(StgPoolSeg, sizeof(void*))
BEGIN_TYPE_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, sizeof(void*)) // vtable pointer
FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_rgData, sizeof(void*))
FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iBuckets, 4)
FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iSize, 4)
FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iCount, 4)
FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iMaxChain, 4)
FIELD_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, m_iFree, 4)
END_TYPE_ESCAPED(CChainedHash<STRINGHASH>, CCHainedHash_STRINGHASH, sizeof(void*))
BEGIN_TYPE(CMiniColDef, 0)
FIELD(CMiniColDef, m_Type, 1)
FIELD(CMiniColDef, m_oColumn, 1)
FIELD(CMiniColDef, m_cbColumn, 1)
END_TYPE(CMiniColDef, 1)
BEGIN_TYPE(CMiniTableDef, 0)
FIELD(CMiniTableDef, m_pColDefs, sizeof(void*))
FIELD(CMiniTableDef, m_cCols, 1)
FIELD(CMiniTableDef, m_iKey, 1)
FIELD(CMiniTableDef, m_cbRec, 1)
END_TYPE(CMiniTableDef, sizeof(void*))
BEGIN_TYPE(CMiniMdBase, 8) //vtable ptr and first field 8-byte alignment
ALIGN_FIELD(CMiniMdBase, m_Schema, sizeof(CMiniMdSchema), 8)
FIELD(CMiniMdBase, m_TblCount, 4)
FIELD(CMiniMdBase, m_fVerifiedByTrustedSource, 4)
ALIGN_FIELD(CMiniMdBase, m_TableDefs, sizeof(CMiniTableDef)*TBL_COUNT, sizeof(void*))
FIELD(CMiniMdBase, m_iStringsMask, 4)
FIELD(CMiniMdBase, m_iGuidsMask, 4)
FIELD(CMiniMdBase, m_iBlobsMask, 4)
END_TYPE(CMiniMdBase, 8)
BEGIN_TYPE(CMiniMdSchemaBase, 0)
FIELD(CMiniMdSchemaBase, m_ulReserved, 4)
FIELD(CMiniMdSchemaBase, m_major, 1)
FIELD(CMiniMdSchemaBase, m_minor, 1)
FIELD(CMiniMdSchemaBase, m_heaps, 1)
FIELD(CMiniMdSchemaBase, m_rid, 1)
FIELD(CMiniMdSchemaBase, m_maskvalid, 8)
FIELD(CMiniMdSchemaBase, m_sorted, 8)
END_TYPE(CMiniMdSchemaBase, 8)
BEGIN_TYPE(CMiniMdSchema, sizeof(CMiniMdSchemaBase))
ALIGN_FIELD(CMiniMdSchema, m_cRecs, 4*TBL_COUNT, 4)
FIELD(CMiniMdSchema, m_ulExtra, 4)
END_TYPE(CMiniMdSchema, 8)