Jump to page: 1 2 3
Thread overview
[Issue 16856] D does not work on FreeBSD current (what will eventually be 12) due to libunwind
Dec 04, 2016
Jonathan M Davis
Dec 05, 2016
Jonathan M Davis
Dec 05, 2016
Jacob Carlborg
May 07, 2017
Nemanja Boric
May 14, 2017
Jonathan M Davis
May 21, 2017
Nemanja Boric
Jun 17, 2017
Jonathan M Davis
Jun 18, 2017
Nemanja Boric
Jun 18, 2017
Nemanja Boric
Jul 08, 2017
Nemanja Boric
Jul 08, 2017
Nemanja Boric
Jul 14, 2017
Jonathan M Davis
Jul 14, 2017
Nemanja Boric
Jul 15, 2017
Vladimir Panteleev
Jul 15, 2017
Jonathan M Davis
Jul 17, 2017
anonymous4
December 04, 2016
https://issues.dlang.org/show_bug.cgi?id=16856

Jonathan M Davis <issues.dlang@jmdavisProg.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
            Summary|D is borked on FreeBSD      |D does not work on FreeBSD
                   |current (what will          |current (what will
                   |eventually be 12)           |eventually be 12) due to
                   |                            |libunwind

--- Comment #1 from Jonathan M Davis <issues.dlang@jmdavisProg.com> ---
Okay. I've confirmed that this is a problem with FreeBSD current in general and not just TrueOS, and I've narrowed down commit in the FreeBSD source tree which broke us. Specifically, it's this one


commit d20793840b5b74acebe80ec710522f7386b452cf
Author: emaste <emaste@FreeBSD.org>
Date:   Wed Jul 27 16:01:44 2016 +0000

    Enable LLVM libunwind by default on amd64 and i386

    It is a maintained and updated runtime exception stack unwinder that
    should be a drop-in replacement.

    It can be disabled by setting WITHOUT_LLVM_LIBUNWIND in src.conf.

    PR:             206039 [exp-run]
    Sponsored by:   The FreeBSD Foundation

and if I rebuild the OS with WITHOUT_LLVM_LIBUNWIND=1, then everything works again. So, clearly, the problem is that FreeBSD changed to using libunwind from whatever they were using before, and whatever we do with dmd and druntime is not compatible with that. The commit message implies that libunwind _should_ be compatible with what was there before, but in our case, it clearly isn't. I don't know if that's a problem with FreeBSD and it truly not being a drop-in replacement, or if we're doing something wrong that happened to work before but doesn't with libunwind, or what. Unfortunately, I know almost nothing about libunwind - just that it has to do with dealing with throwing exceptions, so I really have no idea what the problem could be or what the correct solution is (I don't even know if this involves dmd or just druntime). I'd guess though that we need to do something to become compatible with libunwind.

Since libunwind is not specifically a FreeBSD thing, this may affect something in Linux land. I don't know. But we clearly don't work with FreeBSD 12-to-be right now because of this.

--
December 05, 2016
https://issues.dlang.org/show_bug.cgi?id=16856

--- Comment #2 from Jonathan M Davis <issues.dlang@jmdavisProg.com> ---
If I compile and run this program

void main()
{
    throw new Exception("blah");
}

I get a bus error, and if I run it in gdb, I get this stacktrace:

#0  0x0000000800cd91bf in _Unwind_RaiseException () from /lib/libgcc_s.so.1
#1  0x000000000042a994 in _d_throwdwarf ()
#2  0x000000000042a216 in _Dmain ()
#3  0x000000000042a827 in
_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZ9__lambda1MFZv ()
#4  0x000000000042a76d in
_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ7tryExecMFMDFZvZv ()
#5  0x000000000042a7e3 in _D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ6runAllMFZv ()
#6  0x000000000042a76d in
_D2rt6dmain211_d_run_mainUiPPaPUAAaZiZ7tryExecMFMDFZvZv ()
#7  0x000000000042a6e7 in _d_run_main ()
#8  0x000000000042a2aa in main ()

So, I guess that whatever is going wrong relates to _Unwind_RaisException, which I suppose makes sense, since that would appear to relate to libunwind.

--
December 05, 2016
https://issues.dlang.org/show_bug.cgi?id=16856

Jacob Carlborg <doob@me.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |doob@me.com

--- Comment #3 from Jacob Carlborg <doob@me.com> ---
I would expect libunwind to be used on macOS, where exceptions work fine. But I'm not sure if that's the case.

--
May 07, 2017
https://issues.dlang.org/show_bug.cgi?id=16856

Nemanja Boric <4burgos@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |4burgos@gmail.com

--- Comment #4 from Nemanja Boric <4burgos@gmail.com> ---
I've looked into this, and this is the alignment issue.

The faulty instruction happens here:

https://github.com/llvm-mirror/libunwind/blob/master/src/UnwindLevel1.c#L351

```
  exception_object->private_1 = 0;
```

On FreeBSD-Current, this is executed as:

```
  xorps xmm0, xmm0
  movaps XMMWORD PTR [r14+0x10], xmm0
```

