//=== RecordLayoutBuilder.cpp - Helper class for building record layouts ---==// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/Attr.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/VTableBuilder.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallSet.h" #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" usingnamespaceclang; namespace { /// BaseSubobjectInfo - Represents a single base subobject in a complete class. /// For a class hierarchy like /// /// class A { }; /// class B : A { }; /// class C : A, B { }; /// /// The BaseSubobjectInfo graph for C will have three BaseSubobjectInfo /// instances, one for B and two for A. /// /// If a base is virtual, it will only have one BaseSubobjectInfo allocated. struct BaseSubobjectInfo { … }; /// Externally provided layout. Typically used when the AST source, such /// as DWARF, lacks all the information that was available at compile time, such /// as alignment attributes on fields and pragmas in effect. struct ExternalLayout { … }; /// EmptySubobjectMap - Keeps track of which empty subobjects exist at different /// offsets while laying out a C++ class. class EmptySubobjectMap { … }; void EmptySubobjectMap::ComputeEmptySubobjectSizes() { … } bool EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, CharUnits Offset) const { … } void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD, CharUnits Offset) { … } bool EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, CharUnits Offset) { … } void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info, CharUnits Offset, bool PlacingEmptyBase) { … } bool EmptySubobjectMap::CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info, CharUnits Offset) { … } bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, const CXXRecordDecl *Class, CharUnits Offset) const { … } bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, CharUnits Offset) const { … } bool EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD, CharUnits Offset) { … } void EmptySubobjectMap::UpdateEmptyFieldSubobjects( const CXXRecordDecl *RD, const CXXRecordDecl *Class, CharUnits Offset, bool PlacingOverlappingField) { … } void EmptySubobjectMap::UpdateEmptyFieldSubobjects( const FieldDecl *FD, CharUnits Offset, bool PlacingOverlappingField) { … } ClassSetTy; class ItaniumRecordLayoutBuilder { … }; } // end anonymous namespace void ItaniumRecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { … } /// DeterminePrimaryBase - Determine the primary base of the given class. void ItaniumRecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { … } BaseSubobjectInfo *ItaniumRecordLayoutBuilder::ComputeBaseSubobjectInfo( const CXXRecordDecl *RD, bool IsVirtual, BaseSubobjectInfo *Derived) { … } void ItaniumRecordLayoutBuilder::ComputeBaseSubobjectInfo( const CXXRecordDecl *RD) { … } void ItaniumRecordLayoutBuilder::EnsureVTablePointerAlignment( CharUnits UnpackedBaseAlign) { … } void ItaniumRecordLayoutBuilder::LayoutNonVirtualBases( const CXXRecordDecl *RD) { … } void ItaniumRecordLayoutBuilder::LayoutNonVirtualBase( const BaseSubobjectInfo *Base) { … } void ItaniumRecordLayoutBuilder::AddPrimaryVirtualBaseOffsets( const BaseSubobjectInfo *Info, CharUnits Offset) { … } void ItaniumRecordLayoutBuilder::LayoutVirtualBases( const CXXRecordDecl *RD, const CXXRecordDecl *MostDerivedClass) { … } void ItaniumRecordLayoutBuilder::LayoutVirtualBase( const BaseSubobjectInfo *Base) { … } CharUnits ItaniumRecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { … } void ItaniumRecordLayoutBuilder::InitializeLayout(const Decl *D) { … } void ItaniumRecordLayoutBuilder::Layout(const RecordDecl *D) { … } void ItaniumRecordLayoutBuilder::Layout(const CXXRecordDecl *RD) { … } void ItaniumRecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) { … } void ItaniumRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { … } // Rounds the specified size to have it a multiple of the char size. static uint64_t roundUpSizeToCharAlignment(uint64_t Size, const ASTContext &Context) { … } void ItaniumRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, uint64_t StorageUnitSize, bool FieldPacked, const FieldDecl *D) { … } static bool isAIXLayout(const ASTContext &Context) { … } void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { … } void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, bool InsertExtraPadding) { … } void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { … } void ItaniumRecordLayoutBuilder::UpdateAlignment( CharUnits NewAlignment, CharUnits UnpackedNewAlignment, CharUnits PreferredNewAlignment) { … } uint64_t ItaniumRecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field, uint64_t ComputedOffset) { … } /// Get diagnostic %select index for tag kind for /// field padding diagnostic message. /// WARNING: Indexes apply to particular diagnostics only! /// /// \returns diagnostic %select index. static unsigned getPaddingDiagFromTagKind(TagTypeKind Tag) { … } void ItaniumRecordLayoutBuilder::CheckFieldPadding( uint64_t Offset, uint64_t UnpaddedOffset, uint64_t UnpackedOffset, unsigned UnpackedAlign, bool isPacked, const FieldDecl *D) { … } static const CXXMethodDecl *computeKeyFunction(ASTContext &Context, const CXXRecordDecl *RD) { … } DiagnosticBuilder ItaniumRecordLayoutBuilder::Diag(SourceLocation Loc, unsigned DiagID) { … } /// Does the target C++ ABI require us to skip over the tail-padding /// of the given class (considering it as a base class) when allocating /// objects? static bool mustSkipTailPadding(TargetCXXABI ABI, const CXXRecordDecl *RD) { … } static bool isMsLayout(const ASTContext &Context) { … } // This section contains an implementation of struct layout that is, up to the // included tests, compatible with cl.exe (2013). The layout produced is // significantly different than those produced by the Itanium ABI. Here we note // the most important differences. // // * The alignment of bitfields in unions is ignored when computing the // alignment of the union. // * The existence of zero-width bitfield that occurs after anything other than // a non-zero length bitfield is ignored. // * There is no explicit primary base for the purposes of layout. All bases // with vfptrs are laid out first, followed by all bases without vfptrs. // * The Itanium equivalent vtable pointers are split into a vfptr (virtual // function pointer) and a vbptr (virtual base pointer). They can each be // shared with a, non-virtual bases. These bases need not be the same. vfptrs // always occur at offset 0. vbptrs can occur at an arbitrary offset and are // placed after the lexicographically last non-virtual base. This placement // is always before fields but can be in the middle of the non-virtual bases // due to the two-pass layout scheme for non-virtual-bases. // * Virtual bases sometimes require a 'vtordisp' field that is laid out before // the virtual base and is used in conjunction with virtual overrides during // construction and destruction. This is always a 4 byte value and is used as // an alternative to constructor vtables. // * vtordisps are allocated in a block of memory with size and alignment equal // to the alignment of the completed structure (before applying __declspec( // align())). The vtordisp always occur at the end of the allocation block, // immediately prior to the virtual base. // * vfptrs are injected after all bases and fields have been laid out. In // order to guarantee proper alignment of all fields, the vfptr injection // pushes all bases and fields back by the alignment imposed by those bases // and fields. This can potentially add a significant amount of padding. // vfptrs are always injected at offset 0. // * vbptrs are injected after all bases and fields have been laid out. In // order to guarantee proper alignment of all fields, the vfptr injection // pushes all bases and fields back by the alignment imposed by those bases // and fields. This can potentially add a significant amount of padding. // vbptrs are injected immediately after the last non-virtual base as // lexicographically ordered in the code. If this site isn't pointer aligned // the vbptr is placed at the next properly aligned location. Enough padding // is added to guarantee a fit. // * The last zero sized non-virtual base can be placed at the end of the // struct (potentially aliasing another object), or may alias with the first // field, even if they are of the same type. // * The last zero size virtual base may be placed at the end of the struct // potentially aliasing another object. // * The ABI attempts to avoid aliasing of zero sized bases by adding padding // between bases or vbases with specific properties. The criteria for // additional padding between two bases is that the first base is zero sized // or ends with a zero sized subobject and the second base is zero sized or // trails with a zero sized base or field (sharing of vfptrs can reorder the // layout of the so the leading base is not always the first one declared). // This rule does take into account fields that are not records, so padding // will occur even if the last field is, e.g. an int. The padding added for // bases is 1 byte. The padding added between vbases depends on the alignment // of the object but is at least 4 bytes (in both 32 and 64 bit modes). // * There is no concept of non-virtual alignment, non-virtual alignment and // alignment are always identical. // * There is a distinction between alignment and required alignment. // __declspec(align) changes the required alignment of a struct. This // alignment is _always_ obeyed, even in the presence of #pragma pack. A // record inherits required alignment from all of its fields and bases. // * __declspec(align) on bitfields has the effect of changing the bitfield's // alignment instead of its required alignment. This is the only known way // to make the alignment of a struct bigger than 8. Interestingly enough // this alignment is also immune to the effects of #pragma pack and can be // used to create structures with large alignment under #pragma pack. // However, because it does not impact required alignment, such a structure, // when used as a field or base, will not be aligned if #pragma pack is // still active at the time of use. // // Known incompatibilities: // * all: #pragma pack between fields in a record // * 2010 and back: If the last field in a record is a bitfield, every object // laid out after the record will have extra padding inserted before it. The // extra padding will have size equal to the size of the storage class of the // bitfield. 0 sized bitfields don't exhibit this behavior and the extra // padding can be avoided by adding a 0 sized bitfield after the non-zero- // sized bitfield. // * 2012 and back: In 64-bit mode, if the alignment of a record is 16 or // greater due to __declspec(align()) then a second layout phase occurs after // The locations of the vf and vb pointers are known. This layout phase // suffers from the "last field is a bitfield" bug in 2010 and results in // _every_ field getting padding put in front of it, potentially including the // vfptr, leaving the vfprt at a non-zero location which results in a fault if // anything tries to read the vftbl. The second layout phase also treats // bitfields as separate entities and gives them each storage rather than // packing them. Additionally, because this phase appears to perform a // (an unstable) sort on the members before laying them out and because merged // bitfields have the same address, the bitfields end up in whatever order // the sort left them in, a behavior we could never hope to replicate. namespace { struct MicrosoftRecordLayoutBuilder { … }; } // namespace MicrosoftRecordLayoutBuilder::ElementInfo MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( const ASTRecordLayout &Layout) { … } MicrosoftRecordLayoutBuilder::ElementInfo MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( const FieldDecl *FD) { … } void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) { … } void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) { … } void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) { … } void MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) { … } void MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) { … } static bool recordUsesEBO(const RecordDecl *RD) { … } void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase( const CXXRecordDecl *RD, const CXXRecordDecl *BaseDecl, const ASTRecordLayout &BaseLayout, const ASTRecordLayout *&PreviousBaseLayout) { … } void MicrosoftRecordLayoutBuilder::layoutFields(const RecordDecl *RD) { … } void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) { … } void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) { … } void MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) { … } void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) { … } void MicrosoftRecordLayoutBuilder::injectVFPtr(const CXXRecordDecl *RD) { … } void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) { … } void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { … } // Recursively walks the non-virtual bases of a class and determines if any of // them are in the bases with overridden methods set. static bool RequiresVtordisp(const llvm::SmallPtrSetImpl<const CXXRecordDecl *> & BasesWithOverriddenMethods, const CXXRecordDecl *RD) { … } void MicrosoftRecordLayoutBuilder::computeVtorDispSet( llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtordispSet, const CXXRecordDecl *RD) const { … } /// getASTRecordLayout - Get or compute information about the layout of the /// specified record (struct/union/class), which indicates its size and field /// position information. const ASTRecordLayout & ASTContext::getASTRecordLayout(const RecordDecl *D) const { … } const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) { … } void ASTContext::setNonKeyFunction(const CXXMethodDecl *Method) { … } static uint64_t getFieldOffset(const ASTContext &C, const FieldDecl *FD) { … } uint64_t ASTContext::getFieldOffset(const ValueDecl *VD) const { … } uint64_t ASTContext::lookupFieldBitOffset(const ObjCInterfaceDecl *OID, const ObjCImplementationDecl *ID, const ObjCIvarDecl *Ivar) const { … } /// getObjCLayout - Get or compute information about the layout of the /// given interface. /// /// \param Impl - If given, also include the layout of the interface's /// implementation. This may differ by including synthesized ivars. const ASTRecordLayout & ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, const ObjCImplementationDecl *Impl) const { … } static void PrintOffset(raw_ostream &OS, CharUnits Offset, unsigned IndentLevel) { … } static void PrintBitFieldOffset(raw_ostream &OS, CharUnits Offset, unsigned Begin, unsigned Width, unsigned IndentLevel) { … } static void PrintIndentNoOffset(raw_ostream &OS, unsigned IndentLevel) { … } static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, const ASTContext &C, CharUnits Offset, unsigned IndentLevel, const char* Description, bool PrintSizeInfo, bool IncludeVirtualBases) { … } void ASTContext::DumpRecordLayout(const RecordDecl *RD, raw_ostream &OS, bool Simple) const { … }