llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.48k stars 11.77k forks source link

FreeBSD 11.0-CURRENT clang++ 3.7.1 gets Bus Errors during compilation on arm that has SCTLR bit[1]==1 (alignment required) #26332

Closed markmi closed 8 years ago

markmi commented 8 years ago
Bugzilla Link 25958
Resolution FIXED
Resolved on Jan 05, 2016 13:38
Version 3.7
OS FreeBSD
CC @DimitryAndric,@emaste,@jmolloy,@jyknight

Extended Description

The program being compiled is all of 11 lines or so:

more /tmp/main-5dac8d.cpp

1 ""

1 "main.cc"

template <class _Tp, class _Up> struct has_rebind { template static char test(typename _Xp::template rebind<_Up>* = 0); };

int main () { return 0; }

more /tmp/main-5dac8d.sh

Crash reproducer for FreeBSD clang version 3.7.1 (tags/RELEASE_371/final 255217) 20151225

Driver args: "--driver-mode=g++" "main.cc"

Original command: "/usr/bin/clang++" "-cc1" "-triple" "armv6k--freebsd11.0-gnueabi" "-emit-obj" "-mrelax-all" "-disable-free" "-main-file-name" "main.cc" "-mrelocation-model" "static" "-mthread-model" "posix" "-mdisable-fp-elim" "-masm-verbose" "-mconstructor-aliases" "-target-cpu" "arm1176jzf-s" "-target-feature" "+soft-float" "-target-feature" "+soft-float-abi" "-target-feature" "-neon" "-target-feature" "-crypto" "-target-abi" "aapcs-linux" "-msoft-float" "-mfloat-abi" "soft" "-dwarf-column-info" "-resource-dir" "/usr/bin/../lib/clang/3.7.1" "-internal-isystem" "/usr/include/c++/v1" "-fdeprecated-macro" "-fdebug-compilation-dir" "/root/c_tests" "-ferror-limit" "19" "-fmessage-length" "338" "-mstackrealign" "-fno-signed-char" "-fobjc-runtime=gnustep" "-fcxx-exceptions" "-fexceptions" "-fdiagnostics-show-option" "-fcolor-diagnostics" "-o" "/tmp/main-e20b38.o" "-x" "c++" "main.cc"

"/usr/bin/clang++" "-cc1" "-triple" "armv6k--freebsd11.0-gnueabi" "-emit-obj" "-mrelax-all" "-disable-free" "-main-file-name" "main.cc" "-mrelocation-model" "static" "-mthread-model" "posix" "-mdisable-fp-elim" "-masm-verbose" "-mconstructor-aliases" "-target-cpu" "arm1176jzf-s" "-target-feature" "+soft-float" "-target-feature" "+soft-float-abi" "-target-feature" "-neon" "-target-feature" "-crypto" "-target-abi" "aapcs-linux" "-msoft-float" "-mfloat-abi" "soft" "-dwarf-column-info" "-fdeprecated-macro" "-ferror-limit" "19" "-fmessage-length" "338" "-mstackrealign" "-fno-signed-char" "-fobjc-runtime=gnustep" "-fcxx-exceptions" "-fexceptions" "-fdiagnostics-show-option" "-fcolor-diagnostics" "-x" "c++" "main-5dac8d.cpp"

The code involved is from lib/AST/Type.cpp :

DependentTemplateSpecializationType::DependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, NestedNameSpecifier NNS, const IdentifierInfo Name, unsigned NumArgs, const TemplateArgument Args, QualType Canon) : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true, true, /VariablyModified=*/false, NNS && NNS->containsUnexpandedParameterPack()), NNS(NNS), Name(Name), NumArgs(NumArgs) { assert((!NNS || NNS->isDependent()) && "DependentTemplateSpecializatonType requires dependent qualifier"); for (unsigned I = 0; I != NumArgs; ++I) { if (Args[I].containsUnexpandedParameterPack()) setContainsUnexpandedParameterPack();

new (&getArgBuffer()[I]) TemplateArgument(Args[I]); } }

The failing code is for the "placement new" in the loop:

A) &getArgBuffer()[I] is not always an address for which the vst1.64 instruction gets an aligned address.

but. . .

B) TemplateArgument(Args[I])'s copy construction activity has code (such as the vst1.64) requiring a specific alignment when SCTLR bit[1]==1.

C) Nothing here has any explicitly packed data structures.

As for (A):

