6215 – LLVM-compiled DMD segfaults due to mem.c alignment issues

D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 6215 - LLVM-compiled DMD segfaults due to mem.c alignment issues
Summary: LLVM-compiled DMD segfaults due to mem.c alignment issues
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: Other Mac OS X
: P2 blocker
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
Reported: 2011年06月26日 06:28 UTC by Robert Clipsham
Modified: 2017年08月07日 16:12 UTC (History)
5 users (show)

See Also:


Attachments
Add an attachment (proposed patch, testcase, etc.)

Note You need to log in before you can comment on or make changes to this issue.
Description Robert Clipsham 2011年06月26日 06:28:18 UTC
As of XCode 4.2 (maybe 4.1, I skipped it), Apple has made gcc a symlink for llvm-gcc. When built using llvm-gcc, dmd sefaults in el.c:211:
void test(){}
void main(){}
$ dmd test.d
Segmentation fault
It fails in el.c:211.
Comment 1 Jacob Carlborg 2011年06月26日 08:34:11 UTC
GCC is a symlink for LLVM-GCC with XCode 4.1 as well.
Comment 2 Robert Clipsham 2011年06月26日 11:33:46 UTC
The following patch is a workaround, it seems something's going wrong with the elem recycling system:
----
diff --git a/src/backend/el.c b/src/backend/el.c
index f5fa66d..9cc34fc 100644
--- a/src/backend/el.c
+++ b/src/backend/el.c
@@ -195,6 +195,7 @@ elem *el_calloc()
 static elem ezero;
 
 elcount++;
+#if 0
 if (nextfree)
 { e = nextfree;
 nextfree = e->E1;
@@ -209,6 +210,9 @@ elem *el_calloc()
 eprm_cnt++;
 #endif
 *e = ezero; /* clear it */
+#else
+ e = (elem *)mem_fmalloc(sizeof(elem));
+#endif
 
 #ifdef DEBUG
 e->id = IDelem;
----
If you print e and *e, *e is NULL, hence the segfault when assigned to.
Comment 3 Sean Kelly 2011年08月11日 16:16:23 UTC
The first problem is in el_calloc():
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: 13 at address: 0x00000000
0x0009fc2f in el_calloc () at el.c:189
189	 *e = ezero; /* clear it */
(gdb) p e
1ドル = (elem *) 0xa4e7bc
Current language: auto; currently c++
(gdb) 
I can't explain why this isn't working, but it's easily fixed by replacing the assignment with:
memset(e, 0, sizeof(elem));
That gets us to the next error:
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: 13 at address: 0x00000000
0x000aa08d in evalu8 (e=0xa50988) at evalu8.c:625
625	 esave = *e;
(gdb) p e
1ドル = (elem *) 0xa50988
Current language: auto; currently c++
(gdb) 
Which is similarly fixed by replacing the assignment with:
memcpy(&esave, e, sizeof(elem));
These two changes are enough for LLVM-DMD to build druntime.
Given the two errors above, the problem seems to be with the default assignment operator LLVM generates for the elem struct. It's a very weird problem though.
Comment 4 Brad Roberts 2011年08月11日 16:41:20 UTC
Would you take that info and try the same sort of code in a standalone test case? If struct assignment is indeed the problem, that's a pretty embarrassing llvm bug, imho, and clearly should be reported to either llvm directly or apple as the provider of that version of the compiler.
Comment 5 David Nadlinger 2011年08月12日 02:25:33 UTC
(In reply to comment #3)
> Given the two errors above, the problem seems to be with the default assignment
> operator LLVM generates for the elem struct. It's a very weird problem though.
Note that at least the first error happens with both LLVM-GCC, which uses the GCC frontend, and Clang.
Comment 6 David Nadlinger 2011年08月12日 04:24:54 UTC
The difference in the LLVM IR generated by Clang for the ezero change is only:
- call void @llvm.memcpy.p0i8.p0i8.i32(i8* %17, i8* getelementptr inbounds (%struct.elem* @_ZZ9el_callocvE5ezero, i32 0, i32 0), i32 80, i32 16, i1 false)
+ call void @llvm.memset.p0i8.i32(i8* %17, i8 0, i32 80, i32 1, i1 false)
Note that the second last parameter to memcpy is the alignment (16 bit), but GDB says that »(int)e % 16« is 8.
Comment 7 David Nadlinger 2011年08月12日 05:06:27 UTC
And indeed, __alignof__(*e) gives 16, patching the allocator to 16-byte align everything is easy:
--- a/src/tk/mem.c
+++ b/src/tk/mem.c
@@ -758,7 +758,7 @@ void *mem_fmalloc(unsigned numbytes)
 if (sizeof(size_t) == 2)
 numbytes = (numbytes + 1) & ~1; /* word align */
 else
- numbytes = (numbytes + 3) & ~3; /* dword align */
+ numbytes = (numbytes + 15) & ~15;
 
 /* This ugly flow-of-control is so that the most common case
 drops straight through.
Comment 8 David Nadlinger 2011年08月12日 06:17:46 UTC
A preliminary patch which only 16 byte aligns allocations when building with a LLVM backend is at: https://github.com/D-Programming-Language/dmd/pull/301.
Comment 9 Jacob Carlborg 2011年08月12日 06:24:59 UTC
Is this specific to Mac OS X or is it like this with LLVM in general?
Comment 10 David Nadlinger 2011年08月12日 06:53:35 UTC
(In reply to comment #9)
> Is this specific to Mac OS X or is it like this with LLVM in general?
Happens on my Linux x86_64 box too.
Comment 11 Sean Kelly 2011年08月12日 09:08:45 UTC
Awesome. I figured it was an alignment mistake for the copy, but ran out of time to investigate. What an embarrassing bug for LLVM.
Comment 12 David Nadlinger 2011年08月12日 13:50:59 UTC
(In reply to comment #11)
> Awesome. I figured it was an alignment mistake for the copy, but ran out of
> time to investigate. What an embarrassing bug for LLVM.
Just for clarity, let me note that this is definitely _not_ a bug in LLVM, it just happens with two compilers using LLVM as their backend.


AltStyle によって変換されたページ (->オリジナル) /