where r14 is the pointer to the Unwind_Exception (https://github.com/llvm-mirror/libunwind/blob/master/include/unwind.h#L119-L124) or D runtime part: (https://github.com/dlang/druntime/blob/master/src/rt/unwind.d#L51-L57)

```
struct _Unwind_Exception
{
    align(8) _Unwind_Exception_Class exception_class;
    _Unwind_Exception_Cleanup_Fn exception_cleanup;
    _Unwind_Word private_1;
    _Unwind_Word private_2;
}
```

or

```
struct _Unwind_Exception {
  uint64_t exception_class;
  void (*exception_cleanup)(_Unwind_Reason_Code reason,
                            _Unwind_Exception *exc);
  uintptr_t private_1; // non-zero means forced unwind
  uintptr_t private_2; // holds sp that phase1 found for phase2 to use
#ifndef __LP64__
  // The implementation of _Unwind_Exception uses an attribute mode on the
  // above fields which has the side effect of causing this whole struct to
  // round up to 32 bytes in size. To be more explicit, we add pad fields
  // added for binary compatibility.
  uint32_t reserved[3];
#endif
  // The Itanium ABI requires that _Unwind_Exception objects are "double-word
  // aligned".  GCC has interpreted this to mean "use the maximum useful
  // alignment for the target"; so do we.
} __attribute__((__aligned__));
```

Now, this happens because `movaps` instruction requires 16-bit aligned memory, which is not the case for _Unwind_Exceptin.private_1 - where it is aligned to 8 bits.

Making D definition to align this instance (at least D-allocated) to 16 bits fixes the entire problem - exception handling works:

```
align(16)
struct _Unwind_Exception
{
    _Unwind_Exception_Class exception_class;
    _Unwind_Exception_Cleanup_Fn exception_cleanup;
    _Unwind_Word private_1;
    _Unwind_Word private_2;
}
```


Now, the problem is that I don't know how to effectively calculate the alignment and do whatever the C++ compiler would do. I guess this is necessity, because we want C++ exceptions (generated by the C++ compiler) to work.

GCC documentation is stating: https://gcc.gnu.org/onlinedocs/gcc-4.7.0/gcc/Type-Attributes.html

```
As in the preceding example, you can explicitly specify the alignment (in
bytes) that you wish the compiler to use for a given struct or union type.
Alternatively, you can leave out the alignment factor and just ask the compiler
to align a type to the maximum useful alignment for the target machine you are
compiling for. For example, you could write:

          struct S { short f[3]; } __attribute__ ((aligned));

Whenever you leave out the alignment factor in an aligned attribute specification, the compiler automatically sets the alignment for the type to the largest alignment which is ever used for any data type on the target machine you are compiling for. Doing this can often make copy operations more efficient, because the compiler can use whatever instructions copy the biggest chunks of memory when performing copies to or from the variables which have types that you have aligned this way.

In the example above, if the size of each short is 2 bytes, then the size of the entire struct S type is 6 bytes. The smallest power of two which is greater than or equal to that is 8, so the compiler sets the alignment for the entire struct S type to 8 bytes.

```

Any ideas?

--
May 07, 2017
https://issues.dlang.org/show_bug.cgi?id=16856

--- Comment #5 from github-bugzilla@puremagic.com ---
Commits pushed to master at https://github.com/dlang/druntime

https://github.com/dlang/druntime/commit/c56e8e0d8d599b1742fe85210f07adacf07e5e2a Fix issue 16856: Apply correct alignment on the Unwind_Exception structure

In libundwind, _Unwind_Exception structure is defined as follows:

```
struct _Unwind_Exception
  {
    uint64_t exception_class;
    _Unwind_Exception_Cleanup_Fn exception_cleanup;
    unsigned long private_1;
    unsigned long private_2;
  } __attribute__((__aligned__));
```

so the alignment is done on the entire structure, and it
depends on the architecture. This sets the structure
to be 16bit aligned on the X86_64, so the binary layout
matches and that the C++ compiler's optimizations are still
valid (for example, on FreeBSD-12, exception handling was broken
because libunwind assumes correct alignment, so the fast but fragile
instructions were used.

https://github.com/dlang/druntime/commit/c7182eb2ef3d6cc57c3e3366028753306b4dceb7 Merge pull request #1823 from Burgos/exception_alignment

Fix issue 16856: Apply correct alignment on the Unwind_Exception stru… merged-on-behalf-of: Jonathan M Davis <jmdavis@users.noreply.github.com>

--
May 07, 2017
https://issues.dlang.org/show_bug.cgi?id=16856

github-bugzilla@puremagic.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|---                         |FIXED

--
May 14, 2017
https://issues.dlang.org/show_bug.cgi?id=16856

Jonathan M Davis <issues.dlang@jmdavisProg.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|RESOLVED                    |REOPENED
         Resolution|FIXED                       |---

--- Comment #6 from Jonathan M Davis <issues.dlang@jmdavisProg.com> ---
Well, while the fix seems to have improved the situation, I'm sorry to report that the unit tests for druntime and Phobos still result in bus errors on FreeBSD CURRENT. So, it looks like the fix was insufficient. :(

--
May 21, 2017
https://issues.dlang.org/show_bug.cgi?id=16856

--- Comment #7 from Nemanja Boric <4burgos@gmail.com> ---
Ha, that's a bummer. I'm on a holiday right now with limited access to workstation, but I'll give it a look in early June.

--
June 17, 2017
https://issues.dlang.org/show_bug.cgi?id=16856

--- Comment #8 from github-bugzilla@puremagic.com ---
Commits pushed to stable at https://github.com/dlang/druntime

https://github.com/dlang/druntime/commit/c56e8e0d8d599b1742fe85210f07adacf07e5e2a Fix issue 16856: Apply correct alignment on the Unwind_Exception structure

https://github.com/dlang/druntime/commit/c7182eb2ef3d6cc57c3e3366028753306b4dceb7 Merge pull request #1823 from Burgos/exception_alignment

--
June 17, 2017
https://issues.dlang.org/show_bug.cgi?id=16856

github-bugzilla@puremagic.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|REOPENED                    |RESOLVED
         Resolution|---                         |FIXED

--
« First   ‹ Prev
1 2 3