class DependentTemplateSpecializationType : public TypeWithKeyword, public llvm::FoldingSetNode { . . . const TemplateArgument getArgBuffer() const { return reinterpret_cast<const TemplateArgument>(this+1); } TemplateArgument getArgBuffer() { return reinterpret_cast<TemplateArgument>(this+1); }

clang++ is over-allocating the space for the DependentTemplateSpecializationType objects and using the extra space that is afterwards to hold (a somewhat C-style array of) TemplateArgument instances. But the logic for this does nothing explicit about alignment of the TemplateArgument instance pointers, not even partially via explicitly controlling sizeof(DependentTemplateSpecializationType).

sizeof(TemplateArgument) also needs to be controlled in order to have the notation &getArgBuffer()[I] maintain alignment in its results when &getArgBuffer()[0] is well aligned.

The existing code does not explicitly force any specific minimum TemplateArgument alignment, other than 1. (Implicit ABI rules might get some alignment --if some of those rules are being applied.

Separately there is the issue that the code produced did not treat the pointers returned from getArgBuffer() methods as "opaque pointer" examples but they are. Having compiled with -fmax-type-align=4 the code should have not have required 8 byte alignment (vst1.64). It should have produced code that required 4 (or 2 or 1). Quoting for -fmax-type-align=?:

Instruct the code generator to not enforce a higher alignment than the given number (of bytes) when accessing memory via an opaque pointer or reference

Those pointers certainly are opaque and should be treated as such. The "reinterpret_cast" use is a big clue that clang++ should respect.

In other words: I see two clang++ defects in the overall evidence, one of which directly leads to the Bus Errors being possible.

backtraces and such follow. . .

Program terminated with signal 10, Bus error.

​0 0x00c404d0 in clang::DependentTemplateSpecializationType::DependentTemplateSpecializationType ()

[New Thread 22a18000 (LWP 100173/)] (gdb) bt

​0 0x00c404d0 in clang::DependentTemplateSpecializationType::DependentTemplateSpecializationType ()

​1 0x00d86634 in clang::ASTContext::getDependentTemplateSpecializationType ()

​2 0x00d865d8 in clang::ASTContext::getDependentTemplateSpecializationType ()

​3 0x00d862d4 in clang::ASTContext::getDependentTemplateSpecializationType ()

​4 0x00553b7c in clang::Sema::ActOnTypenameType ()

​5 0x0040cb68 in clang::Parser::TryAnnotateTypeOrScopeToken ()

​6 0x00471198 in $a.28 ()

​7 0x00471198 in $a.28 ()

(gdb) x/1i 0x00c404d0 0xc404d0 <_ZN5clang35DependentTemplateSpecializationTypeC2ENS_21ElaboratedTypeKeywordEPNS_19NestedNameSpecifierEPKNS_14IdentifierInfoEjPKNS_16TemplateArgumentENS_8QualTypeE+356>:
vst1.64 {d16-d17}, [r4]! (gdb) info all-registers r0 0xbfbf9778 -1077962888 r1 0x22ac59c4 581720516 r2 0xc45ff8 12869624 r3 0x2 2 r4 0x22ac59ac 581720492 . . .

DimitryAndric commented 8 years ago

Thanks for reporting that the issue reported is fixed for 3.8.

Unfortunately for FreeBSD, Ian Lapore now reports:

It's a non-starter for us, because unfortunately they appear to have removed support for the -arm-use-movt=0 command line option

This was changed to a subfeature, but I am unsure how to pass a specific subfeature on the clang command line itself.

In any case the point has become a little moot now, since Davide Italiano has turned off movt altogether for FreeBSD in r256641:

http://reviews.llvm.org/rL256641

This is because our linker is currently too old to support the necessary relocation types.

markmi commented 8 years ago

Thanks for reporting that the issue reported is fixed for 3.8.

Unfortunately for FreeBSD, Ian Lapore now reports:

It's a non-starter for us, because unfortunately they appear to have removed support for the -arm-use-movt=0 command line option, so now we can't build ubldr or kernel modules.

-- Ian

I do not know the details in this area but it certainly would be a separate submittal.

jmolloy commented 8 years ago

Hi Mark,

Thanks for your detailed investigation. I can confirm that this is fixed on trunk and therefore will be fixed for LLVM 3.8.

The fixes were done for SPARC, which requires strict accesses much as ARM does with SCTLR=1.

There was a sequence of commits by James Knight that fixed these, but an example is http://reviews.llvm.org/rL242554 .

The fixes were in a similar vein to yours, but required changes in fewer places and there were a few more sticky issues to solve too. I'll CC James here in case he wants to comment on the current state of the clang codebase for self-hosting in a strict alignment environment.

Cheers,

James

markmi commented 8 years ago

FreeBSD folks such as Ian Lepore report things like "I'm using gcc 4.2.1 for arm v4/v5, because clang 3.7 is broken (works to crossbuild, but fails to run native)." [2015-Dec-24 note in an exchange about an 11.0-CURRENT svn commit (r291937).]

To get a quick handle on the size of the investigation effort for alignments of reinterpret_casts to pointer types in llvm/clang I've tried to get approximations of:

A) count of reinterpret_cast's to pointer types that do not involve base types with "char" or "int8" text (on the same line).

and

B) How many files have such reinterpret_cast's.

pwd

/usr/src/contrib/llvm

find -s . -exec grep -E "reinterpret_cast[ \t]<[^>]*" {} \; | grep -v char | grep -v int8 | wc

 789    3453   51918

find -s . -exec grep -E "reinterpret_cast[ \t]<[^>](char|int8)[^>]\" {} \; | wc

 171     854   11326

(Some files may have a mix of both with and without char/int8.)

find -s . -exec grep -E "reinterpret_cast[ \t]<[^>]*" {} \; -print | grep "^.\/" | wc

 264     264   10517

find -s . -exec grep -E "reinterpret_cast[ \t]<[^>](char|int8)[^>]\" {} \; -print | grep "^.\/" | wc

  71      71    2781

(So 264-71==193 to 264 files.)

And also:

C) How many reinterpret_cast's directly involve the text "this" (on the same line):

find -s . -exec grep -E "reinterpret_cast[ \t]<[^>]*.*this" {} \; | grep -v char | grep -v int8 | wc

 132     739    8443

D) How many files is that?

find -s . -exec grep -E "reinterpret_cast[ \t]<[^>]*.*this" {} \; -print | grep "^.\/" | wc

  47      47    1914

find -s . -exec grep -E "reinterpret_cast[ \t]<[^>](char|int8)[^>]*.this" {} \; -print | grep "^.\/" | wc

   5       5     185

(So 47-5==42 to 47 files.)

E) How many reinterpret_cast's do not mention "this", "char", or "int8" (on the same line):

find -s . -exec grep -E "reinterpret_cast[ \t]<[^>]*" {} \; | grep -v this | grep -v char | grep -v int8 | wc

 647    2663   42647

This is the majority of the reinterpret_cast's, by far.

It looks non-trivial to find and adjust the llvm/clang source so that all the places that do not currently deal with proper alignment for SCTLR bit[1]==1 contexts instead do so.

So it is not likely to be happen time soon, much less finish any time soon.

This will limit FreeBSD 11.0's "self hosting on arm" c++ support via the system/clang++ tool chain greatly based on the CTLR bit[1]==1 status: cross builds required from a host not requiring alignment, such as from amd64. (Once some other C++ tool chain is in place on an arm more native work may then be possible.)

