diff options
Diffstat (limited to 'src/md/inc/VerifyLayouts.inc')
-rw-r--r-- | src/md/inc/VerifyLayouts.inc | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/src/md/inc/VerifyLayouts.inc b/src/md/inc/VerifyLayouts.inc new file mode 100644 index 0000000000..4c0bd65b30 --- /dev/null +++ b/src/md/inc/VerifyLayouts.inc @@ -0,0 +1,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) |