Perform dynamic alignment computations so that the data in TypeLocs is

correctly aligned.  Not performing such computations led to misaligned loads,
which crash on some platforms and are generally bad on other platforms.

The implementation of TypeLocBuilder::pushImpl is rather messy; code using
TypeLocBuilder accidentally assumes that partial TypeLocs are
laid out like a complete TypeLoc.  As a followup, I intend to work on
fixing the TypeLocBuilder API to avoid exposing partial TypeLocs; this should
substantially simplify the implemementation.

Fixes PR16144.

llvm-svn: 183466
This commit is contained in:
Eli Friedman 2013-06-07 00:04:31 +00:00
parent f84a03a589
commit 0b3175a6fc
8 changed files with 266 additions and 103 deletions

View File

@ -95,6 +95,10 @@ public:
/// \brief Returns the size of type source info data block for the given type.
static unsigned getFullDataSizeForType(QualType Ty);
/// \brief Returns the alignment of type source info data block for
/// the given type.
static unsigned getLocalAlignmentForType(QualType Ty);
/// \brief Get the type for which this source info wrapper provides
/// information.
QualType getType() const {
@ -229,7 +233,11 @@ public:
}
UnqualTypeLoc getUnqualifiedLoc() const {
return UnqualTypeLoc(getTypePtr(), Data);
unsigned align =
TypeLoc::getLocalAlignmentForType(QualType(getTypePtr(), 0));
uintptr_t dataInt = reinterpret_cast<uintptr_t>(Data);
dataInt = llvm::RoundUpToAlignment(dataInt, align);
return UnqualTypeLoc(getTypePtr(), reinterpret_cast<void*>(dataInt));
}
/// Initializes the local data of this type source info block to
@ -250,10 +258,11 @@ public:
return 0;
}
/// \brief Returns the size of the type source info data block.
unsigned getFullDataSize() const {
return getLocalDataSize() +
getFullDataSizeForType(getType().getLocalUnqualifiedType());
/// \brief Returns the alignment of the type source info data block that is
/// specific to this type.
unsigned getLocalDataAlignment() const {
// We don't preserve any location information.
return 1;
}
private:
@ -280,9 +289,6 @@ inline UnqualTypeLoc TypeLoc::getUnqualifiedLoc() const {
/// \tparam LocalData the structure type of local location data for
/// this type
///
/// sizeof(LocalData) needs to be a multiple of sizeof(void*) or
/// else the world will end.
///
/// TypeLocs with non-constant amounts of local data should override
/// getExtraLocalDataSize(); getExtraLocalData() will then point to
/// this extra memory.
@ -317,12 +323,16 @@ class ConcreteTypeLoc : public Base {
}
public:
unsigned getLocalDataSize() const {
return sizeof(LocalData) + asDerived()->getExtraLocalDataSize();
unsigned getLocalDataAlignment() const {
return std::max(llvm::alignOf<LocalData>(),
asDerived()->getExtraLocalDataAlignment());
}
// Give a default implementation that's useful for leaf types.
unsigned getFullDataSize() const {
return asDerived()->getLocalDataSize() + getInnerTypeSize();
unsigned getLocalDataSize() const {
unsigned size = sizeof(LocalData);
unsigned extraAlign = asDerived()->getExtraLocalDataAlignment();
size = llvm::RoundUpToAlignment(size, extraAlign);
size += asDerived()->getExtraLocalDataSize();
return size;
}
TypeLoc getNextTypeLoc() const {
@ -338,6 +348,10 @@ protected:
return 0;
}
unsigned getExtraLocalDataAlignment() const {
return 1;
}
LocalData *getLocalData() const {
return static_cast<LocalData*>(Base::Data);
}
@ -346,11 +360,17 @@ protected:
/// local data that can't be captured in the Info (e.g. because it's
/// of variable size).
void *getExtraLocalData() const {
return getLocalData() + 1;
unsigned size = sizeof(LocalData);
unsigned extraAlign = asDerived()->getExtraLocalDataAlignment();
size = llvm::RoundUpToAlignment(size, extraAlign);
return reinterpret_cast<char*>(Base::Data) + size;
}
void *getNonLocalData() const {
return static_cast<char*>(Base::Data) + asDerived()->getLocalDataSize();
uintptr_t data = reinterpret_cast<uintptr_t>(Base::Data);
data += asDerived()->getLocalDataSize();
data = llvm::RoundUpToAlignment(data, getNextTypeAlign());
return reinterpret_cast<void*>(data);
}
struct HasNoInnerType {};
@ -373,6 +393,18 @@ private:
return getInnerTypeLoc().getFullDataSize();
}
unsigned getNextTypeAlign() const {
return getNextTypeAlign(asDerived()->getInnerType());
}
unsigned getNextTypeAlign(HasNoInnerType _) const {
return 1;
}
unsigned getNextTypeAlign(QualType T) const {
return TypeLoc::getLocalAlignmentForType(T);
}
TypeLoc getNextTypeLoc(HasNoInnerType _) const {
return TypeLoc();
}
@ -417,7 +449,8 @@ class TypeSpecTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
Type,
TypeSpecLocInfo> {
public:
enum { LocalDataSize = sizeof(TypeSpecLocInfo) };
enum { LocalDataSize = sizeof(TypeSpecLocInfo),
LocalDataAlignment = llvm::AlignOf<TypeSpecLocInfo>::Alignment };
SourceLocation getNameLoc() const {
return this->getLocalData()->NameLoc;
@ -448,8 +481,6 @@ class BuiltinTypeLoc : public ConcreteTypeLoc<UnqualTypeLoc,
BuiltinType,
BuiltinLocInfo> {
public:
enum { LocalDataSize = sizeof(BuiltinLocInfo) };
SourceLocation getBuiltinLoc() const {
return getLocalData()->BuiltinLoc;
}
@ -478,6 +509,10 @@ public:
return needsExtraLocalData() ? sizeof(WrittenBuiltinSpecs) : 0;
}
unsigned getExtraLocalDataAlignment() const {
return needsExtraLocalData() ? llvm::alignOf<WrittenBuiltinSpecs>() : 1;
}
SourceRange getLocalSourceRange() const {
return SourceRange(getBuiltinLoc(), getBuiltinLoc());
}
@ -840,6 +875,10 @@ public:
return this->getNumProtocols() * sizeof(SourceLocation);
}
unsigned getExtraLocalDataAlignment() const {
return llvm::alignOf<SourceLocation>();
}
QualType getInnerType() const {
return getTypePtr()->getBaseType();
}
@ -1166,6 +1205,10 @@ public:
return getNumArgs() * sizeof(ParmVarDecl*);
}
unsigned getExtraLocalDataAlignment() const {
return llvm::alignOf<ParmVarDecl*>();
}
QualType getInnerType() const { return getTypePtr()->getResultType(); }
};
@ -1357,6 +1400,10 @@ public:
return getNumArgs() * sizeof(TemplateArgumentLocInfo);
}
unsigned getExtraLocalDataAlignment() const {
return llvm::alignOf<TemplateArgumentLocInfo>();
}
private:
TemplateArgumentLocInfo *getArgInfos() const {
return static_cast<TemplateArgumentLocInfo*>(getExtraLocalData());
@ -1761,6 +1808,10 @@ public:
return getNumArgs() * sizeof(TemplateArgumentLocInfo);
}
unsigned getExtraLocalDataAlignment() const {
return llvm::alignOf<TemplateArgumentLocInfo>();
}
private:
TemplateArgumentLocInfo *getArgInfos() const {
return static_cast<TemplateArgumentLocInfo*>(getExtraLocalData());

View File

@ -40,13 +40,31 @@ SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) {
return TypeLocRanger().Visit(TL);
}
namespace {
class TypeAligner : public TypeLocVisitor<TypeAligner, unsigned> {
public:
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
return TyLoc.getLocalDataAlignment(); \
}
#include "clang/AST/TypeLocNodes.def"
};
}
/// \brief Returns the alignment of the type source info data block.
unsigned TypeLoc::getLocalAlignmentForType(QualType Ty) {
if (Ty.isNull()) return 1;
return TypeAligner().Visit(TypeLoc(Ty, 0));
}
namespace {
class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> {
public:
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \
return TyLoc.getFullDataSize(); \
return TyLoc.getLocalDataSize(); \
}
#include "clang/AST/TypeLocNodes.def"
};
@ -54,8 +72,18 @@ namespace {
/// \brief Returns the size of the type source info data block.
unsigned TypeLoc::getFullDataSizeForType(QualType Ty) {
if (Ty.isNull()) return 0;
return TypeSizer().Visit(TypeLoc(Ty, 0));
unsigned Total = 0;
TypeLoc TyLoc(Ty, 0);
unsigned MaxAlign = 1;
while (!TyLoc.isNull()) {
unsigned Align = getLocalAlignmentForType(TyLoc.getType());
MaxAlign = std::max(Align, MaxAlign);
Total = llvm::RoundUpToAlignment(Total, Align);
Total += TypeSizer().Visit(TyLoc);
TyLoc = TyLoc.getNextTypeLoc();
}
Total = llvm::RoundUpToAlignment(Total, MaxAlign);
return Total;
}
namespace {

View File

@ -51,6 +51,7 @@ add_clang_library(clangSema
SemaTemplateVariadic.cpp
SemaType.cpp
TargetAttributesSema.cpp
TypeLocBuilder.cpp
)
add_dependencies(clangSema

View File

@ -445,6 +445,7 @@ FieldDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef,
assert(!DeductType.isNull() && "can't build reference to auto");
TLB.push<ReferenceTypeLoc>(DeductType).setSigilLoc(Loc);
}
TypeSourceInfo *TSI = TLB.getTypeSourceInfo(Context, DeductType);
InitializationKind InitKind = InitializationKind::CreateDefault(Loc);
Expr *Init = InitExpr;
@ -476,8 +477,7 @@ FieldDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef,
else
InitKind = InitializationKind::CreateCopy(Loc, Loc);
QualType DeducedType;
if (DeduceAutoType(TLB.getTemporaryTypeLoc(DeductType),
Init, DeducedType) == DAR_Failed) {
if (DeduceAutoType(TSI, Init, DeducedType) == DAR_Failed) {
if (isa<InitListExpr>(Init))
Diag(Loc, diag::err_init_capture_deduction_failure_from_init_list)
<< Id << Init->getSourceRange();
@ -492,7 +492,7 @@ FieldDecl *Sema::checkInitCapture(SourceLocation Loc, bool ByRef,
// the closure type. This member is not a bit-field and not mutable.
// Core issue: the member is (probably...) public.
FieldDecl *NewFD = CheckFieldDecl(
Id, DeducedType, TLB.getTypeSourceInfo(Context, DeductType), LSI->Lambda,
Id, DeducedType, TSI, LSI->Lambda,
Loc, /*Mutable*/ false, /*BitWidth*/ 0, ICIS_NoInit,
Loc, AS_public, /*PrevDecl*/ 0, /*Declarator*/ 0);
LSI->Lambda->addDecl(NewFD);

View File

@ -18,6 +18,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "TypeLocBuilder.h"
using namespace clang;
@ -463,17 +464,13 @@ Sema::CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc,
EllipsisLoc, NumExpansions);
if (Result.isNull())
return 0;
TypeSourceInfo *TSResult = Context.CreateTypeSourceInfo(Result);
PackExpansionTypeLoc TL =
TSResult->getTypeLoc().castAs<PackExpansionTypeLoc>();
TypeLocBuilder TLB;
TLB.pushFullCopy(Pattern->getTypeLoc());
PackExpansionTypeLoc TL = TLB.push<PackExpansionTypeLoc>(Result);
TL.setEllipsisLoc(EllipsisLoc);
// Copy over the source-location information from the type.
memcpy(TL.getNextTypeLoc().getOpaqueData(),
Pattern->getTypeLoc().getOpaqueData(),
Pattern->getTypeLoc().getFullDataSize());
return TSResult;
return TLB.getTypeSourceInfo(Context, Result);
}
QualType Sema::CheckPackExpansion(QualType Pattern, SourceRange PatternRange,

View File

@ -3427,7 +3427,7 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
} else {
// Otherwise, complain about the addition of a qualifier to an
// already-qualified type.
SourceRange R = TLB.getTemporaryTypeLoc(Result).getSourceRange();
SourceRange R = T.getUnqualifiedLoc().getSourceRange();
SemaRef.Diag(R.getBegin(), diag::err_attr_objc_ownership_redundant)
<< Result << R;

View File

@ -0,0 +1,136 @@
//===--- TypeLocBuilder.cpp - Type Source Info collector ------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This files defines TypeLocBuilder, a class for building TypeLocs
// bottom-up.
//
//===----------------------------------------------------------------------===//
#include "TypeLocBuilder.h"
using namespace clang;
void TypeLocBuilder::pushFullCopy(TypeLoc L) {
size_t Size = L.getFullDataSize();
reserve(Size);
SmallVector<TypeLoc, 4> TypeLocs;
TypeLoc CurTL = L;
while (CurTL) {
TypeLocs.push_back(CurTL);
CurTL = CurTL.getNextTypeLoc();
}
for (unsigned i = 0, e = TypeLocs.size(); i < e; ++i) {
TypeLoc CurTL = TypeLocs[e-i-1];
switch (CurTL.getTypeLocClass()) {
#define ABSTRACT_TYPELOC(CLASS, PARENT)
#define TYPELOC(CLASS, PARENT) \
case TypeLoc::CLASS: { \
CLASS##TypeLoc NewTL = push<class CLASS##TypeLoc>(CurTL.getType()); \
memcpy(NewTL.getOpaqueData(), CurTL.getOpaqueData(), NewTL.getLocalDataSize()); \
break; \
}
#include "clang/AST/TypeLocNodes.def"
}
}
}
void TypeLocBuilder::grow(size_t NewCapacity) {
assert(NewCapacity > Capacity);
// Allocate the new buffer and copy the old data into it.
char *NewBuffer = new char[NewCapacity];
unsigned NewIndex = Index + NewCapacity - Capacity;
memcpy(&NewBuffer[NewIndex],
&Buffer[Index],
Capacity - Index);
if (Buffer != InlineBuffer.buffer)
delete[] Buffer;
Buffer = NewBuffer;
Capacity = NewCapacity;
Index = NewIndex;
}
TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment) {
#ifndef NDEBUG
QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
assert(TLast == LastTy &&
"mismatch between last type and new type's inner type");
LastTy = T;
#endif
assert(LocalAlignment <= BufferMaxAlignment && "Unexpected alignment");
// If we need to grow, grow by a factor of 2.
if (LocalSize > Index) {
size_t RequiredCapacity = Capacity + (LocalSize - Index);
size_t NewCapacity = Capacity * 2;
while (RequiredCapacity > NewCapacity)
NewCapacity *= 2;
grow(NewCapacity);
}
// Because we're adding elements to the TypeLoc backwards, we have to
// do some extra work to keep everything aligned appropriately.
// FIXME: This algorithm is a absolute mess because every TypeLoc returned
// needs to be valid. Partial TypeLocs are a terrible idea.
// FIXME: 4 and 8 are sufficient at the moment, but it's pretty ugly to
// hardcode them.
if (LocalAlignment == 4) {
if (NumBytesAtAlign8 == 0) {
NumBytesAtAlign4 += LocalSize;
} else {
unsigned Padding = NumBytesAtAlign4 % 8;
if (Padding == 0) {
if (LocalSize % 8 == 0) {
// Everything is set: there's no padding and we don't need to add
// any.
} else {
assert(LocalSize % 8 == 4);
// No existing padding; add in 4 bytes padding
memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
Index -= 4;
}
} else {
assert(Padding == 4);
if (LocalSize % 8 == 0) {
// Everything is set: there's 4 bytes padding and we don't need
// to add any.
} else {
assert(LocalSize % 8 == 4);
// There are 4 bytes padding, but we don't need any; remove it.
memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
Index += 4;
}
}
NumBytesAtAlign4 += LocalSize;
}
} else if (LocalAlignment == 8) {
if (!NumBytesAtAlign8 && NumBytesAtAlign4 % 8 != 0) {
// No existing padding and misaligned members; add in 4 bytes padding
memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
Index -= 4;
}
// Forget about any padding.
NumBytesAtAlign4 = 0;
NumBytesAtAlign8 += LocalSize;
} else {
assert(LocalSize == 0);
}
Index -= LocalSize;
assert(Capacity - Index == TypeLoc::getFullDataSizeForType(T) &&
"incorrect data size provided to CreateTypeSourceInfo!");
return getTemporaryTypeLoc(T);
}

View File

@ -39,14 +39,19 @@ class TypeLocBuilder {
#endif
/// The inline buffer.
char InlineBuffer[InlineCapacity];
enum { BufferMaxAlignment = llvm::AlignOf<void*>::Alignment };
llvm::AlignedCharArray<BufferMaxAlignment, InlineCapacity> InlineBuffer;
unsigned NumBytesAtAlign4, NumBytesAtAlign8;
public:
TypeLocBuilder()
: Buffer(InlineBuffer), Capacity(InlineCapacity), Index(InlineCapacity) {}
: Buffer(InlineBuffer.buffer), Capacity(InlineCapacity),
Index(InlineCapacity), NumBytesAtAlign4(0), NumBytesAtAlign8(0)
{
}
~TypeLocBuilder() {
if (Buffer != InlineBuffer)
if (Buffer != InlineBuffer.buffer)
delete[] Buffer;
}
@ -59,23 +64,14 @@ class TypeLocBuilder {
/// Pushes a copy of the given TypeLoc onto this builder. The builder
/// must be empty for this to work.
void pushFullCopy(TypeLoc L) {
size_t Size = L.getFullDataSize();
TypeLoc Copy = pushFullUninitializedImpl(L.getType(), Size);
memcpy(Copy.getOpaqueData(), L.getOpaqueData(), Size);
}
/// Pushes uninitialized space for the given type. The builder must
/// be empty.
TypeLoc pushFullUninitialized(QualType T) {
return pushFullUninitializedImpl(T, TypeLoc::getFullDataSizeForType(T));
}
void pushFullCopy(TypeLoc L);
/// Pushes space for a typespec TypeLoc. Invalidates any TypeLocs
/// previously retrieved from this builder.
TypeSpecTypeLoc pushTypeSpec(QualType T) {
size_t LocalSize = TypeSpecTypeLoc::LocalDataSize;
return pushImpl(T, LocalSize).castAs<TypeSpecTypeLoc>();
unsigned LocalAlign = TypeSpecTypeLoc::LocalDataAlignment;
return pushImpl(T, LocalSize, LocalAlign).castAs<TypeSpecTypeLoc>();
}
/// Resets this builder to the newly-initialized state.
@ -84,6 +80,7 @@ class TypeLocBuilder {
LastTy = QualType();
#endif
Index = Capacity;
NumBytesAtAlign4 = NumBytesAtAlign8 = 0;
}
/// \brief Tell the TypeLocBuilder that the type it is storing has been
@ -97,8 +94,10 @@ class TypeLocBuilder {
/// Pushes space for a new TypeLoc of the given type. Invalidates
/// any TypeLocs previously retrieved from this builder.
template <class TyLocType> TyLocType push(QualType T) {
size_t LocalSize = TypeLoc(T, 0).castAs<TyLocType>().getLocalDataSize();
return pushImpl(T, LocalSize).castAs<TyLocType>();
TyLocType Loc = TypeLoc(T, 0).castAs<TyLocType>();
size_t LocalSize = Loc.getLocalDataSize();
unsigned LocalAlign = Loc.getLocalDataAlignment();
return pushImpl(T, LocalSize, LocalAlign).castAs<TyLocType>();
}
/// Creates a TypeSourceInfo for the given type.
@ -127,61 +126,12 @@ class TypeLocBuilder {
}
private:
TypeLoc pushImpl(QualType T, size_t LocalSize) {
#ifndef NDEBUG
QualType TLast = TypeLoc(T, 0).getNextTypeLoc().getType();
assert(TLast == LastTy &&
"mismatch between last type and new type's inner type");
LastTy = T;
#endif
// If we need to grow, grow by a factor of 2.
if (LocalSize > Index) {
size_t RequiredCapacity = Capacity + (LocalSize - Index);
size_t NewCapacity = Capacity * 2;
while (RequiredCapacity > NewCapacity)
NewCapacity *= 2;
grow(NewCapacity);
}
Index -= LocalSize;
return getTemporaryTypeLoc(T);
}
TypeLoc pushImpl(QualType T, size_t LocalSize, unsigned LocalAlignment);
/// Grow to the given capacity.
void grow(size_t NewCapacity) {
assert(NewCapacity > Capacity);
void grow(size_t NewCapacity);
// Allocate the new buffer and copy the old data into it.
char *NewBuffer = new char[NewCapacity];
unsigned NewIndex = Index + NewCapacity - Capacity;
memcpy(&NewBuffer[NewIndex],
&Buffer[Index],
Capacity - Index);
if (Buffer != InlineBuffer)
delete[] Buffer;
Buffer = NewBuffer;
Capacity = NewCapacity;
Index = NewIndex;
}
TypeLoc pushFullUninitializedImpl(QualType T, size_t Size) {
#ifndef NDEBUG
assert(LastTy.isNull() && "pushing full on non-empty TypeLocBuilder");
LastTy = T;
#endif
assert(Index == Capacity && "pushing full on non-empty TypeLocBuilder");
reserve(Size);
Index -= Size;
return getTemporaryTypeLoc(T);
}
public:
/// \brief Retrieve a temporary TypeLoc that refers into this \c TypeLocBuilder
/// object.
///