The C part of clang does appear to compile okay for buildkernel use in the SCTRL bit[1]==1 context. So far all the misalignments have happened in compiling-c++ contexts, which is involved for buildworld and for building many ports.

markmi commented 8 years ago

Context: RPI2B (cortex-a7) with SCTLR bit[1]==1.

The a.out from compiling the later-below 28 or so non-comment/non-blank line program gets a Bus Error during the placement-new construction activity. THis is true for both of the following ways of compiling it (and more):

clang++ -v -std=c++11 -target armv6--freebsd11.0-gnueabi -march=armv7a -mcpu=cortex-a7 -mfloat-abi=softfp -mno-unaligned-access main.cc

or via:

clang++ -v -std=c++11 -target armv6--freebsd11.0-gnueabi -mno-unaligned-access main.cc

The 28 or so code-line program is designed to use somewhat similar techniques to some of those used in the clang++/llvm source code base that get Bus Errors during c++ compiles of source code that uses various parts of C++ notation, just for a much simpler context.

For an armv7 context the -mfloat-abi=softfp compile enables generation of the neon vast1.64 style of instruction that gets the error in the clang++ crashes that I've reported. But that is not required to get the Bus Error. (FreeBSD's buildworld build environment specifies -mfloat-abi=softfp normally for arm variants and so with -march=armv7a involved it then implicitly uses neon in the code generation.)

more main.cc

// Avoid needing headers that will make the compiler crash on rpi2 with SCTLR bit[1]==1: void operator new(unsigned,void p) { return p; }

struct t0 { // The implicit Copy Constructor requires an alignment long long t0_f0; // appropriate to the sizeof/alignof(long long) for SCTLR bit[1]==1. char t0_f1; } c_t0; // sizeof(t0) is an integral multiple of alignof(long long) so that array use can work.

struct / alignas(alignof(struct t0)) / t1 { char t1_f0; // Unlikely to get default align(t1) being an integral multiple (>=1) of // alignof(long long).

struct t0* t0_start(void) { return reinterpret_cast<struct t0*>(this+1); }
// The returned pointer need not be implicitly aligned to the sizeof/alignof(long long)
// unless the alignas is uncommented.

};

struct t2 { struct t1 t2_f0; char t2_f1[2*sizeof(struct t0)]; // t2_f0.t0_start() causes use of this area. };

struct t0 g[2]; extern struct t0 g[2]; // These and their use prevent optimizing everything away.

int main () { struct t2 t2_v0;

for (int i=0; i<2; i++)
    new(t2_v0.t2_f0.t0_start()+i)   t0(c_t0); // i==0 gets Bus Error.

for (int i=0; i<2; i++)
    g[i] = *(t2_v0.t2_f0.t0_start()+i);
return 0;

}

Uncommenting the alignas for struct t1 avoids the Bus Errors. "struct t0" does not need alignas. In code where what is analogous to struct t0 is supposed to be an incomplete type at that point the alignas would need to be independent of the struct t0 details, more like:

alignas(alignof(std::max_align_t))

(with #include having been used first). This is true in the llvm/clang code.

The compilation commands with -v outputs that show the differing neon status are:

clang++ -v -std=c++11 -target armv6--freebsd11.0-gnueabi -march=armv7a -mcpu=cortex-a7 -mfloat-abi=softfp -mno-unaligned-access main.cc

FreeBSD clang version 3.7.1 (tags/RELEASE_371/final 255217) 20151225 Target: armv6--freebsd11.0-gnueabi Thread model: posix "/usr/bin/clang++" -cc1 -triple armv7--freebsd11.0-gnueabi -emit-obj -mrelax-all -disable-free -main-file-name main.cc -mrelocation-model static -mthread-model posix -mdisable-fp-elim -masm-verbose -mconstructor-aliases -target-cpu cortex-a7 -target-feature +soft-float-abi -target-abi aapcs-linux -mfloat-abi soft -backend-option -arm-strict-align -v -dwarf-column-info -resource-dir /usr/bin/../lib/clang/3.7.1 -internal-isystem /usr/include/c++/v1 -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /root/c_tests -ferror-limit 19 -fmessage-length 200 -mstackrealign -fno-signed-char -fobjc-runtime=gnustep -fcxx-exceptions -fexceptions -fdiagnostics-show-option -fcolor-diagnostics -o /tmp/main-615940.o -x c++ main.cc clang -cc1 version 3.7.1 based upon LLVM 3.7.1 default target armv6--freebsd11.0-gnueabi

include "..." search starts here:

include <...> search starts here:

/usr/include/c++/v1 /usr/bin/../lib/clang/3.7.1/include /usr/include End of search list. "/usr/bin/ld" --eh-frame-hdr -dynamic-linker /libexec/ld-elf.so.1 --hash-style=both --enable-new-dtags -o a.out /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o -L/usr/lib /tmp/main-615940.o -lc++ -lm -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/crtend.o /usr/lib/crtn.o

clang++ -v -std=c++11 -target armv6--freebsd11.0-gnueabi -mno-unaligned-access main.cc

FreeBSD clang version 3.7.1 (tags/RELEASE_371/final 255217) 20151225 Target: armv6--freebsd11.0-gnueabi Thread model: posix "/usr/bin/clang++" -cc1 -triple armv6k--freebsd11.0-gnueabi -emit-obj -mrelax-all -disable-free -main-file-name main.cc -mrelocation-model static -mthread-model posix -mdisable-fp-elim -masm-verbose -mconstructor-aliases -target-cpu arm1176jzf-s -target-feature +soft-float -target-feature +soft-float-abi -target-feature -neon -target-feature -crypto -target-abi aapcs-linux -msoft-float -mfloat-abi soft -backend-option -arm-strict-align -v -dwarf-column-info -resource-dir /usr/bin/../lib/clang/3.7.1 -internal-isystem /usr/include/c++/v1 -std=c++11 -fdeprecated-macro -fdebug-compilation-dir /root/c_tests -ferror-limit 19 -fmessage-length 200 -mstackrealign -fno-signed-char -fobjc-runtime=gnustep -fcxx-exceptions -fexceptions -fdiagnostics-show-option -fcolor-diagnostics -o /tmp/main-b1e5fb.o -x c++ main.cc clang -cc1 version 3.7.1 based upon LLVM 3.7.1 default target armv6--freebsd11.0-gnueabi

include "..." search starts here:

include <...> search starts here:

/usr/include/c++/v1 /usr/bin/../lib/clang/3.7.1/include /usr/include End of search list. "/usr/bin/ld" --eh-frame-hdr -dynamic-linker /libexec/ld-elf.so.1 --hash-style=both --enable-new-dtags -o a.out /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o -L/usr/lib /tmp/main-b1e5fb.o -lc++ -lm -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/crtend.o /usr/lib/crtn.o

markmi commented 8 years ago

I've gradually removed more and more Bus Error places by adding alignas(alignof(std::max_align_t)) to various class/struct declarations. But now that I'm up to about 76 such additions I think I'm going to give up on having a personal workaround to enable the clang++ compiler to be used on c++ source code with -march=arm7a with SCTLR bit[1]==1 as the context.

Every single example Bus Error so far is a vst1.64 instruction in clang++ getting a Bus Error for an address that is not aligned appropriately for that instruction. In every case so far forcing alignment with alignas in the involved class/struct declarations has allowed the vst1.64 instruction to work. (No vld1.64 failures have happened so far: the places copied from have been aligned sufficiently.)

Here are the 76 or so examples (not showing #include 's):

find -s . -exec grep "alignas.*max_align_t" {} \; | more

class alignas(alignof(std::max_align_t)) StringMapEntry : public StringMapEntryBase { class alignas(alignof(std::max_align_t)) RegionNodeBase { class alignas(alignof(std::max_align_t)) RegionBase : public RegionNodeBase { class alignas(alignof(std::max_align_t)) FunctionType : public Type { class alignas(alignof(std::max_align_t)) AttributeSetNode : public FoldingSetNode { class alignas(alignof(std::max_align_t)) AttributeSetImpl : public FoldingSetNode { class alignas(alignof(std::max_align_t)) MemoryBufferMem : public MemoryBuffer { class alignas(alignof(std::max_align_t)) MemoryBufferMMapFile : public MemoryBuffer { class alignas(alignof(std::max_align_t)) ImportDecl : public Decl { class alignas(alignof(std::max_align_t)) CXXCtorInitializer { class alignas(alignof(std::max_align_t)) FriendDecl : public Decl { class alignas(alignof(std::max_align_t)) ObjCTypeParamList { class alignas(alignof(std::max_align_t)) OMPThreadPrivateDecl : public Decl { class alignas(alignof(std::max_align_t)) TemplateParameterList { class alignas(alignof(std::max_align_t)) DependentFunctionTemplateSpecializationInfo { class alignas(alignof(std::max_align_t)) NonTypeTemplateParmDecl class alignas(alignof(std::max_align_t)) TemplateTemplateParmDecl : public TemplateDecl, class alignas(alignof(std::max_align_t)) DeclRefExpr : public Expr { class alignas(alignof(std::max_align_t)) OffsetOfExpr : public Expr { class alignas(alignof(std::max_align_t)) MemberExpr : public Expr { class alignas(alignof(std::max_align_t)) CastExpr : public Expr { class alignas(alignof(std::max_align_t)) DesignatedInitExpr : public Expr { class alignas(alignof(std::max_align_t)) Designator { class alignas(alignof(std::max_align_t)) PseudoObjectExpr : public Expr { class alignas(alignof(std::max_align_t)) CXXDefaultArgExpr : public Expr { class alignas(alignof(std::max_align_t)) LambdaExpr : public Expr { class alignas(alignof(std::max_align_t)) TypeTraitExpr : public Expr { class alignas(alignof(std::max_align_t)) OverloadExpr : public Expr { class alignas(alignof(std::max_align_t)) DependentScopeDeclRefExpr : public Expr { class alignas(alignof(std::max_align_t)) ExprWithCleanups : public Expr { class alignas(alignof(std::max_align_t)) CXXUnresolvedConstructExpr : public Expr { class alignas(alignof(std::max_align_t)) CXXDependentScopeMemberExpr : public Expr { class alignas(alignof(std::max_align_t)) FunctionParmPackExpr : public Expr { class alignas(alignof(std::max_align_t)) ObjCArrayLiteral : public Expr { class alignas(alignof(std::max_align_t)) ObjCDictionaryLiteral : public Expr { class alignas(alignof(std::max_align_t)) ObjCMessageExpr : public Expr { template class alignas(alignof(std::max_align_t)) OMPVarListClause : public OMPClause { class alignas(alignof(std::max_align_t)) OMPPrivateClause : public OMPVarListClause { class alignas(alignof(std::max_align_t)) OMPFirstprivateClause : public OMPVarListClause { class alignas(alignof(std::max_align_t)) OMPLastprivateClause : public OMPVarListClause { class alignas(alignof(std::max_align_t)) OMPSharedClause : public OMPVarListClause { class alignas(alignof(std::max_align_t)) OMPReductionClause : public OMPVarListClause { class alignas(alignof(std::max_align_t)) OMPLinearClause : public OMPVarListClause { class alignas(alignof(std::max_align_t)) OMPAlignedClause : public OMPVarListClause { class alignas(alignof(std::max_align_t)) OMPCopyinClause : public OMPVarListClause { class alignas(alignof(std::max_align_t)) OMPCopyprivateClause : public OMPVarListClause { class alignas(alignof(std::max_align_t)) OMPFlushClause : public OMPVarListClause { class alignas(alignof(std::max_align_t)) OMPDependClause : public OMPVarListClause { class alignas(alignof(std::max_align_t)) AttributedStmt : public Stmt { class alignas(alignof(std::max_align_t)) CapturedStmt : public Stmt { class alignas(alignof(std::max_align_t)) CXXTryStmt : public Stmt { class alignas(alignof(std::max_align_t)) ObjCAtTryStmt : public Stmt { class alignas(alignof(std::max_align_t)) OMPExecutableDirective : public Stmt { class alignas(alignof(std::max_align_t)) OMPLoopDirective : public OMPExecutableDirective { class alignas(alignof(std::max_align_t)) TemplateArgument { struct alignas(alignof(std::max_align_t)) TemplateArgumentLocInfo { class alignas(alignof(std::max_align_t)) TemplateArgumentLoc { struct alignas(alignof(std::max_align_t)) ASTTemplateArgumentListInfo { class alignas(alignof(std::max_align_t)) UncommonTemplateNameStorage { class alignas(alignof(std::max_align_t)) OverloadedTemplateStorage : public UncommonTemplateNameStorage { class alignas(alignof(std::max_align_t)) FunctionProtoType : public FunctionType, public llvm::FoldingSetNode { class alignas(alignof(std::max_align_t)) TemplateSpecializationType class alignas(alignof(std::max_align_t)) DependentTemplateSpecializationType : class alignas(alignof(std::max_align_t)) ObjCObjectType : public Type { class alignas(alignof(std::max_align_t)) CGFunctionInfo : public llvm::FoldingSetNode { class alignas(alignof(std::max_align_t)) ModuleMacro : public llvm::FoldingSetNode { class alignas(alignof(std::max_align_t)) AttributeList { // TODO: This should really be called ParsedAttribute class alignas(alignof(std::max_align_t)) CodeCompletionString { class alignas(alignof(std::max_align_t)) ImplicitConversionSequence { struct alignas(alignof(std::max_align_t)) TemplateIdAnnotation { class alignas(alignof(std::max_align_t)) MultiKeywordSelector class alignas(alignof(std::max_align_t)) EHCatchScope : public EHScope { class alignas(alignof(std::max_align_t)) EHCleanupScope : public EHScope { class alignas(alignof(std::max_align_t)) EHFilterScope : public EHScope { class alignas(alignof(std::max_align_t)) CallDeleteDuringNew : public EHScopeStack::Cleanup { class alignas(alignof(std::max_align_t)) CallDeleteDuringConditionalNew : public EHScopeStack::Cleanup {

A bunch of these deal with aligning this+1 that is then reinterpret_cast. (So "this" itself ends up being aligned too but the size may have bene adjusted so that the +1 result is aligned too.)

A few are tied to aligning array entries for when there might be multiple entries (given that the above sort of thing got the start of the array aligned):

find . -exec grep "new[ \t]([^)][" {} \;

    new (&C.Conversions[i]) ImplicitConversionSequence();
new (&ArgsArray[I]) TemplateArgumentLoc(TArgs[I]);
new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]);
new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);

Without such alignas usage [0] would work from the this+1 handling but [1] would fail. (When I found an example for one type I tended to find similar code structure for other types and adjust them at the same time.)

Other examples that I've not gotten around to adjusting may have the array activity inside a method that is called with the index to use, for example the TL.setArgLocInfo below Bus Errors (but was inlined):

TypeSourceInfo * ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, SourceLocation NameLoc, const TemplateArgumentListInfo &Args, QualType Underlying) const { assert(!Name.getAsDependentTemplateName() && "No dependent template names here!"); QualType TST = getTemplateSpecializationType(Name, Args, Underlying);

TypeSourceInfo *DI = CreateTypeSourceInfo(TST); TemplateSpecializationTypeLoc TL = DI->getTypeLoc().castAs(); TL.setTemplateKeywordLoc(SourceLocation()); TL.setTemplateNameLoc(NameLoc); TL.setLAngleLoc(Args.getLAngleLoc()); TL.setRAngleLoc(Args.getRAngleLoc()); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) TL.setArgLocInfo(i, Args[i].getLocInfo()); return DI; }

It appears that much of the reinterpret_cast use in clang++ (and llvm more generally?) for copying to a new place is suspect and should be validated relative to alignment requirements, such as for when SCTLR bit[1]==1 for armv7a contexts.

markmi commented 8 years ago

The following change eliminates the specific Bus Error in clang and allows the 11 line program to compile on an rpi2 --but causes include/clang/AST/Type.h to pollute a namespace via use:

svnlite diff /usr/src/contrib/llvm/

Index: /usr/src/contrib/llvm/tools/clang/include/clang/AST/Type.h

--- /usr/src/contrib/llvm/tools/clang/include/clang/AST/Type.h (revision 292858) +++ /usr/src/contrib/llvm/tools/clang/include/clang/AST/Type.h (working copy) @@ -14,6 +14,8 @@

ifndef LLVM_CLANG_AST_TYPE_H

define LLVM_CLANG_AST_TYPE_H

+#include // for std::max_align_t +

include "clang/AST/NestedNameSpecifier.h"

include "clang/AST/TemplateName.h"

include "clang/Basic/AddressSpaces.h"

@@ -4336,7 +4338,7 @@ /// DependentTemplateSpecializationType - Represents a template /// specialization type whose template cannot be resolved, e.g. /// A::template B -class DependentTemplateSpecializationType : +class alignas(alignof(std::max_align_t)) DependentTemplateSpecializationType : public TypeWithKeyword, public llvm::FoldingSetNode {

/// \brief The nested name specifier containing the qualifier.

alignof(TemplateArgument) is not used because Types.h is used in contexts where TemplateArgument is an incomplete type and the notation would be rejected.

The command that built a Type.o that worked was (from the script log of the build):

--- Type.o --- /usr/bin/clang++ -target armv6--freebsd11.0-gnueabi -march=armv7a -mno-unaligned-access -target armv6-gnueabi-freebsd11.0 --sysroot=/usr/obj/clang/arm.armv6/usr/src/tmp -B/usr/local/arm-gnueabi-freebs d/bin/ --sysroot=/usr/obj/clang/arm.armv6/usr/src/tmp -B/usr/local/arm-gnueabi-freebsd/bin/ -O -pipe -mfloat-abi=softfp -I/usr/src/lib/clang/libclangast/../../../contrib/llvm/include -I/usr/src/lib/c lang/libclangast/../../../contrib/llvm/tools/clang/include -I/usr/src/lib/clang/libclangast/../../../contrib/llvm/tools/clang/lib/AST -I. -I/usr/src/lib/clang/libclangast/../../../contrib/llvm/../../l ib/clang/include -DLLVM_ON_UNIX -DLLVM_ON_FREEBSD -DSTDC_LIMIT_MACROS -DSTDC_CONSTANT_MACROS -DCLANG_ENABLE_ARCMT -DCLANG_ENABLE_STATIC_ANALYZER -fno-strict-aliasing -DLLVM_DEFAULT_TARGET_TRIPLE=\ "armv6-gnueabi-freebsd11.0\" -DLLVM_HOST_TRIPLE=\"armv6-unknown-freebsd11.0\" -DDEFAULT_SYSROOT=\"\" -MD -MP -MF.depend.Type.o -MTType.o -Qunused-arguments -std=c++11 -fno-exceptions -fno-rtti -stdli b=libc++ -Wno-c++11-extensions -c /usr/src/lib/clang/libclangast/../../../contrib/llvm/tools/clang/lib/AST/Type.cpp -o Type.o

So it used (in order):

-target armv6--freebsd11.0-gnueabi -march=armv7a -mno-unaligned-access -target armv6-gnueabi-freebsd11.0

(The first -target is what I supplied, the 2nd is from the FreeBSD build environment.)

STILL FAILS OVERALL HOWEVER. . .

Unfortunately clang++ on the rpi2 with SCTLR bit[1]==1 dies for other c++ syntax when trying to build part of llvm (early in FreeBSD's buildworld):

Program terminated with signal 10, Bus error.

​0 0x00c43d28 in clang::ASTTemplateArgumentListInfo::initializeFrom ()

[New Thread 22a18000 (LWP 100079/)] (gdb) bt

​0 0x00c43d28 in clang::ASTTemplateArgumentListInfo::initializeFrom ()

​1 0x00c43f10 in clang::ASTTemplateKWAndArgsInfo::initializeFrom ()

​2 0x00cdc788 in clang::CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr ()

​3 0x00cdc99c in clang::CXXDependentScopeMemberExpr::Create ()

​4 0x00685384 in clang::Sema::ActOnDependentMemberExpr ()

​5 0x0068abec in clang::Sema::ActOnMemberAccessExpr ()

​6 0x0044a938 in clang::Parser::ParsePostfixExpressionSuffix ()

​7 0x00000000 in ?? ()

(gdb) x/i 0x00c43d28 0xc43d28 <_ZN5clang27ASTTemplateArgumentListInfo14initializeFromERKNS_24TemplateArgumentListInfoERbS4S4+396>: vst1.64 {d16-d17}, [r0]! (gdb) info all-regsisters Undefined info command: "all-regsisters". Try "help info". (gdb) info all-registers r0 0x234b96dc 592156380 . . .

There are lots of places using "this + 1" and reinterpret_cast that therefore have the potential for a mis-matched alignment between the two types involved, just like the one I initially reported (some of the below might not be at risk, I've not inspected all the details of each):

grep "reinterpret_cast.this" lib//*

lib/AST/Decl.cpp: SourceLocation StoredLocs = reinterpret_cast<SourceLocation >(this + 1); lib/AST/Decl.cpp: reinterpret_cast<SourceLocation >(this + 1) = EndLoc; lib/AST/Decl.cpp: = reinterpret_cast<const SourceLocation >(this + 1); lib/AST/Decl.cpp: reinterpret_cast<const SourceLocation >(this + 1)); lib/AST/DeclCXX.cpp: VarDecl MyIndices = reinterpret_cast<VarDecl > (this + 1); lib/AST/DeclOpenMP.cpp: Expr Vars = reinterpret_cast<Expr >(this + 1); lib/AST/DeclTemplate.cpp: void TypesAndInfos = reinterpret_cast<void >(this + 1); lib/AST/DeclTemplate.cpp: std::memcpy(reinterpret_cast<void>(this + 1), Expansions, lib/AST/Expr.cpp: return reinterpret_cast<CXXBaseSpecifier>(static_cast<Type>(this)+1); lib/AST/Expr.cpp: Stmt const SubExprs = reinterpret_cast<Stmt const >(this + 1); lib/AST/Expr.cpp: Stmt const SubExprs = reinterpret_cast<Stmt const >(this + 1); lib/AST/Expr.cpp: Stmt const SubExprs = reinterpret_cast<Stmt const >(this + 1); lib/AST/Expr.cpp: begin = reinterpret_cast<Stmt >(this + 1); lib/AST/ExprCXX.cpp: Stmt StoredArgs = reinterpret_cast<Stmt >(this + 1); lib/AST/ExprCXX.cpp: reinterpret_cast<Decl>(this+1)); lib/AST/Stmt.cpp: Stmt Stmts = reinterpret_cast<Stmt >(this + 1); lib/AST/Stmt.cpp: reinterpret_cast<char >(const_cast<CapturedStmt >(this)) lib/AST/Type.cpp: QualType argSlot = reinterpret_cast<QualType>(this+1); lib/AST/Type.cpp: = reinterpret_cast<TemplateArgument >(this + 1); lib/AST/Type.cpp: TemplateArgument Begin = reinterpret_cast<TemplateArgument >(this + 1); lib/Basic/IdentifierTable.cpp: IdentifierInfo KeyInfo = reinterpret_cast<IdentifierInfo >(this+1); lib/Basic/IdentifierTable.cpp: return reinterpret_cast(this+1); lib/CodeGen/CGCleanup.h: return reinterpret_cast<Handler>(this+1); lib/CodeGen/CGCleanup.h: return reinterpret_cast<const Handler>(this+1); lib/CodeGen/CGCleanup.h: return reinterpret_cast<llvm::Value>(this+1); lib/CodeGen/CGCleanup.h: return reinterpret_cast<llvm::Value const >(this+1); lib/CodeGen/CGExprCXX.cpp: RValue getPlacementArgs() { return reinterpret_cast<RValue>(this+1); } lib/CodeGen/CGExprCXX.cpp: return reinterpret_cast<DominatingValue::saved_type>(this+1); lib/Sema/CodeCompleteConsumer.cpp: Chunk StoredChunks = reinterpret_cast<Chunk *>(this + 1);

But there is lots more use of reinterpret_cast where "this" is not involved that might also have problems. Compare:

grep -l "reinterpret_cast.this" lib//*

lib/AST/Decl.cpp lib/AST/DeclCXX.cpp lib/AST/DeclOpenMP.cpp lib/AST/DeclTemplate.cpp lib/AST/Expr.cpp lib/AST/ExprCXX.cpp lib/AST/Stmt.cpp lib/AST/Type.cpp lib/Basic/IdentifierTable.cpp lib/CodeGen/CGCleanup.h lib/CodeGen/CGExprCXX.cpp lib/Sema/CodeCompleteConsumer.cpp

vs.

grep -l "reinterpret_cast" lib//

lib/AST/APValue.cpp lib/AST/ASTDiagnostic.cpp lib/AST/Decl.cpp lib/AST/DeclCXX.cpp lib/AST/DeclOpenMP.cpp lib/AST/DeclTemplate.cpp lib/AST/DeclarationName.cpp lib/AST/Expr.cpp lib/AST/ExprCXX.cpp lib/AST/ExprConstant.cpp lib/AST/ItaniumMangle.cpp lib/AST/NestedNameSpecifier.cpp lib/AST/ParentMap.cpp lib/AST/Stmt.cpp lib/AST/StmtIterator.cpp lib/AST/Type.cpp lib/AST/TypeLoc.cpp lib/Analysis/CFG.cpp lib/Basic/Diagnostic.cpp lib/Basic/FileManager.cpp lib/Basic/IdentifierTable.cpp lib/CodeGen/CGBlocks.h lib/CodeGen/CGCleanup.cpp lib/CodeGen/CGCleanup.h lib/CodeGen/CGExpr.cpp lib/CodeGen/CGExprCXX.cpp lib/CodeGen/CodeGenModule.cpp lib/CodeGen/MicrosoftCXXABI.cpp lib/Driver/MSVCToolChain.cpp lib/Driver/Tools.h lib/Format/Encoding.h lib/Frontend/CacheTokens.cpp lib/Frontend/DependencyFile.cpp lib/Frontend/TextDiagnostic.cpp lib/Lex/HeaderMap.cpp lib/Lex/LiteralSupport.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseObjc.cpp lib/Parse/ParsePragma.cpp lib/Parse/ParseTentative.cpp lib/Parse/Parser.cpp lib/Rewrite/RewriteRope.cpp lib/Sema/CodeCompleteConsumer.cpp lib/Sema/IdentifierResolver.cpp lib/Sema/SemaCast.cpp lib/Sema/SemaCodeComplete.cpp lib/Sema/SemaDecl.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaDeclObjC.cpp lib/Sema/SemaExprMember.cpp lib/Sema/SemaExprObjC.cpp lib/Sema/SemaInit.cpp lib/Sema/SemaLookup.cpp lib/Sema/SemaStmt.cpp lib/Sema/SemaStmtAsm.cpp lib/Sema/TreeTransform.h lib/Serialization/ASTReader.cpp lib/Serialization/ASTReaderDecl.cpp lib/Serialization/ASTReaderStmt.cpp lib/Serialization/ASTWriter.cpp

markmi commented 8 years ago

I've built clang++ for an rpi2 many ways. All crash in the SCTLR bit[1]==1 context on arm. FreeBSD 11.0-CURRENT (including clang) at was in sue for the report was cross built from amd64 FreeBSD with:

-target armv6--freebsd11.0-gnueabi -march=armv7a -fmax-type-align=4 -mno-unaligned-access -target armv6-gnueabi-freebsd11.0

(Yea, two "-targets" ended up being involved in that order --via the build system adding one to mine.)

That is per the below extraction from the script log of the build showing the specific clang++ source code file that has the source code that I reported:

--- Type.o --- /usr/bin/clang++ -target armv6--freebsd11.0-gnueabi -march=armv7a -fmax-type-align=4 -mno-unaligned-access -target armv6-gnueabi-freebsd11.0 --sysroot=/usr/obj/clang/arm.armv6/usr/src/tmp -B/usr/local /arm-gnueabi-freebsd/bin/ --sysroot=/usr/obj/clang/arm.armv6/usr/src/tmp -B/usr/local/arm-gnueabi-freebsd/bin/ -O -pipe -mfloat-abi=softfp -I/usr/src/lib/clang/libclangast/../../../contrib/llvm/inclu de -I/usr/src/lib/clang/libclangast/../../../contrib/llvm/tools/clang/include -I/usr/src/lib/clang/libclangast/../../../contrib/llvm/tools/clang/lib/AST -I. -I/usr/src/lib/clang/libclangast/../../../c ontrib/llvm/../../lib/clang/include -DLLVM_ON_UNIX -DLLVM_ON_FREEBSD -DSTDC_LIMIT_MACROS -DSTDC_CONSTANT_MACROS -DCLANG_ENABLE_ARCMT -DCLANG_ENABLE_STATIC_ANALYZER -fno-strict-aliasing -DLLVM_DEFA ULT_TARGET_TRIPLE=\"armv6-gnueabi-freebsd11.0\" -DLLVM_HOST_TRIPLE=\"armv6-unknown-freebsd11.0\" -DDEFAULT_SYSROOT=\"\" -MD -MP -MF.depend.Type.o -MTType.o -Qunused-arguments -std=c++11 -fno-exceptio ns -fno-rtti -stdlib=libc++ -Wno-c++11-extensions -c /usr/src/lib/clang/libclangast/../../../contrib/llvm/tools/clang/lib/AST/Type.cpp -o Type.o

Given that clang++ build installed on an rpi2, here is an example using it on the 11 line example source:

/usr/bin/clang++ -target armv6--freebsd11.0-gnueabi -march=armv7a -fmax-type-align=4 -mno-unaligned-access main.cc

clang++: error: unable to execute command: Bus error (core dumped) clang++: error: clang frontend command failed due to signal (use -v to see invocation) FreeBSD clang version 3.7.1 (tags/RELEASE_371/final 255217) 20151225 Target: armv6--freebsd11.0-gnueabi Thread model: posix clang++: note: diagnostic msg: PLEASE submit a bug report to https://bugs.freebsd.org/submit/ and include the crash backtrace, preprocessed source, and associated run script. clang++: note: diagnostic msg:


PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT: Preprocessed source(s) and associated run script(s) are located at: clang++: note: diagnostic msg: /tmp/main-29523a.cpp clang++: note: diagnostic msg: /tmp/main-29523a.sh clang++: note: diagnostic msg:


more /tmp/main-29523a.sh

Crash reproducer for FreeBSD clang version 3.7.1 (tags/RELEASE_371/final 255217) 20151225

Driver args: "--driver-mode=g++" "--target=armv6--freebsd11.0-gnueabi" "-march=armv7a" "-fmax-type-align=4" "-mno-unaligned-access" "main.cc"

Original command: "/usr/bin/clang++" "-cc1" "-triple" "armv7--freebsd11.0-gnueabi" "-emit-obj" "-mrelax-all" "-disable-free" "-main-file-name" "main.cc" "-mrelocation-model" "static" "-mthread-model" "posix" "-mdisable-fp-elim" "-masm-verbose" "-mconstructor-aliases" "-target-cpu" "cortex-a8" "-target-feature" "+soft-float" "-target-feature" "+soft-float-abi" "-target-feature" "-neon" "-target-feature" "-crypto" "-target-abi" "aapcs-linux" "-msoft-float" "-mfloat-abi" "soft" "-backend-option" "-arm-strict-align" "-dwarf-column-info" "-resource-dir" "/usr/bin/../lib/clang/3.7.1" "-internal-isystem" "/usr/include/c++/v1" "-fdeprecated-macro" "-fdebug-compilation-dir" "/root/c_tests" "-ferror-limit" "19" "-fmessage-length" "338" "-mstackrealign" "-fno-signed-char" "-fobjc-runtime=gnustep" "-fcxx-exceptions" "-fexceptions" "-fmax-type-align=4" "-fdiagnostics-show-option" "-fcolor-diagnostics" "-o" "/tmp/main-147b93.o" "-x" "c++" "main.cc"

"/usr/bin/clang++" "-cc1" "-triple" "armv7--freebsd11.0-gnueabi" "-emit-obj" "-mrelax-all" "-disable-free" "-main-file-name" "main.cc" "-mrelocation-model" "static" "-mthread-model" "posix" "-mdisable-fp-elim" "-masm-verbose" "-mconstructor-aliases" "-target-cpu" "cortex-a8" "-target-feature" "+soft-float" "-target-feature" "+soft-float-abi" "-target-feature" "-neon" "-target-feature" "-crypto" "-target-abi" "aapcs-linux" "-msoft-float" "-mfloat-abi" "soft" "-backend-option" "-arm-strict-align" "-dwarf-column-info" "-fdeprecated-macro" "-ferror-limit" "19" "-fmessage-length" "338" "-mstackrealign" "-fno-signed-char" "-fobjc-runtime=gnustep" "-fcxx-exceptions" "-fexceptions" "-fmax-type-align=4" "-fdiagnostics-show-option" "-fcolor-diagnostics" "-x" "c++" "main-29523a.cpp"

more /tmp/main-29523a.cpp

1 ""

1 "main.cc"

template <class _Tp, class _Up> struct has_rebind { template static char test(typename _Xp::template rebind<_Up>* = 0); };

int main () { return 0; }

Anything including from libc++ hits the problem via such a template usage.

I'll note that for gcc "-mno-unaligned-access" is described in a way that packed data structures are mentioned as involved but no data structure is explicitly marked as packed for the code in question in the clang++ source code I talked about:

-munaligned-access -mno-unaligned-access Enables (or disables) reading and writing of 16- and 32- bit values from addresses that are not 16- or 32- bit aligned. By default unaligned access is disabled for all pre-ARMv6 and all ARMv6-M architectures, and enabled for all other architectures. If unaligned access is not enabled then words in packed data structures are accessed a byte at a time.

Of course when the code generator is using vst1.64's there can also be 64-bit (8-Byte) alignment requirements, as it happening in clang++'s internal code for how it was compiled (see above and the original submittal).

jmolloy commented 8 years ago

Hi Mark,

Thanks for raising this. Before checking the specifics of what you found - did you compile Clang with -mno-unaligned-access? We will by default compile assuming SCTLR.A is 0. -mno-unaligned-access switches this assumption off and enables strict alignment mode.

Cheers,

James

markmi commented 8 years ago

This llvm.org submittal is basically a duplicate of what I submitted to FreeBSD's bugzilla:

https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=205663